reorder folders for easy 1:1 upload to boogie server

This commit is contained in:
Robert Wartenberg committed 2026-08-31 11:40:54 +02:00
1 parent de5895f558
commit 6c16e16354
20 files changed
+171 -52

No files matched your search

+13 -3
View File
@@ -1,3 +1,13 @@
<Files "booking-config.php">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>
</Files>
<IfModule mod_rewrite.c>
RewriteEngine On
@@ -44,9 +54,9 @@
# directory request to Contao's front controller.
RewriteRule ^perspektivwerk/?$ perspektivwerk/index.html [L]
# The independent booking administration is a plain PHP application, not a
# Contao route. Serve its directory URL directly as well.
RewriteRule ^booking-admin/?$ booking-admin/index.php [L]
# The standalone booking administration lives below the static mockup and
# must not be handled by Contao's front controller.
RewriteRule ^perspektivwerk/booking-admin/?$ perspektivwerk/booking-admin/index.php [L]
# If the requested filename exists, simply serve it.
# We only want to let Apache serve files and not directories.
@@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
// Copy this file to booking-config.php, then insert the production database URL.
// booking-config.php is intentionally excluded from Git and denied by public/.htaccess.
return [
'database_url' => 'mysql://USER:PASSWORD@database-host:3306/booking_database',
];
@@ -2,9 +2,25 @@
declare(strict_types=1);
function bookingDatabaseUrl(?string $environmentUrl = null, ?string $configurationFile = null): string
{
$url = $environmentUrl ?? getenv('DATABASE_URL');
if (!is_string($url) || trim($url) === '') {
$configurationFile ??= dirname(__DIR__, 2).'/booking-config.php';
if (is_file($configurationFile)) {
$configuration = require $configurationFile;
$url = is_array($configuration) ? ($configuration['database_url'] ?? '') : '';
}
}
if (!is_string($url) || trim($url) === '') {
throw new RuntimeException('DATABASE_URL is not configured and the booking configuration file does not contain a database URL.');
}
return trim($url);
}
function bookingDatabase(): PDO
{
$url = getenv('DATABASE_URL');
$url = bookingDatabaseUrl();
$parts = is_string($url) ? parse_url($url) : false;
if (!is_array($parts) || ($parts['scheme'] ?? '') !== 'mysql' || !isset($parts['host'], $parts['path'], $parts['user'])) {
throw new RuntimeException('DATABASE_URL is not configured correctly.');
@@ -153,7 +153,7 @@ function openBookingDialog(container, event, state) {
function renderComponent(container) {
const project = container.dataset.project === 'produktionsschule' ? 'produktionsschule' : 'perspektivwerk';
const now = new Date();
const state = { apiUrl: container.dataset.apiUrl || '/booking/api.php', csrfToken: '', events: [], currentMonth: new Date(now.getFullYear(), now.getMonth(), 1), selectedDate: '' };
const state = { apiUrl: container.dataset.apiUrl || 'booking/api.php', csrfToken: '', events: [], currentMonth: new Date(now.getFullYear(), now.getMonth(), 1), selectedDate: '' };
const fetchEvents = async () => {
const from = formatDateKey(state.currentMonth);
const to = formatDateKey(new Date(state.currentMonth.getFullYear(), state.currentMonth.getMonth() + 1, 1));
@@ -13,7 +13,7 @@ function page(string $title, string $message, bool $success = false): never
$safeTitle = htmlspecialchars($title, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$safeMessage = htmlspecialchars($message, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$class = $success ? 'success' : 'error';
echo "<!doctype html><html lang=\"de\"><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>$safeTitle</title><style>body{font:18px/1.5 Arial,sans-serif;margin:0;background:#f3f6f3;color:#202020}.box{max-width:42rem;margin:12vh auto;padding:2rem;background:#fff;border-top:6px solid #08752a}.success{color:#08752a}.error{color:#8a1515}a{color:#08752a}</style><main class=\"box\"><h1 class=\"$class\">$safeTitle</h1><p>$safeMessage</p><p><a href=\"/perspektivwerk/\">Zurück zur Terminbuchung</a></p></main></html>";
echo "<!doctype html><html lang=\"de\"><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>$safeTitle</title><style>body{font:18px/1.5 Arial,sans-serif;margin:0;background:#f3f6f3;color:#202020}.box{max-width:42rem;margin:12vh auto;padding:2rem;background:#fff;border-top:6px solid #08752a}.success{color:#08752a}.error{color:#8a1515}a{color:#08752a}</style><main class=\"box\"><h1 class=\"$class\">$safeTitle</h1><p>$safeMessage</p><p><a href=\"../\">Zurück zur Terminbuchung</a></p></main></html>";
exit;
}
@@ -21,10 +21,10 @@
<section class="team-section"><div class="team-copy"><img src="media/wir-sind-fuer-sie-da.svg" alt="Wir sind für Sie da"><p>Unser Team, bestehend aus sozialpädagogischen, pädagogischen und psychologischen Mitarbeiterinnen und Mitarbeitern, <strong>unterstützt Ihren Prozess der beruflichen Orientierung.</strong> Wir arbeiten eng mit den Bearbeiterinnen und Beratern der Agentur für Arbeit, dem Jobcenter und weiteren Beratungsstellen zusammen.</p><p>Die Teilnahme am <strong>PerspektivWerk ist kostenlos.</strong> Sie bestimmen, an welchen Angeboten Sie teilnehmen.</p></div><div class="team-image"><img src="media/perspektivwerk-psych.jpg" alt="Beratungsgespräch im PerspektivWerk"></div></section>
<section class="content page-width" id="projekte"><div class="content-grid"><article><h2>Wer kann zu uns kommen?</h2><p>Menschen zwischen 15 und 65 Jahren, die sich beruflich neu orientieren möchten, beim Einstieg Unterstützung suchen oder ihre Möglichkeiten gemeinsam klären wollen.</p></article><article><h2>1. Orientierung &amp; Ersteinschätzung</h2><p>Sozialpädagogische und psychologische Module helfen dabei, persönliche Situation, Motivation, Belastbarkeit und Stärken einzuschätzen.</p></article><article><h2>2. Praktische Erprobung &amp; Belastungstest</h2><p>Arbeitsproben und praktische Erprobungen machen fachliche, soziale und arbeitsbezogene Kompetenzen sichtbar.</p></article><article><h2>3. Auswertung &amp; Perspektiventwicklung</h2><p>Wir führen die Ergebnisse zusammen und entwickeln konkrete, realistische nächste Schritte.</p></article></div></section>
<section class="page-width" aria-label="Terminbuchung PerspektivWerk">
<div data-sufw-booking data-project="perspektivwerk" data-api-url="/booking/api.php"></div>
<div data-sufw-booking data-project="perspektivwerk" data-api-url="booking/api.php"></div>
</section>
<section class="page-width" aria-label="Terminbuchung Produktionsschule">
<div data-sufw-booking data-project="produktionsschule" data-api-url="/booking/api.php"></div>
<div data-sufw-booking data-project="produktionsschule" data-api-url="booking/api.php"></div>
</section>
<section class="contact page-width" id="kontakt"><h2>Sie haben Fragen zu dieser Maßnahme?</h2><p>Haben Sie Interesse an unserem Angebot, melden Sie sich bei uns. Wir beraten Sie gern vorab zu den weiteren Schritten.</p><p><strong>Kontakt:</strong> <a href="tel:+4917660328929">(0176) 60328929</a> · <a href="mailto:perspektivwerk@sufw.de">perspektivwerk@sufw.de</a> · Dresdner Straße 16, 01326 Dresden</p></section>
</main>
@@ -153,7 +153,7 @@ function openBookingDialog(container, event, state) {
function renderComponent(container) {
const project = container.dataset.project === 'produktionsschule' ? 'produktionsschule' : 'perspektivwerk';
const now = new Date();
const state = { apiUrl: container.dataset.apiUrl || '/booking/api.php', csrfToken: '', events: [], currentMonth: new Date(now.getFullYear(), now.getMonth(), 1), selectedDate: '' };
const state = { apiUrl: container.dataset.apiUrl || 'booking/api.php', csrfToken: '', events: [], currentMonth: new Date(now.getFullYear(), now.getMonth(), 1), selectedDate: '' };
const fetchEvents = async () => {
const from = formatDateKey(state.currentMonth);
const to = formatDateKey(new Date(state.currentMonth.getFullYear(), state.currentMonth.getMonth() + 1, 1));