diff --git a/api.php b/api.php index 06b88d7..95635c9 100644 --- a/api.php +++ b/api.php @@ -1836,14 +1836,29 @@ switch ($action) { 'muokattu' => date('Y-m-d H:i:s'), 'muokkaaja' => currentUser(), ]; - // Duplikaatti-tarkistus: sama verkko/IP ei saa olla jo olemassa - if ($entry['verkko'] !== '' && $entry['tyyppi'] !== 'vlan') { + // Duplikaatti-tarkistus + $skipDuplicateCheck = !empty($input['force']); + if (!$skipDuplicateCheck) { $existingAll = dbLoadIpam($companyId); - foreach ($existingAll as $ex) { - if ($ex['verkko'] === $entry['verkko'] && $ex['id'] !== $entry['id'] && $ex['tyyppi'] !== 'vlan') { - http_response_code(400); - echo json_encode(['error' => 'IP-osoite tai verkko "' . $entry['verkko'] . '" on jo olemassa (' . ($ex['nimi'] ?: 'nimetön') . ')']); - exit; + // Verkko/IP duplikaatti — estä kokonaan + if ($entry['verkko'] !== '' && $entry['tyyppi'] !== 'vlan') { + foreach ($existingAll as $ex) { + if ($ex['verkko'] === $entry['verkko'] && $ex['id'] !== $entry['id'] && $ex['tyyppi'] !== 'vlan') { + http_response_code(400); + echo json_encode(['error' => 'IP-osoite tai verkko "' . $entry['verkko'] . '" on jo olemassa (' . ($ex['nimi'] ?: 'nimetön') . ')']); + exit; + } + } + } + // VLAN duplikaatti — varoitus (409 = confirm) + if ($entry['tyyppi'] === 'vlan' && !empty($entry['vlan_id'])) { + $vlanNum = (int)$entry['vlan_id']; + foreach ($existingAll as $ex) { + if ($ex['tyyppi'] === 'vlan' && (int)$ex['vlan_id'] === $vlanNum && $ex['id'] !== $entry['id']) { + http_response_code(409); + echo json_encode(['warning' => 'VLAN ' . $vlanNum . ' on jo olemassa (' . ($ex['nimi'] ?: 'nimetön') . '). Lisätäänkö silti?']); + exit; + } } } } diff --git a/script.js b/script.js index 714a64f..2b92c44 100644 --- a/script.js +++ b/script.js @@ -3470,7 +3470,22 @@ document.getElementById('ipam-form')?.addEventListener('submit', async (e) => { }; if (id) data.id = id; try { - await apiCall('ipam_save', 'POST', data); + const res = await fetch(`${API}?action=ipam_save`, { + method: 'POST', credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data) + }); + const result = await res.json(); + if (res.status === 409 && result.warning) { + if (confirm(result.warning)) { + data.force = true; + await apiCall('ipam_save', 'POST', data); + } else { + return; + } + } else if (!res.ok) { + throw new Error(result.error || 'Virhe'); + } document.getElementById('ipam-modal').style.display = 'none'; loadIpam(); } catch (e) { alert(e.message); }