feat: Implement API for managing network connections, device types, and uploads

This commit is contained in:
Troy Grunt
2026-02-06 17:56:57 +01:00
parent 5066262fca
commit 3ec3ad7fa5
11 changed files with 1460 additions and 11 deletions

View File

@@ -1,2 +1,194 @@
<?php
// API für Verbindungsdaten (Netzwerkansicht)
/**
* 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';
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;
}
/* =========================
* Aktionen
* ========================= */
/**
* Lädt alle Geräte + Ports + Verbindungen für eine Netzwerkansicht
*/
function loadConnections($sql)
{
$contextId = $_GET['context_id'] ?? null;
if (!$contextId) {
http_response_code(400);
echo json_encode(['error' => 'context_id fehlt']);
return;
}
// TODO: Kontext definieren (Standort, Rack, Floor, gesamtes Netz)
/* ---------- Geräte ---------- */
$devices = $sql->get(
"SELECT id, name, device_type_id, pos_x, pos_y
FROM devices
WHERE context_id = ?",
"i",
[$contextId]
);
/* ---------- 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]
);
/* ---------- 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",
"",
[]
);
echo json_encode([
'devices' => $devices,
'ports' => $ports,
'connections' => $connections
]);
}
/**
* Speichert eine Verbindung (neu oder Update)
*/
function saveConnection($sql)
{
$data = json_decode(file_get_contents('php://input'), true);
if (!$data) {
http_response_code(400);
echo json_encode(['error' => 'Ungültige JSON-Daten']);
return;
}
// TODO: Validierung
// - port_a_id vorhanden
// - port_b_id vorhanden
// - Verbindungstyp erlaubt
if (!empty($data['id'])) {
// UPDATE
$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']
]
);
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
);
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']);
return;
}
// TODO: Prüfen, ob Verbindung existiert
$rows = $sql->set(
"DELETE FROM connections WHERE id = ?",
"i",
[$id]
);
echo json_encode([
'status' => 'deleted',
'rows' => $rows
]);
}

View File

@@ -1,2 +1,175 @@
<?php
// Laden und Speichern von Port-Punkten für den SVG-Port-Editor
/**
* app/api/device_type_ports.php
*
* API für Ports von Gerätetypen
* - Laden der Port-Definitionen (SVG-Port-Editor)
* - Speichern (Position, Typ, Name)
* - Löschen einzelner Ports
*/
require_once __DIR__ . '/../bootstrap.php';
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':
loadPorts($sql);
break;
case 'save':
savePorts($sql);
break;
case 'delete':
deletePort($sql);
break;
default:
http_response_code(400);
echo json_encode(['error' => 'Unbekannte Aktion']);
break;
}
/* =========================
* Aktionen
* ========================= */
/**
* Lädt alle Ports eines Gerätetyps
*/
function loadPorts($sql)
{
$deviceTypeId = $_GET['device_type_id'] ?? null;
if (!$deviceTypeId) {
http_response_code(400);
echo json_encode(['error' => 'device_type_id fehlt']);
return;
}
$ports = $sql->get(
"SELECT
id,
name,
port_type_id,
pos_x,
pos_y,
comment
FROM device_type_ports
WHERE device_type_id = ?
ORDER BY id ASC",
"i",
[$deviceTypeId]
);
echo json_encode($ports);
}
/**
* Speichert alle Ports eines Gerätetyps
* (Bulk-Save aus dem SVG-Editor)
*/
function savePorts($sql)
{
$data = json_decode(file_get_contents('php://input'), true);
if (!$data || empty($data['device_type_id']) || !is_array($data['ports'])) {
http_response_code(400);
echo json_encode(['error' => 'Ungültige Daten']);
return;
}
$deviceTypeId = $data['device_type_id'];
$ports = $data['ports'];
// TODO: Transaktion starten (falls SQL-Klasse das unterstützt)
foreach ($ports as $port) {
// TODO: Validierung:
// - name nicht leer
// - pos_x / pos_y numerisch
// - port_type_id erlaubt
if (!empty($port['id']) && !str_starts_with($port['id'], 'tmp_')) {
/* ---------- UPDATE ---------- */
$sql->set(
"UPDATE device_type_ports
SET name = ?, port_type_id = ?, pos_x = ?, pos_y = ?, comment = ?
WHERE id = ? AND device_type_id = ?",
"siddsii",
[
$port['name'],
$port['port_type_id'],
$port['x'],
$port['y'],
$port['comment'],
$port['id'],
$deviceTypeId
]
);
} else {
/* ---------- INSERT ---------- */
$sql->set(
"INSERT INTO device_type_ports
(device_type_id, name, port_type_id, pos_x, pos_y, comment)
VALUES (?, ?, ?, ?, ?, ?)",
"isidds",
[
$deviceTypeId,
$port['name'],
$port['port_type_id'],
$port['x'],
$port['y'],
$port['comment']
],
true
);
}
}
echo json_encode([
'status' => 'ok'
]);
}
/**
* Löscht einen einzelnen Port
*/
function deletePort($sql)
{
$id = $_GET['id'] ?? null;
if (!$id) {
http_response_code(400);
echo json_encode(['error' => 'ID fehlt']);
return;
}
// TODO: Prüfen, ob Port existiert und nicht verwendet wird
$rows = $sql->set(
"DELETE FROM device_type_ports WHERE id = ?",
"i",
[$id]
);
echo json_encode([
'status' => 'deleted',
'rows' => $rows
]);
}

View File

@@ -1,2 +1,133 @@
<?php
// Datei-Upload für Gerätebilder und SVGs
/**
* app/api/upload.php
*
* Zentrale Upload-API
* - Gerätetyp-Bilder (SVG / JPG / PNG)
* - Floorpläne (SVG)
* - Rack-Ansichten
*
* KEINE Logik für automatische Zuordnung
* -> Upload + Rückgabe von Pfad / Metadaten
*/
require_once __DIR__ . '/../bootstrap.php';
header('Content-Type: application/json');
// TODO: Single-User-Auth prüfen
// if (!$_SESSION['user']) { http_response_code(403); exit; }
/* =========================
* Konfiguration
* ========================= */
// TODO: Upload-Basisverzeichnis aus config.php
$baseUploadDir = __DIR__ . '/../uploads';
// Erlaubte Typen
$allowedMimeTypes = [
'image/svg+xml',
'image/png',
'image/jpeg'
];
// TODO: Max. Dateigröße festlegen (z.B. 5MB)
$maxFileSize = 5 * 1024 * 1024;
/* =========================
* Validierung
* ========================= */
if (empty($_FILES['file'])) {
http_response_code(400);
echo json_encode(['error' => 'Keine Datei hochgeladen']);
exit;
}
$file = $_FILES['file'];
if ($file['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
echo json_encode(['error' => 'Upload-Fehler']);
exit;
}
if ($file['size'] > $maxFileSize) {
http_response_code(400);
echo json_encode(['error' => 'Datei zu groß']);
exit;
}
// MIME-Type prüfen
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
if (!in_array($mimeType, $allowedMimeTypes)) {
http_response_code(400);
echo json_encode(['error' => 'Dateityp nicht erlaubt']);
exit;
}
/* =========================
* Zielverzeichnis
* ========================= */
// TODO: Kategorie definieren (device_types, floors, racks, etc.)
$category = $_POST['category'] ?? 'misc';
// Zielpfad
$targetDir = $baseUploadDir . '/' . preg_replace('/[^a-z0-9_-]/i', '', $category);
// Verzeichnis anlegen falls nötig
if (!is_dir($targetDir)) {
mkdir($targetDir, 0755, true);
}
/* =========================
* Dateiname
* ========================= */
// Originalname bereinigen
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
// TODO: Eindeutigen Namen besser definieren (UUID?)
$filename = uniqid('upload_', true) . '.' . strtolower($extension);
$targetPath = $targetDir . '/' . $filename;
/* =========================
* Datei speichern
* ========================= */
if (!move_uploaded_file($file['tmp_name'], $targetPath)) {
http_response_code(500);
echo json_encode(['error' => 'Datei konnte nicht gespeichert werden']);
exit;
}
/* =========================
* Optional: DB-Eintrag
* ========================= */
// TODO: Optional in Tabelle `uploads` speichern
// $uploadId = $sql->set(
// "INSERT INTO uploads (filename, path, mime_type, category)
// VALUES (?, ?, ?, ?)",
// "ssss",
// [$filename, $targetPath, $mimeType, $category],
// true
// );
/* =========================
* Antwort
* ========================= */
echo json_encode([
'status' => 'ok',
'filename' => $filename,
'path' => str_replace(__DIR__ . '/..', '', $targetPath),
'mime_type' => $mimeType
// 'id' => $uploadId ?? null
]);