Enforce topology rules and fix device deletion flow
This commit is contained in:
4
NEXT.md
4
NEXT.md
@@ -1,14 +1,10 @@
|
|||||||
# NEXT_STEPS
|
# NEXT_STEPS
|
||||||
|
|
||||||
## Aktive Aufgaben (priorisiert)
|
## Aktive Aufgaben (priorisiert)
|
||||||
- [ ] [#11] Encoding- und Umlautfehler bereinigen (inkl. Anzeige in UI-Dateien und Markdown-Dokumenten)
|
|
||||||
|
|
||||||
## Verifikation (Status unklar, nicht als erledigt markieren ohne Reproduktion + Commit)
|
## Verifikation (Status unklar, nicht als erledigt markieren ohne Reproduktion + Commit)
|
||||||
- [ ] [#15] Neue Verbindung: Netzwerkdose auswählbar (Regressionstest in UI durchführen)
|
- [ ] [#15] Neue Verbindung: Netzwerkdose auswählbar (Regressionstest in UI durchführen)
|
||||||
|
|
||||||
## gefundene bugs
|
## gefundene bugs
|
||||||
- [ ] device löschen geht nicht
|
|
||||||
- [ ] TODO Design vereinheitlichen
|
- [ ] TODO Design vereinheitlichen
|
||||||
|
|
||||||
|
|
||||||
- [ ] Validierungsregeln fuer Topologie fest verdrahten (Patchpanel-Port nur mit Patchpanel-Port oder Netzwerkbuchsen-Port).
|
|
||||||
|
|||||||
@@ -77,6 +77,19 @@ function endpointExists($sql, string $type, int $id): bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isTopologyPairAllowed(string $typeA, string $typeB): bool
|
||||||
|
{
|
||||||
|
$allowed = ['device' => true, 'module' => true, 'outlet' => true, 'patchpanel' => true];
|
||||||
|
if (!isset($allowed[$typeA]) || !isset($allowed[$typeB])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($typeA === 'patchpanel' || $typeB === 'patchpanel') {
|
||||||
|
return ($typeA === 'patchpanel' && in_array($typeB, ['patchpanel', 'outlet'], true))
|
||||||
|
|| ($typeB === 'patchpanel' && in_array($typeA, ['patchpanel', 'outlet'], true));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function loadConnections($sql): void
|
function loadConnections($sql): void
|
||||||
{
|
{
|
||||||
$contextType = strtolower(trim((string)($_GET['context_type'] ?? 'all')));
|
$contextType = strtolower(trim((string)($_GET['context_type'] ?? 'all')));
|
||||||
@@ -189,6 +202,9 @@ function saveConnection($sql): void
|
|||||||
if ($portAId <= 0 || $portBId <= 0) {
|
if ($portAId <= 0 || $portBId <= 0) {
|
||||||
jsonError('port_a_id und port_b_id sind erforderlich', 400);
|
jsonError('port_a_id und port_b_id sind erforderlich', 400);
|
||||||
}
|
}
|
||||||
|
if (!isTopologyPairAllowed($portAType, $portBType)) {
|
||||||
|
jsonError('Patchpanel-Ports duerfen nur mit Patchpanel-Ports oder Netzwerkdosen-Ports verbunden werden', 400);
|
||||||
|
}
|
||||||
|
|
||||||
if ($portAType === $portBType && $portAId === $portBId) {
|
if ($portAType === $portBType && $portAId === $portBId) {
|
||||||
jsonError('Port A und Port B duerfen nicht identisch sein', 400);
|
jsonError('Port A und Port B duerfen nicht identisch sein', 400);
|
||||||
|
|||||||
@@ -51,8 +51,49 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function enforceTopologyTypeRules(typeA, typeB) {
|
||||||
|
const allowWithPatchpanel = { patchpanel: true, outlet: true };
|
||||||
|
const selectedA = typeA.value;
|
||||||
|
const selectedB = typeB.value;
|
||||||
|
|
||||||
|
const applyRules = (sourceType, targetSelect) => {
|
||||||
|
for (const option of targetSelect.options) {
|
||||||
|
const value = option.value;
|
||||||
|
if (!value) {
|
||||||
|
option.disabled = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (sourceType === 'patchpanel') {
|
||||||
|
option.disabled = !allowWithPatchpanel[value];
|
||||||
|
} else {
|
||||||
|
option.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetSelect.selectedOptions.length > 0 && targetSelect.selectedOptions[0].disabled) {
|
||||||
|
targetSelect.value = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
applyRules(selectedA, typeB);
|
||||||
|
applyRules(selectedB, typeA);
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
bindPair('port_a_type', 'port_a_id');
|
bindPair('port_a_type', 'port_a_id');
|
||||||
bindPair('port_b_type', 'port_b_id');
|
bindPair('port_b_type', 'port_b_id');
|
||||||
|
|
||||||
|
const typeA = document.getElementById('port_a_type');
|
||||||
|
const typeB = document.getElementById('port_b_type');
|
||||||
|
if (!typeA || !typeB) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncRules = () => {
|
||||||
|
enforceTopologyTypeRules(typeA, typeB);
|
||||||
|
};
|
||||||
|
|
||||||
|
syncRules();
|
||||||
|
typeA.addEventListener('change', syncRules);
|
||||||
|
typeB.addEventListener('change', syncRules);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -42,6 +42,18 @@ $normalizePortType = static function (string $value): string {
|
|||||||
$portAType = $normalizePortType((string)$portAType);
|
$portAType = $normalizePortType((string)$portAType);
|
||||||
$portBType = $normalizePortType((string)$portBType);
|
$portBType = $normalizePortType((string)$portBType);
|
||||||
|
|
||||||
|
$isTopologyPairAllowed = static function (string $typeA, string $typeB): bool {
|
||||||
|
$allowed = ['device' => true, 'module' => true, 'outlet' => true, 'patchpanel' => true];
|
||||||
|
if (!isset($allowed[$typeA]) || !isset($allowed[$typeB])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ($typeA === 'patchpanel' || $typeB === 'patchpanel') {
|
||||||
|
return ($typeA === 'patchpanel' && in_array($typeB, ['patchpanel', 'outlet'], true))
|
||||||
|
|| ($typeB === 'patchpanel' && in_array($typeA, ['patchpanel', 'outlet'], true));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// =========================
|
// =========================
|
||||||
// Validierung (einfach)
|
// Validierung (einfach)
|
||||||
// =========================
|
// =========================
|
||||||
@@ -50,6 +62,9 @@ $errors = [];
|
|||||||
if ($portAId <= 0 || $portBId <= 0) {
|
if ($portAId <= 0 || $portBId <= 0) {
|
||||||
$errors[] = "Beide Ports sind erforderlich";
|
$errors[] = "Beide Ports sind erforderlich";
|
||||||
}
|
}
|
||||||
|
if (!$isTopologyPairAllowed($portAType, $portBType)) {
|
||||||
|
$errors[] = "Patchpanel-Ports duerfen nur mit Patchpanel-Ports oder Netzwerkdosen-Ports verbunden werden";
|
||||||
|
}
|
||||||
|
|
||||||
$otherConnections = $sql->get(
|
$otherConnections = $sql->get(
|
||||||
"SELECT id, port_a_type, port_a_id, port_b_type, port_b_id
|
"SELECT id, port_a_type, port_a_id, port_b_type, port_b_id
|
||||||
|
|||||||
@@ -56,10 +56,10 @@ $dependencies = $sql->single(
|
|||||||
(
|
(
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM connections c
|
FROM connections c
|
||||||
WHERE (c.port_a_type = 'device' AND c.port_a_id IN (
|
WHERE ((c.port_a_type = 'device' OR c.port_a_type = 'device_ports') AND c.port_a_id IN (
|
||||||
SELECT dp3.id FROM device_ports dp3 WHERE dp3.device_id = ?
|
SELECT dp3.id FROM device_ports dp3 WHERE dp3.device_id = ?
|
||||||
))
|
))
|
||||||
OR (c.port_b_type = 'device' AND c.port_b_id IN (
|
OR ((c.port_b_type = 'device' OR c.port_b_type = 'device_ports') AND c.port_b_id IN (
|
||||||
SELECT dp4.id FROM device_ports dp4 WHERE dp4.device_id = ?
|
SELECT dp4.id FROM device_ports dp4 WHERE dp4.device_id = ?
|
||||||
))
|
))
|
||||||
) AS connection_count",
|
) AS connection_count",
|
||||||
@@ -108,8 +108,8 @@ if ($hasDependencies && !$forceDelete) {
|
|||||||
// Connections referenzieren device_ports nur logisch, daher manuell entfernen.
|
// Connections referenzieren device_ports nur logisch, daher manuell entfernen.
|
||||||
$sql->set(
|
$sql->set(
|
||||||
"DELETE FROM connections
|
"DELETE FROM connections
|
||||||
WHERE (port_a_type = 'device' AND port_a_id IN (SELECT id FROM device_ports WHERE device_id = ?))
|
WHERE ((port_a_type = 'device' OR port_a_type = 'device_ports') AND port_a_id IN (SELECT id FROM device_ports WHERE device_id = ?))
|
||||||
OR (port_b_type = 'device' AND port_b_id IN (SELECT id FROM device_ports WHERE device_id = ?))",
|
OR ((port_b_type = 'device' OR port_b_type = 'device_ports') AND port_b_id IN (SELECT id FROM device_ports WHERE device_id = ?))",
|
||||||
"ii",
|
"ii",
|
||||||
[$deviceId, $deviceId]
|
[$deviceId, $deviceId]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ if ($isEdit) {
|
|||||||
(
|
(
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM connections c
|
FROM connections c
|
||||||
WHERE (c.port_a_type = 'device' AND c.port_a_id IN (
|
WHERE ((c.port_a_type = 'device' OR c.port_a_type = 'device_ports') AND c.port_a_id IN (
|
||||||
SELECT dp3.id FROM device_ports dp3 WHERE dp3.device_id = ?
|
SELECT dp3.id FROM device_ports dp3 WHERE dp3.device_id = ?
|
||||||
))
|
))
|
||||||
OR (c.port_b_type = 'device' AND c.port_b_id IN (
|
OR ((c.port_b_type = 'device' OR c.port_b_type = 'device_ports') AND c.port_b_id IN (
|
||||||
SELECT dp4.id FROM device_ports dp4 WHERE dp4.device_id = ?
|
SELECT dp4.id FROM device_ports dp4 WHERE dp4.device_id = ?
|
||||||
))
|
))
|
||||||
) AS connection_count",
|
) AS connection_count",
|
||||||
|
|||||||
@@ -97,10 +97,10 @@ $devices = $sql->get(
|
|||||||
(
|
(
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM connections c
|
FROM connections c
|
||||||
WHERE (c.port_a_type = 'device' AND c.port_a_id IN (
|
WHERE ((c.port_a_type = 'device' OR c.port_a_type = 'device_ports') AND c.port_a_id IN (
|
||||||
SELECT dp3.id FROM device_ports dp3 WHERE dp3.device_id = d.id
|
SELECT dp3.id FROM device_ports dp3 WHERE dp3.device_id = d.id
|
||||||
))
|
))
|
||||||
OR (c.port_b_type = 'device' AND c.port_b_id IN (
|
OR ((c.port_b_type = 'device' OR c.port_b_type = 'device_ports') AND c.port_b_id IN (
|
||||||
SELECT dp4.id FROM device_ports dp4 WHERE dp4.device_id = d.id
|
SELECT dp4.id FROM device_ports dp4 WHERE dp4.device_id = d.id
|
||||||
))
|
))
|
||||||
) AS connection_count
|
) AS connection_count
|
||||||
|
|||||||
Reference in New Issue
Block a user