| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938 |
- <?php
- require_once __DIR__ . "/../config.php";
- require_once __DIR__ . "/../includes/functions.php";
- require_once __DIR__ . "/../includes/version.php";
- require_once __DIR__ . "/../includes/backup.php";
- if (!defined("UPDATE_MANIFEST_URL")) {
- define("UPDATE_MANIFEST_URL", "");
- }
- function settingsUpdaterVersionCompareValue(string $version): string
- {
- return ltrim(trim($version), "vV");
- }
- function settingsGetUpdaterStatus(): array
- {
- $manifestUrl = trim((string) UPDATE_MANIFEST_URL);
- if ($manifestUrl === "") {
- return [
- "label" => "Update-Ziel ist nicht konfiguriert.",
- "available" => false,
- "version" => "",
- ];
- }
- $context = stream_context_create([
- "http" => [
- "method" => "GET",
- "timeout" => 3,
- "ignore_errors" => true,
- "header" => "User-Agent: PSA-Orderform-Settings/" . APP_VERSION . "\r\n",
- ],
- ]);
- $body = @file_get_contents($manifestUrl, false, $context);
- if ($body === false) {
- return [
- "label" => "Update-Status konnte nicht geladen werden.",
- "available" => false,
- "version" => "",
- ];
- }
- $manifest = json_decode($body, true);
- if (!is_array($manifest)) {
- return [
- "label" => "Update-Status ist ungültig.",
- "available" => false,
- "version" => "",
- ];
- }
- $version = trim((string) ($manifest["version"] ?? $manifest["latest"] ?? ""));
- if (!preg_match('/^v\d+\.\d+\.\d+$/', $version)) {
- return [
- "label" => "Update-Version ist ungültig.",
- "available" => false,
- "version" => "",
- ];
- }
- $available =
- version_compare(
- settingsUpdaterVersionCompareValue($version),
- settingsUpdaterVersionCompareValue(APP_VERSION),
- ">",
- );
- return [
- "label" => $available
- ? "Update verfügbar: " . $version
- : "Kein Update verfügbar.",
- "available" => $available,
- "version" => $version,
- ];
- }
- function settingsFormatBackupDate(string $date): string
- {
- $timestamp = strtotime($date);
- if ($timestamp === false) {
- return $date;
- }
- return date("d.m.Y H:i", $timestamp);
- }
- function settingsGetBackupUploadLabel(array $backup): string
- {
- $uploads =
- isset($backup["remote_uploads"]) && is_array($backup["remote_uploads"])
- ? $backup["remote_uploads"]
- : [];
- if (empty($uploads)) {
- return "Nur lokal";
- }
- $successful = 0;
- foreach ($uploads as $upload) {
- if (is_array($upload) && !empty($upload["success"])) {
- $successful++;
- }
- }
- if ($successful === count($uploads)) {
- return "Remote erfolgreich (" . $successful . ")";
- }
- if ($successful > 0) {
- return "Teilweise erfolgreich (" . $successful . "/" . count($uploads) . ")";
- }
- return "Remote fehlgeschlagen";
- }
- function settingsGetBackupCapabilityLabel(array $capability): string
- {
- if (empty($capability["configured"])) {
- return "nicht konfiguriert";
- }
- return !empty($capability["available"]) ? "bereit" : "nicht verfügbar";
- }
- function settingsIsSuperAdmin(): bool
- {
- return normalizeAdminUsername($_SESSION['admin_username'] ?? "") === "admin";
- }
- function settingsGetLocalConfigPath(): string
- {
- return dirname(__DIR__) . "/config.php";
- }
- function settingsReadLocalConfig(): string
- {
- $path = settingsGetLocalConfigPath();
- if (!is_file($path) || !is_readable($path)) {
- return "";
- }
- $content = file_get_contents($path);
- return $content === false ? "" : $content;
- }
- function settingsWriteLocalConfig(string $content): void
- {
- $content = str_replace("\r\n", "\n", $content);
- if (!str_starts_with(ltrim($content), "<?php")) {
- throw new RuntimeException('Die Konfiguration muss mit "<?php" beginnen.');
- }
- try {
- token_get_all($content, TOKEN_PARSE);
- } catch (ParseError $parseError) {
- throw new RuntimeException("PHP-Syntaxfehler: " . $parseError->getMessage());
- }
- $path = settingsGetLocalConfigPath();
- $tmpFile = $path . ".tmp";
- if (file_put_contents($tmpFile, $content, LOCK_EX) === false) {
- throw new RuntimeException("Konfiguration konnte nicht geschrieben werden.");
- }
- $backupDir = DATA_DIR . "backups/config/";
- if (!is_dir($backupDir) && !mkdir($backupDir, 0775, true) && !is_dir($backupDir)) {
- @unlink($tmpFile);
- throw new RuntimeException("Sicherungsverzeichnis konnte nicht angelegt werden.");
- }
- if (is_file($path)) {
- $backupPath = $backupDir . "config-" . date("Ymd-His") . ".php.bak";
- if (!copy($path, $backupPath)) {
- @unlink($tmpFile);
- throw new RuntimeException("Sicherung der bestehenden Konfiguration ist fehlgeschlagen.");
- }
- }
- @chmod($tmpFile, 0664);
- if (!rename($tmpFile, $path)) {
- @unlink($tmpFile);
- throw new RuntimeException("Konfiguration konnte nicht gespeichert werden.");
- }
- if (function_exists("opcache_invalidate")) {
- opcache_invalidate($path, true);
- }
- }
- function settingsFindBackupByFilename(string $filename): ?array
- {
- if ($filename === "" || basename($filename) !== $filename) {
- return null;
- }
- foreach (backupListBackups() as $backup) {
- if (($backup["filename"] ?? "") === $filename) {
- return $backup;
- }
- }
- return null;
- }
- function settingsSendBackupDownload(array $backup): void
- {
- $filename = basename((string) ($backup["filename"] ?? ""));
- $path = backupGetDirectory() . $filename;
- if ($filename === "" || !is_file($path) || !is_readable($path)) {
- throw new RuntimeException("Backup-Datei wurde nicht gefunden.");
- }
- $size = filesize($path);
- if ($size === false) {
- throw new RuntimeException("Backup-Dateigröße konnte nicht gelesen werden.");
- }
- logAccess("Backup downloaded", [
- "filename" => $filename,
- ]);
- header("Content-Type: application/zip");
- header('Content-Disposition: attachment; filename="' . $filename . '"');
- header("Content-Length: " . (string) $size);
- header("X-Content-Type-Options: nosniff");
- readfile($path);
- exit();
- }
- if (empty($_SESSION['admin_logged_in'])) {
- header("Location: login.php");
- exit();
- }
- $pageTitle = "Einstellungen";
- $message = "";
- $messageType = "";
- $isSuperAdmin = settingsIsSuperAdmin();
- if ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['save_settings'])) {
- // Validate CSRF token
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- $settings = array_merge(getSystemSettings(), [
- "order_recipient_email" => $_POST['order_recipient_email'] ?? "",
- "attach_order_pdf_to_admin_email" => isset(
- $_POST['attach_order_pdf_to_admin_email'],
- ),
- "nametag_product_name" => $_POST['nametag_product_name'] ?? "",
- ]);
- if (saveSystemSettings($settings)) {
- logAccess("Admin updated system settings");
- $message = "Einstellungen wurden gespeichert.";
- $messageType = "success";
- } else {
- $message = "Einstellungen konnten nicht gespeichert werden.";
- $messageType = "error";
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['create_backup'])) {
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- try {
- $backup = backupCreate("manual");
- $message =
- "Backup wurde erstellt: " .
- $backup["filename"] .
- " (" .
- backupFormatBytes((int) $backup["size"]) .
- ").";
- $messageType = "success";
- } catch (Throwable $exception) {
- $message = "Backup konnte nicht erstellt werden: " . $exception->getMessage();
- $messageType = "error";
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['download_backup'])) {
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- try {
- $backup = settingsFindBackupByFilename((string) ($_POST["backup_filename"] ?? ""));
- if ($backup === null) {
- throw new RuntimeException("Backup wurde nicht gefunden.");
- }
- settingsSendBackupDownload($backup);
- } catch (Throwable $exception) {
- $message = "Backup konnte nicht heruntergeladen werden: " . $exception->getMessage();
- $messageType = "error";
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['save_local_config'])) {
- if (!$isSuperAdmin) {
- http_response_code(403);
- $message = "Keine Berechtigung für diese Aktion.";
- $messageType = "error";
- } elseif (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- try {
- settingsWriteLocalConfig((string) ($_POST['local_config_content'] ?? ""));
- logAccess("Admin updated local config.php");
- $message = "Lokale Konfiguration wurde gespeichert.";
- $messageType = "success";
- } catch (Throwable $exception) {
- $message = "Konfiguration konnte nicht gespeichert werden: " . $exception->getMessage();
- $messageType = "error";
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['add_category'])) {
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- $categories = getCategories();
- $label = normalizeCategoryLabel($_POST['category_label'] ?? "");
- if (!isValidCategoryLabel($label)) {
- $message = "Bitte geben Sie einen Kategorienamen mit maximal 80 Zeichen ein.";
- $messageType = "error";
- } else {
- $categoryId = generateCategoryIdFromLabel($label, $categories);
- $categories[] = [
- "id" => $categoryId,
- "label" => $label,
- ];
- if (saveCategories($categories)) {
- logAccess("Admin added category", [
- "category_id" => $categoryId,
- "label" => $label,
- ]);
- $message = "Kategorie wurde erfolgreich angelegt.";
- $messageType = "success";
- } else {
- $message = "Kategorie konnte nicht gespeichert werden.";
- $messageType = "error";
- }
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['update_category'])) {
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- $categories = getCategories();
- $categoryId = normalizeCategoryId($_POST['category_id'] ?? "");
- $label = normalizeCategoryLabel($_POST['category_label'] ?? "");
- $found = false;
- if (!isValidCategoryLabel($label)) {
- $message = "Bitte geben Sie einen Kategorienamen mit maximal 80 Zeichen ein.";
- $messageType = "error";
- } else {
- foreach ($categories as &$category) {
- if ($category["id"] === $categoryId) {
- $category["label"] = $label;
- $found = true;
- break;
- }
- }
- unset($category);
- if (!$found) {
- $message = "Kategorie nicht gefunden.";
- $messageType = "error";
- } elseif (saveCategories($categories)) {
- logAccess("Admin updated category", [
- "category_id" => $categoryId,
- "label" => $label,
- ]);
- $message = "Kategorie wurde erfolgreich aktualisiert.";
- $messageType = "success";
- } else {
- $message = "Kategorie konnte nicht gespeichert werden.";
- $messageType = "error";
- }
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['delete_category'])) {
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- $categoryId = normalizeCategoryId($_POST['category_id'] ?? "");
- $label = "";
- $found = false;
- if (isCategoryInUse($categoryId)) {
- $message =
- "Diese Kategorie wird noch von Produkten verwendet und kann nicht gelöscht werden.";
- $messageType = "error";
- } else {
- $categories = array_values(
- array_filter(getCategories(), function ($category) use (
- $categoryId,
- &$found,
- &$label,
- ) {
- if ($category["id"] === $categoryId) {
- $found = true;
- $label = $category["label"];
- return false;
- }
- return true;
- }),
- );
- if (!$found) {
- $message = "Kategorie nicht gefunden.";
- $messageType = "error";
- } elseif (saveCategories($categories)) {
- logAccess("Admin deleted category", [
- "category_id" => $categoryId,
- "label" => $label,
- ]);
- $message = "Kategorie wurde gelöscht.";
- $messageType = "success";
- } else {
- $message = "Kategorie konnte nicht gelöscht werden.";
- $messageType = "error";
- }
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['save_faq'])) {
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- $content = isset($_POST['content']) ? (string) $_POST['content'] : "";
- $faqSettings = array_merge(getSystemSettings(), [
- "startpage_intro_text" => isset($_POST['startpage_intro_text'])
- ? (string) $_POST['startpage_intro_text']
- : "",
- ]);
- if (saveFaqContent($content) && saveSystemSettings($faqSettings)) {
- logAccess("Admin updated FAQ content");
- $message = "FAQ-Inhalt und Startseitentext wurden gespeichert.";
- $messageType = "success";
- } else {
- $message = "FAQ-Inhalt und/oder Startseitentext konnten nicht gespeichert werden.";
- $messageType = "error";
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['add_organization'])) {
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- $organizations = getOrganizations(false);
- $label = normalizeOrganizationLabel($_POST['organization_label'] ?? "");
- $sortOrder = (int) ($_POST['sort_order'] ?? 0);
- $active = isset($_POST['active']);
- if (!isValidOrganizationLabel($label)) {
- $message = "Bitte einen Organisationsnamen mit maximal 120 Zeichen eingeben.";
- $messageType = "error";
- } else {
- $orgId = generateOrganizationIdFromLabel($label, $organizations);
- $organizations[] = [
- "id" => $orgId,
- "label" => $label,
- "sort_order" => $sortOrder,
- "active" => $active,
- ];
- if (saveOrganizations($organizations)) {
- logAccess("Admin added organization", [
- "org_id" => $orgId,
- "label" => $label,
- ]);
- $message = "Organisation wurde angelegt.";
- $messageType = "success";
- } else {
- $message = "Organisation konnte nicht gespeichert werden.";
- $messageType = "error";
- }
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['update_organization'])) {
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- $organizations = getOrganizations(false);
- $organizationId = normalizeOrganizationId($_POST['organization_id'] ?? "");
- $label = normalizeOrganizationLabel($_POST['organization_label'] ?? "");
- $sortOrder = (int) ($_POST['sort_order'] ?? 0);
- $active = isset($_POST['active']);
- $updated = false;
- if (!isValidOrganizationLabel($label)) {
- $message = "Bitte einen Organisationsnamen mit maximal 120 Zeichen eingeben.";
- $messageType = "error";
- } else {
- foreach ($organizations as &$organization) {
- if ($organization["id"] !== $organizationId) {
- continue;
- }
- $organization["label"] = $label;
- $organization["sort_order"] = $sortOrder;
- $organization["active"] = $active;
- $updated = true;
- break;
- }
- unset($organization);
- if (!$updated) {
- $message = "Organisation nicht gefunden.";
- $messageType = "error";
- } elseif (saveOrganizations($organizations)) {
- logAccess("Admin updated organization", [
- "org_id" => $organizationId,
- "label" => $label,
- ]);
- $message = "Organisation wurde aktualisiert.";
- $messageType = "success";
- } else {
- $message = "Organisation konnte nicht gespeichert werden.";
- $messageType = "error";
- }
- }
- }
- } elseif ($_SERVER['REQUEST_METHOD'] === "POST" && isset($_POST['delete_organization'])) {
- if (!validateCsrfToken($_POST['csrf_token'] ?? "")) {
- $message = "Ungültiges Token. Bitte versuchen Sie es erneut.";
- $messageType = "error";
- } else {
- $organizationId = normalizeOrganizationId($_POST['organization_id'] ?? "");
- $orgLabel = "";
- foreach (getOrganizations(false) as $organization) {
- if ($organization["id"] === $organizationId) {
- $orgLabel = $organization["label"];
- break;
- }
- }
- $organizations = array_values(
- array_filter(getOrganizations(false), function ($organization) use (
- $organizationId,
- ) {
- return $organization["id"] !== $organizationId;
- }),
- );
- if (saveOrganizations($organizations)) {
- logAccess("Admin deleted organization", [
- "org_id" => $organizationId,
- "label" => $orgLabel,
- ]);
- $message = "Organisation wurde gelöscht.";
- $messageType = "success";
- } else {
- $message = "Organisation konnte nicht gelöscht werden.";
- $messageType = "error";
- }
- }
- }
- $settings = getSystemSettings();
- $updaterStatus = settingsGetUpdaterStatus();
- $backupCapabilities = backupRemoteCapabilities();
- $backups = backupListBackups();
- $localConfigContent = $isSuperAdmin ? settingsReadLocalConfig() : "";
- $categories = getCategories();
- $products = getProducts();
- $organizations = getOrganizations(false);
- $faqContent = getFaqContent();
- $startpageIntroText = (string) ($settings["startpage_intro_text"] ?? "");
- $editCategoryId = normalizeCategoryId($_GET['edit_category'] ?? "");
- $editingCategory = null;
- if ($editCategoryId !== "") {
- $editingCategory = getCategoryById($editCategoryId);
- if ($editingCategory === null && $message === "") {
- $message = "Ausgewählte Kategorie wurde nicht gefunden.";
- $messageType = "error";
- }
- }
- $editingOrganization = isset($_GET['edit_organization'])
- ? getOrganizationById($_GET['edit_organization'])
- : null;
- $bodyClass = "admin-page";
- include __DIR__ . "/../includes/header.php";
- ?>
- <div class="admin-header">
- <h2>Einstellungen</h2>
- <div>
- <a href="index.php" class="btn btn-secondary">Zurück zum Dashboard</a>
- </div>
- </div>
- <?php if ($message !== ""): ?>
- <div class="alert alert-<?php echo escape($messageType); ?>">
- <?php echo escape($message); ?>
- </div>
- <?php endif; ?>
- <div class="panel panel-lg" id="kategorien">
- <h3>Kategorien</h3>
- <?php if ($editingCategory !== null): ?>
- <h4>Kategorie bearbeiten</h4>
- <form method="POST" action="settings.php#kategorien">
- <?php echo csrfField(); ?>
- <input type="hidden" name="category_id" value="<?php echo escape(
- $editingCategory["id"],
- ); ?>">
- <div class="form-group">
- <label for="category_id_display">ID</label>
- <input type="text" id="category_id_display" value="<?php echo escape(
- $editingCategory["id"],
- ); ?>" readonly>
- <small>Die ID sollte gleichbleiben, damit Produktzuordnungen und Filter-URLs gültig bleiben.</small>
- </div>
- <div class="form-group">
- <label for="category_label_edit">Name *</label>
- <input type="text" id="category_label_edit" name="category_label" maxlength="80" required value="<?php echo escape(
- $editingCategory["label"],
- ); ?>">
- </div>
- <button type="submit" name="update_category" class="btn">Kategorie aktualisieren</button>
- <a href="settings.php#kategorien" class="btn btn-secondary">Abbrechen</a>
- </form>
- <?php else: ?>
- <h4>Neue Kategorie anlegen</h4>
- <form method="POST" action="settings.php#kategorien">
- <?php echo csrfField(); ?>
- <div class="form-group">
- <label for="category_label">Name *</label>
- <input type="text" id="category_label" name="category_label" maxlength="80" required placeholder="z.B. Accessoires">
- <small>Die technische ID wird einmalig automatisch aus dem Namen erzeugt.</small>
- </div>
- <button type="submit" name="add_category" class="btn">Kategorie anlegen</button>
- </form>
- <?php endif; ?>
- <div class="table-responsive mt-4">
- <table class="responsive-table">
- <thead>
- <tr>
- <th>Name</th>
- <th>ID</th>
- <th>Produkte</th>
- <th>Aktionen</th>
- </tr>
- </thead>
- <tbody>
- <?php foreach ($categories as $category): ?>
- <?php
- $productCount = 0;
- foreach ($products as $product) {
- if (productHasCategory($product, $category["id"])) {
- $productCount++;
- }
- }
- ?>
- <tr>
- <td data-label="Name"><?php echo escape(
- $category["label"],
- ); ?></td>
- <td data-label="ID"><code><?php echo escape(
- $category["id"],
- ); ?></code></td>
- <td data-label="Produkte"><?php echo $productCount; ?></td>
- <td data-label="Aktionen">
- <a href="settings.php?edit_category=<?php echo urlencode(
- $category["id"],
- ); ?>#kategorien" class="btn btn-small btn-secondary">Bearbeiten</a>
- <form method="POST" action="settings.php#kategorien" class="inline-form" onsubmit="return confirm('Kategorie wirklich löschen?');">
- <?php echo csrfField(); ?>
- <input type="hidden" name="category_id" value="<?php echo escape(
- $category["id"],
- ); ?>">
- <button type="submit" name="delete_category" class="btn btn-small">Löschen</button>
- </form>
- </td>
- </tr>
- <?php endforeach; ?>
- </tbody>
- </table>
- </div>
- </div>
- <div class="panel panel-lg mt-4" id="faq">
- <h3>FAQ</h3>
- <p class="mb-2">
- Unterstützte Markdown-Syntax: <code>#</code>, <code>##</code>, <code>###</code>, <code>**fett**</code>, <code>*kursiv*</code>, Listen mit <code>-</code> oder <code>1.</code>, Links mit <code>[Text](https://example.com)</code>
- </p>
- <form method="POST" action="settings.php#faq">
- <?php echo csrfField(); ?>
- <div class="form-group">
- <label for="content">FAQ-Inhalt (Markdown)</label>
- <textarea id="content" name="content" rows="18"><?php echo escape(
- $faqContent,
- ); ?></textarea>
- </div>
- <div class="form-group">
- <label for="startpage_intro_text">Startseitentext</label>
- <textarea id="startpage_intro_text" name="startpage_intro_text" rows="6"><?php echo escape(
- $startpageIntroText,
- ); ?></textarea>
- </div>
- <button type="submit" name="save_faq" class="btn">Speichern</button>
- </form>
- </div>
- <div class="panel panel-lg mt-4" id="organisationen">
- <h3>Organisationen</h3>
- <h4><?php echo $editingOrganization
- ? "Organisation bearbeiten"
- : "Neue Organisation"; ?></h4>
- <form method="POST" action="settings.php#organisationen">
- <?php echo csrfField(); ?>
- <?php if ($editingOrganization): ?>
- <input type="hidden" name="organization_id" value="<?php echo escape(
- $editingOrganization["id"],
- ); ?>">
- <?php endif; ?>
- <div class="form-group">
- <label for="organization_label">Name *</label>
- <input type="text" id="organization_label" name="organization_label" required maxlength="120" value="<?php echo escape(
- $editingOrganization["label"] ?? "",
- ); ?>">
- </div>
- <div class="form-group">
- <label for="sort_order">Sortierung</label>
- <input type="number" id="sort_order" name="sort_order" value="<?php echo escape(
- (string) ($editingOrganization["sort_order"] ?? 0),
- ); ?>">
- </div>
- <div class="form-group">
- <label>
- <input type="checkbox" name="active" value="1" <?php echo !isset(
- $editingOrganization["active"],
- ) || !empty($editingOrganization["active"])
- ? "checked"
- : ""; ?>>
- Organisation ist auswählbar
- </label>
- </div>
- <button type="submit" name="<?php echo $editingOrganization
- ? "update_organization"
- : "add_organization"; ?>" class="btn">
- <?php echo $editingOrganization
- ? "Speichern"
- : "Organisation anlegen"; ?>
- </button>
- <?php if ($editingOrganization): ?>
- <a href="settings.php#organisationen" class="btn btn-secondary">Abbrechen</a>
- <?php endif; ?>
- </form>
- <div class="table-responsive mt-4">
- <table class="responsive-table">
- <thead>
- <tr>
- <th>Name</th>
- <th>ID</th>
- <th>Sortierung</th>
- <th>Status</th>
- <th>Aktionen</th>
- </tr>
- </thead>
- <tbody>
- <?php foreach ($organizations as $organization): ?>
- <tr>
- <td data-label="Name"><?php echo escape(
- $organization["label"],
- ); ?></td>
- <td data-label="ID"><code><?php echo escape(
- $organization["id"],
- ); ?></code></td>
- <td data-label="Sortierung"><?php echo (int) $organization[
- "sort_order"
- ]; ?></td>
- <td data-label="Status">
- <span class="status <?php echo !empty(
- $organization["active"]
- )
- ? "status-open"
- : "status-cancelled"; ?>">
- <?php echo !empty($organization["active"])
- ? "Aktiv"
- : "Inaktiv"; ?>
- </span>
- </td>
- <td data-label="Aktionen">
- <a href="settings.php?edit_organization=<?php echo urlencode(
- $organization["id"],
- ); ?>#organisationen" class="btn btn-small">Bearbeiten</a>
- <form method="POST" action="settings.php#organisationen" class="inline-form" onsubmit="return confirm('Organisation wirklich löschen?');">
- <?php echo csrfField(); ?>
- <input type="hidden" name="organization_id" value="<?php echo escape(
- $organization["id"],
- ); ?>">
- <button type="submit" name="delete_organization" class="btn btn-secondary btn-small">Löschen</button>
- </form>
- </td>
- </tr>
- <?php endforeach; ?>
- </tbody>
- </table>
- </div>
- </div>
- <div class="panel panel-lg mt-4" id="allgemein">
- <h3>Allgemein</h3>
- <form method="POST" action="settings.php#allgemein">
- <?php echo csrfField(); ?>
- <div class="form-group">
- <label for="order_recipient_email">Empfängeradresse für interne Bestellungen *</label>
- <input type="email" id="order_recipient_email" name="order_recipient_email" required value="<?php echo escape(
- $settings["order_recipient_email"],
- ); ?>">
- </div>
- <div class="form-group">
- <label class="checkbox-label">
- <input type="checkbox" name="attach_order_pdf_to_admin_email" value="1" <?php echo !empty(
- $settings["attach_order_pdf_to_admin_email"]
- )
- ? "checked"
- : ""; ?>>
- PDF an interne Bestell-E-Mails anhängen
- </label>
- </div>
- <div class="form-group">
- <label for="nametag_product_name">Artikelname für Namensschilder *</label>
- <input type="text" id="nametag_product_name" name="nametag_product_name" required value="<?php echo escape(
- $settings["nametag_product_name"],
- ); ?>">
- <small>Muss exakt dem Produktnamen im Katalog entsprechen. Wird von der Namensschilder-Übersicht verwendet.</small>
- </div>
- <button type="submit" name="save_settings" class="btn">Speichern</button>
- </form>
- </div>
- <div class="panel panel-lg mt-4" id="backups">
- <h3>Backups</h3>
- <p>Lokale Aufbewahrung: <?php echo (int) backupGetRetentionLimit(); ?> Backups</p>
- <p>Automatisches Intervall: <?php echo (int) floor(((int) BACKUP_AUTO_INTERVAL_SECONDS) / 86400); ?> Tage</p>
- <p>
- S3: <?php echo escape(settingsGetBackupCapabilityLabel($backupCapabilities["s3"])); ?> ·
- SFTP: <?php echo escape(settingsGetBackupCapabilityLabel($backupCapabilities["sftp"])); ?> ·
- Custom: <?php echo escape(settingsGetBackupCapabilityLabel($backupCapabilities["custom"])); ?> ·
- Managed: <?php echo escape(settingsGetBackupCapabilityLabel($backupCapabilities["managed"])); ?>
- </p>
- <form method="POST" action="settings.php#backups" class="inline-form">
- <?php echo csrfField(); ?>
- <button type="submit" name="create_backup" class="btn">Backup erstellen</button>
- </form>
- <h4 class="mt-4">Letzte Backups</h4>
- <?php if (empty($backups)): ?>
- <p>Es wurden noch keine Backups erstellt.</p>
- <?php else: ?>
- <div class="table-responsive">
- <table class="responsive-table">
- <thead>
- <tr>
- <th>Erstellt</th>
- <th>Auslöser</th>
- <th>Größe</th>
- <th>Dateien</th>
- <th>Remote</th>
- <th>Aktionen</th>
- </tr>
- </thead>
- <tbody>
- <?php foreach ($backups as $backup): ?>
- <tr>
- <td data-label="Erstellt"><?php echo escape(settingsFormatBackupDate((string) ($backup["created_at"] ?? ""))); ?></td>
- <td data-label="Auslöser"><?php echo (($backup["trigger"] ?? "") === "automatic") ? "Automatisch" : "Manuell"; ?></td>
- <td data-label="Größe"><?php echo escape(backupFormatBytes((int) ($backup["size"] ?? 0))); ?></td>
- <td data-label="Dateien"><?php echo (int) ($backup["file_count"] ?? 0); ?></td>
- <td data-label="Remote"><?php echo escape(settingsGetBackupUploadLabel($backup)); ?></td>
- <td data-label="Aktionen">
- <form method="POST" action="settings.php#backups" class="inline-form">
- <?php echo csrfField(); ?>
- <input type="hidden" name="backup_filename" value="<?php echo escape($backup["filename"] ?? ""); ?>">
- <button type="submit" name="download_backup" class="btn btn-secondary btn-small">Download</button>
- </form>
- </td>
- </tr>
- <?php endforeach; ?>
- </tbody>
- </table>
- </div>
- <?php endif; ?>
- </div>
- <div class="panel panel-lg mt-4">
- <h3>Updater</h3>
- <p>Installierte Version: <?php echo escape(APP_VERSION); ?></p>
- <p>Update-Status: <?php echo escape($updaterStatus["label"]); ?></p>
- <p><a href="updater.php" class="btn btn-secondary">Updater öffnen</a></p>
- </div>
- <?php if ($isSuperAdmin): ?>
- <div class="panel panel-lg mt-4" id="konfiguration">
- <h3>Lokale Konfiguration</h3>
- <p>Bearbeitet <code>config.php</code> direkt auf diesem Server. Diese Datei wird beim Update nicht überschrieben.</p>
- <div class="alert alert-warning">Vor dem Speichern wird die PHP-Syntax geprüft und die vorherige Version automatisch gesichert. Fehlerhafte Änderungen können die gesamte Anwendung lahmlegen.</div>
- <form method="POST" action="settings.php#konfiguration">
- <?php echo csrfField(); ?>
- <div class="form-group">
- <label for="local_config_content">Inhalt von config.php</label>
- <textarea id="local_config_content" name="local_config_content" rows="24" class="config-editor" spellcheck="false"><?php echo escape(
- $localConfigContent,
- ); ?></textarea>
- </div>
- <button type="submit" name="save_local_config" class="btn">Speichern</button>
- </form>
- </div>
- <?php endif; ?>
- <?php include __DIR__ . "/../includes/footer.php"; ?>
|