Files
Walschleber-Kultour-CMS/admin.php
T

378 lines
15 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
// admin.php
declare(strict_types=1);
session_start();
require_once __DIR__ . '/functions.php';
$loggedIn = isset($_SESSION['admin']) && $_SESSION['admin'] === true;
// Login
if (isset($_POST['action']) && $_POST['action'] === 'login') {
if (($_POST['password'] ?? '') === ADMIN_PASSWORD_PLAIN) {
$_SESSION['admin'] = true;
header('Location: admin.php');
exit;
} else {
$error = 'Falsches Passwort.';
}
}
// Logout
if (isset($_GET['logout'])) {
$_SESSION = [];
session_destroy();
header('Location: admin.php');
exit;
}
if ($loggedIn) {
// CREATE/UPDATE
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_event'])) {
$events = load_events();
$id = $_POST['id'] ?: 'evt_' . bin2hex(random_bytes(6));
$title = sanitize_text($_POST['title'] ?? '');
$speaker = sanitize_text($_POST['speaker'] ?? '');
$date = sanitize_text($_POST['date'] ?? '');
$time = sanitize_text($_POST['time'] ?? '19:30');
$venue_name = sanitize_text($_POST['venue_name'] ?? '');
$venue_address = sanitize_text($_POST['venue_address'] ?? '');
$price = sanitize_text($_POST['price'] ?? '');
$doors_open = sanitize_text($_POST['doors_open'] ?? '');
$tickets_info = sanitize_text($_POST['tickets_info'] ?? '');
$reserve_by_mail = isset($_POST['reserve_by_mail']) && $_POST['reserve_by_mail'] === '1';
$reserve_email = trim((string)($_POST['reserve_email'] ?? ''));
if ($reserve_email !== '' && !filter_var($reserve_email, FILTER_VALIDATE_EMAIL)) {
$reserve_email = '';
}
$catering = sanitize_text($_POST['catering'] ?? '');
$tags = sanitize_text($_POST['tags'] ?? '');
$description = trim($_POST['description'] ?? '');
$existing_image = sanitize_text($_POST['existing_image'] ?? '');
if ($title === '' || $date === '') {
$error = 'Titel und Datum sind Pflichtfelder.';
} else {
try {
$imagePath = $existing_image;
if (!empty($_FILES['image']['name'])) {
$imagePath = handle_image_upload($_FILES['image']);
}
$slug = make_slug($title, $date);
// Update falls vorhanden
$events = load_events();
$idx = null;
foreach ($events as $k => $ev) {
if ($ev['id'] === $id) { $idx = $k; break; }
}
$record = [
'id' => $id,
'title' => $title,
'speaker' => $speaker,
'date' => $date,
'time' => $time,
'venue_name' => $venue_name,
'venue_address' => $venue_address,
'price' => $price,
'doors_open' => $doors_open,
'tickets_info' => $tickets_info,
'reserve_by_mail' => $reserve_by_mail,
'reserve_email' => $reserve_email,
'catering' => $catering,
'tags' => $tags,
'description' => $description,
'image' => $imagePath,
'slug' => $slug,
'updated_at' => now_iso()
];
if ($idx !== null) {
$events[$idx] = $record;
} else {
$record['created_at'] = now_iso();
$events[] = $record;
}
save_events($events);
header('Location: admin.php?ok=1');
exit;
} catch (Throwable $e) {
$error = 'Fehler: ' . $e->getMessage();
}
}
}
// DELETE
if (isset($_GET['delete'])) {
$events = load_events();
$id = $_GET['delete'];
$events = array_values(array_filter($events, fn($e) => $e['id'] !== $id));
save_events($events);
header('Location: admin.php?deleted=1');
exit;
}
// EDIT load
$editEvent = null;
if (isset($_GET['edit'])) {
$id = $_GET['edit'];
foreach (load_events() as $e) {
if ($e['id'] === $id) { $editEvent = $e; break; }
}
}
}
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Admin | <?= h(SITE_NAME) ?></title>
<meta name="robots" content="noindex,nofollow">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="/assets/styles.css">
<link rel="icon" href="/assets/logo.png" sizes="32x32" type="image/png">
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary border-bottom sticky-top">
<div class="container">
<a class="navbar-brand brand-logo" href="index.html">
<img src="/assets/logo.png" alt="Walschleber KulTour Logo" height="34" width="34">
<span><?= h(SITE_NAME) ?></span>
</a>
<div class="ms-auto">
<?php if ($loggedIn): ?>
<a class="btn btn-outline-secondary btn-sm" href="admin.php?logout=1">Logout</a>
<?php endif; ?>
</div>
</div>
</nav>
<?php if (!$loggedIn): ?>
<header class="py-5 bg-light border-bottom">
<div class="container">
<div class="akzent-line mb-3"></div>
<h1 class="display-6 mb-2">Admin-Login</h1>
</div>
</header>
<main class="container my-5">
<div class="row justify-content-center">
<div class="col-md-6 col-lg-5">
<div class="p-4 border rounded-3 bg-white">
<?php if (!empty($error)): ?><div class="alert alert-danger"><?= h($error) ?></div><?php endif; ?>
<form method="post" autocomplete="off">
<input type="hidden" name="action" value="login">
<div class="mb-3">
<label class="form-label">Passwort</label>
<input type="password" class="form-control form-control-lg" name="password" required>
</div>
<button class="btn btn-brand btn-lg w-100">Einloggen</button>
</form>
</div>
</div>
</div>
</main>
<?php else: ?>
<header class="py-5 bg-light border-bottom">
<div class="container">
<div class="akzent-line mb-3"></div>
<h1 class="display-6 mb-2">Vorträge verwalten</h1>
<p class="text-muted mb-0">Anlegen, bearbeiten, Bilder hochladen.</p>
</div>
</header>
<main class="container my-4">
<div class="d-flex align-items-center gap-2 mb-3">
<?php if (isset($_GET['ok'])): ?><span class="badge text-bg-success">Gespeichert</span><?php endif; ?>
<?php if (isset($_GET['deleted'])): ?><span class="badge text-bg-warning">Gelöscht</span><?php endif; ?>
</div>
<div class="row g-4">
<div class="col-lg-5">
<div class="card shadow-sm">
<div class="card-body">
<h2 class="h5 mb-3"><?= $editEvent ? 'Vortrag bearbeiten' : 'Neuen Vortrag anlegen' ?></h2>
<?php if (!empty($error)): ?><div class="alert alert-danger"><?= h($error) ?></div><?php endif; ?>
<form method="post" enctype="multipart/form-data">
<input type="hidden" name="id" value="<?= h($editEvent['id'] ?? '') ?>">
<div class="mb-3">
<label class="form-label">Titel*</label>
<input type="text" class="form-control" name="title" required value="<?= h($editEvent['title'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">Referent/Autor</label>
<input type="text" class="form-control" name="speaker" value="<?= h($editEvent['speaker'] ?? '') ?>">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Datum*</label>
<input type="date" class="form-control" name="date" required value="<?= h($editEvent['date'] ?? '') ?>">
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Uhrzeit</label>
<input type="time" class="form-control" name="time" value="<?= h($editEvent['time'] ?? '19:30') ?>">
</div>
</div>
<div class="mb-3">
<label class="form-label">Veranstaltungsort (Name)</label>
<input type="text" class="form-control" name="venue_name" value="<?= h($editEvent['venue_name'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">Adresse (Straße, PLZ Ort)</label>
<input type="text" class="form-control" name="venue_address" value="<?= h($editEvent['venue_address'] ?? '') ?>">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label">Eintritt (z.B. 12 €)</label>
<input type="text" class="form-control" name="price" value="<?= h($editEvent['price'] ?? '') ?>">
</div>
<div class="col-md-6 mb-3">
<label class="form-label">Einlass (z.B. 18:30)</label>
<input type="text" class="form-control" name="doors_open" value="<?= h($editEvent['doors_open'] ?? '') ?>">
</div>
</div>
<div class="mb-3">
<label class="form-label">Ticket/VVK-Info</label>
<input type="text" class="form-control" name="tickets_info" value="<?= h($editEvent['tickets_info'] ?? '') ?>">
</div>
<div class="form-check form-switch mb-2">
<input class="form-check-input" type="checkbox" id="reserve_by_mail" name="reserve_by_mail" value="1" <?= !empty($editEvent['reserve_by_mail']) ? 'checked' : '' ?>>
<label class="form-check-label" for="reserve_by_mail">Tickets per EMail reservieren</label>
</div>
<div class="mb-3" id="reserve_email_wrap">
<label class="form-label">ReservierungsEMail (optional)</label>
<input type="email" class="form-control" name="reserve_email" value="<?= h($editEvent['reserve_email'] ?? '') ?>" placeholder="z.B. tickets@…">
<div class="form-text">Wenn leer, wird versucht, eine EMail-Adresse aus „Ticket/VVKInfo“ zu erkennen. Sonst bleibt der Empfänger leer.</div>
</div>
<div class="mb-3">
<label class="form-label">Verpflegung/Service</label>
<input type="text" class="form-control" name="catering" value="<?= h($editEvent['catering'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">Tags (Kommagetrennt)</label>
<input type="text" class="form-control" name="tags" value="<?= h($editEvent['tags'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">Beschreibung</label>
<textarea class="form-control" name="description" rows="6"><?= h($editEvent['description'] ?? '') ?></textarea>
</div>
<?php if (!empty($editEvent['image'])): ?>
<div class="mb-2">
<img src="<?= h($editEvent['image']) ?>" alt="aktuelles Bild" class="img-fluid rounded">
</div>
<input type="hidden" name="existing_image" value="<?= h($editEvent['image']) ?>">
<?php endif; ?>
<div class="mb-3">
<label class="form-label">Bild (JPG/PNG/WEBP)</label>
<input type="file" class="form-control" name="image" accept=".jpg,.jpeg,.png,.webp">
</div>
<button class="btn btn-brand" name="save_event" value="1">Speichern</button>
<?php if ($editEvent): ?>
<a href="admin.php" class="btn btn-outline-secondary ms-2">Abbrechen</a>
<?php endif; ?>
</form>
</div>
</div>
</div>
<div class="col-lg-7">
<div class="card shadow-sm">
<div class="card-body">
<h2 class="h5 mb-3">Alle Vorträge</h2>
<?php
$events = load_events();
usort($events, 'by_datetime_desc');
?>
<?php if (!$events): ?>
<p class="text-muted">Noch keine Einträge.</p>
<?php else: ?>
<div class="table-responsive">
<table class="table align-middle">
<thead>
<tr>
<th>Datum</th>
<th>Titel</th>
<th>Ort</th>
<th class="text-end"></th>
</tr>
</thead>
<tbody>
<?php foreach ($events as $e): ?>
<tr>
<td><?= h($e['date']) ?> <?= h($e['time']) ?></td>
<td>
<div class="fw-semibold"><?= h($e['title']) ?></div>
<div class="text-muted small"><?= h($e['speaker']) ?></div>
<?php if (!empty($e['reserve_by_mail'])): ?>
<span class="badge text-bg-info">MailReservierung</span>
<?php endif; ?>
</td>
<td><?= h($e['venue_name']) ?></td>
<td class="text-end">
<a class="btn btn-sm btn-outline-primary" href="admin.php?edit=<?= h($e['id']) ?>">Bearbeiten</a>
<a class="btn btn-sm btn-outline-danger" href="admin.php?delete=<?= h($e['id']) ?>" onclick="return confirm('Wirklich löschen?')">Löschen</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<section class="my-4">
<div class="cta-band p-4 d-md-flex justify-content-between align-items-center rounded-4">
<div class="mb-3 mb-md-0">
<p class="section-kicker mb-1">Tipp</p>
<div class="h6 mb-0">Wenn „Ticket/VVK-Info“ eine URL enthält, zeigt die Programmseite automatisch den Button <em>„Tickets sichern“</em>. Wenn „Tickets per EMail reservieren“ aktiv ist, erscheint zusätzlich ein Button, der eine Mailvorlage im Mailprogramm öffnet.</div>
</div>
<a class="btn btn-accent" href="programm.php" target="_blank" rel="noopener">Programm ansehen</a>
</div>
</section>
</div>
</div>
</main>
<?php endif; ?>
<footer class="py-4 border-top mt-5">
<div class="container small d-flex gap-3 flex-wrap">
<span>&copy; <?= date('Y') ?> <?= h(SITE_NAME) ?></span>
<a href="impressum.html">Impressum</a>
<a href="datenschutz.html">Datenschutz</a>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Admin UI: ReservierungsEMail Feld nur anzeigen, wenn „Tickets per EMail reservieren“ aktiv ist
(function () {
const toggle = document.getElementById('reserve_by_mail');
const wrap = document.getElementById('reserve_email_wrap');
if (!toggle || !wrap) return;
const apply = () => { wrap.style.display = toggle.checked ? '' : 'none'; };
toggle.addEventListener('change', apply);
apply();
})();
</script>
</body>
</html>