810 lines
25 KiB
PHP
810 lines
25 KiB
PHP
<?php
|
||
require '_sql.php';
|
||
require '_func.php';
|
||
require '_user.php';
|
||
|
||
session_start();
|
||
$ip = $_SERVER['REMOTE_ADDR'];
|
||
|
||
/* ─────────────────────────────
|
||
Security
|
||
───────────────────────────── */
|
||
if (isIpLocked($ip, $sql)) {
|
||
http_response_code(403);
|
||
exit('Zu viele Fehlversuche.');
|
||
}
|
||
|
||
/* ─────────────────────────────
|
||
Login
|
||
───────────────────────────── */
|
||
if (!($_SESSION['is_admin'] ?? false)) {
|
||
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
$u = $_POST['username'] ?? '';
|
||
$p = $_POST['password'] ?? '';
|
||
|
||
if (
|
||
$u !== $admin_user ||
|
||
$p !== $admin_password
|
||
) {
|
||
registerFailedLogin($ip, $sql);
|
||
$error = 'Login fehlgeschlagen';
|
||
} else {
|
||
clearLoginAttempts($ip, $sql);
|
||
$_SESSION['is_admin'] = true;
|
||
header('Location: admin.php');
|
||
exit;
|
||
}
|
||
}
|
||
?>
|
||
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>Admin Login</title>
|
||
<style>
|
||
body {
|
||
font-family: system-ui, sans-serif;
|
||
background:#0f172a;
|
||
color:#e5e7eb;
|
||
display:flex;
|
||
justify-content:center;
|
||
align-items:center;
|
||
height:100vh;
|
||
}
|
||
form {
|
||
background:#020617;
|
||
padding:2rem;
|
||
border-radius:12px;
|
||
width:320px;
|
||
}
|
||
input,button {
|
||
width:100%;
|
||
padding:.6rem;
|
||
margin-top:.75rem;
|
||
}
|
||
button {
|
||
background:#38bdf8;
|
||
border:0;
|
||
cursor:pointer;
|
||
}
|
||
.err { color:#f87171; margin-top:.5rem; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<form method="post">
|
||
<h2>Admin Login</h2>
|
||
<input name="username" placeholder="Benutzername" required>
|
||
<input name="password" type="password" placeholder="Passwort" required>
|
||
<button>Login</button>
|
||
<?php if (!empty($error)): ?>
|
||
<div class="err"><?= htmlspecialchars($error) ?></div>
|
||
<?php endif; ?>
|
||
</form>
|
||
|
||
</body>
|
||
</html>
|
||
<?php
|
||
exit;
|
||
}
|
||
|
||
/* ─────────────────────────────
|
||
Action Routing
|
||
───────────────────────────── */
|
||
$action = $_GET['action'] ?? null;
|
||
|
||
/* ─────────────────────────────
|
||
UUID DIRECT ACCESS (?uuid=...)
|
||
Create flow if missing
|
||
───────────────────────────── */
|
||
if (!$action && isset($_GET['uuid'])) {
|
||
$uuid = $_GET['uuid'];
|
||
|
||
// Prüfen ob UUID existiert
|
||
$token = $sql->single(
|
||
"SELECT * FROM access_tokens WHERE uuid = ?",
|
||
"s",
|
||
[$uuid]
|
||
);
|
||
|
||
if ($token) {
|
||
// UUID existiert → weiter zum edit-Formular
|
||
$action = 'uuid_edit';
|
||
$_GET['uuid'] = $uuid;
|
||
} else {
|
||
// UUID existiert nicht → Initial-Form
|
||
$action = 'uuid_create_initial';
|
||
$_GET['uuid'] = $uuid;
|
||
}
|
||
}
|
||
|
||
/* ─────────────────────────────
|
||
CREATE IDENTITY
|
||
───────────────────────────── */
|
||
if ($action === 'identity_create') {
|
||
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
$name = trim($_POST['name'] ?? '');
|
||
|
||
if ($name !== '') {
|
||
$sql->set(
|
||
"INSERT INTO identities (name) VALUES (?)",
|
||
"s",
|
||
[$name]
|
||
);
|
||
header('Location: admin.php');
|
||
exit;
|
||
}
|
||
}
|
||
?>
|
||
<!doctype html>
|
||
<html><head><meta charset="utf-8"><title>Identität anlegen</title><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||
</head>
|
||
<body>
|
||
<h1>Neue Identität</h1>
|
||
<form method="post">
|
||
<input name="name" placeholder="Name der Identität" required>
|
||
<button>Speichern</button>
|
||
</form>
|
||
<p><a href="admin.php">← zurück</a></p>
|
||
</body></html>
|
||
<?php
|
||
exit;
|
||
}
|
||
|
||
/* ─────────────────────────────
|
||
INITIAL UUID CREATION
|
||
───────────────────────────── */
|
||
if ($action === 'uuid_create_initial') {
|
||
|
||
$uuid = $_GET['uuid'];
|
||
|
||
// Alle Identitäten für Auswahl
|
||
$identities = $sql->get("SELECT * FROM identities ORDER BY name ASC");
|
||
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
$identityId = (int)($_POST['identity_id'] ?? 0);
|
||
$notes = trim($_POST['notes'] ?? '');
|
||
|
||
if (!$identityId) {
|
||
$error = 'Bitte eine Identität auswählen.';
|
||
} else {
|
||
// UUID anlegen
|
||
$sql->set(
|
||
"INSERT INTO access_tokens (identity_id, uuid, notes) VALUES (?, ?, ?)",
|
||
"iss",
|
||
[$identityId, $uuid, $notes]
|
||
);
|
||
|
||
// Weiterleiten zum Bearbeitungsformular
|
||
header("Location: admin.php?action=uuid_edit&uuid=$uuid");
|
||
exit;
|
||
}
|
||
}
|
||
|
||
?>
|
||
<!doctype html>
|
||
<html>
|
||
<head><meta charset="utf-8"><title>Neue UUID anlegen</title><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||
</head>
|
||
<body>
|
||
<h1>Neue UUID anlegen</h1>
|
||
|
||
<form method="post">
|
||
<label>Identität auswählen:
|
||
<select name="identity_id" required>
|
||
<option value="">-- bitte wählen --</option>
|
||
<?php foreach ($identities as $i): ?>
|
||
<option value="<?= $i['id'] ?>"><?= htmlspecialchars($i['name']) ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</label>
|
||
<br><br>
|
||
<label>Notiz (optional):<br>
|
||
<textarea name="notes" rows="3"></textarea>
|
||
</label>
|
||
<br><br>
|
||
<button>Speichern</button>
|
||
</form>
|
||
|
||
<?php if (!empty($error)): ?>
|
||
<p style="color:red"><?= htmlspecialchars($error) ?></p>
|
||
<?php endif; ?>
|
||
|
||
<p><a href="admin.php">← zurück zum Dashboard</a></p>
|
||
</body>
|
||
</html>
|
||
<?php
|
||
exit;
|
||
}
|
||
|
||
/* ─────────────────────────────
|
||
EDIT IDENTITY
|
||
───────────────────────────── */
|
||
if ($action === 'identity_edit') {
|
||
function renderValueFieldElement(string $type, string $value, string $name = 'value', string $id = null, array $extraAttrs = [], array $filesForIdentity = []): string
|
||
{
|
||
$safeValue = htmlspecialchars($value);
|
||
$idAttr = $id ? ' id="' . htmlspecialchars($id) . '"' : '';
|
||
$extraAttrString = '';
|
||
foreach ($extraAttrs as $attr => $attrVal) {
|
||
$extraAttrString .= ' ' . htmlspecialchars($attr) . '="' . htmlspecialchars($attrVal) . '"';
|
||
}
|
||
|
||
if ($type === 'file') {
|
||
$options = '<option value="">-- Datei wählen --</option>';
|
||
foreach ($filesForIdentity as $file) {
|
||
$fileId = (string)(int)$file['id'];
|
||
$selected = $fileId === $value ? ' selected' : '';
|
||
$options .= sprintf(
|
||
'<option value="%s"%s>%s</option>',
|
||
htmlspecialchars($fileId),
|
||
$selected,
|
||
htmlspecialchars($file['filename'])
|
||
);
|
||
}
|
||
return "<select name=\"" . htmlspecialchars($name) . "\" style=\"width:100%\"{$idAttr}{$extraAttrString}>{$options}</select>";
|
||
}
|
||
|
||
if ($type === 'multi') {
|
||
return "<textarea name=\"" . htmlspecialchars($name) . "\" rows=\"3\" style=\"width:100%\"{$idAttr}{$extraAttrString}>{$safeValue}</textarea>";
|
||
}
|
||
|
||
$inputType = $type === 'url' ? 'url' : 'text';
|
||
return "<input type=\"{$inputType}\" name=\"" . htmlspecialchars($name) . "\" value=\"{$safeValue}\" style=\"width:100%\"{$idAttr}{$extraAttrString}>";
|
||
}
|
||
$id = (int)($_GET['id'] ?? 0);
|
||
|
||
$identity = $sql->single(
|
||
"SELECT * FROM identities WHERE id = ?",
|
||
"i",
|
||
[$id]
|
||
);
|
||
|
||
if (!$identity) {
|
||
exit('Identität nicht gefunden');
|
||
}
|
||
|
||
$fileUploadErrors = [];
|
||
$fileUploadSuccess = 0;
|
||
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
|
||
if (isset($_POST['upload_files'])) {
|
||
$filesInput = $_FILES['files'] ?? null;
|
||
$hasSelection = false;
|
||
if ($filesInput) {
|
||
if (is_array($filesInput['name'])) {
|
||
foreach ($filesInput['name'] as $fileName) {
|
||
if (trim((string)$fileName) !== '') {
|
||
$hasSelection = true;
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
$hasSelection = trim((string)$filesInput['name']) !== '';
|
||
}
|
||
}
|
||
|
||
if ($filesInput && $hasSelection) {
|
||
$uploadDir = __DIR__ . '/../files/';
|
||
if (!is_dir($uploadDir) && !mkdir($uploadDir, 0755, true) && !is_dir($uploadDir)) {
|
||
$fileUploadErrors[] = 'Upload-Verzeichnis kann nicht erstellt werden.';
|
||
} else {
|
||
$total = is_array($filesInput['name']) ? count($filesInput['name']) : 1;
|
||
$uploaded = 0;
|
||
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||
for ($i = 0; $i < $total; $i++) {
|
||
$originalName = is_array($filesInput['name']) ? $filesInput['name'][$i] : $filesInput['name'];
|
||
$error = is_array($filesInput['error']) ? $filesInput['error'][$i] : $filesInput['error'];
|
||
$tmpName = is_array($filesInput['tmp_name']) ? $filesInput['tmp_name'][$i] : $filesInput['tmp_name'];
|
||
|
||
if ($error === UPLOAD_ERR_NO_FILE) {
|
||
continue;
|
||
}
|
||
|
||
$originalName = trim((string)$originalName);
|
||
if ($originalName === '') {
|
||
continue;
|
||
}
|
||
|
||
if ($error !== UPLOAD_ERR_OK) {
|
||
$fileUploadErrors[] = sprintf('Fehler beim Hochladen von %s.', $originalName);
|
||
continue;
|
||
}
|
||
|
||
if (!is_uploaded_file($tmpName)) {
|
||
$fileUploadErrors[] = sprintf('Datei %s konnte nicht verarbeitet werden.', $originalName);
|
||
continue;
|
||
}
|
||
|
||
$safeName = preg_replace('/[^A-Za-z0-9._-]/', '_', basename($originalName));
|
||
if ($safeName === '') {
|
||
$safeName = 'file';
|
||
}
|
||
$storedName = bin2hex(random_bytes(12)) . '_' . $safeName;
|
||
$destination = $uploadDir . $storedName;
|
||
|
||
if (!move_uploaded_file($tmpName, $destination)) {
|
||
$fileUploadErrors[] = sprintf('Speichern von %s fehlgeschlagen.', $originalName);
|
||
continue;
|
||
}
|
||
|
||
$mimeType = $finfo ? finfo_file($finfo, $destination) : 'application/octet-stream';
|
||
$sql->set(
|
||
"INSERT INTO files (identity_id, filename, stored_name, mime_type)
|
||
VALUES (?, ?, ?, ?)",
|
||
"isss",
|
||
[$id, $originalName, $storedName, $mimeType]
|
||
);
|
||
$uploaded++;
|
||
}
|
||
|
||
if ($finfo) {
|
||
finfo_close($finfo);
|
||
}
|
||
|
||
if ($uploaded > 0) {
|
||
$fileUploadSuccess = $uploaded;
|
||
}
|
||
}
|
||
} else {
|
||
$fileUploadErrors[] = 'Bitte wählen Sie mindestens eine Datei aus.';
|
||
}
|
||
}
|
||
|
||
// Identität umbenennen
|
||
if (isset($_POST['rename'])) {
|
||
$sql->set(
|
||
"UPDATE identities SET name = ? WHERE id = ?",
|
||
"si",
|
||
[trim($_POST['name']), $id]
|
||
);
|
||
}
|
||
|
||
// Neues Feld
|
||
if (isset($_POST['add_field'])) {
|
||
$sql->set(
|
||
"INSERT INTO identity_fields (identity_id, field_key, field_value, typ)
|
||
VALUES (?, ?, ?, ?)",
|
||
"isss",
|
||
[
|
||
$id,
|
||
trim($_POST['key']),
|
||
trim($_POST['value']),
|
||
$_POST['typ'] ?? 'single'
|
||
]
|
||
);
|
||
}
|
||
|
||
// Feld aktualisieren
|
||
if (isset($_POST['update_field'])) {
|
||
$sql->set(
|
||
"UPDATE identity_fields
|
||
SET field_key = ?, field_value = ?, typ = ?
|
||
WHERE id = ? AND identity_id = ?",
|
||
"sssii",
|
||
[
|
||
trim($_POST['key']),
|
||
trim($_POST['value']),
|
||
$_POST['typ'] ?? 'single',
|
||
(int)$_POST['field_id'],
|
||
$id
|
||
]
|
||
);
|
||
}
|
||
|
||
// Feld löschen
|
||
if (isset($_POST['delete_field'])) {
|
||
$sql->set(
|
||
"DELETE FROM identity_fields
|
||
WHERE id = ? AND identity_id = ?",
|
||
"ii",
|
||
[(int)$_POST['field_id'], $id]
|
||
);
|
||
}
|
||
|
||
header("Location: admin.php?action=identity_edit&id=$id");
|
||
exit;
|
||
}
|
||
|
||
$fields = $sql->get(
|
||
"SELECT * FROM identity_fields WHERE identity_id = ? ORDER BY id ASC",
|
||
"i",
|
||
[$id]
|
||
);
|
||
|
||
$identityFiles = $sql->get(
|
||
"SELECT id, filename FROM files WHERE identity_id = ? ORDER BY uploaded_at DESC",
|
||
"i",
|
||
[$id]
|
||
);
|
||
if ($identityFiles === false) {
|
||
$identityFiles = [];
|
||
}
|
||
?>
|
||
<!doctype html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>Identität bearbeiten</title>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||
|
||
</head>
|
||
<body>
|
||
|
||
<h1><?= htmlspecialchars($identity['name']) ?></h1>
|
||
|
||
<form method="post">
|
||
<input name="name" value="<?= htmlspecialchars($identity['name']) ?>">
|
||
<button name="rename">Umbenennen</button>
|
||
</form>
|
||
|
||
<h2>Felder</h2>
|
||
|
||
<table border="1" cellpadding="6" cellspacing="0">
|
||
<thead>
|
||
<tr>
|
||
<th>Key</th>
|
||
<th>Wert</th>
|
||
<th>Typ</th>
|
||
<th>Aktion</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
|
||
<?php foreach ($fields as $f): ?>
|
||
<tr>
|
||
<form method="post">
|
||
<td>
|
||
<input name="key"
|
||
value="<?= htmlspecialchars($f['field_key']) ?>">
|
||
</td>
|
||
<td class="value-cell">
|
||
<div data-value-wrapper class="value-field-wrapper">
|
||
<?= renderValueFieldElement($f['typ'], $f['field_value'], 'value', null, [], $identityFiles) ?>
|
||
</div>
|
||
</td>
|
||
<td>
|
||
<select name="typ" data-typ-switch>
|
||
<option value="single" <?= $f['typ']==='single'?'selected':'' ?>>einzeilig</option>
|
||
<option value="multi" <?= $f['typ']==='multi'?'selected':'' ?>>mehrzeilig</option>
|
||
<option value="file" <?= $f['typ']==='file'?'selected':'' ?>>Datei</option>
|
||
<option value="url" <?= $f['typ']==='url'?'selected':'' ?>>URL</option>
|
||
</select>
|
||
</td>
|
||
<td>
|
||
<input type="hidden" name="field_id" value="<?= (int)$f['id'] ?>">
|
||
<button name="update_field">💾</button>
|
||
<button name="delete_field"
|
||
onclick="return confirm('Feld wirklich löschen?')">🗑</button>
|
||
</td>
|
||
</form>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
|
||
</tbody>
|
||
</table>
|
||
|
||
<h3>Neues Feld</h3>
|
||
<form method="post">
|
||
<input name="key" placeholder="Feldname" required>
|
||
<div data-value-wrapper class="value-field-wrapper" data-placeholder="Wert">
|
||
<?= renderValueFieldElement('single', '', 'value', 'new-field-value', ['placeholder' => 'Wert'], $identityFiles) ?>
|
||
</div>
|
||
<select name="typ" data-typ-switch>
|
||
<option value="single">einzeilig</option>
|
||
<option value="multi">mehrzeilig</option>
|
||
<option value="file">Datei</option>
|
||
<option value="url">URL</option>
|
||
</select>
|
||
<button name="add_field">➕ Feld hinzufügen</button>
|
||
</form>
|
||
|
||
<h3>Dateien hochladen</h3>
|
||
<form method="post" enctype="multipart/form-data">
|
||
<input type="file" name="files[]" multiple>
|
||
<button name="upload_files">Hochladen</button>
|
||
</form>
|
||
|
||
<?php if ($fileUploadSuccess > 0): ?>
|
||
<p style="color:#22c55e; margin-top:.5rem;">
|
||
<?= $fileUploadSuccess ?> Datei<?= $fileUploadSuccess === 1 ? '' : 'en' ?> hochgeladen.
|
||
</p>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($fileUploadErrors)): ?>
|
||
<ul style="color:#f87171; margin-top:.5rem;">
|
||
<?php foreach ($fileUploadErrors as $error): ?>
|
||
<li><?= htmlspecialchars($error) ?></li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!empty($identityFiles)): ?>
|
||
<h3>Vorhandene Dateien</h3>
|
||
<ul>
|
||
<?php foreach ($identityFiles as $file): ?>
|
||
<li><?= htmlspecialchars($file['filename']) ?> (ID <?= (int)$file['id'] ?>)</li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
<?php endif; ?>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
const identityFiles = <?= json_encode(array_map(function ($file) {
|
||
return [
|
||
'id' => (int)$file['id'],
|
||
'filename' => $file['filename'],
|
||
];
|
||
}, $identityFiles), JSON_UNESCAPED_UNICODE | JSON_HEX_TAG) ?: '[]' ?>;
|
||
function createValueFieldElement(type, opts) {
|
||
opts = opts || {};
|
||
var element;
|
||
if (type === 'multi') {
|
||
element = document.createElement('textarea');
|
||
element.rows = 3;
|
||
} else if (type === 'file') {
|
||
element = document.createElement('select');
|
||
} else {
|
||
element = document.createElement('input');
|
||
element.type = type === 'url' ? 'url' : 'text';
|
||
}
|
||
|
||
element.name = opts.name || 'value';
|
||
element.style.width = '100%';
|
||
if (opts.id) {
|
||
element.id = opts.id;
|
||
}
|
||
|
||
if (type === 'file') {
|
||
var placeholder = opts.placeholder || '-- Datei wählen --';
|
||
var defaultOption = document.createElement('option');
|
||
defaultOption.value = '';
|
||
defaultOption.textContent = placeholder;
|
||
element.appendChild(defaultOption);
|
||
|
||
identityFiles.forEach(function (file) {
|
||
var option = document.createElement('option');
|
||
option.value = file.id;
|
||
option.textContent = file.filename;
|
||
if (opts.value && String(opts.value) === String(file.id)) {
|
||
option.selected = true;
|
||
}
|
||
element.appendChild(option);
|
||
});
|
||
|
||
return element;
|
||
}
|
||
|
||
if (opts.placeholder) {
|
||
element.setAttribute('placeholder', opts.placeholder);
|
||
}
|
||
element.value = opts.value || '';
|
||
return element;
|
||
}
|
||
|
||
function updateValueField(select) {
|
||
var form = select.closest('form');
|
||
if (!form) {
|
||
return;
|
||
}
|
||
var wrapper = form.querySelector('[data-value-wrapper]');
|
||
if (!wrapper) {
|
||
return;
|
||
}
|
||
|
||
var existing = wrapper.querySelector('[name="value"]');
|
||
var opts = {
|
||
name: existing ? existing.name : 'value',
|
||
id: existing ? existing.id : '',
|
||
placeholder: existing ? existing.getAttribute('placeholder') : wrapper.getAttribute('data-placeholder') || '',
|
||
value: existing ? existing.value : ''
|
||
};
|
||
|
||
if (select.value === 'file') {
|
||
delete opts.value;
|
||
}
|
||
|
||
wrapper.textContent = '';
|
||
wrapper.appendChild(createValueFieldElement(select.value, opts));
|
||
}
|
||
|
||
var switchers = document.querySelectorAll('select[data-typ-switch]');
|
||
for (var i = 0; i < switchers.length; i++) {
|
||
switchers[i].addEventListener('change', function () {
|
||
updateValueField(this);
|
||
});
|
||
}
|
||
});
|
||
</script>
|
||
|
||
|
||
<p><a href="admin.php">← zurück</a></p>
|
||
|
||
</body>
|
||
</html>
|
||
<?php
|
||
exit;
|
||
}
|
||
|
||
/* ─────────────────────────────
|
||
CREATE UUID
|
||
───────────────────────────── */
|
||
if ($action === 'uuid_create') {
|
||
|
||
$identityId = (int)($_GET['identity_id'] ?? 0);
|
||
|
||
$uuid = uuid_create(UUID_TYPE_RANDOM);
|
||
|
||
$sql->set(
|
||
"INSERT INTO access_tokens (identity_id, uuid)
|
||
VALUES (?, ?)",
|
||
"is",
|
||
[$identityId, $uuid]
|
||
);
|
||
|
||
header("Location: admin.php?action=uuid_edit&uuid=$uuid");
|
||
exit;
|
||
}
|
||
|
||
/* ─────────────────────────────
|
||
EDIT UUID
|
||
───────────────────────────── */
|
||
if ($action === 'uuid_edit') {
|
||
$uuid = $_GET['uuid'] ?? '';
|
||
|
||
$token = $sql->single(
|
||
"SELECT * FROM access_tokens WHERE uuid = ?",
|
||
"s",
|
||
[$uuid]
|
||
);
|
||
|
||
if (!$token) exit('UUID nicht gefunden');
|
||
|
||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
|
||
$sql->set(
|
||
"DELETE FROM token_permissions WHERE token_id = ?",
|
||
"i",
|
||
[$token['id']]
|
||
);
|
||
|
||
foreach ($_POST['fields'] ?? [] as $key) {
|
||
$sql->set(
|
||
"INSERT INTO token_permissions (token_id, field_key)
|
||
VALUES (?, ?)",
|
||
"is",
|
||
[$token['id'], $key]
|
||
);
|
||
}
|
||
|
||
$sql->set(
|
||
"UPDATE access_tokens SET notes = ? WHERE id = ?",
|
||
"si",
|
||
[trim($_POST['notes']), $token['id']]
|
||
);
|
||
}
|
||
|
||
// Alle Felder der zugehörigen Identität
|
||
$fields = $sql->get(
|
||
"SELECT field_key, field_value FROM identity_fields WHERE identity_id = ?",
|
||
"i",
|
||
[$token['identity_id']]
|
||
);
|
||
|
||
// Welche Felder aktuell für diesen Token erlaubt sind
|
||
$allowed = array_column(
|
||
$sql->get(
|
||
"SELECT field_key FROM token_permissions WHERE token_id = ?",
|
||
"i",
|
||
[$token['id']]
|
||
),
|
||
'field_key'
|
||
);
|
||
|
||
// Name der Identität
|
||
$identity = $sql->single(
|
||
"SELECT name FROM identities WHERE id = ?",
|
||
"i",
|
||
[$token['identity_id']]
|
||
);
|
||
?>
|
||
<!doctype html>
|
||
<html><head><meta charset="utf-8"><title>UUID bearbeiten</title><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||
</head>
|
||
<body>
|
||
<h1>UUID bearbeiten</h1>
|
||
<p><strong>UUID:</strong> <code><?= htmlspecialchars($uuid) ?></code></p>
|
||
<p><strong>Identität:</strong> <?= htmlspecialchars($identity['name']) ?></p>
|
||
|
||
<form method="post">
|
||
<h3>Sichtbare Felder</h3>
|
||
<?php foreach ($fields as $f): ?>
|
||
<label>
|
||
<input type="checkbox" name="fields[]"
|
||
value="<?= htmlspecialchars($f['field_key']) ?>"
|
||
<?= in_array($f['field_key'], $allowed) ? 'checked' : '' ?>>
|
||
<?= htmlspecialchars($f['field_key']) ?>:
|
||
<em><?= htmlspecialchars($f['field_value']) ?></em>
|
||
</label><br>
|
||
<?php endforeach; ?>
|
||
|
||
<h3>Notiz</h3>
|
||
<textarea name="notes" rows="4"><?= htmlspecialchars($token['notes']) ?></textarea>
|
||
<br>
|
||
<button>Speichern</button>
|
||
</form>
|
||
|
||
<p><a href="admin.php">← zurück</a></p>
|
||
</body></html>
|
||
<?php
|
||
exit;
|
||
}
|
||
|
||
/* ─────────────────────────────
|
||
DASHBOARD (UUIDs + Identitäten)
|
||
───────────────────────────── */
|
||
$tokens = $sql->get(
|
||
"SELECT t.uuid, t.notes, i.name AS identity_name
|
||
FROM access_tokens t
|
||
JOIN identities i ON t.identity_id = i.id
|
||
ORDER BY t.created_at DESC"
|
||
);
|
||
|
||
$identities = $sql->get("SELECT * FROM identities ORDER BY id DESC");
|
||
?>
|
||
<!doctype html>
|
||
<html lang="de">
|
||
<head><meta charset="utf-8"><title>Admin Dashboard</title><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||
</head>
|
||
<body>
|
||
|
||
<h1>Admin Dashboard</h1>
|
||
|
||
<h2>Alle UUIDs</h2>
|
||
<?php if (!empty($tokens)): ?>
|
||
<table border="1" cellpadding="5" cellspacing="0">
|
||
<thead>
|
||
<tr>
|
||
<th>UUID</th>
|
||
<th>Identität</th>
|
||
<th>Notiz</th>
|
||
<th>Aktion</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach ($tokens as $t): ?>
|
||
<tr>
|
||
<td><code><?= htmlspecialchars($t['uuid']) ?></code></td>
|
||
<td><?= htmlspecialchars($t['identity_name']) ?></td>
|
||
<td><?= htmlspecialchars($t['notes']) ?></td>
|
||
<td><a href="admin.php?action=uuid_edit&uuid=<?= urlencode($t['uuid']) ?>">bearbeiten</a></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
<?php else: ?>
|
||
<p>Keine UUIDs vorhanden.</p>
|
||
<?php endif; ?>
|
||
|
||
<hr>
|
||
|
||
<h2>Identitäten</h2>
|
||
<p><a href="admin.php?action=identity_create">➕ Identität anlegen</a></p>
|
||
<ul>
|
||
<?php foreach ($identities as $i): ?>
|
||
<li>
|
||
<strong><?= htmlspecialchars($i['name']) ?></strong>
|
||
– <a href="admin.php?action=identity_edit&id=<?= $i['id'] ?>">bearbeiten</a>
|
||
</li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
|
||
<p><a href="logout.php">Logout</a></p>
|
||
</body>
|
||
</html>
|
||
<?php
|
||
//TODO einheitliches dunkles design
|
||
?>
|