From f237ffb5a721e35d9356fed985973be52d1f2952 Mon Sep 17 00:00:00 2001 From: samuelbiasgit Date: Thu, 27 Aug 2026 13:08:12 +0200 Subject: [PATCH 1/2] make scheduler integrations optional --- docker-compose.yml | 2 ++ docker/scheduler.py | 79 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 71 insertions(+), 10 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 583e49f..4123c80 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,6 +24,8 @@ services: HA_TOKEN: ${HA_TOKEN:?set HA_TOKEN} OPENWEATHER_API_KEY: ${OPENWEATHER_API_KEY:?set OPENWEATHER_API_KEY} CKAL_XLSX_DIR: /data/ckal-xlsx + STRATO_SYNC_ENABLED: ${STRATO_SYNC_ENABLED:-true} + BRANDSCHUTZ_MAIL_ENABLED: ${BRANDSCHUTZ_MAIL_ENABLED:-true} volumes: - profile_pictures:/var/www/html/intranet_repo/general_files/profile_pictures - content_news:/var/www/html/intranet_repo/projects/contentpanel/insertion/news diff --git a/docker/scheduler.py b/docker/scheduler.py index 3cf2ad9..7f05d83 100644 --- a/docker/scheduler.py +++ b/docker/scheduler.py @@ -37,23 +37,65 @@ def prepare_ssh_key() -> Path: def calendar_sync(): - run([PYTHON, str(ROOT / 'ckal_upload_client/client.py')], cwd=ROOT / 'ckal_upload_client') - run([PYTHON, str(ROOT / 'pdf_python/create_pdf.py')], cwd=ROOT / 'pdf_python') - run(['/bin/bash', str(ROOT / 'pdf_python/pdf_to_png.sh')], cwd=ROOT / 'pdf_python') + # CKalender-XLSX verarbeiten + run( + [PYTHON, str(ROOT / 'ckal_upload_client/client.py')], + cwd=ROOT / 'ckal_upload_client' + ) + + # PDF erzeugen + run( + [PYTHON, str(ROOT / 'pdf_python/create_pdf.py')], + cwd=ROOT / 'pdf_python' + ) + + # PDF in Dashboard-PNGs umwandeln + run( + ['/bin/bash', str(ROOT / 'pdf_python/pdf_to_png.sh')], + cwd=ROOT / 'pdf_python' + ) + + # STRATO-Synchronisation kann z. B. im DEV deaktiviert werden + strato_sync_enabled = os.getenv( + 'STRATO_SYNC_ENABLED', + 'true' + ).strip().lower() in ('1', 'true', 'yes', 'on') + + if not strato_sync_enabled: + print('STRATO Sync deaktiviert', flush=True) + print('Calendar Sync erfolgreich (ohne STRATO)', flush=True) + return required('STRATO_SSH_USER') required('STRATO_REMOTE_PATH') + host = os.getenv('STRATO_SSH_HOST', 'ssh.strato.de') port = os.getenv('STRATO_SSH_PORT', '22') - known_hosts = Path(os.getenv('STRATO_KNOWN_HOSTS_FILE', '/run/secrets/known_hosts')) + + known_hosts = Path( + os.getenv( + 'STRATO_KNOWN_HOSTS_FILE', + '/run/secrets/known_hosts' + ) + ) + if not known_hosts.is_file(): - raise RuntimeError(f'known_hosts missing: {known_hosts}') + raise RuntimeError( + f'known_hosts missing: {known_hosts}' + ) + key = prepare_ssh_key() + if not PDF_OUTPUT.is_file() or PDF_OUTPUT.stat().st_size == 0: - raise RuntimeError(f'PDF missing/empty: {PDF_OUTPUT}') + raise RuntimeError( + f'PDF missing/empty: {PDF_OUTPUT}' + ) run([ - '/usr/bin/scp', '-O', '-q', '-P', port, + '/usr/bin/scp', + '-O', + '-q', + '-P', port, '-i', str(key), '-o', 'IdentitiesOnly=yes', '-o', 'BatchMode=yes', @@ -62,24 +104,41 @@ def calendar_sync(): str(PDF_OUTPUT), f"{required('STRATO_SSH_USER')}@{host}:{required('STRATO_REMOTE_PATH')}", ]) + print('Calendar Sync erfolgreich', flush=True) def brandschutz_once_per_month(): now = datetime.now() + if now.day != 1 or now.hour < 8: return + brandschutz_enabled = os.getenv( + 'BRANDSCHUTZ_MAIL_ENABLED', + 'true' + ).strip().lower() in ('1', 'true', 'yes', 'on') + + if not brandschutz_enabled: + print('Brandschutz-Mail deaktiviert', flush=True) + return + marker = STATE_DIR / 'brandschutz-last-attempt' month = now.strftime('%Y-%m') + if marker.exists() and marker.read_text().strip() == month: return - # At-most-once: erst markieren, dann ausführen. Bei Fehler manuell prüfen und Marker löschen. + # At-most-once: erst markieren, dann ausführen marker.write_text(month + '\n') - print(f'Brandschutz-Lauf {month}', flush=True) - run(['/usr/local/bin/php', '/var/www/html/intranet_repo/projects/brandschutz/brandschutz_cron.php']) + print(f'Brandschutz-Lauf {month}', flush=True) + + run([ + '/usr/local/bin/php', + '/var/www/html/intranet_repo/projects/brandschutz/brandschutz_cron.php' + ]) + def main(): STATE_DIR.mkdir(parents=True, exist_ok=True) From ffb5cd336d5359586d3eed28d697201c7816852b Mon Sep 17 00:00:00 2001 From: leonie 3 Date: Thu, 27 Aug 2026 20:11:57 +0200 Subject: [PATCH 2/2] tutorial fixed --- README.md | 192 ++++++++++++++++++++++++++++++++++----- docker-compose.local.yml | 4 +- 2 files changed, 171 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index bd170f2..f45f35e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,102 @@ # Intranet lokal aufsetzen -## 1. Docker installieren +# 0. Git installieren und Repository klonen + +Bevor das Intranet lokal eingerichtet werden kann, muss Git installiert und das Repository heruntergeladen werden. + +## Windows + +Git for Windows kann direkt über `winget` installiert werden: + +```powershell +winget install --id Git.Git -e --source winget +``` + +Alternativ kann **Git for Windows** über heruntergeladen und installiert werden. + +Nach der Installation PowerShell, Windows Terminal oder Git Bash neu öffnen und prüfen: + +```bash +git --version +``` + +> Wird das Projekt anschließend mit Docker über WSL 2 verwendet, empfiehlt es sich, auch das Repository innerhalb des WSL-Dateisystems zu klonen, z. B. unter `~/src/intranet`. + +### macOS + +Falls Homebrew noch nicht installiert ist, die Installationsanleitung unter verwenden. + +Git über Homebrew installieren: + +```bash +brew install git +``` + +Danach prüfen: + +```bash +git --version +``` + +## Git konfigurieren + +Beim ersten Einrichten den eigenen Namen und die E-Mail-Adresse für Commits hinterlegen: + +```bash +git config --global user.name "Vorname Nachname" +git config --global user.email "name@example.com" +``` + +## Repository klonen + +### macOS / Linux / WSL + +```bash +cd ~/Documents +git clone https://git.pelpino.de/NAK-Reinickendorf/intranet.git +cd intranet +``` + +### Windows + +```powershell +cd $HOME\Documents +git clone https://git.pelpino.de/NAK-Reinickendorf/intranet.git +cd intranet +``` + +Beim Klonen über HTTPS können Benutzername und Personal Access Token abgefragt werden. Als Passwort wird in diesem Fall der **Token**, nicht das normale Account-Passwort verwendet. + +## HTTPS-Zugangsdaten speichern + +### macOS + +```bash +git config --global credential.helper osxkeychain +``` + +Beim nächsten Zugriff einmal Benutzername und Token eingeben. Anschließend werden die Zugangsdaten im macOS-Schlüsselbund gespeichert. + +### Windows + +Git for Windows enthält den **Git Credential Manager**. Bei der ersten Authentifizierung können die Zugangsdaten darüber sicher gespeichert werden. + +## Repository prüfen + +```bash +git status +git remote -v +``` + +Das Remote Repository sollte auf folgende Adresse verweisen: + +```text +https://git.pelpino.de/NAK-Reinickendorf/intranet.git +``` + +--- + +## 2. Docker installieren ### Windows + WSL 2 — empfohlen @@ -70,14 +166,14 @@ sudo chmod a+r /etc/apt/keyrings/docker.asc **4. Docker-Repository einrichten** ```bash -sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null < /dev/null < Der Dump enthält Produktivdaten. Nicht committen oder weitergeben. +Wenn pgAdmin im Browser auf einem entfernten Server läuft, wird die Backup-Datei serverseitig gespeichert. Sie kann anschließend über **Tools → Storage Manager** heruntergeladen werden. + +> Der Dump enthält Produktivdaten. Nicht committen, weitergeben oder in ungeschützten Cloud-Ordnern speichern. --- -## 5. Lokale Datenbank starten +## 6. Lokale Datenbank starten Im Projektroot: @@ -230,9 +344,17 @@ Status prüfen: docker compose -f docker-compose.local.yml ps ``` +Der Datenbank-Container sollte nach einigen Sekunden den Status `healthy` anzeigen. + +Optional kann geprüft werden, ob pgvector verfügbar ist: + +```bash +docker exec -it intranet-local-db-1 psql -U intranet -d intranet -c "CREATE EXTENSION IF NOT EXISTS vector;" +``` + --- -## 6. Dump mit pgAdmin importieren +## 7. Dump mit pgAdmin importieren In pgAdmin einen neuen Server registrieren: @@ -250,16 +372,18 @@ Danach: 1. Lokale Datenbank `intranet` rechtsklicken. 2. **Restore…** auswählen. -3. **Format: Custom**. +3. **Format: Custom or tar** wählen. 4. `intranet.dump` auswählen. 5. Unter **Data Options → Do not save**: - **Owner: Yes** - **Privileges: Yes** -6. **Include CREATE DATABASE statement: No** +6. **Include CREATE DATABASE statement: No**. 7. **Clean before restore: No** beim ersten Import. 8. **Restore** starten. -Soll die lokale Datenbank später vollständig durch einen neuen Dump ersetzt werden: +Der Restore sollte ohne Fehler zur fehlenden Extension `vector` durchlaufen. Falls `pg_restore` mit `extension "vector" is not available` abbricht, prüfen, ob in `docker-compose.local.yml` tatsächlich `pgvector/pgvector:pg18` verwendet wird. + +Soll die lokale Datenbank später vollständig durch einen neuen Dump ersetzt werden, kann das lokale Setup zurückgesetzt werden: ```bash docker compose -f docker-compose.local.yml down -v @@ -268,16 +392,22 @@ docker compose -f docker-compose.local.yml up -d db Danach den Dump erneut importieren. -> `down -v` löscht neben PostgreSQL auch die übrigen lokalen Intranet-Volumes. +> **Achtung:** `down -v` löscht nicht nur PostgreSQL, sondern auch alle übrigen lokalen Intranet-Volumes, z. B. Profilbilder, Aushänge und andere Laufzeitdaten. Nur verwenden, wenn diese Daten bewusst verworfen werden sollen. --- -## 7. Intranet starten +## 8. Intranet starten ```bash docker compose -f docker-compose.local.yml up -d --build ``` +Status prüfen: + +```bash +docker compose -f docker-compose.local.yml ps +``` + Aufrufen: @@ -290,34 +420,50 @@ Die lokale Compose-Datei setzt `session.cookie_secure=0`, da lokal HTTP statt HT ## Entwicklung -Status: +### Status prüfen ```bash docker compose -f docker-compose.local.yml ps ``` -Logs: +### Web-Logs anzeigen ```bash docker compose -f docker-compose.local.yml logs -f web ``` +### Datenbank-Logs anzeigen + +```bash +docker compose -f docker-compose.local.yml logs -f db +``` + +### Änderungen an PHP, CSS und JavaScript + +Änderungen unter `web/` werden durch den Bind-Mount direkt in den laufenden Container übernommen. Ein Rebuild ist normalerweise nicht notwendig. + +Nach dem Speichern reicht in der Regel ein Reload im Browser. + +### Änderungen am Dockerfile + Nach Änderungen am `Dockerfile` neu bauen: ```bash docker compose -f docker-compose.local.yml up -d --build ``` -Normale Änderungen unter `web/` benötigen durch den Bind-Mount keinen Rebuild. - -Stoppen: +### Stoppen ```bash docker compose -f docker-compose.local.yml down ``` -Komplett zurücksetzen: +Die Docker-Volumes bleiben dabei erhalten. + +### Komplett zurücksetzen ```bash docker compose -f docker-compose.local.yml down -v -``` \ No newline at end of file +``` + +> **Achtung:** Dabei werden alle lokalen Docker-Volumes des Projekts gelöscht, einschließlich der lokalen PostgreSQL-Datenbank. diff --git a/docker-compose.local.yml b/docker-compose.local.yml index 744a116..a532162 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -36,7 +36,7 @@ services: - calendar_pdf:/var/www/html/pdf db: - image: postgres:${POSTGRES_VERSION:-16} + image: pgvector/pgvector:pg18 ports: - "127.0.0.1:5432:5432" environment: @@ -45,7 +45,7 @@ services: POSTGRES_USER: ${DB_USER:?set DB_USER in .env} POSTGRES_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD in .env} volumes: - - postgres_data:/var/lib/postgresql/data + - postgres_data:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U \"$${POSTGRES_USER}\" -d \"$${POSTGRES_DB}\""] interval: 5s