reorder folders for easy 1:1 upload to boogie server
This commit is contained in:
1 parent
de5895f558
commit
6c16e16354
20 files changed
+170
-51
No files matched your search
@@ -5,6 +5,7 @@
|
||||
/public/share
|
||||
/public/system
|
||||
/public/vendor
|
||||
/public/booking-config.php
|
||||
/system
|
||||
/bin/console
|
||||
/node_modules/
|
||||
|
||||
@@ -58,7 +58,11 @@ http://localhost:8080/perspektivwerk/
|
||||
|
||||
Die genaue Contao-, PHP- und Template-Version der öffentlichen Seite ist nicht verlässlich aus dem ausgelieferten HTML ableitbar. Das Setup bildet daher die wahrscheinlichste Komponentenfamilie nach; es ist kein Dump der Produktivinstallation. IONOS/Hosting, Matomo-Konfiguration, Inhalte, Templates und Erweiterungen müssen bei Bedarf separat ergänzt werden.
|
||||
|
||||
Die Terminlogik liegt in `public/booking/booking.js` als browsernatives ES-Modul. Für die statische Perspektivwerk-Vorschau liegen identische Kopien unter `public/perspektivwerk/js/`.
|
||||
Der vollständige, statisch auslieferbare Perspektivwerk-DocumentRoot liegt in
|
||||
`public/perspektivwerk/`. Er enthält die Buchungs-API unter `booking/` und die
|
||||
Verwaltung unter `booking-admin/`. Die Vorschau verwendet relative API-URLs und
|
||||
funktioniert dadurch lokal unter `/perspektivwerk/` sowie auf dem Server direkt
|
||||
im DocumentRoot.
|
||||
|
||||
Für einen einfachen Upload der vollständigen statischen Mockup-Seite auf den
|
||||
Testserver steht unter Windows dieses Skript bereit:
|
||||
@@ -67,17 +71,27 @@ Testserver steht unter Windows dieses Skript bereit:
|
||||
scripts\Deploy-Perspektivwerk.bat
|
||||
```
|
||||
|
||||
Es überträgt `public\perspektivwerk\*` rekursiv nach
|
||||
`boogie:/html/perspektivwerk/`. Voraussetzung ist ein konfigurierter
|
||||
OpenSSH-Zugang mit dem Host-Alias `boogie`.
|
||||
Es überträgt den vollständigen Ordner `public\perspektivwerk` und dessen
|
||||
benachbarte Konfigurationsdatei `public\booking-config.php` nach
|
||||
`boogie:html/perspektivwerk/`. Damit entsteht der Server-DocumentRoot unter
|
||||
`html/perspektivwerk/perspektivwerk/`; die Konfigurationsdatei liegt eine Ebene
|
||||
darüber und damit außerhalb des DocumentRoots. Anschließend setzt es per SSH
|
||||
lesbare Dateien und durchsuchbare Verzeichnisse.
|
||||
|
||||
Vor dem ersten Upload `public\booking-config.php.example` nach
|
||||
`public\booking-config.php` kopieren und dort die Produktiv-`database_url`
|
||||
eintragen. Die echte Konfigurationsdatei ist von Git ausgeschlossen; sie wird
|
||||
bei fehlender oder leerer PHP-Umgebungsvariable `DATABASE_URL` verwendet. Die
|
||||
mit übertragene `.htaccess` verweigert den HTTP-Zugriff auf diese Datei.
|
||||
Voraussetzung ist ein konfigurierter OpenSSH-Zugang mit dem Host-Alias
|
||||
`boogie`.
|
||||
|
||||
## Datenbankgestützte Buchungsdemo
|
||||
|
||||
Die Buchungsdemo lädt ihre Termine aus MariaDB und speichert eine Anmeldung
|
||||
über `public/booking/api.php`. Die API wird unabhängig von Contao direkt durch
|
||||
Apache ausgeliefert, verwendet aber dieselbe `DATABASE_URL` wie Contao. Dadurch
|
||||
funktioniert sie aus der Vorschau `/perspektivwerk/` und aus dem Contao-
|
||||
HTML-Element gleichermaßen.
|
||||
über `public/perspektivwerk/booking/api.php`. Die API wird unabhängig von
|
||||
Contao direkt durch Apache ausgeliefert. In der statischen Vorschau liegt sie
|
||||
relativ unter `/perspektivwerk/booking/api.php`.
|
||||
|
||||
Vor dem ersten Aufruf müssen die externen Migrationen eingespielt werden:
|
||||
|
||||
@@ -156,7 +170,7 @@ nach 30 Minuten ab.
|
||||
## Eigenständiges PHP-Backend
|
||||
|
||||
Die Testverwaltung läuft unabhängig von Contao unter
|
||||
<http://localhost:8080/booking-admin/>. Sie bietet für PW und PS:
|
||||
<http://localhost:8080/perspektivwerk/booking-admin/>. Sie bietet für PW und PS:
|
||||
|
||||
- Termin anlegen, bearbeiten sowie aktivieren/deaktivieren,
|
||||
- Übersicht und Entfernen von Teilnahmen,
|
||||
@@ -215,34 +229,43 @@ Contao maskiert nicht freigegebene HTML-Tags auch im Inhaltselement **HTML**. Vo
|
||||
|
||||
Danach den Contao-Cache über **Systemwartung** leeren und das Inhaltselement erneut speichern. Keine globale Freigabe mit `*` verwenden. Wer ein HTML-Inhaltselement bearbeiten darf, kann mit dem freigegebenen `script`-Tag JavaScript auf der Website ausführen; diese Bearbeitungsrechte müssen daher auf vertrauenswürdige Backend-Nutzer beschränkt bleiben.
|
||||
|
||||
Die Termin- und Kapazitätsdaten kommen aus `/booking/api.php`; Datenbankzugänge
|
||||
oder SQL gehören niemals in das HTML oder das Browser-JavaScript.
|
||||
Die Termin- und Kapazitätsdaten kommen in der statischen Vorschau aus
|
||||
`/perspektivwerk/booking/api.php`; Datenbankzugänge oder SQL gehören niemals in
|
||||
das HTML oder das Browser-JavaScript.
|
||||
`public/perspektivwerk/js/booking.js` und die zugehörige CSS-Datei sind die für
|
||||
den statischen Upload bestimmte Kopie. Ein Test stellt sicher, dass beide
|
||||
Asset-Paare gleich bleiben. Nach Änderungen können sie lokal synchronisiert
|
||||
werden mit:
|
||||
|
||||
```powershell
|
||||
Copy-Item public\booking\booking.js public\perspektivwerk\js\booking.js -Force
|
||||
Copy-Item public\booking\booking.css public\perspektivwerk\js\booking.css -Force
|
||||
Copy-Item public\perspektivwerk\booking\booking.js public\perspektivwerk\js\booking.js -Force
|
||||
Copy-Item public\perspektivwerk\booking\booking.css public\perspektivwerk\js\booking.css -Force
|
||||
```
|
||||
|
||||
Der vorhandene SCP-Upload überträgt weiterhin nur die statische
|
||||
Perspektivwerk-Seite. Für einen externen Einsatz der Buchungsdemo müssen
|
||||
zusätzlich `/booking/api.php`, die Migrationen und die sichere
|
||||
`DATABASE_URL`-Konfiguration auf dem Zielserver bereitgestellt werden.
|
||||
Der vorhandene SCP-Upload überträgt den vollständigen statischen
|
||||
Perspektivwerk-DocumentRoot einschließlich Buchungsdemo. Vor dem externen
|
||||
Einsatz müssen die Migrationen eingespielt und `booking-config.php` mit einer
|
||||
sicheren Datenbank-URL befüllt sein.
|
||||
|
||||
## Statische Perspektivwerk-Seite übertragen
|
||||
|
||||
Das Skript [scripts/Deploy-Perspektivwerk.ps1](scripts/Deploy-Perspektivwerk.ps1) überträgt ausschließlich den Inhalt von `public/perspektivwerk/` per SCP und korrigiert anschließend die Lesbarkeit auf dem Server per SSH. Dieser Ordner enthält auch `js/booking.js` und `js/booking.css`. Es lädt weder Contao noch die Datenbank oder andere Projektdateien hoch.
|
||||
Das Skript [scripts/Deploy-Perspektivwerk.bat](scripts/Deploy-Perspektivwerk.bat) überträgt den Ordner `public/perspektivwerk/` als vollständigen DocumentRoot per SCP und korrigiert anschließend die Lesbarkeit auf dem Server per SSH. Es lädt weder Contao noch Datenbank-Migrationen hoch.
|
||||
|
||||
```powershell
|
||||
.\scripts\Deploy-Perspektivwerk.ps1
|
||||
```bat
|
||||
scripts\Deploy-Perspektivwerk.bat
|
||||
```
|
||||
|
||||
Der Hostname `boogie` wird aus der lokalen SSH-Konfiguration verwendet. Der vollständige Inhalt wird per SCP-Aufruf nach `/home/boogie/html/perspektivwerk/` übertragen. Anschließend führt ein separater SSH-Aufruf `chmod -R a+rX /home/boogie/html/perspektivwerk` aus. Die Passphrase des SSH-Schlüssels wird daher in der Regel zweimal abgefragt.
|
||||
Der Hostname `boogie` wird aus der lokalen SSH-Konfiguration verwendet. Der
|
||||
Ordner landet unter `/home/boogie/html/perspektivwerk/perspektivwerk/`; die
|
||||
Konfiguration liegt daneben unter `/home/boogie/html/perspektivwerk/booking-config.php`.
|
||||
Anschließend führt ein separater SSH-Aufruf `chmod -R a+rX
|
||||
/home/boogie/html/perspektivwerk` aus. Die Passphrase des SSH-Schlüssels wird
|
||||
daher in der Regel zweimal abgefragt.
|
||||
|
||||
Vor dem Upload gibt das Skript den vollständigen Zielpfad aus. Damit lässt sich direkt prüfen, ob `booking.js` unter `/home/boogie/html/perspektivwerk/js/booking.js` landet. Das große `X` in `a+rX` setzt das Ausführungsrecht nur auf Verzeichnissen und auf bereits ausführbaren Dateien; normale HTML-, CSS- und JavaScript-Dateien erhalten kein unnötiges Ausführungsbit.
|
||||
Vor dem Upload muss die ignorierte `booking-config.php` befüllt sein. Das große
|
||||
`X` in `a+rX` setzt das Ausführungsrecht nur auf Verzeichnissen und auf bereits
|
||||
ausführbaren Dateien; normale HTML-, CSS- und JavaScript-Dateien erhalten kein
|
||||
unnötiges Ausführungsbit.
|
||||
|
||||
## Versionierter Contao-Seitenzustand
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ services:
|
||||
APP_ENV: dev
|
||||
CONTAO_ENVIRONMENT: dev
|
||||
DATABASE_URL: mysql://perspektivwerk:perspektivwerk@db:3306/perspektivwerk?serverVersion=mariadb-10.11.0
|
||||
BOOKING_BASE_URL: http://localhost:8080
|
||||
BOOKING_BASE_URL: http://localhost:8080/perspektivwerk
|
||||
BOOKING_MAIL_TRANSPORT: database
|
||||
command:
|
||||
- sh
|
||||
|
||||
@@ -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',
|
||||
];
|
||||
File renamed without changes.
File renamed without changes.
+17
-1
@@ -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.');
|
||||
File renamed without changes.
+1
-1
@@ -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));
|
||||
+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;
|
||||
}
|
||||
|
||||
File renamed without changes.
@@ -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 & 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 & Belastungstest</h2><p>Arbeitsproben und praktische Erprobungen machen fachliche, soziale und arbeitsbezogene Kompetenzen sichtbar.</p></article><article><h2>3. Auswertung & 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));
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
set "SOURCE=%~dp0..\public\perspektivwerk\*"
|
||||
set "SOURCE=%~dp0..\public\perspektivwerk"
|
||||
set "TARGET=boogie:html/perspektivwerk/"
|
||||
set "CONFIG=%~dp0..\public\booking-config.php"
|
||||
|
||||
echo Lade das PerspektivWerk-Mockup nach %TARGET% hoch ...
|
||||
echo Lade den Perspektivwerk-DocumentRoot und die Konfiguration nach %TARGET% hoch ...
|
||||
scp -r "%SOURCE%" "%TARGET%"
|
||||
|
||||
if errorlevel 1 (
|
||||
@@ -12,4 +13,12 @@ if errorlevel 1 (
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Setze Leseberechtigungen auf %TARGET% ...
|
||||
ssh boogie "chmod -R a+rX html/perspektivwerk/"
|
||||
|
||||
if errorlevel 1 (
|
||||
echo Berechtigungen konnten nicht gesetzt werden.
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo Upload abgeschlossen.
|
||||
@@ -0,0 +1,16 @@
|
||||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||||
$deployBatchPath = Join-Path $projectRoot 'scripts\Deploy-Perspektivwerk.bat'
|
||||
$htaccessPath = Join-Path $projectRoot 'public\.htaccess'
|
||||
|
||||
Describe 'Perspektivwerk deployment' {
|
||||
It 'deploys the complete Perspektivwerk document root and its sibling configuration file' {
|
||||
$script = Get-Content -LiteralPath $deployBatchPath -Raw
|
||||
$htaccess = Get-Content -LiteralPath $htaccessPath -Raw
|
||||
|
||||
$script | Should Match 'public\\booking-config\.php'
|
||||
$script | Should Match 'public\\perspektivwerk"'
|
||||
$script | Should Match 'boogie:html/perspektivwerk/'
|
||||
$htaccess | Should Match '<Files "booking-config\.php">'
|
||||
$htaccess | Should Match 'Require all denied'
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@ $projectRoot = Split-Path -Parent $PSScriptRoot
|
||||
$mockupPath = Join-Path $projectRoot 'public\perspektivwerk\index.html'
|
||||
$bookingScriptPath = Join-Path $projectRoot 'public\perspektivwerk\js\booking.js'
|
||||
$bookingStylesPath = Join-Path $projectRoot 'public\perspektivwerk\js\booking.css'
|
||||
$contaoBookingScriptPath = Join-Path $projectRoot 'public\booking\booking.js'
|
||||
$contaoBookingStylesPath = Join-Path $projectRoot 'public\booking\booking.css'
|
||||
$deploymentBookingScriptPath = Join-Path $projectRoot 'public\perspektivwerk\booking\booking.js'
|
||||
$deploymentBookingStylesPath = Join-Path $projectRoot 'public\perspektivwerk\booking\booking.css'
|
||||
$htaccessPath = Join-Path $projectRoot 'public\.htaccess'
|
||||
|
||||
Describe 'Perspektivwerk static route' {
|
||||
@@ -19,26 +19,28 @@ Describe 'Perspektivwerk static route' {
|
||||
$mockup | Should Match 'href="js/booking\.css"'
|
||||
$mockup | Should Match 'data-sufw-booking data-project="perspektivwerk"'
|
||||
$mockup | Should Match 'data-sufw-booking data-project="produktionsschule"'
|
||||
$mockup | Should Match 'data-api-url="booking/api\.php"'
|
||||
$mockup | Should Not Match 'data-api-url="/booking/api\.php"'
|
||||
$mockup.IndexOf('data-project="perspektivwerk"') | Should BeLessThan $mockup.IndexOf('data-project="produktionsschule"')
|
||||
$mockup | Should Match 'src="js/booking\.js"'
|
||||
}
|
||||
|
||||
It 'keeps the Contao and static-preview asset copies identical' {
|
||||
(Test-Path -LiteralPath $contaoBookingScriptPath) | Should Be $true
|
||||
(Test-Path -LiteralPath $contaoBookingStylesPath) | Should Be $true
|
||||
(Get-FileHash -LiteralPath $bookingScriptPath).Hash | Should Be (Get-FileHash -LiteralPath $contaoBookingScriptPath).Hash
|
||||
(Get-FileHash -LiteralPath $bookingStylesPath).Hash | Should Be (Get-FileHash -LiteralPath $contaoBookingStylesPath).Hash
|
||||
It 'keeps the deployed API assets and static-preview copies identical' {
|
||||
(Test-Path -LiteralPath $deploymentBookingScriptPath) | Should Be $true
|
||||
(Test-Path -LiteralPath $deploymentBookingStylesPath) | Should Be $true
|
||||
(Get-FileHash -LiteralPath $bookingScriptPath).Hash | Should Be (Get-FileHash -LiteralPath $deploymentBookingScriptPath).Hash
|
||||
(Get-FileHash -LiteralPath $bookingStylesPath).Hash | Should Be (Get-FileHash -LiteralPath $deploymentBookingStylesPath).Hash
|
||||
}
|
||||
|
||||
It 'keeps the enabled submit button visibly rendered' {
|
||||
$script = Get-Content -LiteralPath $contaoBookingScriptPath -Raw
|
||||
$script = Get-Content -LiteralPath $deploymentBookingScriptPath -Raw
|
||||
|
||||
$script | Should Match "submitButton\.style\.visibility = 'visible'"
|
||||
$script | Should Match "actions\.style\.position = 'sticky'"
|
||||
}
|
||||
|
||||
It 'defines colours for the booking form action buttons' {
|
||||
$styles = Get-Content -LiteralPath $contaoBookingStylesPath -Raw
|
||||
$styles = Get-Content -LiteralPath $deploymentBookingStylesPath -Raw
|
||||
|
||||
$styles | Should Match '\.sufw-booking__form-actions button\s*\{[^}]*background-color:\s*#08752a'
|
||||
$styles | Should Match '\.sufw-booking__form-actions button\s*\{[^}]*color:\s*#fff'
|
||||
@@ -47,9 +49,12 @@ Describe 'Perspektivwerk static route' {
|
||||
It 'routes /perspektivwerk to the static entry point before the Contao fallback' {
|
||||
$htaccess = Get-Content -LiteralPath $htaccessPath -Raw
|
||||
$staticRouteIndex = $htaccess.IndexOf('RewriteRule ^perspektivwerk/?$ perspektivwerk/index.html [L]')
|
||||
$adminRouteIndex = $htaccess.IndexOf('RewriteRule ^perspektivwerk/booking-admin/?$ perspektivwerk/booking-admin/index.php [L]')
|
||||
$fallbackIndex = $htaccess.IndexOf('RewriteRule ^ %{ENV:BASE}/index.php [L]')
|
||||
|
||||
$staticRouteIndex | Should BeGreaterThan -1
|
||||
$staticRouteIndex | Should BeLessThan $fallbackIndex
|
||||
$adminRouteIndex | Should BeGreaterThan -1
|
||||
$adminRouteIndex | Should BeLessThan $fallbackIndex
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require __DIR__.'/../public/perspektivwerk/booking/backend.php';
|
||||
|
||||
function expectSame(string $expected, string $actual, string $message): void
|
||||
{
|
||||
if ($expected !== $actual) {
|
||||
throw new RuntimeException($message."\nExpected: $expected\nActual: $actual");
|
||||
}
|
||||
}
|
||||
|
||||
$configFile = tempnam(sys_get_temp_dir(), 'sufw-booking-config-');
|
||||
if ($configFile === false) throw new RuntimeException('Temporary configuration file could not be created.');
|
||||
|
||||
try {
|
||||
file_put_contents($configFile, "<?php\nreturn ['database_url' => 'mysql://fallback:secret@database:3306/booking'];\n");
|
||||
|
||||
expectSame(
|
||||
'mysql://fallback:secret@database:3306/booking',
|
||||
bookingDatabaseUrl('', $configFile),
|
||||
'The configuration file must be used when DATABASE_URL is empty.'
|
||||
);
|
||||
expectSame(
|
||||
'mysql://environment:secret@database:3306/booking',
|
||||
bookingDatabaseUrl('mysql://environment:secret@database:3306/booking', $configFile),
|
||||
'DATABASE_URL must take precedence over the configuration file.'
|
||||
);
|
||||
} finally {
|
||||
unlink($configFile);
|
||||
}
|
||||
|
||||
echo "booking backend configuration tests passed\n";
|
||||
@@ -13,9 +13,9 @@ test('liefert eine externe, idempotente Anfangsmigration für Termine und Anmeld
|
||||
|
||||
test('hält die statische Vorschaukopie der Buchungsassets identisch', async () => {
|
||||
const [componentScript, previewScript, componentStyle, previewStyle] = await Promise.all([
|
||||
readFile(new URL('../public/booking/booking.js', import.meta.url), 'utf8'),
|
||||
readFile(new URL('../public/perspektivwerk/booking/booking.js', import.meta.url), 'utf8'),
|
||||
readFile(new URL('../public/perspektivwerk/js/booking.js', import.meta.url), 'utf8'),
|
||||
readFile(new URL('../public/booking/booking.css', import.meta.url), 'utf8'),
|
||||
readFile(new URL('../public/perspektivwerk/booking/booking.css', import.meta.url), 'utf8'),
|
||||
readFile(new URL('../public/perspektivwerk/js/booking.css', import.meta.url), 'utf8'),
|
||||
]);
|
||||
|
||||
@@ -61,12 +61,8 @@ test('liefert zusätzliche lokale Demo-Termine für Juli und August', async () =
|
||||
});
|
||||
|
||||
test('liefert die unabhängige Verwaltung unter booking-admin mit getrennten Bereichen', async () => {
|
||||
const [routes, admin] = await Promise.all([
|
||||
readFile(new URL('../public/.htaccess', import.meta.url), 'utf8'),
|
||||
readFile(new URL('../public/booking-admin/index.php', import.meta.url), 'utf8'),
|
||||
]);
|
||||
const admin = await readFile(new URL('../public/perspektivwerk/booking-admin/index.php', import.meta.url), 'utf8');
|
||||
|
||||
assert.match(routes, /\^booking-admin\/\?\$ booking-admin\/index\.php/);
|
||||
assert.match(admin, /view === 'registrations'/);
|
||||
assert.match(admin, /view === 'export'/);
|
||||
assert.doesNotMatch(admin, /getenv\(/);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
|
||||
import { bookingConfirmationMessage, canSubmitBookingForm, formatDateKey, formatEventDuration, getSlotsForDate, requiresIntroductionDetails, validateBookingForm } from '../public/booking/booking.js';
|
||||
import { bookingConfirmationMessage, canSubmitBookingForm, formatDateKey, formatEventDuration, getSlotsForDate, requiresIntroductionDetails, validateBookingForm } from '../public/perspektivwerk/booking/booking.js';
|
||||
|
||||
const events = [
|
||||
{ id: 'one', project: 'perspektivwerk', startsAt: '2026-09-14 08:00:00', endsAt: '2026-09-18 16:00:00', status: 'available' },
|
||||
|
||||
Reference in new issue
Block a user