293 lines
10 KiB
PHP
293 lines
10 KiB
PHP
<?php
|
|
/**
|
|
* app/modules/connections/edit.php
|
|
*
|
|
* Verbindung anlegen / bearbeiten
|
|
*/
|
|
|
|
$connectionId = (int)($_GET['id'] ?? 0);
|
|
$connection = null;
|
|
|
|
if ($connectionId > 0) {
|
|
$connection = $sql->single(
|
|
"SELECT id, port_a_type, port_a_id, port_b_type, port_b_id, vlan_config, comment
|
|
FROM connections
|
|
WHERE id = ?",
|
|
"i",
|
|
[$connectionId]
|
|
);
|
|
}
|
|
|
|
$normalizePortType = static function (string $value): string {
|
|
$map = [
|
|
'device' => 'device',
|
|
'device_ports' => 'device',
|
|
'module' => 'module',
|
|
'module_ports' => 'module',
|
|
'outlet' => 'outlet',
|
|
'network_outlet_ports' => 'outlet',
|
|
'patchpanel' => 'patchpanel',
|
|
'floor_patchpanel' => 'patchpanel',
|
|
'floor_patchpanel_ports' => 'patchpanel',
|
|
];
|
|
$key = strtolower(trim($value));
|
|
return $map[$key] ?? 'device';
|
|
};
|
|
|
|
$portAType = $normalizePortType((string)($connection['port_a_type'] ?? 'device'));
|
|
$portBType = $normalizePortType((string)($connection['port_b_type'] ?? 'device'));
|
|
$portAId = (int)($connection['port_a_id'] ?? 0);
|
|
$portBId = (int)($connection['port_b_id'] ?? 0);
|
|
|
|
$endpointOptions = [
|
|
'device' => [],
|
|
'module' => [],
|
|
'outlet' => [],
|
|
'patchpanel' => [],
|
|
];
|
|
|
|
$occupiedByType = [
|
|
'device' => [],
|
|
'module' => [],
|
|
'outlet' => [],
|
|
'patchpanel' => [],
|
|
];
|
|
$occupiedRows = $sql->get(
|
|
"SELECT id, port_a_type, port_a_id, port_b_type, port_b_id
|
|
FROM connections
|
|
WHERE id <> ?",
|
|
"i",
|
|
[$connectionId]
|
|
);
|
|
foreach ((array)$occupiedRows as $row) {
|
|
$typeA = $normalizePortType((string)($row['port_a_type'] ?? ''));
|
|
$idA = (int)($row['port_a_id'] ?? 0);
|
|
if ($idA > 0 && isset($occupiedByType[$typeA])) {
|
|
$occupiedByType[$typeA][$idA] = true;
|
|
}
|
|
|
|
$typeB = $normalizePortType((string)($row['port_b_type'] ?? ''));
|
|
$idB = (int)($row['port_b_id'] ?? 0);
|
|
if ($idB > 0 && isset($occupiedByType[$typeB])) {
|
|
$occupiedByType[$typeB][$idB] = true;
|
|
}
|
|
}
|
|
|
|
$isEndpointAllowed = static function (string $type, int $id) use ($occupiedByType, $portAType, $portAId, $portBType, $portBId): bool {
|
|
if ($id <= 0) {
|
|
return false;
|
|
}
|
|
if ($type === 'outlet') {
|
|
return true;
|
|
}
|
|
if ($type === $portAType && $id === $portAId) {
|
|
return true;
|
|
}
|
|
if ($type === $portBType && $id === $portBId) {
|
|
return true;
|
|
}
|
|
return empty($occupiedByType[$type][$id]);
|
|
};
|
|
|
|
// Auto-heal: ensure each outlet has at least one selectable port.
|
|
$outletsWithoutPorts = $sql->get(
|
|
"SELECT o.id
|
|
FROM network_outlets o
|
|
LEFT JOIN network_outlet_ports nop ON nop.outlet_id = o.id
|
|
GROUP BY o.id
|
|
HAVING COUNT(nop.id) = 0",
|
|
"",
|
|
[]
|
|
);
|
|
foreach ((array)$outletsWithoutPorts as $outletRow) {
|
|
$outletId = (int)($outletRow['id'] ?? 0);
|
|
if ($outletId <= 0) {
|
|
continue;
|
|
}
|
|
$sql->set(
|
|
"INSERT INTO network_outlet_ports (outlet_id, name) VALUES (?, 'Port 1')",
|
|
"i",
|
|
[$outletId]
|
|
);
|
|
}
|
|
|
|
$devicePorts = $sql->get(
|
|
"SELECT dp.id, dp.name, d.name AS owner_name
|
|
FROM device_ports dp
|
|
JOIN devices d ON d.id = dp.device_id
|
|
ORDER BY d.name, dp.name",
|
|
"",
|
|
[]
|
|
);
|
|
foreach ($devicePorts as $row) {
|
|
$id = (int)$row['id'];
|
|
if (!$isEndpointAllowed('device', $id)) {
|
|
continue;
|
|
}
|
|
$endpointOptions['device'][] = [
|
|
'id' => $id,
|
|
'label' => $row['owner_name'] . ' / ' . $row['name'],
|
|
];
|
|
}
|
|
|
|
$modulePorts = $sql->get(
|
|
"SELECT
|
|
mp.id,
|
|
mp.name,
|
|
m.name AS module_name,
|
|
MIN(d.name) AS device_name
|
|
FROM module_ports mp
|
|
JOIN modules m ON m.id = mp.module_id
|
|
LEFT JOIN device_port_modules dpm ON dpm.module_id = m.id
|
|
LEFT JOIN device_ports dp ON dp.id = dpm.device_port_id
|
|
LEFT JOIN devices d ON d.id = dp.device_id
|
|
GROUP BY mp.id, mp.name, m.name
|
|
ORDER BY device_name, module_name, mp.name",
|
|
"",
|
|
[]
|
|
);
|
|
foreach ($modulePorts as $row) {
|
|
$id = (int)$row['id'];
|
|
if (!$isEndpointAllowed('module', $id)) {
|
|
continue;
|
|
}
|
|
$deviceName = trim((string)($row['device_name'] ?? '')) ?: 'Unzugeordnet';
|
|
$endpointOptions['module'][] = [
|
|
'id' => $id,
|
|
'label' => $deviceName . ' / ' . $row['module_name'] . ' / ' . $row['name'],
|
|
];
|
|
}
|
|
|
|
$outletPorts = $sql->get(
|
|
"SELECT nop.id, nop.name, o.name AS outlet_name, r.name AS room_name, f.name AS floor_name
|
|
FROM network_outlet_ports nop
|
|
JOIN network_outlets o ON o.id = nop.outlet_id
|
|
LEFT JOIN rooms r ON r.id = o.room_id
|
|
LEFT JOIN floors f ON f.id = r.floor_id
|
|
ORDER BY floor_name, room_name, outlet_name, nop.name",
|
|
"",
|
|
[]
|
|
);
|
|
foreach ($outletPorts as $row) {
|
|
$id = (int)$row['id'];
|
|
if (!$isEndpointAllowed('outlet', $id)) {
|
|
continue;
|
|
}
|
|
$parts = array_filter([(string)($row['floor_name'] ?? ''), (string)($row['room_name'] ?? ''), (string)$row['outlet_name'], (string)$row['name']]);
|
|
$endpointOptions['outlet'][] = [
|
|
'id' => $id,
|
|
'label' => implode(' / ', $parts),
|
|
];
|
|
}
|
|
|
|
$patchpanelPorts = $sql->get(
|
|
"SELECT fpp.id, fpp.name, fp.name AS patchpanel_name, f.name AS floor_name
|
|
FROM floor_patchpanel_ports fpp
|
|
JOIN floor_patchpanels fp ON fp.id = fpp.patchpanel_id
|
|
LEFT JOIN floors f ON f.id = fp.floor_id
|
|
ORDER BY floor_name, patchpanel_name, fpp.name",
|
|
"",
|
|
[]
|
|
);
|
|
foreach ($patchpanelPorts as $row) {
|
|
$id = (int)$row['id'];
|
|
if (!$isEndpointAllowed('patchpanel', $id)) {
|
|
continue;
|
|
}
|
|
$parts = array_filter([(string)($row['floor_name'] ?? ''), (string)$row['patchpanel_name'], (string)$row['name']]);
|
|
$endpointOptions['patchpanel'][] = [
|
|
'id' => $id,
|
|
'label' => implode(' / ', $parts),
|
|
];
|
|
}
|
|
|
|
$vlanValue = '';
|
|
if (!empty($connection['vlan_config'])) {
|
|
$decoded = json_decode((string)$connection['vlan_config'], true);
|
|
if (is_array($decoded)) {
|
|
$vlanValue = implode(',', array_map('trim', $decoded));
|
|
} else {
|
|
$vlanValue = (string)$connection['vlan_config'];
|
|
}
|
|
}
|
|
|
|
$renderEndpointOptions = static function (array $optionsByType, int $selectedId): void {
|
|
foreach ($optionsByType as $type => $options) {
|
|
foreach ($options as $entry) {
|
|
$isSelected = ((int)$entry['id'] === $selectedId) ? ' selected' : '';
|
|
echo '<option value="' . (int)$entry['id'] . '" data-endpoint-type="' . htmlspecialchars((string)$type) . '"' . $isSelected . '>';
|
|
echo htmlspecialchars((string)$entry['label']);
|
|
echo '</option>';
|
|
}
|
|
}
|
|
};
|
|
?>
|
|
|
|
<div class="device-edit">
|
|
<h1><?php echo $connection ? 'Verbindung bearbeiten' : 'Neue Verbindung'; ?></h1>
|
|
|
|
<form method="post" action="?module=connections&action=save" class="edit-form">
|
|
<?php if ($connection): ?>
|
|
<input type="hidden" name="id" value="<?php echo (int)$connection['id']; ?>">
|
|
<?php endif; ?>
|
|
|
|
<fieldset>
|
|
<legend>Endpunkt A</legend>
|
|
<div class="form-group">
|
|
<label for="port_a_type">Typ</label>
|
|
<select id="port_a_type" name="port_a_type" required>
|
|
<option value="device" <?php echo $portAType === 'device' ? 'selected' : ''; ?>>Geraeteport</option>
|
|
<option value="module" <?php echo $portAType === 'module' ? 'selected' : ''; ?>>Modulport</option>
|
|
<option value="outlet" <?php echo $portAType === 'outlet' ? 'selected' : ''; ?>>Netzwerkdose</option>
|
|
<option value="patchpanel" <?php echo $portAType === 'patchpanel' ? 'selected' : ''; ?>>Patchpanel-Port</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="port_a_id">Port</label>
|
|
<select id="port_a_id" name="port_a_id" required data-selected-id="<?php echo (int)$portAId; ?>">
|
|
<option value="">- Port waehlen -</option>
|
|
<?php $renderEndpointOptions($endpointOptions, $portAId); ?>
|
|
</select>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<fieldset>
|
|
<legend>Endpunkt B</legend>
|
|
<div class="form-group">
|
|
<label for="port_b_type">Typ</label>
|
|
<select id="port_b_type" name="port_b_type" required>
|
|
<option value="device" <?php echo $portBType === 'device' ? 'selected' : ''; ?>>Geraeteport</option>
|
|
<option value="module" <?php echo $portBType === 'module' ? 'selected' : ''; ?>>Modulport</option>
|
|
<option value="outlet" <?php echo $portBType === 'outlet' ? 'selected' : ''; ?>>Netzwerkdose</option>
|
|
<option value="patchpanel" <?php echo $portBType === 'patchpanel' ? 'selected' : ''; ?>>Patchpanel-Port</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="port_b_id">Port</label>
|
|
<select id="port_b_id" name="port_b_id" required data-selected-id="<?php echo (int)$portBId; ?>">
|
|
<option value="">- Port waehlen -</option>
|
|
<?php $renderEndpointOptions($endpointOptions, $portBId); ?>
|
|
</select>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<fieldset>
|
|
<legend>Details</legend>
|
|
<div class="form-group">
|
|
<label for="vlan_config">VLANs (kommagetrennt)</label>
|
|
<input type="text" id="vlan_config" name="vlan_config" value="<?php echo htmlspecialchars($vlanValue); ?>" placeholder="z.B. 10,20,30">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="comment">Kommentar</label>
|
|
<textarea id="comment" name="comment" rows="3"><?php echo htmlspecialchars($connection['comment'] ?? ''); ?></textarea>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<fieldset class="form-actions">
|
|
<button type="submit" class="button button-primary">Speichern</button>
|
|
<a href="?module=connections&action=list" class="button">Abbrechen</a>
|
|
</fieldset>
|
|
</form>
|
|
</div>
|
|
<script src="/assets/js/connections-edit-form.js" defer></script>
|