div TODOs

This commit is contained in:
2026-02-16 13:56:01 +01:00
parent 12141485ae
commit 510a248edb
36 changed files with 1500 additions and 1533 deletions

View File

@@ -1,194 +1,273 @@
<?php
/**
* app/api/connections.php
*
* API für Netzwerkverbindungen (Port ↔ Port)
* - Laden der Topologie
* - Anlegen / Bearbeiten / Löschen von Verbindungen
* - Unterstützt freie Verbindungstypen (Kupfer, LWL, BNC, Token Ring, etc.)
*/
require_once __DIR__ . '/../bootstrap.php';
requireAuth();
header('Content-Type: application/json');
// TODO: Single-User-Auth prüfen
// if (!$_SESSION['user']) { http_response_code(403); exit; }
$action = $_GET['action'] ?? 'load';
/* =========================
* Router
* ========================= */
switch ($action) {
case 'load':
loadConnections($sql);
break;
case 'save':
saveConnection($sql);
break;
case 'delete':
deleteConnection($sql);
break;
default:
http_response_code(400);
echo json_encode(['error' => 'Unbekannte Aktion']);
break;
jsonError('Unbekannte Aktion', 400);
}
/* =========================
* Aktionen
* ========================= */
/**
* Lädt alle Geräte + Ports + Verbindungen für eine Netzwerkansicht
*/
function loadConnections($sql)
function jsonError(string $message, int $status = 400): void
{
$contextId = $_GET['context_id'] ?? null;
http_response_code($status);
echo json_encode(['error' => $message]);
exit;
}
if (!$contextId) {
http_response_code(400);
echo json_encode(['error' => 'context_id fehlt']);
return;
function normalizeEndpointType(string $type): ?string
{
$map = [
'device' => 'device',
'device_ports' => 'device',
'module' => 'module',
'module_ports' => 'module',
'outlet' => 'outlet',
'network_outlet_ports' => 'outlet',
'patchpanel' => 'patchpanel',
'floor_patchpanel_ports' => 'patchpanel',
];
$key = strtolower(trim($type));
return $map[$key] ?? null;
}
function endpointExists($sql, string $type, int $id): bool
{
if ($id <= 0) {
return false;
}
// TODO: Kontext definieren (Standort, Rack, Floor, gesamtes Netz)
if ($type === 'device') {
$row = $sql->single('SELECT id FROM device_ports WHERE id = ?', 'i', [$id]);
return !empty($row);
}
if ($type === 'module') {
$row = $sql->single('SELECT id FROM module_ports WHERE id = ?', 'i', [$id]);
return !empty($row);
}
if ($type === 'outlet') {
$row = $sql->single('SELECT id FROM network_outlet_ports WHERE id = ?', 'i', [$id]);
return !empty($row);
}
if ($type === 'patchpanel') {
$row = $sql->single('SELECT id FROM floor_patchpanel_ports WHERE id = ?', 'i', [$id]);
return !empty($row);
}
return false;
}
function loadConnections($sql): void
{
$contextType = strtolower(trim((string)($_GET['context_type'] ?? 'all')));
$contextId = isset($_GET['context_id']) ? (int)$_GET['context_id'] : 0;
$where = '';
$bindType = '';
$bindValues = [];
if ($contextType !== 'all') {
if ($contextId <= 0) {
jsonError('context_id fehlt oder ist ungueltig', 400);
}
if ($contextType === 'location') {
$where = ' WHERE b.location_id = ?';
$bindType = 'i';
$bindValues = [$contextId];
} elseif ($contextType === 'building') {
$where = ' WHERE f.building_id = ?';
$bindType = 'i';
$bindValues = [$contextId];
} elseif ($contextType === 'floor') {
$where = ' WHERE r.floor_id = ?';
$bindType = 'i';
$bindValues = [$contextId];
} elseif ($contextType === 'rack') {
$where = ' WHERE d.rack_id = ?';
$bindType = 'i';
$bindValues = [$contextId];
} else {
jsonError('Ungueltiger Kontext. Erlaubt: all, location, building, floor, rack', 400);
}
}
/* ---------- Geräte ---------- */
$devices = $sql->get(
"SELECT id, name, device_type_id, pos_x, pos_y
FROM devices
WHERE context_id = ?",
"i",
[$contextId]
"SELECT d.id, d.name, d.device_type_id, d.rack_id, 0 AS pos_x, 0 AS pos_y
FROM devices d
LEFT JOIN racks r ON r.id = d.rack_id
LEFT JOIN floors f ON f.id = r.floor_id
LEFT JOIN buildings b ON b.id = f.building_id" . $where,
$bindType,
$bindValues
);
/* ---------- Ports ---------- */
$ports = $sql->get(
"SELECT p.id, p.device_id, p.name, p.port_type_id
FROM ports p
JOIN devices d ON d.id = p.device_id
WHERE d.context_id = ?",
"i",
[$contextId]
"SELECT dp.id, dp.device_id, dp.name, dp.port_type_id
FROM device_ports dp
JOIN devices d ON d.id = dp.device_id
LEFT JOIN racks r ON r.id = d.rack_id
LEFT JOIN floors f ON f.id = r.floor_id
LEFT JOIN buildings b ON b.id = f.building_id" . $where,
$bindType,
$bindValues
);
/* ---------- Verbindungen ---------- */
$connections = $sql->get(
"SELECT
c.id,
c.connection_type_id,
c.port_a_id,
c.port_b_id,
c.vlan,
c.mode,
c.comment
FROM connections c",
"",
"SELECT id, connection_type_id, port_a_type, port_a_id, port_b_type, port_b_id, vlan_config, mode, comment
FROM connections",
'',
[]
);
echo json_encode([
'devices' => $devices,
'ports' => $ports,
'connections' => $connections
'devices' => $devices ?: [],
'ports' => $ports ?: [],
'connections' => $connections ?: []
]);
}
/**
* Speichert eine Verbindung (neu oder Update)
*/
function saveConnection($sql)
function resolveConnectionTypeId($sql, array $data): int
{
$data = json_decode(file_get_contents('php://input'), true);
if (!$data) {
http_response_code(400);
echo json_encode(['error' => 'Ungültige JSON-Daten']);
return;
if (!empty($data['connection_type_id'])) {
$requestedId = (int)$data['connection_type_id'];
$exists = $sql->single('SELECT id FROM connection_types WHERE id = ?', 'i', [$requestedId]);
if (!$exists) {
jsonError('connection_type_id existiert nicht', 400);
}
return $requestedId;
}
// TODO: Validierung
// - port_a_id vorhanden
// - port_b_id vorhanden
// - Verbindungstyp erlaubt
$defaultType = $sql->single('SELECT id FROM connection_types ORDER BY id ASC LIMIT 1');
if (!$defaultType) {
jsonError('Kein Verbindungstyp vorhanden', 400);
}
return (int)$defaultType['id'];
}
function saveConnection($sql): void
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
jsonError('Methode nicht erlaubt', 405);
}
$data = json_decode(file_get_contents('php://input'), true);
if (!is_array($data)) {
jsonError('Ungueltige JSON-Daten', 400);
}
$portAType = normalizeEndpointType((string)($data['port_a_type'] ?? ''));
$portBType = normalizeEndpointType((string)($data['port_b_type'] ?? ''));
$portAId = (int)($data['port_a_id'] ?? 0);
$portBId = (int)($data['port_b_id'] ?? 0);
if ($portAType === null || $portBType === null) {
jsonError('port_a_type/port_b_type ungueltig', 400);
}
if ($portAId <= 0 || $portBId <= 0) {
jsonError('port_a_id und port_b_id sind erforderlich', 400);
}
if ($portAType === $portBType && $portAId === $portBId) {
jsonError('Port A und Port B duerfen nicht identisch sein', 400);
}
if (!endpointExists($sql, $portAType, $portAId) || !endpointExists($sql, $portBType, $portBId)) {
jsonError('Mindestens ein Endpunkt existiert nicht', 400);
}
$connectionTypeId = resolveConnectionTypeId($sql, $data);
$vlanConfig = $data['vlan_config'] ?? null;
if (is_array($vlanConfig)) {
$vlanConfig = json_encode($vlanConfig);
} elseif (!is_string($vlanConfig) && $vlanConfig !== null) {
jsonError('vlan_config muss String, Array oder null sein', 400);
}
$mode = isset($data['mode']) ? (string)$data['mode'] : null;
$comment = isset($data['comment']) ? (string)$data['comment'] : null;
if (!empty($data['id'])) {
// UPDATE
$id = (int)$data['id'];
$existing = $sql->single('SELECT id FROM connections WHERE id = ?', 'i', [$id]);
if (!$existing) {
jsonError('Verbindung existiert nicht', 404);
}
$rows = $sql->set(
"UPDATE connections
SET connection_type_id = ?, port_a_id = ?, port_b_id = ?, vlan = ?, mode = ?, comment = ?
WHERE id = ?",
"iiiissi",
[
$data['connection_type_id'],
$data['port_a_id'],
$data['port_b_id'],
$data['vlan'],
$data['mode'],
$data['comment'],
$data['id']
]
'UPDATE connections
SET connection_type_id = ?, port_a_type = ?, port_a_id = ?, port_b_type = ?, port_b_id = ?, vlan_config = ?, mode = ?, comment = ?
WHERE id = ?',
'isisisssi',
[$connectionTypeId, $portAType, $portAId, $portBType, $portBId, $vlanConfig, $mode, $comment, $id]
);
echo json_encode([
'status' => 'updated',
'rows' => $rows
]);
} else {
// INSERT
$id = $sql->set(
"INSERT INTO connections
(connection_type_id, port_a_id, port_b_id, vlan, mode, comment)
VALUES (?, ?, ?, ?, ?, ?)",
"iiiiss",
[
$data['connection_type_id'],
$data['port_a_id'],
$data['port_b_id'],
$data['vlan'],
$data['mode'],
$data['comment']
],
true
);
if ($rows === false) {
jsonError('Update fehlgeschlagen', 500);
}
echo json_encode([
'status' => 'created',
'id' => $id
]);
}
}
/**
* Löscht eine Verbindung
*/
function deleteConnection($sql)
{
$id = $_GET['id'] ?? null;
if (!$id) {
http_response_code(400);
echo json_encode(['error' => 'ID fehlt']);
echo json_encode(['status' => 'updated', 'rows' => $rows]);
return;
}
// TODO: Prüfen, ob Verbindung existiert
$rows = $sql->set(
"DELETE FROM connections WHERE id = ?",
"i",
[$id]
$id = $sql->set(
'INSERT INTO connections (connection_type_id, port_a_type, port_a_id, port_b_type, port_b_id, vlan_config, mode, comment)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
'isisisss',
[$connectionTypeId, $portAType, $portAId, $portBType, $portBId, $vlanConfig, $mode, $comment],
true
);
echo json_encode([
'status' => 'deleted',
'rows' => $rows
]);
if ($id === false) {
jsonError('Insert fehlgeschlagen', 500);
}
echo json_encode(['status' => 'created', 'id' => $id]);
}
function deleteConnection($sql): void
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST' && $_SERVER['REQUEST_METHOD'] !== 'DELETE') {
jsonError('Methode nicht erlaubt', 405);
}
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if ($id <= 0) {
jsonError('ID fehlt', 400);
}
$existing = $sql->single('SELECT id FROM connections WHERE id = ?', 'i', [$id]);
if (!$existing) {
jsonError('Verbindung existiert nicht', 404);
}
$rows = $sql->set('DELETE FROM connections WHERE id = ?', 'i', [$id]);
if ($rows === false) {
jsonError('Loeschen fehlgeschlagen', 500);
}
echo json_encode(['status' => 'deleted', 'rows' => $rows]);
}