div TODOs
This commit is contained in:
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -1,175 +1,199 @@
|
||||
<?php
|
||||
/**
|
||||
* 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';
|
||||
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':
|
||||
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;
|
||||
jsonError('Unbekannte Aktion', 400);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Aktionen
|
||||
* ========================= */
|
||||
|
||||
/**
|
||||
* Lädt alle Ports eines Gerätetyps
|
||||
*/
|
||||
function loadPorts($sql)
|
||||
function jsonError(string $message, int $status = 400): void
|
||||
{
|
||||
$deviceTypeId = $_GET['device_type_id'] ?? null;
|
||||
http_response_code($status);
|
||||
echo json_encode(['error' => $message]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!$deviceTypeId) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'device_type_id fehlt']);
|
||||
return;
|
||||
function loadPorts($sql): void
|
||||
{
|
||||
$deviceTypeId = isset($_GET['device_type_id']) ? (int)$_GET['device_type_id'] : 0;
|
||||
if ($deviceTypeId <= 0) {
|
||||
jsonError('device_type_id fehlt', 400);
|
||||
}
|
||||
|
||||
$ports = $sql->get(
|
||||
"SELECT
|
||||
id,
|
||||
name,
|
||||
port_type_id,
|
||||
pos_x,
|
||||
pos_y,
|
||||
comment
|
||||
'SELECT id, name, port_type_id, x, y, metadata
|
||||
FROM device_type_ports
|
||||
WHERE device_type_id = ?
|
||||
ORDER BY id ASC",
|
||||
"i",
|
||||
ORDER BY id ASC',
|
||||
'i',
|
||||
[$deviceTypeId]
|
||||
);
|
||||
|
||||
echo json_encode($ports);
|
||||
echo json_encode($ports ?: []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Speichert alle Ports eines Gerätetyps
|
||||
* (Bulk-Save aus dem SVG-Editor)
|
||||
*/
|
||||
function savePorts($sql)
|
||||
function validatePortTypeId($sql, $portTypeId): ?int
|
||||
{
|
||||
$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;
|
||||
if ($portTypeId === null || $portTypeId === '' || (int)$portTypeId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$deviceTypeId = $data['device_type_id'];
|
||||
$ports = $data['ports'];
|
||||
$value = (int)$portTypeId;
|
||||
$exists = $sql->single('SELECT id FROM port_types WHERE id = ?', 'i', [$value]);
|
||||
if (!$exists) {
|
||||
jsonError('port_type_id ist ungueltig', 400);
|
||||
}
|
||||
|
||||
// TODO: Transaktion starten (falls SQL-Klasse das unterstützt)
|
||||
return $value;
|
||||
}
|
||||
|
||||
foreach ($ports as $port) {
|
||||
function savePorts($sql): void
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
jsonError('Methode nicht erlaubt', 405);
|
||||
}
|
||||
|
||||
// TODO: Validierung:
|
||||
// - name nicht leer
|
||||
// - pos_x / pos_y numerisch
|
||||
// - port_type_id erlaubt
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
if (!is_array($data) || empty($data['device_type_id']) || !isset($data['ports']) || !is_array($data['ports'])) {
|
||||
jsonError('Ungueltige Daten', 400);
|
||||
}
|
||||
|
||||
if (!empty($port['id']) && !str_starts_with($port['id'], 'tmp_')) {
|
||||
$deviceTypeId = (int)$data['device_type_id'];
|
||||
if ($deviceTypeId <= 0) {
|
||||
jsonError('device_type_id ist ungueltig', 400);
|
||||
}
|
||||
|
||||
/* ---------- 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
|
||||
]
|
||||
$deviceType = $sql->single('SELECT id FROM device_types WHERE id = ?', 'i', [$deviceTypeId]);
|
||||
if (!$deviceType) {
|
||||
jsonError('Geraetetyp existiert nicht', 404);
|
||||
}
|
||||
|
||||
$sql->set('START TRANSACTION');
|
||||
|
||||
foreach ($data['ports'] as $index => $port) {
|
||||
if (!is_array($port)) {
|
||||
$sql->set('ROLLBACK');
|
||||
jsonError('Port-Eintrag an Position ' . $index . ' ist ungueltig', 400);
|
||||
}
|
||||
|
||||
$name = trim((string)($port['name'] ?? ''));
|
||||
if ($name === '') {
|
||||
$sql->set('ROLLBACK');
|
||||
jsonError('Port-Name darf nicht leer sein', 400);
|
||||
}
|
||||
|
||||
$x = $port['x'] ?? null;
|
||||
$y = $port['y'] ?? null;
|
||||
if (!is_numeric($x) || !is_numeric($y)) {
|
||||
$sql->set('ROLLBACK');
|
||||
jsonError('x und y muessen numerisch sein', 400);
|
||||
}
|
||||
|
||||
$x = (int)round((float)$x);
|
||||
$y = (int)round((float)$y);
|
||||
$portTypeId = validatePortTypeId($sql, $port['port_type_id'] ?? null);
|
||||
|
||||
$metadataRaw = $port['metadata'] ?? null;
|
||||
$metadata = null;
|
||||
if (is_array($metadataRaw)) {
|
||||
$metadata = json_encode($metadataRaw);
|
||||
} elseif (is_string($metadataRaw) && $metadataRaw !== '') {
|
||||
json_decode($metadataRaw, true);
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
$sql->set('ROLLBACK');
|
||||
jsonError('metadata ist kein gueltiges JSON', 400);
|
||||
}
|
||||
$metadata = $metadataRaw;
|
||||
}
|
||||
|
||||
$isExisting = !empty($port['id']) && !str_starts_with((string)$port['id'], 'tmp_');
|
||||
if ($isExisting) {
|
||||
$portId = (int)$port['id'];
|
||||
$ok = $sql->set(
|
||||
'UPDATE device_type_ports
|
||||
SET name = ?, port_type_id = ?, x = ?, y = ?, metadata = ?
|
||||
WHERE id = ? AND device_type_id = ?',
|
||||
'siiisii',
|
||||
[$name, $portTypeId, $x, $y, $metadata, $portId, $deviceTypeId]
|
||||
);
|
||||
|
||||
} else {
|
||||
if ($ok === false) {
|
||||
$sql->set('ROLLBACK');
|
||||
jsonError('Update fehlgeschlagen', 500);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ---------- 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
|
||||
);
|
||||
$ok = $sql->set(
|
||||
'INSERT INTO device_type_ports (device_type_id, name, port_type_id, x, y, metadata)
|
||||
VALUES (?, ?, ?, ?, ?, ?)',
|
||||
'isiiis',
|
||||
[$deviceTypeId, $name, $portTypeId, $x, $y, $metadata],
|
||||
true
|
||||
);
|
||||
|
||||
if ($ok === false) {
|
||||
$sql->set('ROLLBACK');
|
||||
jsonError('Insert fehlgeschlagen', 500);
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'ok'
|
||||
]);
|
||||
$sql->set('COMMIT');
|
||||
|
||||
echo json_encode(['status' => 'ok']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht einen einzelnen Port
|
||||
*/
|
||||
function deletePort($sql)
|
||||
function deletePort($sql): void
|
||||
{
|
||||
$id = $_GET['id'] ?? null;
|
||||
|
||||
if (!$id) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'ID fehlt']);
|
||||
return;
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST' && $_SERVER['REQUEST_METHOD'] !== 'DELETE') {
|
||||
jsonError('Methode nicht erlaubt', 405);
|
||||
}
|
||||
|
||||
// TODO: Prüfen, ob Port existiert und nicht verwendet wird
|
||||
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||
if ($id <= 0) {
|
||||
jsonError('ID fehlt', 400);
|
||||
}
|
||||
|
||||
$rows = $sql->set(
|
||||
"DELETE FROM device_type_ports WHERE id = ?",
|
||||
"i",
|
||||
[$id]
|
||||
$port = $sql->single('SELECT id, device_type_id, name FROM device_type_ports WHERE id = ?', 'i', [$id]);
|
||||
if (!$port) {
|
||||
jsonError('Port existiert nicht', 404);
|
||||
}
|
||||
|
||||
$usage = $sql->single(
|
||||
'SELECT COUNT(*) AS cnt
|
||||
FROM devices d
|
||||
JOIN device_ports dp ON dp.device_id = d.id
|
||||
WHERE d.device_type_id = ? AND dp.name = ?',
|
||||
'is',
|
||||
[(int)$port['device_type_id'], (string)$port['name']]
|
||||
);
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'deleted',
|
||||
'rows' => $rows
|
||||
]);
|
||||
if (!empty($usage) && (int)$usage['cnt'] > 0) {
|
||||
jsonError('Port wird bereits von realen Geraeten genutzt und kann nicht geloescht werden', 409);
|
||||
}
|
||||
|
||||
$rows = $sql->set('DELETE FROM device_type_ports WHERE id = ?', 'i', [$id]);
|
||||
if ($rows === false) {
|
||||
jsonError('Loeschen fehlgeschlagen', 500);
|
||||
}
|
||||
|
||||
echo json_encode(['status' => 'deleted', 'rows' => $rows]);
|
||||
}
|
||||
|
||||
@@ -1,133 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* 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';
|
||||
requireAuth();
|
||||
|
||||
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
|
||||
$baseUploadDir = defined('UPLOAD_BASE_DIR') ? UPLOAD_BASE_DIR : (__DIR__ . '/../uploads');
|
||||
$maxFileSize = defined('UPLOAD_MAX_FILE_SIZE') ? (int)UPLOAD_MAX_FILE_SIZE : (5 * 1024 * 1024);
|
||||
$allowedCategories = defined('UPLOAD_ALLOWED_CATEGORIES') ? UPLOAD_ALLOWED_CATEGORIES : ['misc'];
|
||||
$allowedMimeTypes = [
|
||||
'image/svg+xml',
|
||||
'image/png',
|
||||
'image/jpeg'
|
||||
'image/svg+xml' => 'svg',
|
||||
'image/png' => 'png',
|
||||
'image/jpeg' => 'jpg',
|
||||
];
|
||||
|
||||
// TODO: Max. Dateigröße festlegen (z.B. 5MB)
|
||||
$maxFileSize = 5 * 1024 * 1024;
|
||||
|
||||
/* =========================
|
||||
* Validierung
|
||||
* ========================= */
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
jsonError('Methode nicht erlaubt', 405);
|
||||
}
|
||||
|
||||
if (empty($_FILES['file'])) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Keine Datei hochgeladen']);
|
||||
exit;
|
||||
jsonError('Keine Datei hochgeladen', 400);
|
||||
}
|
||||
|
||||
$file = $_FILES['file'];
|
||||
|
||||
if ($file['error'] !== UPLOAD_ERR_OK) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Upload-Fehler']);
|
||||
exit;
|
||||
if (!is_array($file) || $file['error'] !== UPLOAD_ERR_OK) {
|
||||
jsonError('Upload-Fehler', 400);
|
||||
}
|
||||
|
||||
if ($file['size'] > $maxFileSize) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'Datei zu groß']);
|
||||
exit;
|
||||
if ((int)$file['size'] > $maxFileSize) {
|
||||
jsonError('Datei zu gross', 400);
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (!isset($allowedMimeTypes[$mimeType])) {
|
||||
jsonError('Dateityp nicht erlaubt', 400);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* 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);
|
||||
$category = strtolower(trim((string)($_POST['category'] ?? 'misc')));
|
||||
if ($category === '' || !in_array($category, $allowedCategories, true)) {
|
||||
jsonError('Ungueltige Kategorie', 400);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Dateiname
|
||||
* ========================= */
|
||||
$targetDir = rtrim($baseUploadDir, '/\\') . DIRECTORY_SEPARATOR . $category;
|
||||
if (!is_dir($targetDir) && !mkdir($targetDir, 0755, true) && !is_dir($targetDir)) {
|
||||
jsonError('Upload-Verzeichnis konnte nicht erstellt werden', 500);
|
||||
}
|
||||
|
||||
// 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
|
||||
* ========================= */
|
||||
$extension = $allowedMimeTypes[$mimeType];
|
||||
$filename = sprintf('%s_%s.%s', $category, bin2hex(random_bytes(16)), $extension);
|
||||
$targetPath = $targetDir . DIRECTORY_SEPARATOR . $filename;
|
||||
|
||||
if (!move_uploaded_file($file['tmp_name'], $targetPath)) {
|
||||
http_response_code(500);
|
||||
echo json_encode(['error' => 'Datei konnte nicht gespeichert werden']);
|
||||
exit;
|
||||
jsonError('Datei konnte nicht gespeichert werden', 500);
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Optional: DB-Eintrag
|
||||
* ========================= */
|
||||
$publicPath = '/uploads/' . $category . '/' . $filename;
|
||||
$uploadId = null;
|
||||
|
||||
// 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
|
||||
* ========================= */
|
||||
$uploadTableExists = $sql->single("SHOW TABLES LIKE 'uploads'");
|
||||
if (!empty($uploadTableExists)) {
|
||||
$uploadId = $sql->set(
|
||||
'INSERT INTO uploads (filename, path, mime_type, category) VALUES (?, ?, ?, ?)',
|
||||
'ssss',
|
||||
[$filename, $publicPath, $mimeType, $category],
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'status' => 'ok',
|
||||
'filename' => $filename,
|
||||
'path' => str_replace(__DIR__ . '/..', '', $targetPath),
|
||||
'mime_type' => $mimeType
|
||||
// 'id' => $uploadId ?? null
|
||||
'path' => $publicPath,
|
||||
'mime_type' => $mimeType,
|
||||
'id' => $uploadId,
|
||||
]);
|
||||
|
||||
function jsonError(string $message, int $status = 400): void
|
||||
{
|
||||
http_response_code($status);
|
||||
echo json_encode(['error' => $message]);
|
||||
exit;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user