Files
nexus/modules/pihole/pages/instances.php
Lars Gebhardt-Kusche 463b2cf5e1
All checks were successful
Deploy / deploy-staging (push) Successful in 5s
Deploy / deploy-production (push) Has been skipped
pi hole
2026-04-27 00:41:37 +02:00

242 lines
9.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
$moduleName = 'pihole';
$assets = app()->assets();
$assets->addStyle('/module/pihole/asset?file=pihole.css');
$assets->addScript('/module/pihole/asset?file=pihole_instances.js', 'footer', true);
require_admin();
$settings = modules()->settings($moduleName);
$notice = null;
$error = null;
$loadInstances = function (array $settings): array {
$normalizeSecret = static function (array $row): string {
$password = trim((string)($row['password'] ?? ''));
if ($password !== '') {
return $password;
}
return trim((string)($row['token'] ?? ''));
};
$instances = [];
$rawJson = trim((string)($settings['instances_json'] ?? ''));
if ($rawJson !== '') {
$decoded = json_decode($rawJson, true);
if (is_array($decoded)) {
foreach ($decoded as $row) {
if (!is_array($row)) {
continue;
}
$id = trim((string)($row['id'] ?? ''));
$url = trim((string)($row['url'] ?? ''));
if ($id === '' || $url === '') {
continue;
}
$instances[$id] = [
'id' => $id,
'name' => trim((string)($row['name'] ?? '')) ?: $id,
'url' => $url,
'password' => $normalizeSecret($row),
'is_primary' => !empty($row['is_primary']),
];
}
}
}
if (!$instances) {
foreach (['primary', 'secondary'] as $key) {
$url = trim((string)($settings[$key . '_url'] ?? ''));
if ($url === '') {
continue;
}
$instances[$key] = [
'id' => $key,
'name' => trim((string)($settings[$key . '_name'] ?? '')) ?: ($key === 'primary' ? 'Primaer' : 'Sekundaer'),
'url' => $url,
'password' => trim((string)($settings[$key . '_token'] ?? '')),
'is_primary' => $key === 'primary',
];
}
}
return $instances;
};
$instances = $loadInstances($settings);
$sanitizeId = function (string $id): string {
$id = preg_replace('/[^a-zA-Z0-9_-]/', '', $id);
return trim((string)$id);
};
$saveInstances = function (array $settings, array $instances): void {
$payload = $settings;
$payload['instances_json'] = json_encode(array_values($instances), JSON_UNESCAPED_UNICODE);
modules()->saveSettings('pihole', $payload);
};
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$deleteId = trim((string)($_POST['delete_id'] ?? ''));
$currentId = trim((string)($_POST['current_id'] ?? ''));
$instanceId = trim((string)($_POST['instance_id'] ?? ''));
$name = trim((string)($_POST['name'] ?? ''));
$url = trim((string)($_POST['url'] ?? ''));
$password = trim((string)($_POST['password'] ?? ''));
$isPrimary = isset($_POST['is_primary']);
if ($deleteId !== '') {
if (isset($instances[$deleteId])) {
unset($instances[$deleteId]);
$notice = 'Instanz geloescht.';
}
} else {
$instanceId = $sanitizeId($instanceId);
if ($instanceId === '' || $url === '') {
$error = 'Bitte ID und URL angeben.';
} else {
$existingPassword = '';
if ($currentId !== '' && isset($instances[$currentId])) {
$existingPassword = (string)($instances[$currentId]['password'] ?? '');
}
$passwordToStore = $password !== '' ? $password : $existingPassword;
if ($currentId !== '' && $currentId !== $instanceId) {
unset($instances[$currentId]);
}
$instances[$instanceId] = [
'id' => $instanceId,
'name' => $name !== '' ? $name : $instanceId,
'url' => $url,
'password' => $passwordToStore,
'is_primary' => $isPrimary,
];
if ($isPrimary) {
foreach ($instances as $id => &$row) {
$row['is_primary'] = ($id === $instanceId);
}
unset($row);
$settings['primary_id'] = $instanceId;
}
$notice = $currentId !== '' ? 'Instanz aktualisiert.' : 'Instanz gespeichert.';
}
}
if (!$error) {
$saveInstances($settings, $instances);
$settings = modules()->settings($moduleName);
$instances = $loadInstances($settings);
}
}
$primaryId = trim((string)($settings['primary_id'] ?? ''));
if ($primaryId === '') {
foreach ($instances as $id => $row) {
if (!empty($row['is_primary'])) {
$primaryId = $id;
break;
}
}
}
?>
<?= module_shell_header('pihole', [
'title' => 'Pi-hole Instanzen',
'description' => 'Pi-hole Instanzen hinzufuegen, bearbeiten und loeschen.',
]) ?>
<div class="module-flow">
<section class="module-box">
<div class="module-box-head">
<div>
<h2 class="module-box-title">Instanzen</h2>
<p>Pi-hole Instanzen hinzufuegen, bearbeiten und loeschen.</p>
</div>
<div style="display:flex; gap:10px; flex-wrap:wrap;">
<button class="module-button module-button--primary" type="button" data-instance-new>+ Neue Instanz</button>
</div>
</div>
<?php if ($error): ?>
<div class="setup-db-message setup-db-message--error" style="margin-top:16px;">
<?= e($error) ?>
</div>
<?php elseif ($notice): ?>
<div class="setup-db-message setup-db-message--success" style="margin-top:16px;">
<?= e($notice) ?>
</div>
<?php endif; ?>
<div class="module-box-grid module-box-grid--panels" style="margin-top:16px;">
<?php if (!$instances): ?>
<div class="module-box-soft">Keine Instanzen vorhanden.</div>
<?php else: ?>
<?php foreach ($instances as $instance): ?>
<div class="module-box-soft pihole-instance-card"
data-instance-id="<?= e((string)$instance['id']) ?>"
data-name="<?= e((string)($instance['name'] ?? '')) ?>"
data-url="<?= e((string)($instance['url'] ?? '')) ?>"
data-primary="<?= !empty($instance['is_primary']) ? '1' : '0' ?>">
<div class="pihole-instance-header">
<div>
<strong><?= e((string)($instance['name'] ?? '')) ?></strong>
<div class="muted">ID: <?= e((string)($instance['id'] ?? '')) ?></div>
<div class="muted">URL: <?= e((string)($instance['url'] ?? '')) ?></div>
</div>
<?php if (!empty($instance['is_primary']) || $instance['id'] === $primaryId): ?>
<span class="pihole-status">Primaer</span>
<?php endif; ?>
</div>
<div class="pihole-card-actions">
<button class="module-button module-button--secondary module-button--small" type="button" data-instance-edit>Bearbeiten</button>
<button class="module-button module-button--secondary module-button--small" type="button" data-instance-test>Test Verbindung</button>
<form method="post" onsubmit="return confirm('Instanz wirklich loeschen?')">
<input type="hidden" name="delete_id" value="<?= e((string)($instance['id'] ?? '')) ?>">
<button class="module-button module-button--secondary module-button--small" type="submit">Loeschen</button>
</form>
</div>
<div class="pihole-test-result" data-instance-result></div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</section>
</div>
<div class="modal" data-instance-modal aria-hidden="true">
<div class="modal-card">
<div class="modal-header">
<strong data-instance-modal-title>Neue Instanz</strong>
<button class="icon-button" type="button" data-instance-close>×</button>
</div>
<form method="post" class="form-grid" style="margin-top:.75rem;" data-instance-form>
<input type="hidden" name="current_id" value="">
<label class="form-field">
<span class="muted">ID</span>
<input type="text" name="instance_id" placeholder="z.B. pihole-main" required>
</label>
<label class="form-field">
<span class="muted">Name</span>
<input type="text" name="name" placeholder="z.B. Pi-hole Main" required>
</label>
<label class="form-field">
<span class="muted">URL</span>
<input type="text" name="url" placeholder="http://pi-hole.local" required>
</label>
<label class="form-field">
<span class="muted">Passwort / App-Passwort (leer lassen = unveraendert)</span>
<input type="password" name="password" placeholder="Pi-hole Passwort oder App-Passwort" autocomplete="new-password">
</label>
<label class="form-field" style="align-items:center;">
<span class="muted">Als Primaer verwenden</span>
<input type="checkbox" name="is_primary" value="1">
</label>
<div style="display:flex; gap:10px; flex-wrap:wrap;">
<button class="cta-button" type="submit" data-instance-submit>Speichern</button>
<button class="nav-link" type="button" data-instance-cancel>Zuruecksetzen</button>
</div>
</form>
</div>
</div>
<?= module_shell_footer() ?>