From 8a53234eb68fe053d934c84ef0814f5488c84d90 Mon Sep 17 00:00:00 2001 From: Marijn Date: Wed, 14 Oct 2026 13:34:37 +0200 Subject: [PATCH] PIVOT 1.1.0 --- .dockerignore | 38 + .gitignore | 19 + DATABASE.md | 203 +++++ Dockerfile | 51 ++ MEERDERE_SCHOLEN.md | 69 ++ OVERDRACHT.md | 111 +++ README.Docker.md | 22 + app.py | 303 +++++++ beheer.py | 292 +++++++ blueprints/__init__.py | 0 blueprints/admin.py | 291 +++++++ blueprints/afwezigheden_bp.py | 157 ++++ blueprints/auth.py | 326 ++++++++ blueprints/basisonderwijs_bp.py | 67 ++ blueprints/bugreport_bp.py | 74 ++ blueprints/bugreport_overzicht_bp.py | 62 ++ blueprints/co2_sensor.py | 125 +++ blueprints/contacten_bp.py | 115 +++ blueprints/dashboard_bp.py | 19 + blueprints/database_bp.py | 100 +++ blueprints/devices.py | 603 ++++++++++++++ blueprints/facturatie_bp.py | 96 +++ blueprints/gedeelde_drives_bp.py | 116 +++ blueprints/gmail_delegatie_bp.py | 156 ++++ blueprints/gmail_labels_bp.py | 84 ++ blueprints/google_admin.py | 112 +++ blueprints/google_licenties_bp.py | 95 +++ blueprints/gopro_bp.py | 378 +++++++++ blueprints/handleidingen_bp.py | 273 +++++++ blueprints/handtekeningen_bp.py | 179 ++++ blueprints/internaat_bp.py | 229 ++++++ blueprints/ipblokkade_bp.py | 285 +++++++ blueprints/leerlingenaantal_bp.py | 273 +++++++ blueprints/nieuw_schooljaar_accounts_bp.py | 51 ++ blueprints/nieuw_schooljaar_toestellen_bp.py | 39 + blueprints/personeel_bp.py | 318 ++++++++ blueprints/personeelsaantal_bp.py | 232 ++++++ blueprints/qr_code_bp.py | 125 +++ blueprints/repairs.py | 145 ++++ blueprints/scholen_bp.py | 683 ++++++++++++++++ blueprints/sgr_groepen_bp.py | 65 ++ blueprints/signpost_devices_bp.py | 135 ++++ blueprints/skore_bp.py | 66 ++ blueprints/smartschool_activiteit_bp.py | 104 +++ blueprints/smartschool_bp.py | 108 +++ blueprints/students.py | 190 +++++ blueprints/tools.py | 44 + blueprints/tweestaps_bp.py | 177 ++++ blueprints/verzendlijsten_bp.py | 124 +++ compose.yaml | 27 + config.py | 107 +++ database.py | 106 +++ rechten.py | 475 +++++++++++ requirements.txt | 17 + services/CIP_inleveren.py | 66 ++ services/CIP_uitdelen.py | 51 ++ services/__init__.py | 0 services/aanwezigheid_service.py | 69 ++ services/afwezigheden_service.py | 296 +++++++ services/bingel_service.py | 186 +++++ services/co2_service.py | 81 ++ services/coaccounts_service.py | 200 +++++ services/contacten_service.py | 391 +++++++++ services/facturatie_service.py | 405 ++++++++++ services/gedeelde_drives_service.py | 280 +++++++ services/gmail_delegatie_overzicht.py | 169 ++++ services/gmail_delegation_service.py | 199 +++++ services/gmail_label_service.py | 237 ++++++ services/google_license_service.py | 276 +++++++ services/google_service.py | 391 +++++++++ services/gopro_service.py | 641 +++++++++++++++ services/handleidingen_standaard.py | 347 ++++++++ services/handtekening_service.py | 443 ++++++++++ services/html_schoon.py | 115 +++ services/internaat_service.py | 233 ++++++ services/ipblokkade.py | 196 +++++ services/personeel_service.py | 371 +++++++++ services/sgr_groepen_service.py | 193 +++++ services/signpost_byod_service.py | 140 ++++ services/skore_service.py | 326 ++++++++ services/smartschool_api.py | 122 +++ services/sync_service.py | 549 +++++++++++++ services/tabelnamen.py | 148 ++++ services/toestellen.py | 121 +++ services/toestellen_import.py | 419 ++++++++++ services/tweestaps_service.py | 515 ++++++++++++ services/verzendlijsten_service.py | 173 ++++ sql/centraal.sql | 315 ++++++++ sql/installatie_pivot_26-27.sql | 806 +++++++++++++++++++ sql/school.sql | 448 +++++++++++ static/PIVOT_transparant_logo.png | Bin 0 -> 1231200 bytes static/global.css | 593 ++++++++++++++ static/img/go-logo.png | Bin 0 -> 6483 bytes static/pivot_logo.png | Bin 0 -> 405860 bytes static/pivot_mark.png | Bin 0 -> 149100 bytes templates/CO2_sensor.html | 126 +++ templates/Inventaris_Leerlingen.html | 153 ++++ templates/_handleiding_stijl.html | 30 + templates/_personeel.html | 32 + templates/_toestel_zoekveld.html | 90 +++ templates/aanwezigheden.html | 247 ++++++ templates/admin_accounts.html | 143 ++++ templates/admin_gebruiker.html | 75 ++ templates/admin_rechten.html | 201 +++++ templates/afwezigheden.html | 208 +++++ templates/base.html | 147 ++++ templates/bingel.html | 179 ++++ templates/bugreport.html | 53 ++ templates/bugreport_overzicht.html | 102 +++ templates/contacten.html | 352 ++++++++ templates/dashboard.html | 268 ++++++ templates/database_toestellen.html | 161 ++++ templates/facturatie.html | 213 +++++ templates/gedeelde_drives.html | 320 ++++++++ templates/gmail_delegatie.html | 273 +++++++ templates/gmail_labels.html | 159 ++++ templates/google_beheer.html | 162 ++++ templates/google_licenties.html | 269 +++++++ templates/gopro.html | 460 +++++++++++ templates/gopro_verzameld.html | 291 +++++++ templates/grafiek.html | 80 ++ templates/handleiding.html | 71 ++ templates/handleiding_bewerken.html | 271 +++++++ templates/handleidingen.html | 52 ++ templates/handtekeningen.html | 506 ++++++++++++ templates/herstellingen.html | 235 ++++++ templates/informat_velden.html | 49 ++ templates/inleveren.html | 190 +++++ templates/internen.html | 217 +++++ templates/internet_connection.html | 56 ++ templates/inventaris.html | 310 +++++++ templates/ipblokkade.html | 365 +++++++++ templates/ipblokkade_school.html | 143 ++++ templates/laatkomers.html | 231 ++++++ templates/leerlingenaantal.html | 198 +++++ templates/nieuw_schooljaar_accounts.html | 113 +++ templates/nieuw_schooljaar_toestellen.html | 93 +++ templates/pdf_template_leerkracht.html | 112 +++ templates/pdf_template_leerling.html | 110 +++ templates/personeel_beoordelen.html | 68 ++ templates/personeel_dagoverzicht.html | 134 +++ templates/personeel_detail.html | 134 +++ templates/personeel_mijn.html | 57 ++ templates/personeel_nieuw.html | 172 ++++ templates/pin.html | 50 ++ templates/qr_code.html | 53 ++ templates/scholen.html | 100 +++ templates/school_bewerken.html | 201 +++++ templates/school_test.html | 40 + templates/sgr_groepen.html | 151 ++++ templates/signpost_devices.html | 61 ++ templates/skore.html | 122 +++ templates/smartschool_activiteit.html | 282 +++++++ templates/smartschool_beheer.html | 180 +++++ templates/template_leerkracht.html | 56 ++ templates/toestellen.html | 416 ++++++++++ templates/tweestaps.html | 354 ++++++++ templates/uitdelen.html | 158 ++++ templates/verzendlijst.html | 119 +++ templates/verzendlijsten.html | 166 ++++ tenancy.py | 747 +++++++++++++++++ 161 files changed, 31109 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 DATABASE.md create mode 100644 Dockerfile create mode 100644 MEERDERE_SCHOLEN.md create mode 100644 OVERDRACHT.md create mode 100644 README.Docker.md create mode 100644 app.py create mode 100644 beheer.py create mode 100644 blueprints/__init__.py create mode 100644 blueprints/admin.py create mode 100644 blueprints/afwezigheden_bp.py create mode 100644 blueprints/auth.py create mode 100644 blueprints/basisonderwijs_bp.py create mode 100644 blueprints/bugreport_bp.py create mode 100644 blueprints/bugreport_overzicht_bp.py create mode 100644 blueprints/co2_sensor.py create mode 100644 blueprints/contacten_bp.py create mode 100644 blueprints/dashboard_bp.py create mode 100644 blueprints/database_bp.py create mode 100644 blueprints/devices.py create mode 100644 blueprints/facturatie_bp.py create mode 100644 blueprints/gedeelde_drives_bp.py create mode 100644 blueprints/gmail_delegatie_bp.py create mode 100644 blueprints/gmail_labels_bp.py create mode 100644 blueprints/google_admin.py create mode 100644 blueprints/google_licenties_bp.py create mode 100644 blueprints/gopro_bp.py create mode 100644 blueprints/handleidingen_bp.py create mode 100644 blueprints/handtekeningen_bp.py create mode 100644 blueprints/internaat_bp.py create mode 100644 blueprints/ipblokkade_bp.py create mode 100644 blueprints/leerlingenaantal_bp.py create mode 100644 blueprints/nieuw_schooljaar_accounts_bp.py create mode 100644 blueprints/nieuw_schooljaar_toestellen_bp.py create mode 100644 blueprints/personeel_bp.py create mode 100644 blueprints/personeelsaantal_bp.py create mode 100644 blueprints/qr_code_bp.py create mode 100644 blueprints/repairs.py create mode 100644 blueprints/scholen_bp.py create mode 100644 blueprints/sgr_groepen_bp.py create mode 100644 blueprints/signpost_devices_bp.py create mode 100644 blueprints/skore_bp.py create mode 100644 blueprints/smartschool_activiteit_bp.py create mode 100644 blueprints/smartschool_bp.py create mode 100644 blueprints/students.py create mode 100644 blueprints/tools.py create mode 100644 blueprints/tweestaps_bp.py create mode 100644 blueprints/verzendlijsten_bp.py create mode 100644 compose.yaml create mode 100644 config.py create mode 100644 database.py create mode 100644 rechten.py create mode 100644 requirements.txt create mode 100644 services/CIP_inleveren.py create mode 100644 services/CIP_uitdelen.py create mode 100644 services/__init__.py create mode 100644 services/aanwezigheid_service.py create mode 100644 services/afwezigheden_service.py create mode 100644 services/bingel_service.py create mode 100644 services/co2_service.py create mode 100644 services/coaccounts_service.py create mode 100644 services/contacten_service.py create mode 100644 services/facturatie_service.py create mode 100644 services/gedeelde_drives_service.py create mode 100644 services/gmail_delegatie_overzicht.py create mode 100644 services/gmail_delegation_service.py create mode 100644 services/gmail_label_service.py create mode 100644 services/google_license_service.py create mode 100644 services/google_service.py create mode 100644 services/gopro_service.py create mode 100644 services/handleidingen_standaard.py create mode 100644 services/handtekening_service.py create mode 100644 services/html_schoon.py create mode 100644 services/internaat_service.py create mode 100644 services/ipblokkade.py create mode 100644 services/personeel_service.py create mode 100644 services/sgr_groepen_service.py create mode 100644 services/signpost_byod_service.py create mode 100644 services/skore_service.py create mode 100644 services/smartschool_api.py create mode 100644 services/sync_service.py create mode 100644 services/tabelnamen.py create mode 100644 services/toestellen.py create mode 100644 services/toestellen_import.py create mode 100644 services/tweestaps_service.py create mode 100644 services/verzendlijsten_service.py create mode 100644 sql/centraal.sql create mode 100644 sql/installatie_pivot_26-27.sql create mode 100644 sql/school.sql create mode 100644 static/PIVOT_transparant_logo.png create mode 100644 static/global.css create mode 100644 static/img/go-logo.png create mode 100644 static/pivot_logo.png create mode 100644 static/pivot_mark.png create mode 100644 templates/CO2_sensor.html create mode 100644 templates/Inventaris_Leerlingen.html create mode 100644 templates/_handleiding_stijl.html create mode 100644 templates/_personeel.html create mode 100644 templates/_toestel_zoekveld.html create mode 100644 templates/aanwezigheden.html create mode 100644 templates/admin_accounts.html create mode 100644 templates/admin_gebruiker.html create mode 100644 templates/admin_rechten.html create mode 100644 templates/afwezigheden.html create mode 100644 templates/base.html create mode 100644 templates/bingel.html create mode 100644 templates/bugreport.html create mode 100644 templates/bugreport_overzicht.html create mode 100644 templates/contacten.html create mode 100644 templates/dashboard.html create mode 100644 templates/database_toestellen.html create mode 100644 templates/facturatie.html create mode 100644 templates/gedeelde_drives.html create mode 100644 templates/gmail_delegatie.html create mode 100644 templates/gmail_labels.html create mode 100644 templates/google_beheer.html create mode 100644 templates/google_licenties.html create mode 100644 templates/gopro.html create mode 100644 templates/gopro_verzameld.html create mode 100644 templates/grafiek.html create mode 100644 templates/handleiding.html create mode 100644 templates/handleiding_bewerken.html create mode 100644 templates/handleidingen.html create mode 100644 templates/handtekeningen.html create mode 100644 templates/herstellingen.html create mode 100644 templates/informat_velden.html create mode 100644 templates/inleveren.html create mode 100644 templates/internen.html create mode 100644 templates/internet_connection.html create mode 100644 templates/inventaris.html create mode 100644 templates/ipblokkade.html create mode 100644 templates/ipblokkade_school.html create mode 100644 templates/laatkomers.html create mode 100644 templates/leerlingenaantal.html create mode 100644 templates/nieuw_schooljaar_accounts.html create mode 100644 templates/nieuw_schooljaar_toestellen.html create mode 100644 templates/pdf_template_leerkracht.html create mode 100644 templates/pdf_template_leerling.html create mode 100644 templates/personeel_beoordelen.html create mode 100644 templates/personeel_dagoverzicht.html create mode 100644 templates/personeel_detail.html create mode 100644 templates/personeel_mijn.html create mode 100644 templates/personeel_nieuw.html create mode 100644 templates/pin.html create mode 100644 templates/qr_code.html create mode 100644 templates/scholen.html create mode 100644 templates/school_bewerken.html create mode 100644 templates/school_test.html create mode 100644 templates/sgr_groepen.html create mode 100644 templates/signpost_devices.html create mode 100644 templates/skore.html create mode 100644 templates/smartschool_activiteit.html create mode 100644 templates/smartschool_beheer.html create mode 100644 templates/template_leerkracht.html create mode 100644 templates/toestellen.html create mode 100644 templates/tweestaps.html create mode 100644 templates/uitdelen.html create mode 100644 templates/verzendlijst.html create mode 100644 templates/verzendlijsten.html create mode 100644 tenancy.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..61e71c8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,38 @@ +# Include any files or directories that you don't want to be copied to your +# container here (e.g., local build artifacts, temporary files, etc.). +# +# For more help, visit the .dockerignore file reference guide at +# https://docs.docker.com/go/build-context-dockerignore/ + +**/.DS_Store +**/__pycache__ +**/.venv +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/bin +**/charts +**/docker-compose* +**/compose.y*ml +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +geheimen +import +config.ini +**/*api_key*.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..27037ec --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Geheimen: NOOIT in git (wachtwoorden, sleutels, Google-serviceaccounts) +config.ini +geheimen/ +import/ +.env +*api_key*.json + +# Python +__pycache__/ +*.pyc +venv/ +.venv/ + +# Logboeken en tijdelijke bestanden +*.log +.vscode/ +.idea/ +.DS_Store +Thumbs.db diff --git a/DATABASE.md b/DATABASE.md new file mode 100644 index 0000000..5bf8301 --- /dev/null +++ b/DATABASE.md @@ -0,0 +1,203 @@ +# PIVOT-database (structuur 2026-27) + +De database volgt `pivot_database_structuur_26-27` en is verdeeld zoals PIVOT 1.1.0 met meerdere scholen werkt: + +| Database | Inhoud | +|---|---| +| **centraal** (`pivot`, zie `config.ini › centrale_database`) | `Scholen`, `Gebruikers`, `Veiligheidsgroepen`, `Onderdelen`, `Gebruiker_rechten`, `Leerlingenaantal_tellingen`, `Personeelsaantal_tellingen`, `Personeelsaantal_huidig`, `IP_blokkades`, `PIVOT_instellingen`, `Koppeling_tests`, `Handleidingen`, `Handleidingen_versies`, `Logs`, `Bugs`, `Status` | +| **één per school** (bv. `pivot_sg_antwerpen`) | `Campus`, `Lokalen`, `Wifi`, `Toestellen`, `Signpost_DB`, `Opmerkingen`, `Signpost_herstellingen_DB`, `Leerlingen`, `Eigendom`, `Co_accounts`, `CO2_Metingen`, `Schooljaar` + de tabellen van de modules (2FA, afwezigheden, personeel, licenties, mailbox-delegatie) | + +## Installeren + +``` +mysql -u -p < sql/installatie_pivot_26-27.sql +``` + +Daarmee heb je: + +- de centrale database `pivot` +- de school **Scholengroep Antwerpen** (code `sg-antwerpen`) met database `pivot_sg_antwerpen` +- de gebruiker **Marijn**, wachtwoord `Binnenin10`, rol **Administrator** + +Je kan het script ook in MySQL Workbench of phpMyAdmin importeren. Het mag meermaals uitgevoerd worden. + +**Andere naam voor de centrale database** (bv. `pivot_test`)? Pas dan de naam aan op **beide** regels +(`CREATE DATABASE` én `USE`) onder *1. Centrale database*, en zet dezelfde naam in `config.ini › centrale_database`. + +**Gebruik een nieuwe, lege database.** Staan er nog tabellen van de vorige versie in (bv. `scholen` of +`gebruikers`), dan stopt het script met de melding *"STOP: deze database bevat nog oude PIVOT-tabellen"*, +en PIVOT start niet met die database. MySQL op Windows maakt geen onderscheid tussen `Scholen` en `scholen`, +dus anders zou de nieuwe tabel stilletjes niet aangemaakt worden. +Log daarna in, kies *Scholengroep Antwerpen* en vul via **🏫 Alle scholen beheren › Bewerken** het e-maildomein, +Smartschool, Informat, Google, ... in. + +Losse bestanden: + +- `sql/centraal.sql`: enkel de centrale tabellen +- `sql/school.sql`: de tabellen van één school (uit te voeren in een lege database) + +## Een database voor een nieuwe school + +Kies één van deze manieren: + +1. **In PIVOT**: 🏫 Alle scholen beheren › Nieuwe school › *Database aanmaken?* › **Ja, nieuwe lege PIVOT-database**. + Vergeten? Open de school via *Bewerken*: onder *Database* staat dan **🗄️ Database nu aanmaken**. +2. **Opdrachtregel**: `python beheer.py nieuwe-schooldatabase pivot_` +3. **Met de hand**: `CREATE DATABASE pivot_;` en daarna `sql/school.sql` in die database uitvoeren. + +De MySQL-gebruiker uit `config.ini` moet daarvoor databases mogen aanmaken. + +## Een kopie van een school + +🏫 Alle scholen beheren › Nieuwe school › *Database aanmaken?* › **Ja, kopie van … (met gegevens)**. +PIVOT kopieert alle tabellen mét gegevens naar een **nieuwe** database (bestaat ze al en bevat ze tabellen, dan stopt het). +Vink aan wat je nog wil overnemen: + +- **Koppelingen en instellingen** (Smartschool, Informat, Google-sleutel, …): na het aanmaken kom je op *Bewerken* om ze na te kijken. +- **Gebruikersrechten**: wie rechten heeft in de bronschool, krijgt dezelfde rechten in de kopie. + +Een testkopie zet je best op *niet actief*: dan lopen er geen geplande synchronisaties (afwezigheden, Skore, 2FA) voor. +Op de opdrachtregel: `python beheer.py kopieer-school BRONCODE pivot_` (enkel de database). + +## Rechten + +Iedereen heeft **één account** voor alle scholen (tabel `Gebruikers`). Per school vink je aan op welke **onderdelen** +iemand rechten heeft (tabel `Gebruiker_rechten`: gebruiker × school × onderdeel). +Zo kan iemand in school A *2FA tijdelijk uitzetten* en in school B niet. + +- **Administrator** (Veiligheidsgroep 1): alle rechten in alle scholen. Beheert gebruikers, rechten en scholen. +- **Gebruiker** (Veiligheidsgroep 2): enkel wat per school aangevinkt is. Zonder vinkje in een school kan hij er niet inloggen. +- Wie in een school het recht **Gebruikers & rechten** heeft, kan in díe school gebruikers aanmaken en hun rechten instellen. + Administrators wijzigen kan hij niet. +- Leerkrachten zonder account die met Google inloggen, krijgen zoals vroeger enkel de personeelsmodule. + +Een wijziging in de rechten geldt meteen, ook als de gebruiker al ingelogd is. +Wie in meerdere scholen rechten heeft, wisselt bovenaan van school. + +Beheren kan in PIVOT via **⚙️ Beheer › 🔐 Gebruikers & rechten**, of op de opdrachtregel: + +``` +python beheer.py gebruiker jan --email jan@school.be # nieuwe gebruiker (vraagt wachtwoord) +python beheer.py gebruiker marijn --admin # administrator maken +python beheer.py rechten jan sg-antwerpen tweestaps_uitzetten co2 +python beheer.py rechten jan sg-antwerpen # rechten tonen +python beheer.py rechten jan sg-antwerpen alles | geen +``` + +| Onderdeel (code) | Wat | +|---|---| +| `eigendom_bekijken` | Eigendom bekijken | +| `toestellen_uitdelen` | Toestellen uitdelen en inleveren | +| `toestellen_beheren` | Toestelleninventaris beheren | +| `toestel_blokkeren` | Chromebook blokkeren / deblokkeren | +| `herstellingen` | Herstellingen | +| `signpost` | Signpost-toestellen | +| `leerlingen_bekijken` | Leerlingen bekijken en bewerken | +| `leerlingen_synchroniseren` | Leerlingen toevoegen en synchroniseren (Informat, Google) | +| `google_wachtwoord` | Google-wachtwoord resetten | +| `google_accounts` | Google-accounts aanmaken | +| `tweestaps_codes` | 2FA: back-upcodes tonen / aanmaken | +| `tweestaps_uitzetten` | 2FA tijdelijk uitzetten (uitzondering) | +| `google_licenties` | Google-licenties | +| `gmail_delegatie` | Mailbox-delegatie | +| `verzendlijsten` | Verzendlijsten (Google Groepen) bekijken, aanmaken en aanpassen | +| `smartschool` | Smartschool-wachtwoorden & info | +| `smartschool_activiteit` | Activiteit co-accounts & berichten | +| `afwezigheden` | Afwezigheden leerlingen (B-codes) | +| `laatkomers` | Laatkomers (codes voor te laat uit Smartschool) | +| `skore` | Skore-synchronisatie starten en plannen | +| `personeel_directie` | Personeel: aanvragen goedkeuren | +| `personeel_secretariaat` | Personeel: dagoverzicht | +| `co2` | CO2-sensoren | +| `qr_codes` | QR-code generator | +| `bugs_bekijken` / `bugs_beheren` | Bugs bekijken / status wijzigen | +| `nieuw_schooljaar` | Nieuw schooljaar (accounts & toestellen) | +| `leerlingenaantal` | Leerlingenaantallen van alle scholen (blok *Leerlingen*) | +| `personeelsaantal` | Personeelsaantallen van alle scholen (blok *Personeel*) | +| `gopro` | GO! Pro: personeel van de school uit Informat, rollen en export (blok *Personeel*) | +| `koppelingen` | Koppelingen van deze school | +| `gebruikersbeheer` | Gebruikers & rechten van deze school | +| `database_toestellen` | Beheer › Database: toestellen importeren uit Excel | + +Een nieuw onderdeel voeg je toe in `rechten.py › ONDERDELEN`. Bij het opstarten komt het automatisch in de tabel `Onderdelen`. + +## Verschillen met de PDF + +Wat PIVOT extra nodig heeft, staat in `sql/school.sql` gemarkeerd met `[+]`. + +- **Scholen**: `Instellingsnummer` is het officiële nummer van de school; het nummer voor de Informat-koppeling + staat apart in `Informat_instellingsnummer` (die twee verschillen). `Onderwijsniveau` (`kleuter`, `basis` of `secundair`) + bepaalt de subtotalen bij de leerlingenaantallen. Scholen heeft naast de PDF-velden ook `Code`, `Hostnamen`, `Actief`, `Db_naam`, `Instellingen` (versleutelde koppelingen) + en `Google_sleutel`. `Domein` mag meerdere domeinen bevatten, gescheiden door komma's. +- **Gebruikers** bevat `Passwoordhash` (werkzeug-hash, nooit het wachtwoord zelf) plus `Actief`. + `Veiligheidsgroep` verwijst naar de tabel `Veiligheidsgroepen`. +- **Leerlingenaantal_tellingen** (extra): de leerlingenaantallen per school op een gekozen peildatum +- **gmail_delegaties** / **gmail_delegaties_scan** (extra, per school): alle lopende e-mailmachtigingen (Mailbox-delegatie), opgehaald door alle mailboxen af te gaan (dagelijks of met 🔄 Vernieuwen) en meteen bijgewerkt bij wijzigingen in PIVOT +- **internaat_aanwezigheid** (extra, per school): aanwezigheidsregister van het internaat (per intern, dag en moment ochtend/avond) +- **gmail_label_log** / **gmail_label_items** (extra, per school): opdrachten "e-mails met een label naar een andere mailbox" en welke berichten al gekopieerd zijn (zodat een herstart ze overslaat). Vereist het Google-bereik `gmail.modify`. +- **gmail_handtekening** / **gmail_handtekening_log** (extra, per school): Gmail › Handtekeningen: het HTML-sjabloon, het logo (publiek op `/handtekening-logo//`), de gekozen OU's en de schakelaar voor nachtelijk opnieuw toepassen (één rij, ID = 1), en per gebruiker wanneer de handtekening gezet werd. Functie en telefoon staan niet in PIVOT maar in Google. Vereist `gmail.settings.basic` en `admin.directory.user`. +- **contact_lijsten** / **contact_lijst_items** (extra, per school): Gmail › Contacten › Contactlijsten: een label met vaste contacten dat PIVOT in de persoonlijke contacten van iedereen in de gekozen OU's zet (People API, scope `contacts`). PIVOT herkent zijn contacten in de mailboxen aan het eigen veld `PIVOT` = `lijst:#`. De zichtbaarheid in het adresboek staat enkel in Google. +- **Leerlingen.Vertrokken_op** (extra): datum waarop de leerling bij "Informat & SS sync" niet meer actief was in Informat (NULL = actief). Vertrokken leerlingen worden niet verwijderd, enkel verborgen in de lijst. + (Scholengroep › Leerlingenaantallen › *Telling op peildatum*). Wordt bij het opstarten automatisch aangemaakt. +- **Personeelsaantal_huidig** en **Personeelsaantal_tellingen** (extra): de personeelsaantallen per school, nu en op + een gekozen peildatum (Personeel › Personeelsaantallen). Geteld uit de Informat Personeel-API: wie op die dag een + lopende opdracht heeft. Worden bij het opstarten automatisch aangemaakt. +- **GoPro_verzameltabel** (extra, centraal): de groene personeelsleden (account in Google) van alle scholen samen voor één GO! Pro-CSV; wie hierin staat, wordt op de GO! Pro-pagina van zijn school niet meer getoond (herkend aan school + personeelslid of aan het e-mailadres); met de schakelaar 🌙 op de GO! Pro-pagina (PIVOT_instellingen `gopro_nachtelijk`) gebeurt het verzamelen elke nacht tussen 2 en 6 uur voor alle scholen; kolom `Soort`: `groen` (gaat mee in de CSV), `genegeerd` (rode lijst: nooit meer tonen, niet exporteren) of `verzonden` (met ✅ Markeer als verzonden: al naar GO! Pro gestuurd, nooit opnieuw toevoegen; `Verzonden`, `Verzonden_door`) +- **IP_blokkades** (extra): IP-adressen en reeksen die geweigerd (of altijd toegelaten) worden, voor alle scholen; bij "altijd toestaan" kunnen één of meer scholen aangeduid worden (`Scholen`, codes met komma gescheiden, ter info) + (Beheer › Beveiliging › IP-blokkades, enkel administrators; een gebruiker met het recht `ip_whitelist` ziet enkel de toegestane adressen van zijn school, voegt er toe voor die school en verwijdert enkel zijn eigen regels — `Gebruiker_ID`). Staat PIVOT achter een reverse proxy, zet dan + `config.ini › [algemeen] proxy_aantal` op het aantal proxy's (meestal 1), anders ziet PIVOT het adres van de proxy. + De schakelaar *Enkel "Altijd toestaan" binnenlaten* staat in **PIVOT_instellingen** (`ip_enkel_toegestaan` = 1). + Toch buitengesloten? Zet hem rechtstreeks in de database uit: + `UPDATE PIVOT_instellingen SET Waarde = '0' WHERE Sleutel = 'ip_enkel_toegestaan';` (geldt binnen 30 seconden). +- **Handleidingen** en **Handleidingen_versies** (extra): de handleidingen onder 📘 Handleidingen op het dashboard + (HTML, met schermafbeeldingen) en de laatste 30 vorige versies per handleiding. PIVOT levert er twee mee + (2FA-uitzondering en mailbox-delegatie in Google Admin); die komen bij het opstarten in de tabel. + Enkel administrators kunnen ze bewerken. +- **Logs** bevat ook `School_ID`, `Actie` en `IP`. PIVOT schrijft er elke bezochte pagina in + (uit te zetten met `config.ini › logboek = nee`). +- **Bugs** bevat ook wie de bug meldde (`Gebruiker_ID`, `Gebruikersnaam`) en in welke school. +- **Toestellen** bevat `Serienummer`, `Type`, `Status` en `Geblokkeerd` (nodig om te blokkeren in Google en voor uitdelen/inleveren). + `Geblokkeerd` (1 = geblokkeerd in Google Admin) wordt vanzelf toegevoegd; de knop in 💻 Alle toestellen en 🔒 bij Eigendom + houden hem bij, en "Chromebooks ophalen uit Google" neemt de status uit Google over. + `Schooleigen_ID` is het toestelnummer van de school; in de code heette dat vroeger `KAMXM_nummer`. + Aanvullen kan ook in bulk via **⚙️ Beheer › 🗄️ Database › Toestellen importeren**: sjabloon downloaden, Excel uploaden, + voorbeeld nakijken en bevestigen. Toestellen worden herkend aan `Schooleigen_ID` (anders `Serienummer`); er wordt nooit + iets verwijderd en een lege cel wist niets (`services/toestellen_import.py`). +- **Signpost_DB**: één rij per toestel (`Toestel_ID` = sleutel). Het veld "Aankoopberdrag" heet `Aankoopbedrag`. + De synchronisatie met Signpost maakt een toestel aan als het serienummer nog niet bestaat. +- **Opmerkingen** en **Signpost_herstellingen_DB** verwijzen naar `Toestellen.Toestel_ID`. Dat is hetzelfde nummer als + `Signpost_DB.Toestel_ID`, maar zo werkt het ook voor toestellen die niet via Signpost gekocht zijn. + Herstellingen hebben ook een `Datum` en de leerling (`Leerling_ID`). +- **Eigendom** houdt ook de geschiedenis bij: `Datum_inlevering` leeg betekent dat de leerling het toestel nu heeft. + De vroegere tabel `Eigendom_archief` is niet meer nodig. +- **Co-accounts** heet `Co_accounts` en "Laatste aanmelding" heet `Laatste_aanmelding` (geen streepjes of spaties in namen). +- **Campus.School_ID** verwijst naar `Scholen.School_ID` in de centrale database. Een harde foreign key kan niet, + want een schooldatabase kan op een andere server staan. +- **Lokalen.Campus_ID** mag leeg zijn: een CO2-sensor met een nieuwe lokaalnaam maakt automatisch een lokaal aan. + Koppel het daarna aan een campus. +- **Wifi** kreeg een optionele `Campus_ID`. +- **Schooljaar** (`2026` → `2026-27`) is een extra tabel voor `Leerlingen.Schooljaar_ID`. +- **smartschool_coaccounts** (extra, per school): alle co-accounts uit Smartschool met klas, leerling en laatste + aanmelding (Smartschool › Co-accounts). Wordt automatisch aangemaakt en één keer per dag opnieuw opgehaald. +- **gopro_keuzes** (extra, per school): de GO! Pro-functie en -rol per personeelslid (`Person_ID` uit Informat). + Wordt automatisch aangemaakt; zonder keuze is het *Leerkracht* (een directeur: *Directeur*). + +## Windows → Linux: tabelnamen met hoofdletters + +MySQL op Windows bewaart tabelnamen in kleine letters (`lower_case_table_names = 1`); op Linux (`= 0`) zijn +`toestellen` en `Toestellen` verschillende tabellen. Bij het opstarten (en bij **Testen** van een school) herstelt +PIVOT dit automatisch voor de centrale database en alle schooldatabases (`services/tabelnamen.py`), enkel op een +server met `lower_case_table_names = 0` en enkel voor de tabellen die PIVOT kent: + +- alleen `toestellen` bestaat → hernoemd naar `Toestellen`; +- beide bestaan en `Toestellen` is leeg → de lege tabel weg, `toestellen` hernoemd; +- beide bevatten gegevens → niets gewijzigd, melding in het serverlogboek (zelf samenvoegen). + +Wat er gebeurde, staat in het serverlogboek (regels die beginnen met `PIVOT tabelnamen:`). + +## Aantal verbindingen ("Too many connections") + +PIVOT houdt per database (centraal + elke school) een pool van verbindingen open: `config.ini › [database] › +pool_size` (standaard 3). In totaal dus ongeveer (aantal scholen + 1) × pool_size per draaiend PIVOT-proces. Dat moet +onder `max_connections` van MySQL blijven (standaard 151). Krijg je "1040 Too many connections", verhoog dan +`max_connections` in `my.ini` / `my.cnf` (bv. `max_connections = 500`) of verlaag `pool_size`. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e8abc08 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +# syntax=docker/dockerfile:1 + +# Comments are provided throughout this file to help you get started. +# If you need more help, visit the Dockerfile reference guide at +# https://docs.docker.com/go/dockerfile-reference/ + +# Want to help us make this template better? Share your feedback here: https://forms.gle/ybq9Krt8jtBL3iCk7 + +ARG PYTHON_VERSION=3.12.2 +FROM python:${PYTHON_VERSION}-slim as base + +# Prevents Python from writing pyc files. +ENV PYTHONDONTWRITEBYTECODE=1 + +# Keeps Python from buffering stdout and stderr to avoid situations where +# the application crashes without emitting any logs due to buffering. +ENV PYTHONUNBUFFERED=1 + +WORKDIR /app + +# Create a non-privileged user that the app will run under. +# See https://docs.docker.com/go/dockerfile-user-best-practices/ +ARG UID=10001 +RUN adduser \ + --disabled-password \ + --gecos "" \ + --home "/nonexistent" \ + --shell "/sbin/nologin" \ + --no-create-home \ + --uid "${UID}" \ + appuser + +# Download dependencies as a separate step to take advantage of Docker's caching. +# Leverage a cache mount to /root/.cache/pip to speed up subsequent builds. +# Leverage a bind mount to requirements.txt to avoid having to copy them into +# into this layer. +RUN --mount=type=cache,target=/root/.cache/pip \ + --mount=type=bind,source=requirements.txt,target=requirements.txt \ + python -m pip install -r requirements.txt + +# Switch to the non-privileged user to run the application. +USER appuser + +# Copy the source code into the container. +COPY . . + +# Expose the port that the application listens on. +EXPOSE 5001 + +# Run the application. +CMD python3 app.py diff --git a/MEERDERE_SCHOLEN.md b/MEERDERE_SCHOLEN.md new file mode 100644 index 0000000..d0e30d2 --- /dev/null +++ b/MEERDERE_SCHOLEN.md @@ -0,0 +1,69 @@ +# PIVOT voor meerdere scholen (versie 1.1.0) + +Eén PIVOT voor alle scholen. Zie **DATABASE.md** voor de databasestructuur (2026-27), de installatie en de rechten. + +Elke school heeft: + +- een **eigen database** (zelfde tabellen, eigen gegevens). De PIVOT-gebruikers en hun rechten per school staan centraal; +- een **eigen e-maildomein** (of meerdere). Bij *Inloggen met Google* wordt de school daaraan herkend; +- **eigen koppelingen**: Smartschool (webservice-wachtwoord, OneRoster), Informat (instellingsnummer, client-ID/secret), + Google (serviceaccount-sleutel, admin, SMTP, OU's, 2FA), Signpost/M4S, CO2-netwerk en personeelsinstellingen. + +Alles wat per school verschilt staat in de tabel `Scholen` van de centrale database. Geheimen (wachtwoorden, +client-secrets en de Google-sleutel) worden daar **versleuteld** bewaard. `config.ini` bevat enkel nog wat voor alle scholen geldt. + +## Eerste installatie / overzetten van 1.0.9 + +1. **Versleutelingssleutel maken** en veilig bewaren (zonder deze sleutel zijn de opgeslagen geheimen onleesbaar): + ``` + python beheer.py nieuwe-sleutel + ``` + Zet ze in de omgevingsvariabele `PIVOT_SLEUTEL` (of laat PIVOT ze zelf aanmaken in `geheimen/pivot.key`). + Zet ook `FLASK_SECRET_KEY` (willekeurige lange tekst) en `PIVOT_DB_PASSWORD`. +2. **config.ini invullen**: databaseserver, `superbeheerders` (Google-accounts van de scholengroep-ICT), + en eventueel een gedeelde Google-login (`[google_sso]`). +3. **Databases aanmaken**: `mysql -u -p < sql/installatie_pivot_26-27.sql` + (centrale database `pivot`, school Scholengroep Antwerpen + database, administrator Marijn). Zie DATABASE.md. +4. **Bestaande school importeren** uit de oude config.ini (alle wachtwoorden worden versleuteld overgenomen): + ``` + python beheer.py importeer-config pad/naar/oude/config.ini --google-sleutel pad/naar/kamxm_api_key.json + ``` +5. Starten, inloggen met Google als superbeheerder → **🏫 Alle scholen beheren** → **Nieuwe school** voor de andere scholen. + Bij een nieuwe school kan PIVOT de database meteen aanmaken (lege standaardstructuur, of een volledige kopie + van een bestaande school, mét gegevens en desgewenst met haar koppelingen en gebruikersrechten). Geef daarna via **🔐 Gebruikers & rechten** de juiste mensen rechten in die school. +6. Per school: **🩺 Testen** controleert database, Smartschool, OneRoster, Informat, Google en Signpost. + +## Wie mag wat + +| Rol | Hoe | Mag | +|---|---|---| +| Administrator | `Gebruikers.Veiligheidsgroep = 1` (bv. Marijn), of Google-account in `config.ini › superbeheerders` | alles in alle scholen: scholen toevoegen, gebruikers en rechten beheren, wisselen tussen scholen | +| Gebruiker | `Veiligheidsgroep = 2` + rechten per school | enkel de aangevinkte onderdelen, enkel in die scholen (zie DATABASE.md) | +| Leerkracht | Google-login, in de personeels-OU's, geen account | enkel de personeelsmodule | + +Een administrator kan ook met gebruikersnaam en wachtwoord inloggen. Geef die rol dus enkel aan wie dat echt nodig heeft, +met een sterk wachtwoord. + +## Hoe wordt de school bepaald? + +1. **Eigen webadres**: krijgt een school een hostnaam (bv. `pivot.school.be`), dan ligt de school daar vast. +2. **Google-login**: het domein van het e-mailadres bepaalt de school. +3. **Gebruikersnaam/wachtwoord**: de gebruiker kiest de school in een keuzelijst (die wordt onthouden op het toestel). + +## Google-login + +- **Gedeeld** (aanrader): één OAuth-client (type *Webtoepassing*, toestemmingsscherm *Extern*) in `config.ini › [google_sso]`. + Werkt voor alle domeinen. Redirect-URI: `https:///callback`. +- **Per school**: vul bij de school *Google-login client-ID/secret* in (bv. een *Interne* app in de Workspace van die school). + +## Achtergrondtaken + +De dagelijkse synchronisatie van afwezigheden en het opruimen van 2FA-uitzonderingen lopen nu voor **alle actieve +scholen** (elk op het eigen sync-uur). Scholen zonder Smartschool-wachtwoord of Google-sleutel worden overgeslagen. + +## Aandachtspunten + +- **CO2-sensoren**: de scanner zoekt op het netwerk van de school. Draait PIVOT centraal, dan moet de server die netwerken kunnen bereiken. +- **Schooljaar**: leeg laten = automatisch (wisselt op 1 september). De Informat-telling gebruikt nu *vandaag + 1 maand* als + referentiedatum (vroeger vast `2027-1-3`) en het schooljaar van de school (vroeger vast `2025-26`). +- De kolom `KAMXM_nummer` behoudt die naam in elke schooldatabase (het is een interne kolomnaam). In de schermen staat "Toestelnummer". diff --git a/OVERDRACHT.md b/OVERDRACHT.md new file mode 100644 index 0000000..7a5f101 --- /dev/null +++ b/OVERDRACHT.md @@ -0,0 +1,111 @@ +# PIVOT 1.1.0 (meerdere scholen) – overdracht + +Dit document vat samen hoe PIVOT in elkaar zit, welke afspraken er in de code gelden en wat er recent bijkwam. +Het is bedoeld voor wie verder werkt aan PIVOT (zelf, of samen met een AI-assistent: geef dan dit bestand en de +zip van het project mee). Lees ook **MEERDERE_SCHOLEN.md** (installatie, rollen) en **DATABASE.md** (tabellen). + +> ⚠️ `config.ini` en de map `geheimen/` bevatten echte wachtwoorden en sleutels. Deel ze niet en zet ze nooit in +> een chat, ticket of e-mail. Geef een collega een kopie van het project **zonder** die bestanden en laat hem/haar +> een eigen `config.ini` invullen. + +--- + +## 1. Architectuur in het kort + +- **Flask-app** (`app.py`) met ±40 blueprints (`blueprints/`) en de logica in `services/`; HTML in `templates/` + (Jinja, `base.html` + `static/global.css`). +- **Multi-tenant** (`tenancy.py`): één centrale database (`Scholen`, `Gebruikers`, rechten, logs, ...) en één database + per school (toestellen, leerlingen, ...). + - `huidige_school()` = de school van het verzoek; `in_school(school)` / `met_school(fn)` voor achtergrondthreads. + - Instellingen per school = `Veld(...)` in `tenancy.VELDEN` (verschijnen vanzelf in 🔌 Koppelingen); + lezen met `school.get('SLEUTEL')` of `Config.SLEUTEL` (metaclass leest de huidige school). + - `school.cache` = per-school geheugen (wordt leeggemaakt bij wijzigingen aan de school). + - `school_singleton(cls, init)` = één object per school (gebruikt voor achtergrondtaken met `status`-dict). + - `google_credentials(scopes, subject)` = serviceaccount van de school, gedelegeerd naar `subject`. +- **Database** (`database.py`): `execute_query` (schooldatabase), `central_query` (centraal); `commit=True` geeft + het aantal rijen terug. Pools per database (`config.ini › [database] › pool_size`, standaard 3). +- **Rechten** (`rechten.py`): `ONDERDELEN` = lijst (code, naam, categorie); routes met `@recht_vereist('code')`, + templates met `{% if mag('code') %}`. Een nieuw onderdeel verschijnt vanzelf in 🔐 Gebruikers & rechten. + `log(...)` schrijft in het logboek. +- **Achtergrondtaken**: threads gestart in `app.py` (enkel in het echte proces, niet in de reloader): + afwezigheden, 2FA, Skore, GO! Pro (nachtelijk verzamelen), Gmail-handtekeningen (nachtelijk). Taken die maar één keer + per dag mogen lopen, "claimen" de dag met een `UPDATE ... WHERE` (werkt ook met meerdere processen). +- **Opstarten**: `tenancy.ensure_schema()` (centrale tabellen) en `services/tabelnamen.py` (zie §5). + +## 2. Afspraken in de code + +- Alles in het **Nederlands** (namen, meldingen, commentaar). +- Tabellen die een module zelf nodig heeft: `CREATE TABLE IF NOT EXISTS` in een `ensure_tables()`/`*_ensure()` in de + service, én dezelfde DDL in `sql/school.sql` of `sql/centraal.sql` + `sql/installatie_pivot_26-27.sql`, én een regel + in `DATABASE.md`. Kolommen die later bijkomen: `SHOW COLUMNS` + `ALTER TABLE` in de ensure-functie. +- Tabelnamen met hoofdletters moeten exact kloppen (Linux!); zie §5. +- **Templates**: + - `{% block main_class %}wide{% endblock %}` voor brede tabellen; tabellen met zoeken/sorteren/paginering in de + browser (helpers `perPagina(sleutel, standaard)` en `perPaginaKiezer(...)` uit `base.html`). + - In HTML-attributen (`onsubmit="..."`, `onchange`, `data-...`) altijd `|tojson|forceescape`, anders breekt het + attribuut op de aanhalingstekens (bevestigingsvragen werkten daardoor niet meer). + - Elementen die met het `hidden`-attribuut verborgen worden: zet `[hidden] { display: none !important; }` in de + pagina-CSS (knopstijlen overschrijven het anders). +- **CSV-exports**: `;` als scheidingsteken en UTF-8 met BOM (Excel). **Excel**: openpyxl. +- **Google-fouten** vertalen naar begrijpelijke meldingen (`vriendelijk(e)` in de services) mét de scope die ontbreekt. + +## 3. Nieuw onderdeel toevoegen (checklist) + +1. `services/_service.py` (logica, tabellen) en `blueprints/_bp.py` (routes). +2. Blueprint registreren in `app.py`. +3. Recht in `rechten.ONDERDELEN` (code, naam, categorie). +4. Link in het juiste blok van `templates/dashboard.html` (`{% if mag('code') %}`; voeg de code ook toe aan de + `mag(...)`-voorwaarde van het blok). +5. Nieuwe Google-scope? Toevoegen aan de lijst + tabel in `services/handleidingen_standaard.py` (de handleiding in + de database wordt **niet** automatisch bijgewerkt: zelf aanpassen in 📘 Handleidingen). +6. SQL-bestanden en `DATABASE.md` bijwerken. + +## 4. Overzicht van recente onderdelen + +| Onderdeel | Bestanden | Opmerkingen | +|---|---|---| +| IP-blokkades / whitelist | `ipblokkade_bp.py`, `services/ipblokkade.py` | gewone gebruikers met recht `ip_whitelist` zien/beheren enkel hun eigen school | +| Aanmelden | `blueprints/auth.py` | geen schoolkeuze meer: laatste school → domein → cookie → laagste instellingsnummer; domeinen mogen gedeeld worden door meerdere scholen | +| GO! Pro + verzameltabel | `gopro_bp.py`, `gopro_service.py`, `gopro*.html` | verzameltabel (centraal), rode lijst, verzonden, nachtelijk verzamelen; periode = lopend schooljaar (1/9–31/8) | +| Leerlingfacturatie | `facturatie_bp.py`, `facturatie_service.py` | Informat Invoice API (GraphQL); scope per toegangsgroep (`_`), wordt zelf gezocht | +| Internaat | `internaat_bp.py`, `internaat_service.py`, `aanwezigheid_service.py` | Internaat WEB API; aanwezigheden per week; Smartschool-check "voornaam achternaam" | +| Gmail | `gmail_delegatie_bp.py`, `gmail_labels_bp.py`, `handtekeningen_bp.py`, `contacten_bp.py`, `verzendlijsten_bp.py` | delegaties (+ overzicht), mails verplaatsen, handtekeningen (functie/telefoon uit Google, nachtelijk), contactlijsten in mailboxen + zichtbaarheid adresboek | +| Google | `google_licenties_bp.py`, `gedeelde_drives_bp.py` | licenties (customerId: domein of klant-ID), gedeelde drives: leden/rechten, "waar is iemand lid van", gebruiker vervangen (zelfde rol) | +| Smartschool | `sgr_groepen_bp.py`, `sgr_groepen_service.py` | subgroepen + leden van een hoofdgroep (standaard "groepen GO-Antwerpen") | +| Basisonderwijs | `basisonderwijs_bp.py`, `bingel_service.py` | blok enkel bij Onderwijsniveau = basis; Bingel-Excel (klas uit Informat-inschrijvingen, klasnummer alfabetisch) | +| Toestellen | `devices.py`, `inventaris.html`, `toestellen.html` | eigendom: alle leerlingen + filter met/zonder toestel, historie per leerling en per toestel, knoppen uitdelen/inleveren; Alle toestellen: blokkeren/deblokkeren in Google (kolom `Toestellen.Geblokkeerd`) | +| Dashboard | `dashboard.html` | blokken Gmail, Internaat, Basisonderwijs, Leerlingfacturatie, Links (website + Smartschool) | + +Benodigde Google-scopes (domeinbrede delegatie) staan in 📘 Handleidingen; recent bijgekomen: +`gmail.modify`, `gmail.settings.basic`, `contacts`, `drive`. De bijbehorende API's (Gmail, People, Drive, +Enterprise License Manager) moeten aanstaan in het Cloud-project van het serviceaccount. + +## 5. Omgeving en installatie-aandachtspunten + +- **Windows → Linux**: MySQL op Windows bewaart tabelnamen in kleine letters; op Linux (`lower_case_table_names = 0`) + herstelt `services/tabelnamen.py` dat bij het opstarten en bij 🩺 Testen (enkel voor de tabellen die PIVOT kent; + zijn beide versies gevuld, dan enkel een melding in het logboek). +- **"1040 Too many connections"**: (aantal scholen + 1) × `pool_size` per PIVOT-proces moet onder `max_connections` + van MySQL blijven. Oplossing: `SET PERSIST max_connections = 500;` of `pool_size` verlagen. +- **Productie**: liefst nginx (HTTPS, Let's Encrypt) + gunicorn/waitress i.p.v. de Flask-ontwikkelserver, en de + poort van PIVOT enkel intern openzetten. Het logo van Gmail-handtekeningen (`/handtekening-logo/...`) moet wel + publiek bereikbaar zijn (de IP-blokkering slaat die route over). + +## 6. Nog niet getest tegen de echte omgeving / openstaand + +Onderstaande onderdelen werden enkel getest met nagebootste antwoorden; bij het eerste echte gebruik goed nakijken: + +- **Bingel**: het veld met de klas in de Informat-inschrijvingen (`inschrKlassen`); de pagina toont de veldnamen + die Informat teruggeeft als iets leeg blijft. +- **SGR groepen**: formaat van `getAllGroupsAndClasses` (XML/base64) en de leden per groep. +- **Contactlijsten** (People API), **gedeelde drives** (Drive API), **handtekeningen** (Gmail sendAs). +- **Licenties**: terugval op de klant-ID als het schooldomein geen primair domein is. +- **Leerlingfacturatie**: automatisch zoeken van de scope (identityserver). +- Informat-fout "SqlDateTime overflow" bij één school = foute datum in Informat zelf (niet in PIVOT). + +## 7. Verder werken + +- Elke wijziging werd telkens als volledige zip van `Pivot_1.1.0` aangeleverd (zonder `__pycache__`). +- Bij een nieuwe vraag aan een AI-assistent: geef dit bestand, `DATABASE.md`, `MEERDERE_SCHOLEN.md` en de + betrokken bestanden mee (of de hele zip zonder `config.ini`/`geheimen/`), en beschrijf wat je wil met een + schermafbeelding erbij. diff --git a/README.Docker.md b/README.Docker.md new file mode 100644 index 0000000..54cff9e --- /dev/null +++ b/README.Docker.md @@ -0,0 +1,22 @@ +### Building and running your application + +When you're ready, start your application by running: +`docker compose up --build`. + +Your application will be available at http://localhost:5001. + +### Deploying your application to the cloud + +First, build your image, e.g.: `docker build -t myapp .`. +If your cloud uses a different CPU architecture than your development +machine (e.g., you are on a Mac M1 and your cloud provider is amd64), +you'll want to build the image for that platform, e.g.: +`docker build --platform=linux/amd64 -t myapp .`. + +Then, push it to your registry, e.g. `docker push myregistry.com/myapp`. + +Consult Docker's [getting started](https://docs.docker.com/go/get-started-sharing/) +docs for more detail on building and pushing. + +### References +* [Docker's Python guide](https://docs.docker.com/language/python/) \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..f31544f --- /dev/null +++ b/app.py @@ -0,0 +1,303 @@ +import os +from flask import Flask, render_template, redirect, url_for +from config import Config +import tenancy +import rechten +from tenancy import school_op_code, school_voor_host, GeenSchoolFout, KoppelingOntbreekt + +#----------------------------------------------------- +# Blueprints importeren +#----------------------------------------------------- +from blueprints.devices import devices_bp +from blueprints.students import students_bp +from blueprints.repairs import repairs_bp +from blueprints.auth import auth_bp, oauth # OAuth toegevoegd aan import +from blueprints.dashboard_bp import main_bp +from blueprints.google_admin import google_bp +from blueprints.admin import admin_bp +from blueprints.tools import tools_bp +from blueprints.co2_sensor import co2_sensor_bp +from blueprints.smartschool_bp import smartschool_bp +from blueprints.leerlingenaantal_bp import leerlingenaantal_bp +from blueprints.handleidingen_bp import handleidingen_bp, lijst as handleidingen_lijst, mag_lezen as handleidingen_mag_lezen +from blueprints.nieuw_schooljaar_accounts_bp import account_verplaatsen_bp +from blueprints.nieuw_schooljaar_toestellen_bp import toestellen_verplaatsen_bp +from blueprints.qr_code_bp import qr_code_bp +from blueprints.smartschool_activiteit_bp import ss_bp +from services.smartschool_api import SmartschoolService +from blueprints.bugreport_bp import bugreport_bp +from blueprints.bugreport_overzicht_bp import bugreport_overzicht_bp +from blueprints.signpost_devices_bp import signpost_devices_bp +from blueprints.google_licenties_bp import google_licenties_bp +from blueprints.gmail_delegatie_bp import gmail_delegatie_bp +from blueprints.afwezigheden_bp import afwezigheden_bp +from services.afwezigheden_service import AfwezighedenService +from blueprints.tweestaps_bp import tweestaps_bp +from services.tweestaps_service import TweestapsService +from blueprints.personeel_bp import personeel_bp +from blueprints.scholen_bp import scholen_bp +from blueprints.skore_bp import skore_bp +from services import skore_service +from services import personeel_service +from flask import session, request, flash, g +#------------------------------------------------------ +# Services importeren +#------------------------------------------------------ +from services.co2_service import CO2Scanner + + +def create_app(): + # Maak de app aan + app = Flask(__name__) + app.config.from_object(Config) + if Config.PROXY_AANTAL: + # Achter een reverse proxy: het echte IP-adres komt uit X-Forwarded-For (enkel van die proxy's vertrouwd) + from werkzeug.middleware.proxy_fix import ProxyFix + n = Config.PROXY_AANTAL + app.wsgi_app = ProxyFix(app.wsgi_app, x_for=n, x_proto=n, x_host=n) + # Handleidingen bevatten schermafbeeldingen (base64); Flask laat standaard maar 500 kB formulierdata toe + app.config['MAX_FORM_MEMORY_SIZE'] = 30 * 1024 * 1024 + + #------------------------------------------------------ + # OAuth Initialisatie + #------------------------------------------------------ + oauth.init_app(app) + + + # Google-login: clients worden per school (of gedeeld) aangemaakt in blueprints/auth.py + + # Centrale tabellen (Scholen, Gebruikers, rechten, Logs, Bugs) aanmaken indien nodig + try: + tenancy.ensure_schema() + except Exception as e: + print(f"PIVOT: centrale database niet bereikbaar bij opstarten: {e}", flush=True) + # Databases van de scholen: tabelnamen met hoofdletters herstellen (Windows → Linux), zie services/tabelnamen.py + try: + from services.tabelnamen import herstel_alle_scholen + herstel_alle_scholen() + except Exception as e: + print(f"PIVOT: tabelnamen van de scholen nakijken mislukt: {e}", flush=True) + + #------------------------------------------------------ + # Blueprints registreren + #------------------------------------------------------ + # Registreert alle url prefixen voor zichtbaarheid en om naamconflicten te vermijden + app.register_blueprint(auth_bp) + app.register_blueprint(main_bp) + app.register_blueprint(devices_bp, url_prefix='/devices') + app.register_blueprint(students_bp, url_prefix='/leerlingen') + app.register_blueprint(repairs_bp, url_prefix='/herstellingen') + app.register_blueprint(google_bp, url_prefix='/google') + app.register_blueprint(admin_bp, url_prefix='/admin') + app.register_blueprint(tools_bp, url_prefix='/tools') + app.register_blueprint(co2_sensor_bp, url_prefix='/co2') + app.register_blueprint(smartschool_bp, url_prefix='/ss') + + + #------------------------- + app.register_blueprint(leerlingenaantal_bp, url_prefix='/scholengroep') + from blueprints.gopro_bp import gopro_bp + app.register_blueprint(gopro_bp, url_prefix='/scholengroep/gopro') + from blueprints.facturatie_bp import facturatie_bp + app.register_blueprint(facturatie_bp, url_prefix='/leerlingfacturatie') + from blueprints.gmail_labels_bp import gmail_labels_bp + app.register_blueprint(gmail_labels_bp, url_prefix='/google/labels-verplaatsen') + from blueprints.handtekeningen_bp import handtekeningen_bp, handtekening_logo_bp + app.register_blueprint(handtekeningen_bp, url_prefix='/google/handtekeningen') + app.register_blueprint(handtekening_logo_bp) + from blueprints.contacten_bp import contacten_bp + from blueprints.gedeelde_drives_bp import gedeelde_drives_bp + app.register_blueprint(gedeelde_drives_bp, url_prefix='/google/gedeelde-drives') + from blueprints.basisonderwijs_bp import basisonderwijs_bp + app.register_blueprint(basisonderwijs_bp, url_prefix='/basisonderwijs') + app.register_blueprint(contacten_bp, url_prefix='/google/contacten') + from blueprints.internaat_bp import internaat_bp + app.register_blueprint(internaat_bp, url_prefix='/internaat') + from blueprints.sgr_groepen_bp import sgr_groepen_bp + app.register_blueprint(sgr_groepen_bp, url_prefix='/smartschool/sgr-groepen') + from blueprints.personeelsaantal_bp import personeelsaantal_bp + app.register_blueprint(personeelsaantal_bp, url_prefix='/personeelsaantallen') + #--------------------------- + + #------------------------- + app.register_blueprint(account_verplaatsen_bp, url_prefix='/nieuw_schooljaar') + #--------------------------- + + #---------------------------- + app.register_blueprint(toestellen_verplaatsen_bp, url_prefix='/nieuw_schooljaar_toestellen') + #--------------------------- + + #--------------------------- + app.register_blueprint(qr_code_bp, url_prefix='/qr_code') + #---------------------------- + + #----------------------------- + app.register_blueprint(ss_bp,url_prefix='/activiteit') + #------------------------------ + + #----------------------------- + app.register_blueprint(bugreport_bp,url_prefix='/bugreport') + app.register_blueprint(bugreport_overzicht_bp,url_prefix='/bugreport_overzicht') + #------------------------------ + app.register_blueprint(signpost_devices_bp,url_prefix='/signpost_devices') + app.register_blueprint(google_licenties_bp, url_prefix='/google_licenties') + app.register_blueprint(gmail_delegatie_bp, url_prefix='/gmail_delegatie') + app.register_blueprint(afwezigheden_bp, url_prefix='/afwezigheden') + app.register_blueprint(tweestaps_bp, url_prefix='/2fa') + app.register_blueprint(personeel_bp, url_prefix='/personeel') + app.register_blueprint(scholen_bp, url_prefix='/scholen') + app.register_blueprint(skore_bp, url_prefix='/skore') + app.register_blueprint(handleidingen_bp, url_prefix='/handleidingen') + from blueprints.verzendlijsten_bp import verzendlijsten_bp + app.register_blueprint(verzendlijsten_bp, url_prefix='/google/verzendlijsten') + from blueprints.ipblokkade_bp import ipblokkade_bp + app.register_blueprint(ipblokkade_bp, url_prefix='/beheer/ip-blokkades') + from blueprints.database_bp import database_bp + app.register_blueprint(database_bp, url_prefix='/beheer/database') # Beheer › Database (Excel-import) + + #------------------------------------------------------ + # Welke school? (per request) + #------------------------------------------------------ + # Endpoints die zonder gekozen school werken + ZONDER_SCHOOL = ('static', 'index', 'auth.', 'scholen.') + # Publieke pagina's (zonder login): school via hostnaam of ?school=code + PUBLIEK = ('tools.',) + + # IP-blokkades: als eerste controle, voor elke aanvraag (ook de loginpagina en statische bestanden) + @app.before_request + def ip_blokkade(): + from services import ipblokkade + if request.endpoint == 'handtekening_logo.logo': + return None # het logo van de Gmail-handtekening moet voor iedereen (ook Google) bereikbaar zijn + if ipblokkade.controleer(request.remote_addr): + return ("Toegang geweigerd" + "
" + "

Toegang geweigerd

Je hebt geen toegang tot deze site.

", 403) + return None + + @app.before_request + def bepaal_school(): + ep = request.endpoint or '' + host_school = school_voor_host(request.host) + g.school = None + + if session.get('auth'): + code = session.get('school') + school = school_op_code(code) if code else None + if code and school is None: + session.clear() + flash("Je school is niet (meer) actief in PIVOT. Log opnieuw in.", "error") + return redirect(url_for('auth.login')) + if host_school and school and host_school.code != school.code and not session.get('superbeheerder'): + # Sessie van een andere school op het adres van deze school → opnieuw inloggen + session.clear() + return redirect(url_for('auth.login')) + g.school = school + if school is None and not ep.startswith(ZONDER_SCHOOL): + # Superbeheerder zonder gekozen school + return redirect(url_for('scholen.overzicht')) + else: + g.school = host_school + if g.school is None and ep.startswith(PUBLIEK): + g.school = school_op_code(request.args.get('school')) + if g.school is None and ep.startswith(PUBLIEK): + flash("Kies eerst een school.", "error") + return redirect(url_for('auth.login')) + return None + + @app.errorhandler(GeenSchoolFout) + def geen_school(e): + session.clear() + flash(str(e), "error") + return redirect(url_for('auth.login')) + + @app.errorhandler(KoppelingOntbreekt) + def koppeling_ontbreekt(e): + flash(str(e), "error") + return redirect(url_for('main.dashboard')) + + # Leerkrachten die via Google inloggen (groep 5) hebben enkel toegang tot de personeelsmodule + @app.before_request + def beperk_leerkrachten(): + if session.get('security_group') != personeel_service.LEERKRACHT_GROEP: + return None + ep = request.endpoint or '' + if ep == 'static' or ep.startswith('personeel.') or ep.startswith('auth.'): + return None + if ep not in ('main.dashboard', 'index'): + flash("Je hebt enkel toegang tot de module afwezigheden en activiteiten.", "error") + return redirect(url_for('personeel.mijn')) + + # Dagelijkse synchronisatie van afwezigheden (B-codes) uit Smartschool. + # In debugmodus start Flask twee processen; enkel het 'echte' proces start de taak. + # Eén achtergrondtaak per soort, die telkens alle scholen overloopt. + if not app.debug or os.environ.get('WERKZEUG_RUN_MAIN') == 'true': + AfwezighedenService.start_scheduler() + TweestapsService.start_scheduler() # verlopen 2FA-uitzonderingen automatisch beëindigen + skore_service.start_scheduler() # geplande Skore-synchronisatie per school + from services import gopro_service + gopro_service.start_scheduler() # GO! Pro: 's nachts de groene naar de verzameltabel (als de schakelaar aan staat) + from services import handtekening_service + handtekening_service.start_scheduler() # Gmail-handtekeningen 's nachts opnieuw zetten (per school, schakelaar) + #------------------------------ + + @app.context_processor + def inject_school_info(): + school = g.get('school') + info = { + 'school': school, + 'version': app.config.get('APP_VERSION'), + 'is_superbeheerder': bool(session.get('superbeheerder')), + 'school_name': school.naam if school else '', + 'school_name_short': school.code if school else '', + 'contact_email': school.get('CONTACT_EMAIL') if school else '', + 'personeel_rollen': set(), + # Rechten: {% if mag('herstellingen') %} ... {% endif %} + 'mag': rechten.heeft_recht, + 'is_admin': rechten.is_admin(), + 'andere_scholen': [], + 'handleidingen_lijst': handleidingen_lijst, + 'mag_handleidingen': handleidingen_mag_lezen, # functie: enkel opgehaald waar gebruikt (dashboard) + } + if school and session.get('auth'): + info['personeel_rollen'] = personeel_service.rollen(session) + info['andere_scholen'] = mijn_andere_scholen(school) + return info + + def mijn_andere_scholen(school): + """Andere scholen waarin de ingelogde gebruiker rechten heeft (om te wisselen).""" + try: + if rechten.is_admin(): + return [s for s in tenancy.alle_scholen() if s.code != school.code] + gid = session.get('gebruiker_id') + if not gid: + return [] + ids = rechten.scholen_met_rechten(gid) + return [s for s in tenancy.alle_scholen() if s.id in ids and s.code != school.code] + except Exception: + return [] + + # Logboek: elke bezochte pagina van een ingelogde gebruiker → tabel Logs (centrale database) + LOG_OVERSLAAN = ('static', 'co2_sensor.get_scan_status', 'co2_sensor.get_cleanup_status', + 'afwezigheden.status') + LOGBOEK = Config.LOGBOEK + + @app.after_request + def logboek(response): + if LOGBOEK and session.get('auth') and request.endpoint and request.endpoint not in LOG_OVERSLAAN \ + and response.status_code < 500: + rechten.log(actie=request.method if request.method != 'GET' else None) + return response + + # Definieert de root, wordt uitgevoerd zodra iemand op de startpagina komt + @app.route('/') + def index(): + return redirect(url_for('auth.login')) + + return app + +# Start de applicatie +if __name__ == "__main__": + app = create_app() + # Debug aanzetten via config.ini › [algemeen] › debug = ja + app.run(debug=Config.DEBUG, host='0.0.0.0', port=5001) \ No newline at end of file diff --git a/beheer.py b/beheer.py new file mode 100644 index 0000000..4406cb5 --- /dev/null +++ b/beheer.py @@ -0,0 +1,292 @@ +""" +Beheer van PIVOT vanaf de opdrachtregel. + + python beheer.py init + Maakt de tabellen van de centrale database aan (Scholen, Gebruikers, rechten, Logs, Bugs). + + python beheer.py nieuwe-schooldatabase DATABASE + Maakt een lege schooldatabase met de standaardstructuur (sql/school.sql). + + python beheer.py gebruiker NAAM [--wachtwoord W] [--email E] [--admin] + Maakt een PIVOT-gebruiker aan, of zet een nieuw wachtwoord / maakt hem administrator. + + python beheer.py rechten NAAM SCHOOLCODE [onderdeel ...|alles|geen] + Toont of zet de rechten van een gebruiker in een school. + + python beheer.py importeer-config OUDE_CONFIG.ini [--google-sleutel sleutel.json] [--code kamxm] [--db Pivot_26-27] + Zet een school uit een config.ini van PIVOT 1.0.x in het scholenregister + (alle wachtwoorden en koppelingen worden versleuteld overgenomen). + + python beheer.py lijst + Toont alle scholen. + + python beheer.py kopieer-school BRONCODE NIEUWE_DATABASE + Maakt een nieuwe database als volledige kopie (tabellen + gegevens) van de database van BRONCODE. + Registreer ze daarna als school via PIVOT (Nieuwe school › Database aanmaken? › Nee, bestaat al). + + python beheer.py nieuwe-sleutel + Toont een nieuwe versleutelingssleutel (voor PIVOT_SLEUTEL). +""" +import argparse +import configparser +import json +import os +import sys + +from cryptography.fernet import Fernet + +# Oude config.ini → velden in het scholenregister +MAPPING = { + ('schoolgegevens', 'admin_email'): 'ADMIN_EMAIL', + ('schooljaar', 'huidig_schooljaar'): 'SCHOOLYEAR', + ('google', 'ou_nieuwe_lln'): 'STUDENT_OU', + ('google', 'google_sso_clientid'): 'GOOGLE_SSO_CLIENTID', + ('google', 'google_sso_clientsecret'): 'GOOGLE_SSO_CLIENTSECRET', + ('google', 'google_smtp_server'): 'GOOGLE_SMTP_SERVER', + ('google', 'google_smtp_port'): 'GOOGLE_SMTP_PORT', + ('google', 'google_sender_adres'): 'GOOGLE_SMTP_SENDER_adres', + ('google', 'google_email_passsword'): 'GOOGLE_SMTP_EMAIL_PASSWORD', + ('google', 'google_api_scopes'): 'GOOGLE_API_SCOPES_RAW', + ('google', 'tweestaps_uitzondering_groep'): 'TWEESTAPS_UITZONDERING_GROEP', + ('google', 'tweestaps_ous'): 'TWEESTAPS_OUS', + ('google', 'tweestaps_groepen'): 'TWEESTAPS_GROEPEN_RAW', + ('informat', 'client_id'): 'INFORMAT_ID', + ('informat', 'client_secret'): 'INFORMAT_SECRET', + ('informat', 'intitute_number'): 'INFORMAT_INST_NUMBER', + ('informat', 'autho_url'): 'INFORMAT_AUTH_URL', + ('informat', 'api_base'): 'INFORMAT_API_BASE', + ('informat', 'scope'): 'INFORMAT_SCOPE', + ('smartschool', 'ss_client_id'): 'SS_CLIENT_ID', + ('smartschool', 'ss_client_secret'): 'SS_CLIENT_SECRET', + ('smartschool', 'ss_api_pw'): 'SS_API_PW', + ('smartschool', 'ss_api_platform'): 'SS_API_PLATFORM', + ('smartschool', 'afwezigheid_codes'): 'AFWEZIGHEID_CODES', + ('smartschool', 'afwezigheid_sync_uur'): 'AFWEZIGHEID_SYNC_UUR', + ('CO2_sensor', 'co2_netwerk'): 'CO2_NETWORK', + ('CO2_sensor', 'co2_beginadres'): 'CO2_START_ADDR', + ('CO2_sensor', 'co2_eindadres'): 'CO2_END_ADDR', + ('CO2_sensor', 'co2_waardedrempel'): 'CO2_THRESHOLD', + ('CO2_sensor', 'co2_scan_interval'): 'CO2_INTERVAL', + ('personeel', 'personeel_ous'): 'PERSONEEL_OUS', + ('personeel', 'directie'): 'PERSONEEL_DIRECTIE', + ('personeel', 'secretariaat'): 'PERSONEEL_SECRETARIAAT', + ('personeel', 'secretariaat_mail'): 'PERSONEEL_SECRETARIAAT_MAIL', + ('personeel', 'mails_versturen'): 'PERSONEEL_MAILS', + ('m4s', 'm4s_base_data_url'): 'M4S_BASE_URL', + ('m4s', 'm4s_auth_url'): 'M4S_AUTH_URL', + ('m4s', 'm4s_clientid'): 'M4S_CLIENT_ID', + ('m4s', 'm4s_clientsecret'): 'M4S_CLIENT_SECRET', + ('m4s', 'm4s_institutionguid'): 'M4S_INSTITUTIONGUID', + ('m4s', 'm4s_repair_location_type'): 'M4S_REPAIR_LOCATION_TYPE', + ('m4s', 'm4s_repair_status'): 'M4S_REPAIR_STATUS', + ('m4s', 'm4s_truth_statement'): 'M4S_TRUTH_STATEMENT', + ('m4s', 'm4s_repair_at_institution'): 'M4S_REPAIR_AT_INTITUTION', + ('m4s', 'm4s_contact_first_name'): 'M4S_CONTACT_FIRST_NAME', + ('m4s', 'm4s_contact_last_name'): 'M4S_CONTACT_LAST_NAME', + ('m4s', 'm4s_contact_email'): 'M4S_CONTACT_EMAIL', + ('m4s', 'm4s_contact_phone'): 'M4S_CONTACT_PHONE', + ('m4s', 'm4s_repair_street'): 'M4S_REPAIR_STREET', + ('m4s', 'm4s_repair_streetnumber'): 'M4S_REPAIR_STREETNUMBER', + ('m4s', 'm4s_repair_zipcode'): 'M4S_REPAIR_ZIPCODE', + ('m4s', 'm4s_repair_city'): 'M4S_REPAIIR_CITY', + ('m4s', 'm4s_repair_countrycode'): 'M4S_REPAIR_COUNTRYCODE', + ('m4s', 'm4s_language_code'): 'M4S_LANGUAGE_CODE', + ('m4s', 'm4s_billing_first_name'): 'M4S_BILLING_FIRST_NAME', + ('m4s', 'm4s_billing_last_name'): 'M4S_BILLING_LAST_NAME', + ('m4s', 'm4s_billing_email'): 'M4S_BILLING_EMAIL', + ('m4s', 'm4s_billing_phone'): 'M4S_BILLING_PHONE', +} + + +def lees_oude_config(pad): + cp = configparser.ConfigParser() + if not cp.read(pad, encoding='utf-8'): + sys.exit(f"Kan {pad} niet lezen.") + waarden = {} + for (sectie, key), veld in MAPPING.items(): + if cp.has_option(sectie, key): + v = cp.get(sectie, key).strip() + if v and v != 'None': + waarden[veld] = v + # Smartschool-platform zonder https:// en pad + if 'SS_API_PLATFORM' in waarden: + waarden['SS_API_PLATFORM'] = waarden['SS_API_PLATFORM'].replace('https://', '').replace('http://', '').split('/')[0] + return cp, waarden + + +def cmd_importeer(args): + import tenancy + from config import Config + cp, waarden = lees_oude_config(args.config) + code = (args.code or cp.get('schoolgegevens', 'school_afkorting', fallback='')).strip().lower() + naam = cp.get('schoolgegevens', 'schoolnaam', fallback=code).strip() + domein = cp.get('schoolgegevens', 'schooldomein', fallback='').strip().lower() + db_naam = args.db or cp.get('database', 'database_name', fallback='').strip() + if not code or not domein or not db_naam: + sys.exit("Code, schooldomein of databasenaam ontbreekt (gebruik --code / --db).") + + # Eigen databaseserver/gebruiker enkel overnemen als die verschilt van de nieuwe config.ini + for key, veld, standaard in [('host', 'DB_HOST', Config.DB_HOST), ('user', 'DB_USER', Config.DB_USER), + ('password', 'DB_PASSWORD', Config.DB_PASSWORD)]: + v = cp.get('database', key, fallback='').strip() + if v and v != standaard: + waarden[veld] = v + + # Google-serviceaccount + sleutel = None + kandidaten = [args.google_sleutel] if args.google_sleutel else [ + cp.get('google', 'location_linux', fallback=''), cp.get('google', 'location', fallback='')] + for pad in kandidaten: + if pad and os.path.exists(pad): + with open(pad, encoding='utf-8') as f: + sleutel = json.load(f) + print(f"Google-sleutel gelezen uit {pad}") + break + if not sleutel: + print("⚠ Geen Google-sleutel gevonden; upload hem later via /scholen (of gebruik --google-sleutel).") + + tenancy.ensure_schema() + bestaand = tenancy.school_op_code(code, ook_inactief=True) + if bestaand and not args.overschrijven: + sys.exit(f"School '{code}' bestaat al. Gebruik --overschrijven om bij te werken.") + tenancy.opslaan(code, naam, domein, '', db_naam, True, waarden, sleutel, + gebruiker='beheer.py', nieuw=not bestaand) + print(f"✓ School {naam} ({code}) opgeslagen: domein {domein}, database {db_naam}, " + f"{len(waarden)} instellingen{', Google-sleutel' if sleutel else ''}.") + + +def cmd_lijst(args): + import tenancy + tenancy.ensure_schema() + scholen = tenancy.alle_scholen(ook_inactief=True) + if not scholen: + print("Nog geen scholen.") + for s in scholen: + print(f"{s.code:<12} {s.naam:<40} {','.join(s.domeinen):<30} db={s.db_naam:<20} " + f"{'actief' if s.actief else 'INACTIEF'}{' google✓' if s.google_sleutel else ''}") + + +def cmd_kopieer(args): + import tenancy + from blueprints.scholen_bp import kopieer_school_db + bron = tenancy.school_op_code(args.bron, ook_inactief=True) + if not bron: + sys.exit(f"Onbekende school {args.bron}") + ok, msg = kopieer_school_db(bron, args.database, {}) + print(msg) + sys.exit(0 if ok else 1) + + +def cmd_nieuwe_schooldatabase(args): + from blueprints.scholen_bp import maak_schooldatabase + ok, msg = maak_schooldatabase(args.database) + print(msg) + sys.exit(0 if ok else 1) + + +def cmd_gebruiker(args): + import getpass + import tenancy + import rechten + from database import central_query + from werkzeug.security import generate_password_hash + tenancy.ensure_schema() + pw = args.wachtwoord + bestaand = rechten.zoek_gebruiker(args.naam) + if pw is None and not bestaand: + pw = getpass.getpass("Wachtwoord: ") + groep = rechten.ADMIN if args.admin else None + if bestaand: + gid = bestaand['Gebruiker_ID'] + if pw: + central_query("UPDATE Gebruikers SET Passwoordhash = %s WHERE Gebruiker_ID = %s", + (generate_password_hash(pw), gid), commit=True) + if args.email: + central_query("UPDATE Gebruikers SET Emailadres = %s WHERE Gebruiker_ID = %s", + (args.email.lower(), gid), commit=True) + if groep: + central_query("UPDATE Gebruikers SET Veiligheidsgroep = %s, Actief = 1 WHERE Gebruiker_ID = %s", + (groep, gid), commit=True) + print(f"✓ Gebruiker {bestaand['Gebruikersnaam']} bijgewerkt.") + else: + central_query("INSERT INTO Gebruikers (Gebruikersnaam, Veiligheidsgroep, Passwoordhash, Emailadres) " + "VALUES (%s, %s, %s, %s)", + (args.naam, groep or rechten.GEBRUIKER, generate_password_hash(pw) if pw else None, + args.email.lower() if args.email else None), commit=True) + print(f"✓ Gebruiker {args.naam} aangemaakt ({'Administrator' if groep else 'Gebruiker'}).") + + +def cmd_rechten(args): + import tenancy + import rechten + g = rechten.zoek_gebruiker(args.naam) + school = tenancy.school_op_code(args.school, ook_inactief=True) + if not g or not school: + sys.exit("Onbekende gebruiker of school.") + if args.onderdelen: + if args.onderdelen == ['alles']: + codes = rechten.CODES + elif args.onderdelen == ['geen']: + codes = [] + else: + onbekend = [c for c in args.onderdelen if c not in rechten.CODES] + if onbekend: + sys.exit(f"Onbekende onderdelen: {', '.join(onbekend)}\nMogelijk: {', '.join(rechten.CODES)}") + codes = args.onderdelen + rechten.zet_rechten(g['Gebruiker_ID'], school.id, codes, door='beheer.py') + huidig = rechten.rechten_van(g['Gebruiker_ID'], school.id) + print(f"{g['Gebruikersnaam']} in {school.naam}:") + for code, naam, cat in rechten.ONDERDELEN: + print(f" [{'x' if code in huidig else ' '}] {code:<26} {naam}") + + +def main(): + p = argparse.ArgumentParser(description="PIVOT beheer") + sub = p.add_subparsers(dest='cmd', required=True) + sub.add_parser('init') + i = sub.add_parser('importeer-config') + i.add_argument('config') + i.add_argument('--code') + i.add_argument('--db') + i.add_argument('--google-sleutel') + i.add_argument('--overschrijven', action='store_true') + sub.add_parser('lijst') + k = sub.add_parser('kopieer-school', aliases=['kopieer-schema']) + k.add_argument('bron') + k.add_argument('database') + sub.add_parser('nieuwe-sleutel') + n = sub.add_parser('nieuwe-schooldatabase') + n.add_argument('database') + gb = sub.add_parser('gebruiker') + gb.add_argument('naam') + gb.add_argument('--wachtwoord') + gb.add_argument('--email') + gb.add_argument('--admin', action='store_true') + r = sub.add_parser('rechten') + r.add_argument('naam') + r.add_argument('school') + r.add_argument('onderdelen', nargs='*') + args = p.parse_args() + + if args.cmd == 'nieuwe-sleutel': + print(Fernet.generate_key().decode()) + elif args.cmd == 'init': + import tenancy + tenancy.ensure_schema() + print("✓ Centrale tabellen aangemaakt (of bestonden al).") + elif args.cmd == 'importeer-config': + cmd_importeer(args) + elif args.cmd == 'lijst': + cmd_lijst(args) + elif args.cmd in ('kopieer-school', 'kopieer-schema'): + cmd_kopieer(args) + elif args.cmd == 'nieuwe-schooldatabase': + cmd_nieuwe_schooldatabase(args) + elif args.cmd == 'gebruiker': + cmd_gebruiker(args) + elif args.cmd == 'rechten': + cmd_rechten(args) + + +if __name__ == '__main__': + main() diff --git a/blueprints/__init__.py b/blueprints/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/blueprints/admin.py b/blueprints/admin.py new file mode 100644 index 0000000..83fa8a5 --- /dev/null +++ b/blueprints/admin.py @@ -0,0 +1,291 @@ +""" +Gebruikers & rechten. + +- Administrators: alle gebruikers, alle scholen, rol (Administrator/Gebruiker) wijzigen. +- Gebruikers met het recht 'gebruikersbeheer' in een school: gebruikers aanmaken en hun + rechten in DIE school(en) instellen. Ze kunnen geen administrators wijzigen. + +Gebruikers staan in de centrale database (één account voor alle scholen); de rechten per +school in Gebruiker_rechten. +""" +from collections import OrderedDict + +from flask import Blueprint, render_template, request, session, redirect, url_for, flash +from werkzeug.security import generate_password_hash + +import rechten +from rechten import ADMIN, GEBRUIKER, VEILIGHEIDSGROEPEN, ONDERDELEN, is_admin +from database import central_query, central_insert +from tenancy import alle_scholen, school_op_code + +admin_bp = Blueprint('admin', __name__) + +MIN_WACHTWOORD = 8 + + +# ------------------------------------------------------------------ +# Hulpfuncties +# ------------------------------------------------------------------ +def beheerbare_scholen(): + """Scholen waarvan de ingelogde gebruiker de rechten mag instellen.""" + scholen = alle_scholen(ook_inactief=True) + if is_admin(): + return scholen + gid = session.get('gebruiker_id') + if not gid: + return [] + rows = central_query( + "SELECT r.School_ID FROM Gebruiker_rechten r JOIN Onderdelen o ON o.Onderdeel_ID = r.Onderdeel_ID " + "WHERE r.Gebruiker_ID = %s AND o.Code = 'gebruikersbeheer'", (gid,)) + ids = {r['School_ID'] for r in rows} + return [s for s in scholen if s.id in ids] + + +def _toegang(): + """None als de gebruiker hier mag komen, anders een redirect.""" + if not session.get('auth') or not session.get('school'): + return redirect(url_for('auth.login')) + if not is_admin() and not rechten.heeft_recht('gebruikersbeheer'): + flash("Je hebt geen rechten om gebruikers te beheren.", "error") + return redirect(url_for('main.dashboard')) + return None + + +def _aantal_admins(behalve=None): + rows = central_query("SELECT COUNT(*) AS n FROM Gebruikers WHERE Veiligheidsgroep = %s AND Actief = 1 " + "AND Gebruiker_ID <> %s", (ADMIN, behalve or 0)) + return rows[0]['n'] + + +def _onderdelen_per_categorie(): + groepen = OrderedDict() + for code, naam, cat in ONDERDELEN: + groepen.setdefault(cat, []).append((code, naam)) + return groepen + + +def _wachtwoord_ok(pw, pw2): + if pw != pw2: + return "De wachtwoorden komen niet overeen." + if len(pw) < MIN_WACHTWOORD: + return f"Het wachtwoord moet minstens {MIN_WACHTWOORD} tekens hebben." + return None + + +# ------------------------------------------------------------------ +# Overzicht + nieuwe gebruiker +# ------------------------------------------------------------------ +@admin_bp.route("/settings", methods=["GET"]) +def settings(): + weg = _toegang() + if weg: + return weg + users = central_query( + "SELECT g.Gebruiker_ID, g.Gebruikersnaam, g.Emailadres, g.Veiligheidsgroep, g.Actief, g.Last_login, " + " v.Naam AS Rol " + "FROM Gebruikers g JOIN Veiligheidsgroepen v ON v.Veiligheidsgroep = g.Veiligheidsgroep " + "ORDER BY g.Veiligheidsgroep, g.Gebruikersnaam") + if not is_admin(): + users = [u for u in users if int(u['Veiligheidsgroep']) != ADMIN] + + # Aantal rechten per gebruiker per school (voor het overzicht) + per = {} + for r in central_query("SELECT Gebruiker_ID, School_ID, COUNT(*) AS n FROM Gebruiker_rechten " + "GROUP BY Gebruiker_ID, School_ID"): + per.setdefault(r['Gebruiker_ID'], {})[r['School_ID']] = r['n'] + scholen = {s.id: s for s in alle_scholen(ook_inactief=True)} + for u in users: + u['scholen'] = sorted(((scholen[sid].naam, n) for sid, n in per.get(u['Gebruiker_ID'], {}).items() + if sid in scholen), key=lambda x: (-x[1], x[0].lower())) + + return render_template("admin_accounts.html", users=users, groepen=VEILIGHEIDSGROEPEN, + ADMIN=ADMIN, totaal_onderdelen=len(ONDERDELEN)) + + +@admin_bp.route("/gebruiker/nieuw", methods=["POST"]) +def nieuw(): + weg = _toegang() + if weg: + return weg + naam = (request.form.get('username') or '').strip() + email = (request.form.get('email') or '').strip().lower() or None + pw = request.form.get('password') or '' + pw2 = request.form.get('password_confirm') or '' + groep = int(request.form.get('veiligheidsgroep') or GEBRUIKER) + if groep not in VEILIGHEIDSGROEPEN or (groep == ADMIN and not is_admin()): + groep = GEBRUIKER + + fout = None + if not naam: + fout = "Vul een gebruikersnaam in." + elif not pw and not email: + fout = "Geef een wachtwoord, of een e-mailadres om met Google in te loggen." + elif pw: + fout = _wachtwoord_ok(pw, pw2) + if not fout and rechten.zoek_gebruiker(naam): + fout = f"Er bestaat al een gebruiker '{naam}'." + if not fout and email and rechten.zoek_gebruiker(email): + fout = f"Het e-mailadres {email} is al in gebruik." + if fout: + flash(fout, "error") + return redirect(url_for('admin.settings', nieuw=1)) + + nieuw_id = central_insert( + "INSERT INTO Gebruikers (Gebruikersnaam, Veiligheidsgroep, Passwoordhash, Emailadres, Actief) " + "VALUES (%s, %s, %s, %s, 1)", + (naam, groep, generate_password_hash(pw) if pw else None, email)) + rechten.log(actie=f"Gebruiker {naam} aangemaakt") + if groep == ADMIN: + flash(f"Administrator '{naam}' aangemaakt.", "success") + return redirect(url_for('admin.settings')) + flash(f"Gebruiker '{naam}' aangemaakt. Vink nu aan wat hij per school mag.", "success") + return redirect(url_for('admin.gebruiker_rechten', gid=nieuw_id)) + + +# ------------------------------------------------------------------ +# Eén gebruiker: account (gegevens, rol, wachtwoord) +# ------------------------------------------------------------------ +def _gebruiker_of_terug(gid): + """(gebruiker, None) of (None, redirect).""" + u = rechten.gebruiker_op_id(gid) + if not u: + flash("Onbekende gebruiker.", "error") + return None, redirect(url_for('admin.settings')) + if int(u['Veiligheidsgroep']) == ADMIN and not is_admin(): + flash("Enkel een administrator kan een administrator wijzigen.", "error") + return None, redirect(url_for('admin.settings')) + return u, None + + +@admin_bp.route("/gebruiker/", methods=["GET", "POST"]) +def gebruiker(gid): + weg = _toegang() + if weg: + return weg + u, weg = _gebruiker_of_terug(gid) + if weg: + return weg + zelf = gid == session.get('gebruiker_id') + if request.method == 'POST': + return _bewaar_account(u, zelf) + return render_template("admin_gebruiker.html", u=u, groepen=VEILIGHEIDSGROEPEN, ADMIN=ADMIN, zelf=zelf, + min_wachtwoord=MIN_WACHTWOORD) + + +# ------------------------------------------------------------------ +# Eén gebruiker: rechten, één school tegelijk +# ------------------------------------------------------------------ +@admin_bp.route("/gebruiker//rechten", methods=["GET", "POST"]) +def gebruiker_rechten(gid): + weg = _toegang() + if weg: + return weg + u, weg = _gebruiker_of_terug(gid) + if weg: + return weg + scholen = beheerbare_scholen() + per_id = {s.id: s for s in scholen} + aantallen = {} + for r in central_query("SELECT School_ID, COUNT(*) AS n FROM Gebruiker_rechten WHERE Gebruiker_ID = %s " + "GROUP BY School_ID", (gid,)): + aantallen[r['School_ID']] = r['n'] + + if request.method == 'POST': + sid = request.form.get('school_id', type=int) + if sid not in per_id: + flash("Je mag de rechten in deze school niet instellen.", "error") + return redirect(url_for('admin.gebruiker_rechten', gid=gid)) + codes = [c for c in rechten.CODES if request.form.get(f"r|{c}")] + doel = [sid] + if request.form.get('ook_alle'): + doel = list(per_id) + else: + doel += [int(x) for x in request.form.getlist('ook') if x.isdigit() and int(x) in per_id] + doel = list(dict.fromkeys(doel)) + door = session.get('user') + for school_id in doel: + rechten.zet_rechten(gid, school_id, codes, door=door) + if len(doel) == 1: + rechten.log(actie=f"Rechten van {u['Gebruikersnaam']} in {per_id[sid].naam} gewijzigd") + flash(f"Rechten van {u['Gebruikersnaam']} in {per_id[sid].naam} opgeslagen.", "success") + else: + rechten.log(actie=f"Rechten van {u['Gebruikersnaam']} in {len(doel)} scholen gewijzigd") + flash(f"Rechten van {u['Gebruikersnaam']} opgeslagen in {len(doel)} scholen.", "success") + return redirect(url_for('admin.gebruiker_rechten', gid=gid, school=sid)) + + # Welke school tonen: gevraagd > huidige school > eerste school met rechten > eerste school + gekozen = request.args.get('school', type=int) + if gekozen not in per_id: + huidig = school_op_code(session.get('school') or '') + huidig_id = huidig.id if huidig else None + if huidig_id in per_id and (aantallen.get(huidig_id) or not aantallen): + gekozen = huidig_id + else: + met = [s.id for s in scholen if aantallen.get(s.id)] + gekozen = met[0] if met else (scholen[0].id if scholen else None) + + lijst = sorted(scholen, key=lambda s: (not aantallen.get(s.id), s.naam.lower())) + return render_template("admin_rechten.html", u=u, scholen=lijst, gekozen=per_id.get(gekozen), + aantallen=aantallen, huidig=rechten.rechten_van(gid, gekozen) if gekozen else set(), + categorieen=_onderdelen_per_categorie(), ADMIN=ADMIN, totaal=len(ONDERDELEN)) + + +def _bewaar_account(u, zelf): + gid = u['Gebruiker_ID'] + email = (request.form.get('email') or '').strip().lower() or None + pw = request.form.get('new_password') or '' + pw2 = request.form.get('new_password_confirm') or '' + actief = 1 if request.form.get('actief') else 0 + groep = int(u['Veiligheidsgroep']) + if is_admin() and request.form.get('veiligheidsgroep'): + groep = int(request.form['veiligheidsgroep']) + if groep not in VEILIGHEIDSGROEPEN: + groep = int(u['Veiligheidsgroep']) + + terug = redirect(url_for('admin.gebruiker', gid=gid)) + if zelf and (not actief or groep != int(u['Veiligheidsgroep'])): + flash("Je kan je eigen rol niet wijzigen en jezelf niet uitschakelen.", "error") + return terug + if int(u['Veiligheidsgroep']) == ADMIN and (groep != ADMIN or not actief) and _aantal_admins(behalve=gid) == 0: + flash("Er moet minstens één actieve administrator overblijven.", "error") + return terug + if email: + ander = rechten.zoek_gebruiker(email) + if ander and ander['Gebruiker_ID'] != gid: + flash(f"Het e-mailadres {email} is al in gebruik.", "error") + return terug + if pw: + fout = _wachtwoord_ok(pw, pw2) + if fout: + flash(fout, "error") + return terug + central_query("UPDATE Gebruikers SET Passwoordhash = %s WHERE Gebruiker_ID = %s", + (generate_password_hash(pw), gid), commit=True) + + central_query("UPDATE Gebruikers SET Emailadres = %s, Veiligheidsgroep = %s, Actief = %s WHERE Gebruiker_ID = %s", + (email, groep, actief, gid), commit=True) + rechten.log(actie=f"Account {u['Gebruikersnaam']} gewijzigd") + flash(f"Account van {u['Gebruikersnaam']} opgeslagen.", "success") + return terug + + +@admin_bp.route("/gebruiker//verwijderen", methods=["POST"]) +def verwijderen(gid): + weg = _toegang() + if weg: + return weg + u = rechten.gebruiker_op_id(gid) + if not u: + return redirect(url_for('admin.settings')) + if not is_admin(): + flash("Enkel een administrator kan gebruikers verwijderen.", "error") + elif gid == session.get('gebruiker_id'): + flash("Je kan jezelf niet verwijderen.", "error") + elif int(u['Veiligheidsgroep']) == ADMIN and _aantal_admins(behalve=gid) == 0: + flash("Er moet minstens één actieve administrator overblijven.", "error") + else: + central_query("DELETE FROM Gebruikers WHERE Gebruiker_ID = %s", (gid,), commit=True) + rechten.log(actie=f"Gebruiker {u['Gebruikersnaam']} verwijderd") + flash(f"Gebruiker '{u['Gebruikersnaam']}' is verwijderd.", "success") + return redirect(url_for('admin.settings')) + return redirect(url_for('admin.gebruiker', gid=gid)) diff --git a/blueprints/afwezigheden_bp.py b/blueprints/afwezigheden_bp.py new file mode 100644 index 0000000..d4225e5 --- /dev/null +++ b/blueprints/afwezigheden_bp.py @@ -0,0 +1,157 @@ +import csv +import io +from datetime import date, datetime +from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify, Response +from tenancy import huidige_school, per_school +from blueprints.auth import login_required +from rechten import recht_vereist +from services.afwezigheden_service import AfwezighedenService, schooljaar_start + +afwezigheden_bp = Blueprint('afwezigheden', __name__) +service = per_school(AfwezighedenService) + +_tables_ready = set() # scholen waarvoor de tabellen al gecontroleerd zijn + + +def _ensure_tables(): + if huidige_school().code not in _tables_ready: + try: + service.ensure_tables() + _tables_ready.add(huidige_school().code) + except Exception as e: + flash(f"Kon de afwezigheidstabellen niet aanmaken: {e}", "error") + + +def _filters(): + """Leest de filters uit de URL, met het huidige schooljaar als standaard.""" + def parse(v, standaard): + try: + return datetime.strptime(v, '%Y-%m-%d').date() if v else standaard + except ValueError: + return standaard + van = parse(request.args.get('van'), schooljaar_start()) + tot = parse(request.args.get('tot'), date.today()) + if van > tot: + van, tot = tot, van + code = (request.args.get('code') or '').upper() or None + if code and code not in service.codes: + code = None + try: + minimum = max(1, int(request.args.get('min') or 1)) + except ValueError: + minimum = 1 + return dict(van=van, tot=tot, code=code, zoek=(request.args.get('zoek') or '').strip(), minimum=minimum) + + +#--------------------------------------------- +# Overzicht +#--------------------------------------------- +@afwezigheden_bp.route('/', methods=['GET']) +@login_required +@recht_vereist('afwezigheden') +def overzicht(): + _ensure_tables() + f = _filters() + rows, fout, laatste = [], None, {'m': None, 'd': None} + try: + rows = service.overzicht(f['van'], f['tot'], f['code'], f['zoek'], f['minimum']) + laatste = service.laatste_sync() + except Exception as e: + fout = f"Gegevens konden niet gelezen worden: {e}" + + totaal_halve_dagen = sum(r['Halve_dagen'] for r in rows) + return render_template('afwezigheden.html', rows=rows, f=f, fout=fout, laatste=laatste, + codes=service.codes, status=service.status, + totaal_halve_dagen=totaal_halve_dagen) + + +#--------------------------------------------- +# Detail per leerling (JSON, voor het uitklappen in de tabel) +#--------------------------------------------- +@afwezigheden_bp.route('/leerling/.json', methods=['GET']) +@login_required +@recht_vereist('afwezigheden') +def leerling(internnummer): + f = _filters() + dagen = service.detail(internnummer, f['van'], f['tot'], f['code']) + return jsonify([{'datum': d['Datum'].strftime('%d-%m-%Y'), + 'weekdag': ['ma', 'di', 'wo', 'do', 'vr', 'za', 'zo'][d['Datum'].weekday()], + 'vm': d['VM'], 'nm': d['NM']} for d in dagen]) + + +#--------------------------------------------- +# Synchronisatie +#--------------------------------------------- +@afwezigheden_bp.route('/sync', methods=['POST']) +@login_required +@recht_vereist('afwezigheden', 'laatkomers') +def sync(): + if not huidige_school().heeft('SS_API_PLATFORM', 'SS_API_PW'): + flash("Smartschool is nog niet ingesteld voor deze school: vul het platform (bv. school.smartschool.be) " + "en het webservice-wachtwoord in via 🔌 Koppelingen van deze school.", "error") + return redirect(url_for('afwezigheden.laatkomers' if request.form.get('terug') == 'laatkomers' + else 'afwezigheden.overzicht')) + _ensure_tables() + volledig = request.form.get('volledig') == '1' + if service.sync_in_background(volledig=volledig): + flash("Synchronisatie met Smartschool gestart. Dit kan enkele minuten duren.", "info") + else: + flash("Er loopt al een synchronisatie.", "warning") + if request.form.get('terug') == 'laatkomers': + return redirect(url_for('afwezigheden.laatkomers', **{k: v for k, v in request.args.items()})) + return redirect(url_for('afwezigheden.overzicht', **{k: v for k, v in request.args.items()})) + + +@afwezigheden_bp.route('/status.json', methods=['GET']) +@login_required +@recht_vereist('afwezigheden', 'laatkomers') +def status(): + s = service.status + return jsonify(bezig=s['bezig'], voortgang=s['voortgang'], totaal=s['totaal'], + resultaat=s['laatste_resultaat'], fout=s['laatste_fout']) + + +#--------------------------------------------- +# Export +#--------------------------------------------- +@afwezigheden_bp.route('/export.csv', methods=['GET']) +@login_required +@recht_vereist('afwezigheden') +def export_csv(): + f = _filters() + rows = service.overzicht(f['van'], f['tot'], f['code'], f['zoek'], f['minimum']) + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') + w.writerow(['Internnummer', 'Voornaam', 'Naam', 'Gebruikersnaam', 'Halve dagen', 'Dagen', + 'Eerste', 'Laatste', 'Datums']) + for r in rows: + dagen = service.detail(r['Internnummer'], f['van'], f['tot'], f['code']) + datums = ', '.join(d['Datum'].strftime('%d/%m') + ('' if d['VM'] and d['NM'] else (' VM' if d['VM'] else ' NM')) + for d in sorted(dagen, key=lambda x: x['Datum'])) + w.writerow([r['Internnummer'], r['Voornaam'] or '', r['Naam'] or '', r['Gebruikersnaam'] or '', + r['Halve_dagen'], r['Dagen'], r['Eerste'].strftime('%d-%m-%Y'), + r['Laatste'].strftime('%d-%m-%Y'), datums]) + naam = f"afwezigheden_{f['code'] or '-'.join(service.codes)}_{f['van']:%Y%m%d}-{f['tot']:%Y%m%d}.csv" + return Response('' + buf.getvalue(), mimetype='text/csv', + headers={'Content-Disposition': f'attachment; filename={naam}'}) + + +#--------------------------------------------- +# Laatkomers +#--------------------------------------------- +@afwezigheden_bp.route('/laatkomers', methods=['GET']) +@login_required +@recht_vereist('laatkomers') +def laatkomers(): + """Alle leerlingen die dit schooljaar (of in de gekozen periode) te laat waren.""" + _ensure_tables() + f = _filters() + rows, fout, laatste = [], None, {'m': None, 'd': None} + try: + rows = service.laatkomers(f['van'], f['tot']) + laatste = service.laatste_sync() + except Exception as e: + fout = f"Gegevens konden niet gelezen worden: {e}" + return render_template('laatkomers.html', rows=rows, f=f, fout=fout, laatste=laatste, + codes=service.laat_codes, status=service.status, + totaal=sum(r['Aantal'] for r in rows)) diff --git a/blueprints/auth.py b/blueprints/auth.py new file mode 100644 index 0000000..bb48532 --- /dev/null +++ b/blueprints/auth.py @@ -0,0 +1,326 @@ +from flask import Blueprint, render_template, request, session, redirect, url_for, flash, current_app, make_response +from werkzeug.security import check_password_hash +import time +import functools +from authlib.integrations.flask_client import OAuth +from config import Config +from tenancy import (alle_scholen, school_op_code, school_voor_email, scholen_voor_email, school_voor_host, in_school, + huidige_school) +import rechten +from rechten import recht_vereist, ADMIN, GEBRUIKER + +auth_bp = Blueprint('auth', __name__) +oauth = OAuth() + +SCHOOL_COOKIE = 'pivot_school' # onthoudt de laatst gekozen school op dit toestel +GOOGLE_METADATA = 'https://accounts.google.com/.well-known/openid-configuration' + + +def _google_client(school=None): + """ + Google-login client: die van de school als die een eigen OAuth-client heeft, + anders de gedeelde client uit config.ini. Geeft (naam, client) of (None, None). + """ + if school and school.heeft('GOOGLE_SSO_CLIENTID', 'GOOGLE_SSO_CLIENTSECRET'): + naam = f"google_{school.code}_{''.join(c for c in school.versie if c.isdigit())}" + cid, secret = school.get('GOOGLE_SSO_CLIENTID'), school.get('GOOGLE_SSO_CLIENTSECRET') + elif Config.SSO_CLIENT_ID and Config.SSO_CLIENT_SECRET: + naam, cid, secret = 'google', Config.SSO_CLIENT_ID, Config.SSO_CLIENT_SECRET + else: + return None, None + client = oauth.create_client(naam) + if client is None: + client = oauth.register(name=naam, client_id=cid, client_secret=secret, + server_metadata_url=GOOGLE_METADATA, + client_kwargs={'scope': 'openid email profile'}) + return naam, client + + +def gekozen_school(): + """School die vastligt via de hostnaam, of anders de laatst gekozen school (cookie).""" + return school_voor_host(request.host) or school_op_code(request.cookies.get(SCHOOL_COOKIE)) + + +def _nummer(school): + """Sorteersleutel: laagste officiële instellingsnummer eerst; scholen zonder nummer achteraan.""" + nr = ''.join(c for c in str(school.get('INSTELLINGSNUMMER') or '') if c.isdigit()) + return (0, int(nr), school.naam.lower()) if nr else (1, 0, school.naam.lower()) + + +def standaard_school(scholen=None): + """De school met het laagste instellingsnummer (voor wie nog nooit aangemeld was).""" + scholen = alle_scholen() if scholen is None else list(scholen) + return min(scholen, key=_nummer) if scholen else None + + +def kies_school(gebruiker=None, toegang=None, ook=()): + """ + De school die na het aanmelden geladen wordt (het aanmeldscherm vraagt geen school meer): + 1) de laatst actieve school van de gebruiker, + 2) voor een nieuwe gebruiker: de school van zijn e-maildomein (+ eventueel de scholen in `ook`), + 3) de laatst gekozen school op dit toestel (cookie), 4) als laatste redmiddel: het laagste instellingsnummer. + Telkens enkel scholen waarvoor toegang(school) True is (als `toegang` gegeven is). + """ + ok = toegang or (lambda s: True) + domein = _volgens_domein((gebruiker or {}).get('Emailadres')) + for s in [school_op_code((gebruiker or {}).get('Laatste_school')), *domein, *ook, + school_op_code(request.cookies.get(SCHOOL_COOKIE))]: + if s and ok(s): + return s + return standaard_school(s for s in alle_scholen() if ok(s)) + + +def _volgens_domein(email): + """Scholen met het e-maildomein (een domein kan door meerdere scholen gedeeld worden): de laatst gekozen + school op dit toestel eerst, dan op instellingsnummer.""" + lijst = sorted(scholen_voor_email(email), key=_nummer) + cookie = request.cookies.get(SCHOOL_COOKIE) + return sorted(lijst, key=lambda s: s.code != cookie) + + +def is_superbeheerder(email): + return (email or '').lower() in Config.SUPERBEHEERDERS + + +def _login_ok(school, user, naam, groep, superbeheerder=False, gebruiker=None): + """ + Zet de sessie. `gebruiker` is de rij uit de centrale tabel Gebruikers (of None voor een + superbeheerder uit config.ini of een leerkracht zonder PIVOT-account). + Administrators (Veiligheidsgroep 1) zijn superbeheerder: alle rechten in alle scholen. + """ + admin = bool(gebruiker and int(gebruiker['Veiligheidsgroep']) == ADMIN) + session.clear() + session["auth"] = True + session["user"] = user + session["naam"] = naam + session["gebruiker_id"] = gebruiker['Gebruiker_ID'] if gebruiker else None + session["admin"] = admin or bool(superbeheerder) + session["superbeheerder"] = admin or bool(superbeheerder) + if groep is None and gebruiker: + groep = ADMIN if session["admin"] else GEBRUIKER + session["security_group"] = int(groep) if groep is not None else None + session["school"] = school.code if school else None + if gebruiker: + rechten.registreer_login(gebruiker['Gebruiker_ID'], request.remote_addr) + if school: + rechten.bewaar_laatste_school(gebruiker['Gebruiker_ID'], school.code) + + +def _onthoud_school(response, school): + if school: + response.set_cookie(SCHOOL_COOKIE, school.code, max_age=365 * 24 * 3600, samesite='Lax', + secure=request.is_secure, httponly=True) + return response + + +#---------------------------------------------- +# BRUTE FORCE BEVEILIGING +#---------------------------------------------- +attempts = {} + +def client_ip(): + return request.remote_addr + +def is_locked(): + ip = client_ip() + if ip in attempts and attempts[ip]['count'] >= 5: + elapsed = time.time() - attempts[ip]['last_time'] + if elapsed < 60: + return True, int(60 - elapsed) + else: + attempts.pop(ip) + return False, 0 + +def record_failure(): + ip = client_ip() + if ip not in attempts: + attempts[ip] = {'count': 1, 'last_time': time.time()} + else: + attempts[ip]['count'] += 1 + attempts[ip]['last_time'] = time.time() + +#---------------------------------------------- +# --- GOOGLE SSO ROUTES --- +#---------------------------------------------- + +@auth_bp.route('/google-login') +def google_login(): + """Start het Google inlogproces. De school volgt uit de hostnaam, ?school=code of het e-maildomein.""" + vast = school_voor_host(request.host) or school_op_code(request.args.get('school')) + # Zonder vaste school: de Google-client van de laatst gekozen school op dit toestel (of de standaardschool). + # Welke school na het aanmelden geladen wordt, beslist de callback. + school = vast or school_op_code(request.cookies.get(SCHOOL_COOKIE)) or standaard_school() + naam, client = _google_client(school) + if not client: + flash("Inloggen met Google is (nog) niet ingesteld.", "error") + return redirect(url_for('auth.login')) + session['sso'] = {'client': naam, 'school': vast.code if vast else ''} + extra = {'prompt': 'select_account'} + if vast and len(vast.domeinen) == 1: + extra['hd'] = school.domein # Google toont enkel accounts van dit domein + redirect_uri = url_for('auth.callback', _external=True) + return client.authorize_redirect(redirect_uri, **extra) + + +@auth_bp.route('/callback') +def callback(): + """Verwerkt het antwoord van Google en bepaalt de school op basis van het e-maildomein.""" + sso = session.pop('sso', None) or {} + try: + client = oauth.create_client(sso.get('client') or 'google') + token = client.authorize_access_token() + user_info = token.get('userinfo') or {} + except Exception as e: + flash("Fout bij ophalen van Google gegevens.", "error") + return redirect(url_for('auth.login')) + + email = (user_info.get('email') or '').lower() + if not email or user_info.get('email_verified') is False: + flash("Google gaf geen geverifieerd e-mailadres terug.", "error") + return redirect(url_for('auth.login')) + naam = user_info.get('name') or email + super_ = is_superbeheerder(email) + + # Geregistreerde PIVOT-gebruiker (centrale tabel Gebruikers)? + try: + gebruiker = rechten.zoek_gebruiker(email) + except Exception: + flash("De centrale PIVOT-database is niet bereikbaar.", "error") + return redirect(url_for('auth.login')) + if gebruiker and not gebruiker['Actief']: + gebruiker = None + + def heeft_toegang(s): + return bool(gebruiker) and (super_ or rechten.mag_in_school(gebruiker, s)) + + gekozen = school_op_code(sso.get('school')) # enkel als de school vastligt (hostnaam) + domeinscholen = _volgens_domein(email) # meerdere scholen kunnen hetzelfde domein hebben + volgens_domein = next((s for s in domeinscholen if heeft_toegang(s)), None) or \ + (domeinscholen[0] if domeinscholen else None) + if gekozen: + school = gekozen + elif gebruiker and heeft_toegang_ergens(gebruiker, super_): + # Laatst actieve school → school van het e-maildomein → laatst gekozen op dit toestel → laagste nummer + school = kies_school(gebruiker, heeft_toegang, ook=domeinscholen) + elif super_: + school = kies_school(None, None, ook=domeinscholen) + else: + school = volgens_domein + + if gekozen and gekozen not in domeinscholen and not super_ and not heeft_toegang(gekozen): + flash(f"{email} hoort niet bij {gekozen.naam}.", "error") + return redirect(url_for('auth.login')) + + if school is None: + if super_ or (gebruiker and int(gebruiker['Veiligheidsgroep']) == ADMIN): + # Superbeheerder van wie het domein bij geen school hoort: meteen naar scholenbeheer + _login_ok(None, email, naam, None, superbeheerder=True, gebruiker=gebruiker) + flash("Ingelogd als superbeheerder. Kies of maak een school.", "success") + return redirect(url_for('scholen.overzicht')) + flash(f"Het domein van {email} hoort bij geen enkele school in PIVOT.", "error") + return redirect(url_for('auth.login')) + + # 1) PIVOT-gebruiker met rechten in deze school + if heeft_toegang(school): + _login_ok(school, gebruiker['Gebruikersnaam'], naam, None, super_, gebruiker=gebruiker) + flash(f"Succesvol ingelogd via Google: {gebruiker['Gebruikersnaam']}", "success") + return _onthoud_school(redirect(url_for("main.dashboard")), school) + + # 2) Superbeheerder van de scholengroep (config.ini) → beheerder in elke school + if super_: + _login_ok(school, email, naam, ADMIN, True) + return _onthoud_school(redirect(url_for("main.dashboard")), school) + + # 3) Personeelslid van de school (personeels-OU's) → beperkte toegang tot de personeelsmodule. + # Delen meerdere scholen het domein, dan de eerste school waar hij personeelslid is. + from services.personeel_service import is_personeelslid, LEERKRACHT_GROEP + for kandidaat in [school] + [s for s in domeinscholen if s is not school and not gekozen]: + with in_school(kandidaat): + if is_personeelslid(email): + _login_ok(kandidaat, email, naam, LEERKRACHT_GROEP) + return _onthoud_school(redirect(url_for("personeel.mijn")), kandidaat) + + flash(f"Toegang geweigerd: {email} is niet geregistreerd in PIVOT van {school.naam}.", "error") + return redirect(url_for('auth.login')) + +def heeft_toegang_ergens(gebruiker, super_=False): + return bool(gebruiker) and (super_ or any(rechten.mag_in_school(gebruiker, s) for s in alle_scholen())) + + +#---------------------------------------------- +# --- HANDMATIGE LOGIN/LOGOUT --- +#---------------------------------------------- + +def _login_pagina(school=None): + vast = school_voor_host(request.host) + return render_template("pin.html", + scholen=alle_scholen(), + gekozen=vast or school or gekozen_school(), + school_vast=bool(vast), + google_aan=bool(Config.SSO_CLIENT_ID) or any( + s.heeft('GOOGLE_SSO_CLIENTID') for s in alle_scholen())) + + +@auth_bp.route("/login", methods=["GET", "POST"]) +def login(): + locked, wait_time = is_locked() + if locked: + flash(f"Te veel pogingen. Probeer opnieuw over {wait_time} seconden.", "error") + return _login_pagina() + + if request.method == "POST": + entered_username = request.form.get("username", "").strip() + entered_password = request.form.get("password", "") + school = school_voor_host(request.host) # ligt de school vast via de hostnaam? + + if not entered_username or not entered_password: + record_failure() + flash("Vul zowel gebruikersnaam als wachtwoord in.", "error") + return _login_pagina(school) + + try: + gebruiker = rechten.zoek_gebruiker(entered_username) + except Exception: + flash("De centrale PIVOT-database is niet bereikbaar.", "error") + return _login_pagina(school) + + if (gebruiker and gebruiker['Actief'] and gebruiker['Passwoordhash'] + and check_password_hash(gebruiker['Passwoordhash'], entered_password)): + attempts.pop(client_ip(), None) + if school and not rechten.mag_in_school(gebruiker, school): + flash(f"Je hebt geen rechten in {school.naam}. Vraag een administrator om toegang.", "error") + return _login_pagina(school) + # Geen school gevraagd: laatst actieve school, anders de school van het e-maildomein + school = school or kies_school(gebruiker, lambda s: rechten.mag_in_school(gebruiker, s)) + if not school: + flash("Je hebt nog geen rechten in een school. Vraag een administrator om toegang.", "error") + return _login_pagina() + _login_ok(school, gebruiker['Gebruikersnaam'], gebruiker['Gebruikersnaam'], None, gebruiker=gebruiker) + flash(f"Welkom terug, {gebruiker['Gebruikersnaam']}!", "success") + return _onthoud_school(redirect(url_for("main.dashboard")), school) + + record_failure() + flash("Ongeldige inloggegevens.", "error") + return _login_pagina(school) + + return _login_pagina() + +@auth_bp.route('/logout') +def logout(): + session.clear() + flash("Je bent nu uitgelogd.", "success") + return redirect(url_for('auth.login')) + +#---------------------------------------------- +# --- DECORATORS --- +#---------------------------------------------- + +def login_required(view_func): + @functools.wraps(view_func) + def wrapped_view(*args, **kwargs): + if not session.get("auth") or not session.get("school"): + return redirect(url_for("auth.login")) + return view_func(*args, **kwargs) + return wrapped_view + +# Rechten per school: zie rechten.py (recht_vereist, heeft_recht, admin_vereist) diff --git a/blueprints/basisonderwijs_bp.py b/blueprints/basisonderwijs_bp.py new file mode 100644 index 0000000..b0ef269 --- /dev/null +++ b/blueprints/basisonderwijs_bp.py @@ -0,0 +1,67 @@ +"""Basisonderwijs › Bingel: leerlingenlijst uit Informat als Excel voor de import in Bingel.""" +import io +from datetime import date + +from flask import Blueprint, render_template, request, Response, redirect, url_for, flash + +from blueprints.auth import login_required +from rechten import recht_vereist +from services import bingel_service as bs +from tenancy import huidige_school + +basisonderwijs_bp = Blueprint('basisonderwijs', __name__) +KOLOMMEN = ['Klas', 'Voornaam', 'Familienaam', 'Wachtwoord', 'Klasnummer', 'Geslacht'] + + +@basisonderwijs_bp.route('/bingel', methods=['GET']) +@login_required +@recht_vereist('bingel') +def bingel(): + rijen, voorbeeld, fout, waarschuwing = [], {}, None, None + try: + rijen, voorbeeld, waarschuwing = bs.leerlingen(vernieuw=bool(request.args.get('vernieuw'))) + except bs.BingelFout as e: + fout = str(e) + except Exception as e: + fout = f"Leerlingen ophalen uit Informat mislukt: {e}" + if request.args.get('vernieuw'): + return redirect(url_for('basisonderwijs.bingel')) + klassen = sorted({r['klas'] for r in rijen}, key=str.lower) + return render_template('bingel.html', rijen=rijen, klassen=klassen, voorbeeld=voorbeeld, fout=fout, waarschuwing=waarschuwing, + kolommen=KOLOMMEN, school_naam=huidige_school().naam, + zonder_klas=sum(1 for r in rijen if not r['klas']), + zonder_geslacht=sum(1 for r in rijen if r['geslacht'] not in ('M', 'V'))) + + +@basisonderwijs_bp.route('/bingel/export.xlsx', methods=['GET']) +@login_required +@recht_vereist('bingel') +def bingel_export(): + from openpyxl import Workbook + from openpyxl.styles import Font + try: + rijen, _, _ = bs.leerlingen() + except Exception as e: + flash(str(e), "error") + return redirect(url_for('basisonderwijs.bingel')) + gekozen = request.args.getlist('klas') # aangevinkte klassen (niets = alle) + if gekozen: + rijen = [r for r in rijen if r['klas'] in gekozen] + klas = gekozen[0] if len(gekozen) == 1 else '' + wb = Workbook() + ws = wb.active + ws.title = 'Leerlingen' + ws.append(KOLOMMEN) + for c in ws[1]: + c.font = Font(bold=True) + for r in rijen: + ws.append([r['klas'], r['voornaam'], r['naam'], '', r['klasnummer'], r['geslacht']]) + for kol, breedte in zip('ABCDEF', (12, 18, 22, 14, 11, 10)): + ws.column_dimensions[kol].width = breedte + ws.freeze_panes = 'A2' + buf = io.BytesIO() + wb.save(buf) + deel = ''.join(c if c.isalnum() else '_' for c in klas) + '_' if klas else '' + return Response(buf.getvalue(), mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + headers={'Content-Disposition': f"attachment; filename=Bingel_{huidige_school().code}_{deel}" + f"{date.today():%Y%m%d}.xlsx"}) diff --git a/blueprints/bugreport_bp.py b/blueprints/bugreport_bp.py new file mode 100644 index 0000000..2069b76 --- /dev/null +++ b/blueprints/bugreport_bp.py @@ -0,0 +1,74 @@ +from datetime import datetime +from flask import Blueprint, render_template, request, redirect, url_for, flash, session +from database import central_query +from blueprints.auth import login_required +from rechten import recht_vereist + +bugreport_bp = Blueprint('bugreport', __name__) + +@bugreport_bp.route('/', methods=['GET']) +@login_required +def bugreport(): + """Toont het bugreport formulier.""" + + if 'security_group' not in session: + flash('Je moet eerst inloggen om een bug te rapporteren.', 'error') + return redirect(url_for('auth.login')) + + return render_template('bugreport.html') + + +@bugreport_bp.route('/submit', methods=['POST']) +@login_required +def bugreport_submit(): + """Verwerkt het ingezonden bugreport en slaat het op in de database.""" + + + # Gegevens ophalen uit het HTML formulier + tijdstip_str = request.form.get('tijdstip') + omschrijving = request.form.get('omschrijving') + foutcode = request.form.get('foutcode') # Kan leeg zijn (None of lege string) + + # Automatische gegevens + gebruiker_id = session["user"] # Of session.get('email'), afhankelijk van je login-systeem + status = 'Nieuw' + + # Validatie (html5 required is een back-up, server-side validatie is veiliger) + if not tijdstip_str or not omschrijving: + flash('Tijdstip en omschrijving zijn verplichte velden!', 'error') + return redirect(url_for('bugreport.bugreport_page')) + + try: + # Converteren van datetime-local string (YYYY-MM-DDTHH:MM) naar MySQL formaat + tijdstip = datetime.strptime(tijdstip_str, '%Y-%m-%dT%H:%M') + except ValueError: + flash('Ongeldig datum- of tijdformaat ontvangen.', 'error') + return redirect(url_for('bugreport.bugreport_page')) + + # SQL query om de bug op te slaan + # Pas de tabelnaam ('bugs') en kolomnamen aan naar jouw exacte database-schema + # Centrale database: Bugs (Bugstatus_ID 1 = Nieuw) + from tenancy import huidige_school + school = huidige_school(verplicht=False) + query = """ + INSERT INTO Bugs (Timestamp, Omschrijving, Foutcode, Bugstatus_ID, Gebruiker_ID, Gebruikersnaam, School_ID) + VALUES (%s, %s, %s, 1, %s, %s, %s) + """ + params = (tijdstip, omschrijving, foutcode or None, session.get('gebruiker_id'), gebruiker_id, + school.id if school else None) + + try: + # Voer de query uit met commit=True om de data op te slaan + central_query(query, params, commit=True) + + # Succesmelding sturen en doorverwijzen naar het dashboard + flash('Je bugreport is succesvol ingediend! Bedankt voor je feedback.', 'success') + return redirect(url_for('main.dashboard')) + + except Exception as e: + # Log de fout eventueel in de console voor debugging + print(f"Database error tijdens bugreport: {e}") + + # Foutmelding tonen aan de gebruiker + flash('Er ging iets mis bij het opslaan in de database. Probeer het later opnieuw.', 'error') + return redirect(url_for('bugreport.bugreport_page')) \ No newline at end of file diff --git a/blueprints/bugreport_overzicht_bp.py b/blueprints/bugreport_overzicht_bp.py new file mode 100644 index 0000000..2dc1539 --- /dev/null +++ b/blueprints/bugreport_overzicht_bp.py @@ -0,0 +1,62 @@ +from flask import Blueprint, render_template, request, session, redirect, url_for, flash, jsonify +from database import central_query +from blueprints.auth import login_required +from rechten import recht_vereist + + + +# We noemen de blueprint 'devices' +bugreport_overzicht_bp = Blueprint('bugreport_overzicht', __name__) + +#------------------------------------------------- +# --- ROUTE TOESTELLEN (Inventaris Toestellen) --- +#------------------------------------------------- +@bugreport_overzicht_bp.route("/", methods=["GET", "POST"]) +@login_required +@recht_vereist('bugs_bekijken', 'bugs_beheren') +def bugreport_overzicht(): + query = request.form.get("query", "") if request.method == "POST" else request.args.get("query", "") + message = None + + search_term = f"%{query}%" + # Bugs staan in de centrale database (gelden voor PIVOT, niet voor één school) + sql = """ + SELECT * FROM ( + SELECT b.Bug_ID, b.Gebruikersnaam AS Gebruiker, b.Timestamp AS Datum, b.Omschrijving, b.Foutcode, + st.Omschrijving AS Status, sc.School_naam AS School + FROM Bugs b + JOIN Status st ON st.Bugstatus_ID = b.Bugstatus_ID + LEFT JOIN Scholen sc ON sc.School_ID = b.School_ID + ) x + WHERE CONCAT_WS(' ', Bug_ID, Gebruiker, Datum, Omschrijving, Foutcode, Status, School) LIKE %s + ORDER BY Bug_ID DESC + """ + + results = central_query(sql, (search_term,)) + + + if query and not results: + message = f"Geen resultaten gevonden voor '{query}'." + elif not results: + message = "Er zijn momenteel geen bugreports." + + return render_template("bugreport_overzicht.html", results=results, query=query, message=message) + +#--------------------------------- +# --- STATUS UPDATES --- +#--------------------------------- +@bugreport_overzicht_bp.route("/update_bugreport", methods=["POST"]) +@login_required +@recht_vereist('bugs_beheren') +def bugreport_wijzig_status(): + Bug_ID = request.form.get("Bug_ID") + new_status = request.form.get("new_status") + query = request.form.get("query", "") + + if new_status in ["Nieuw", "In behandeling", "Fixed"]: + central_query("UPDATE Bugs SET Bugstatus_ID = (SELECT Bugstatus_ID FROM Status WHERE Omschrijving = %s) " + "WHERE Bug_ID = %s", (new_status, Bug_ID), commit=True) + flash(f"Status van {Bug_ID} gewijzigd naar {new_status}", "success") + + return redirect(url_for("bugreport_overzicht.bugreport_overzicht", query=query)) + diff --git a/blueprints/co2_sensor.py b/blueprints/co2_sensor.py new file mode 100644 index 0000000..fee17b6 --- /dev/null +++ b/blueprints/co2_sensor.py @@ -0,0 +1,125 @@ +from flask import Blueprint, render_template, redirect, url_for, flash, jsonify, request +from services.co2_service import CO2Scanner +from database import execute_query +from blueprints.auth import login_required +from rechten import recht_vereist +from tenancy import per_school + +co2_sensor_bp = Blueprint('co2_sensor', __name__) +scanner = per_school(CO2Scanner) # één scanner per school + +#---------------------------------------------- +# Route voor het CO2 dashboard +#---------------------------------------------- + +@co2_sensor_bp.route('/dashboard') +@login_required +@recht_vereist('co2') +def dashboard(): + # haalt de meest recente record voor elke ruimte + query = """ + SELECT lk.Naam AS lokaal, m.ppm, m.Timestamp AS timestamp + FROM CO2_Metingen m + JOIN Lokalen lk ON lk.Lokaal_ID = m.Lokaal_ID + WHERE m.Meting_ID IN (SELECT MAX(Meting_ID) FROM CO2_Metingen GROUP BY Lokaal_ID) + ORDER BY lk.Naam ASC + """ + sensors = execute_query(query) + return render_template('CO2_sensor.html', sensors=sensors) + +#--------------------------------------------- +# Routes en Logica +#---------------------------------------------- +# Verwijderd record ouder dan 7 dagen uit DB +def perform_cleanup(): + """Verwijder data ouder dan 7 dagen uit de database.""" + query = "DELETE FROM CO2_Metingen WHERE Timestamp < NOW() - INTERVAL 7 DAY" + try: + execute_query(query, commit=True) + print("Database opruiming voltooid.") + except Exception as e: + print(f"Fout bij database opruiming: {e}") + + +# Toggleknop voor automatisch verwijderen +@co2_sensor_bp.route('/toggle_auto_delete', methods=['POST']) +@login_required +@recht_vereist('co2') +def toggle_auto_delete(): + """Schakelt het automatisch verwijderen van oude data aan/uit.""" + data = request.get_json() + is_active = data.get('active', False) + + # Hier kun je een variabele in de scanner of een config opslaan + # Voor nu simuleren we de status-bevestiging + scanner.auto_delete = is_active + + if is_active: + perform_cleanup() + + return jsonify({'active': scanner.auto_delete}) + + +@co2_sensor_bp.route('/get_cleanup_status') +@login_required +@recht_vereist('co2') +def get_cleanup_status(): + """Geeft de huidige status van de auto-delete instelling terug.""" + # Zorg dat 'auto_delete' bestaat in je CO2Scanner klasse of gebruik een globale + status = getattr(scanner, 'auto_delete', False) + return jsonify({'active': status}) + + +# Eenmalige scan uitvoeren +@co2_sensor_bp.route('/scan') +@login_required +@recht_vereist('co2') +def scan_co2(): + """Trigger één handmatige scan-ronde.""" + scanner.perform_scan() + flash("Handmatige scan voltooid.", "success") + return redirect(url_for('co2_sensor.dashboard')) + +# Start herhalende scan +@co2_sensor_bp.route('/toggle_continuous_scan', methods=['POST']) +@login_required +@recht_vereist('co2') +def toggle_continuous_scan(): + """Schakelt de achtergrond-thread aan of uit via de website.""" + data = request.get_json() + if data.get('active'): + scanner.start() + else: + scanner.stop() + return jsonify({'active': scanner.active}) + +@co2_sensor_bp.route('/get_scan_status') +@login_required +@recht_vereist('co2') +def get_scan_status(): + """Zorgt dat de switch in de HTML op de juiste stand staat bij laden.""" + return jsonify({'active': scanner.active}) + + +#----------------------------------------------- +# Opent grafiekvenster met 50 waarden +#----------------------------------------------- +@co2_sensor_bp.route('/grafiek/') +@login_required +@recht_vereist('co2') +def grafiek(lokaal): + # Haal de laatste 50 metingen op (oud → nieuw) + results = execute_query( + "SELECT ppm, timestamp FROM (" + " SELECT m.ppm, m.Timestamp AS timestamp FROM CO2_Metingen m " + " JOIN Lokalen lk ON lk.Lokaal_ID = m.Lokaal_ID WHERE lk.Naam = %s " + " ORDER BY m.Timestamp DESC LIMIT 50) x ORDER BY timestamp ASC", + (lokaal,) + ) + + # Split de data voor Chart.js + # We gebruiken ASC zodat de grafiek van links (oud) naar rechts (nieuw) loopt + labels = [row['timestamp'].strftime("%d-%m %H:%M:%S") if hasattr(row['timestamp'], 'strftime') else str(row['timestamp']) for row in results] + values = [row['ppm'] for row in results] + + return render_template('grafiek.html', lokaal=lokaal, labels=labels, data=values) \ No newline at end of file diff --git a/blueprints/contacten_bp.py b/blueprints/contacten_bp.py new file mode 100644 index 0000000..4695e89 --- /dev/null +++ b/blueprints/contacten_bp.py @@ -0,0 +1,115 @@ +"""Gmail › Contacten: contactlijsten in de mailboxen en het adresboek van de organisatie (zichtbaar/verborgen).""" + +from flask import Blueprint, render_template, request, session, jsonify + +from blueprints.auth import login_required +from rechten import recht_vereist, log +from services import contacten_service as cs + +contacten_bp = Blueprint('contacten', __name__) +TABS = ('lijsten', 'adresboek') + + +def _door(): + return session.get('naam') or session.get('user') + + +@contacten_bp.route('/', methods=['GET']) +@login_required +@recht_vereist('gmail_contacten') +def overzicht(): + tab = request.args.get('tab') if request.args.get('tab') in TABS else TABS[0] + ctx = {'tab': tab, 'fout': None, 'status': cs.LijstSync().status} + try: + if tab == 'adresboek': + ctx['ous'] = cs.ou_lijst() + ctx['ou'] = request.args.get('ou') or '' + ctx['met_sub'] = 'sub' not in request.args or '1' in request.args.getlist('sub') + ctx['gebruikers'] = cs.gebruikers_in([ctx['ou']], ctx['met_sub']) if ctx['ou'] else [] + else: + ctx['lijsten'] = cs.lijsten() + lid = request.args.get('lijst', type=int) + ctx['gekozen'] = cs.lijst(lid) if lid else None + ctx['nieuw'] = bool(request.args.get('nieuw')) + if ctx['gekozen'] or ctx['nieuw']: + ctx['ous'] = cs.ou_lijst() + except cs.ContactFout as e: + ctx['fout'] = str(e) + except Exception as e: + ctx['fout'] = cs.vriendelijk(e) + return render_template('contacten.html', **ctx) + + +# --------------------------------------------------------------------- +# 1. Adresboek +# --------------------------------------------------------------------- +@contacten_bp.route('/adresboek', methods=['POST']) +@login_required +@recht_vereist('gmail_contacten') +def adresboek(): + d = request.get_json(silent=True) or {} + emails = [e for e in d.get('emails') or [] if isinstance(e, str)][:2000] + if not emails: + return jsonify(ok=False, fout="Niemand gekozen."), 400 + try: + fouten = cs.zet_zichtbaar(emails, bool(d.get('zichtbaar'))) + except Exception as e: + return jsonify(ok=False, fout=cs.vriendelijk(e)), 400 + log(f"Contacten: {len(emails)} gebruiker(s) {'zichtbaar' if d.get('zichtbaar') else 'verborgen'} in het adresboek") + return jsonify(ok=not fouten, fouten=fouten, aantal=len(emails) - len(fouten)) + + +# --------------------------------------------------------------------- +# 2. Contactlijsten in de mailboxen +# --------------------------------------------------------------------- +@contacten_bp.route('/lijst/bewaren', methods=['POST']) +@login_required +@recht_vereist('gmail_contacten') +def lijst_bewaren(): + d = request.get_json(silent=True) or {} + lid = int(d['id']) if str(d.get('id') or '').isdigit() else None + oud = cs.lijst(lid) if lid else None + try: + lid = cs.lijst_bewaren(lid, d.get('naam'), [o for o in d.get('ous') or [] if isinstance(o, str)], + bool(d.get('met_sub')), [i for i in d.get('items') or [] if isinstance(i, dict)], _door()) + except cs.ContactFout as e: + return jsonify(ok=False, fout=str(e)), 400 + log(f"Contacten: contactlijst {d.get('naam')} bewaard") + gestart = False + # Stond de lijst al in de mailboxen? Dan meteen bijwerken (ook bij wie er door een OU-wijziging uit valt) + if oud and oud.get('Laatste_sync'): + gestart = cs.LijstSync().start(lid, oude_naam=oud['Naam'], oude_ous=oud['ous']) + return jsonify(ok=True, id=lid, gestart=gestart) + + +@contacten_bp.route('/lijst//sync', methods=['POST']) +@login_required +@recht_vereist('gmail_contacten') +def lijst_sync(lijst_id): + if not cs.LijstSync().start(lijst_id): + return jsonify(ok=False, fout="Er loopt al een opdracht."), 409 + log(f"Contacten: contactlijst {lijst_id} naar de mailboxen") + return jsonify(ok=True) + + +@contacten_bp.route('/lijst//verwijderen', methods=['POST']) +@login_required +@recht_vereist('gmail_contacten') +def lijst_verwijderen(lijst_id): + l = cs.lijst(lijst_id) + if not l: + return jsonify(ok=False, fout="Lijst niet gevonden."), 404 + log(f"Contacten: contactlijst {l['Naam']} verwijderd") + if l.get('Laatste_sync'): + if not cs.LijstSync().start(lijst_id, verwijderen=True): + return jsonify(ok=False, fout="Er loopt al een opdracht."), 409 + return jsonify(ok=True, gestart=True) + cs.lijst_verwijderen_db(lijst_id) + return jsonify(ok=True, gestart=False) + + +@contacten_bp.route('/status.json', methods=['GET']) +@login_required +@recht_vereist('gmail_contacten') +def status(): + return jsonify(cs.LijstSync().status) diff --git a/blueprints/dashboard_bp.py b/blueprints/dashboard_bp.py new file mode 100644 index 0000000..eadea7c --- /dev/null +++ b/blueprints/dashboard_bp.py @@ -0,0 +1,19 @@ +from flask import Blueprint, render_template, session +from blueprints.auth import login_required + +main_bp = Blueprint('main', __name__) + +#--------------------------------------------- +# Functie open dahboard +#--------------------------------------------- +@main_bp.route('/dashboard') +@login_required +def dashboard(): + # We halen de naam en de groep uit de sessie die in auth.py zijn opgeslagen + user_name = session.get('user') + user_group = session.get('security_group') + + # We geven 'current_user' door zodat je HTML {% if current_user == 'admin' %} werkt + return render_template('dashboard.html', + current_user=user_name, + security_group=user_group) \ No newline at end of file diff --git a/blueprints/database_bp.py b/blueprints/database_bp.py new file mode 100644 index 0000000..33505f1 --- /dev/null +++ b/blueprints/database_bp.py @@ -0,0 +1,100 @@ +""" +Beheer › Database: tabellen van de school aanvullen vanuit Excel. + +Toestellen: + GET /beheer/database/toestellen → pagina (upload + sjabloon) + GET /beheer/database/toestellen/sjabloon.xlsx → sjabloon downloaden + POST /beheer/database/toestellen/controleren → Excel lezen en voorbeeld tonen (niets bewaard) + POST /beheer/database/toestellen/importeren → bevestigen: het voorbeeld uitvoeren +""" +import json + +from flask import Blueprint, render_template, request, Response, redirect, url_for, flash, session + +from blueprints.auth import login_required +from database import execute_query +from rechten import recht_vereist, log +from services import toestellen_import as ti +from tenancy import huidige_school + +database_bp = Blueprint('database_beheer', __name__) + + +@database_bp.route('/toestellen', methods=['GET']) +@login_required +@recht_vereist('database_toestellen') +def toestellen(): + try: + aantal = execute_query("SELECT COUNT(*) AS n FROM Toestellen")[0]['n'] + except Exception: + aantal = None + return render_template('database_toestellen.html', plan=None, aantal=aantal, kolommen=ti.KOLOMMEN, + statussen=ti.STATUSSEN, max_rijen=ti.MAX_RIJEN) + + +@database_bp.route('/toestellen/sjabloon.xlsx', methods=['GET']) +@login_required +@recht_vereist('database_toestellen') +def toestellen_sjabloon(): + school = huidige_school() + data = ti.maak_sjabloon(school.naam) + return Response(data, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + headers={'Content-Disposition': f"attachment; filename=Sjabloon_toestellen_{school.code}.xlsx"}) + + +@database_bp.route('/toestellen/controleren', methods=['POST']) +@login_required +@recht_vereist('database_toestellen') +def toestellen_controleren(): + terug = redirect(url_for('database_beheer.toestellen')) + bestand = request.files.get('bestand') + if not bestand or not bestand.filename: + flash("Kies eerst een Excel-bestand.", "error") + return terug + if not bestand.filename.lower().endswith(('.xlsx', '.xlsm')): + flash("Enkel Excel-bestanden (.xlsx) kunnen ingelezen worden. Sla een .xls of .csv eerst op als .xlsx.", "error") + return terug + modus = 'overschrijven' if request.form.get('modus') == 'overschrijven' else 'aanvullen' + try: + rijen, onbekend = ti.lees_excel(bestand) + except ti.ImportFout as e: + flash(str(e), "error") + return terug + if not rijen: + flash("Het bestand bevat geen toestellen (enkel kolomkoppen of lege rijen).", "warning") + return terug + try: + plan = ti.maak_plan(rijen, modus) + except Exception as e: + flash(f"Controleren mislukt: {e}", "error") + return terug + return render_template('database_toestellen.html', plan=plan, bestandsnaam=bestand.filename, onbekend=onbekend, + rijen_json=json.dumps(rijen, ensure_ascii=False), kolommen=ti.KOLOMMEN, + statussen=ti.STATUSSEN, max_rijen=ti.MAX_RIJEN, aantal=None) + + +@database_bp.route('/toestellen/importeren', methods=['POST']) +@login_required +@recht_vereist('database_toestellen') +def toestellen_importeren(): + terug = redirect(url_for('database_beheer.toestellen')) + modus = 'overschrijven' if request.form.get('modus') == 'overschrijven' else 'aanvullen' + try: + rijen = json.loads(request.form.get('rijen') or '[]') + if not isinstance(rijen, list) or len(rijen) > ti.MAX_RIJEN or not all(isinstance(r, dict) for r in rijen): + raise ValueError + except ValueError: + flash("De gegevens van het voorbeeld zijn ongeldig. Upload het bestand opnieuw.", "error") + return terug + try: + plan, nieuw, bijgewerkt = ti.voer_uit(rijen, modus, session.get('user')) + except Exception as e: + flash(f"Importeren mislukt, er is niets bewaard: {e}", "error") + return terug + t = plan['tellers'] + log(f"Toestellen geïmporteerd uit Excel: {nieuw} nieuw, {bijgewerkt} bijgewerkt ({modus})") + ongewijzigd = f", {t['ongewijzigd']} ongewijzigd" if t['ongewijzigd'] else "" + flash(f"Import klaar: {nieuw} toestel(len) toegevoegd, {bijgewerkt} bijgewerkt{ongewijzigd}.", "success") + if t['fout']: + flash(f"{t['fout']} rij(en) met een fout werden overgeslagen.", "warning") + return terug diff --git a/blueprints/devices.py b/blueprints/devices.py new file mode 100644 index 0000000..99dd023 --- /dev/null +++ b/blueprints/devices.py @@ -0,0 +1,603 @@ +import sys +from flask import Blueprint, render_template, request, session, redirect, url_for, flash, jsonify +from database import execute_query +from services import CIP_inleveren +from services import CIP_uitdelen +from blueprints.auth import login_required +from rechten import recht_vereist +from database import execute_query, execute_insert, get_db_connection +from services import toestellen as tst +from blueprints.google_admin import google_service +from googleapiclient.errors import HttpError + + +# We noemen de blueprint 'devices' +devices_bp = Blueprint('devices', __name__) + +#------------------------------------------------- +# --- ROUTE TOESTELLEN (Inventaris Toestellen) --- +#------------------------------------------------- +@devices_bp.route("/inventaris", methods=["GET", "POST"]) +@login_required +@recht_vereist('toestellen_beheren') +def inventaris_toestellen(): + query = request.form.get("query", "") if request.method == "POST" else request.args.get("query", "") + message = None + + search_term = f"%{query}%" + try: + tst.ensure_geblokkeerd() + geblokkeerd = "t.Geblokkeerd" + except Exception as e: # bv. geen ALTER-rechten: pagina blijft werken + sys.stderr.write(f"Kolom Toestellen.Geblokkeerd: {e}\n") + geblokkeerd = "0" + sql = f""" + SELECT * FROM ( + SELECT t.Toestel_ID, t.Schooleigen_ID AS KAMXM_nummer, sp.Signpostnummer, t.Serienummer, t.Type, + DATE_FORMAT(sp.Garantie, '%d-%m-%Y') AS Garantie, t.Status, {geblokkeerd} AS Geblokkeerd, + {tst.LAATSTE_OPMERKING} AS Opmerking + FROM Toestellen t + LEFT JOIN Signpost_DB sp ON sp.Toestel_ID = t.Toestel_ID + ) x + WHERE CONCAT_WS(' ', KAMXM_nummer, Signpostnummer, Serienummer, Type, Opmerking) LIKE %s + ORDER BY KAMXM_nummer IS NULL, KAMXM_nummer + """ + + results = execute_query(sql, (search_term,)) + + + if query and not results: + message = f"Geen resultaten gevonden voor '{query}'." + elif not results: + message = "Er zijn momenteel geen toestellen in de inventaris." + + return render_template("toestellen.html", results=results, query=query, message=message) + +@devices_bp.route("/google_import", methods=["POST"]) +@login_required +@recht_vereist('toestellen_beheren') +def google_import(): + """Chromebooks uit Google Admin in de inventaris zetten: nieuwe serienummers toevoegen en een ontbrekend model + aanvullen. Er wordt niets verwijderd of overschreven.""" + from config import Config + # Leeg = alle Chromebooks van het domein; anders enkel deze OU's (met sub-OU's) + ous = [o.strip() for o in str(Config.CHROMEBOOK_OUS or '').split(',') if o.strip()] + try: + toestellen = google_service.lijst_chromebooks(ous) + except HttpError as e: + fout = str(e) + if 'INVALID_OU_ID' in fout or 'Invalid Input: OrgUnit' in fout or ('400' in fout and ous): + flash(f"Een OU bestaat niet in Google: {', '.join(ous)}. Pas 'OU's van de Chromebooks' aan bij " + "🔌 Koppelingen van deze school (volledig pad, bv. /ChromeBooks Medewerkers).", "error") + else: + flash(f"Chromebooks ophalen bij Google mislukt: {e}", "error") + return redirect(url_for("devices.inventaris_toestellen")) + except Exception as e: + flash(f"Chromebooks ophalen bij Google mislukt: {e}", "error") + return redirect(url_for("devices.inventaris_toestellen")) + + try: + tst.ensure_geblokkeerd() + kol = "Geblokkeerd" + except Exception: + kol = "NULL AS Geblokkeerd" + bestaand = {(r['Serienummer'] or '').strip().upper(): r for r in + execute_query(f"SELECT Toestel_ID, Serienummer, Type, {kol} FROM Toestellen WHERE Serienummer IS NOT NULL")} + nieuw = aangevuld = blok_bijgewerkt = 0 + fouten = [] + # Het veld Item-ID (Asset ID) uit Google wordt bewust NIET overgenomen: het wordt soms voor andere info gebruikt + # (bv. een lokaal) en is dan niet uniek. Het toestelnummer van de school vul je in de inventaris of via Signpost. + for d in toestellen: + serie = d['serialNumber'].strip() + model = (d.get('model') or '').strip()[:100] or None + try: + rij = bestaand.get(serie.upper()) + in_google = 1 if d.get('status') == 'DISABLED' else 0 + if not rij: + nieuw_id = execute_insert("INSERT INTO Toestellen (Serienummer, Type, Status) VALUES (%s, %s, 'Beschikbaar')", + (serie, model)) + if in_google and kol == "Geblokkeerd": + tst.zet_geblokkeerd(nieuw_id, True) + bestaand[serie.upper()] = {'Type': model} + nieuw += 1 + continue + if model and not rij['Type']: + execute_query("UPDATE Toestellen SET Type = %s WHERE Toestel_ID = %s", (model, rij['Toestel_ID']), + commit=True) + aangevuld += 1 + # Blokkeerstatus overnemen uit Google (daar kan het ook rechtstreeks gewijzigd zijn) + if rij.get('Geblokkeerd') is not None and int(rij['Geblokkeerd'] or 0) != in_google: + tst.zet_geblokkeerd(rij['Toestel_ID'], in_google) + blok_bijgewerkt += 1 + except Exception as e: + fouten.append(f"{serie}: {e}") + sys.stderr.write(f"Chromebook-import {serie}: {e}\n") + bereik = f" uit {', '.join(ous)}" if ous else "" + flash(f"{len(toestellen)} Chromebook(s) gevonden in Google{bereik}: {nieuw} nieuw in de inventaris, " + f"{aangevuld} aangevuld, {len(toestellen) - nieuw - aangevuld - len(fouten)} stonden er al." + + (f" Blokkeerstatus bijgewerkt bij {blok_bijgewerkt} toestel(len)." if blok_bijgewerkt else ""), "success") + if fouten: + flash(f"{len(fouten)} toestel(len) konden niet verwerkt worden: " + "; ".join(fouten[:5]) + + (" …" if len(fouten) > 5 else ""), "error") + return redirect(url_for("devices.inventaris_toestellen")) + + +@devices_bp.route("/google_info", methods=["GET"]) +@login_required +@recht_vereist('toestellen_beheren') +def google_info(): + """JSON met gebruiksinfo uit Google Admin voor één toestel (voor de knop 'Google-info').""" + try: + info, fout = google_service.chromebook_info(request.args.get('serie', '')) + except Exception as e: + info, fout = None, f"Google gaf een fout: {e}" + if fout: + return jsonify(ok=False, fout=fout) + # Naam van de leerling erbij als het e-mailadres in de leerlingenlijst staat + emails = [g['email'] for g in info['gebruikers'] if g['email']] + namen = {} + if emails: + try: + # Gebruikersnaam staat er soms als volledig e-mailadres, soms enkel het deel vóór de @ + sleutels = list(dict.fromkeys([e.lower() for e in emails] + [e.split('@')[0].lower() for e in emails])) + plek = ','.join(['%s'] * len(sleutels)) + for r in execute_query(f"SELECT Gebruikersnaam, Voornaam, Naam FROM Leerlingen WHERE Gebruikersnaam IN ({plek})", + tuple(sleutels)): + namen[(r['Gebruikersnaam'] or '').lower()] = f"{r.get('Voornaam') or ''} {r.get('Naam') or ''}".strip() + except Exception: + pass + for g in info['gebruikers']: + g['naam'] = namen.get(g['email'].lower()) or namen.get(g['email'].split('@')[0].lower(), '') + return jsonify(ok=True, info=info) + + +#----------------------------------------------------- +# Functie achter bewerk toestel knop +#----------------------------------------------------- +@devices_bp.route("/bewerk_toestel", methods=["POST"]) +@login_required +@recht_vereist('toestellen_beheren') +def bewerk_toestel(): + """Verwerkt de POST-gegevens om een toestelrecord bij te werken.""" + + # Gebruik de gegevens uit het formulier + toestel_id = request.form.get("toestel_id") + schooleigen_id = (request.form.get("schooleigen_id") or "").strip() or None + serienummer = request.form.get("serienummer") + signpostnummer = request.form.get("signpostnummer") + type_toestel = request.form.get("type") + garantie = request.form.get("garantie") + opmerking = request.form.get("opmerking") + query = request.form.get("query", "") + + if not toestel_id: + flash("Fout: Uniek nummer ontbreekt. Kan toestel niet bijwerken.", "error") + return redirect(url_for("devices.inventaris_toestellen")) + + try: + tst.lees_datum(garantie) # eerst valideren, zodat er niets half bewaard wordt + execute_query("UPDATE Toestellen SET Schooleigen_ID = %s, Serienummer = %s, Type = %s WHERE Toestel_ID = %s", + (schooleigen_id, (serienummer or '').strip() or None, (type_toestel or '').strip() or None, + toestel_id), commit=True) + tst.bewaar_signpost(toestel_id, signpostnummer, garantie) + tst.voeg_opmerking_toe(toestel_id, opmerking, session.get('user')) + flash(f"Toestel {schooleigen_id or serienummer} succesvol bijgewerkt.", "success") + + except ValueError as err: + flash(str(err), "error") + except Exception as err: + flash(f"Databasefout bij het bewerken van het toestel: {err}", "error") + + # BELANGRIJK: Gebruik de blueprint prefix 'devices.' in de redirect + return redirect(url_for("devices.inventaris_toestellen", query=query)) + + +#------------------------------------------------- +# --- ROUTE EIGENDOM (koppeling toestel-leerling) --- +#------------------------------------------------- +@devices_bp.route("/eigendom", methods=["GET", "POST"]) +@login_required +@recht_vereist('eigendom_bekijken') +def inventaris_eigendom(): + query = (request.form.get("query") or request.args.get("query") or "").strip() + + # Alle huidige leerlingen, met het toestel dat ze nu hebben (of zonder toestel). Vertrokken leerlingen enkel + # als ze nog een toestel hebben. Een leerling met twee toestellen staat er twee keer in. + # Met zoekterm: elk woord moet voorkomen in internnummer, naam, gebruikersnaam, SS-nummer, toestel of opmerkingen. + try: + from services.sync_service import zorg_vertrokken_kolom + zorg_vertrokken_kolom() + vertrokken = "l.Vertrokken_op IS NULL OR " + except Exception: + vertrokken = "" + sql = f""" + SELECT * FROM ( + SELECT e.Eigendom_ID, l.Internnummer AS internnummer, l.Voornaam, l.Naam, l.Gebruikersnaam, l.SS_nummer, + t.Schooleigen_ID AS kamxm_nummer, t.Serienummer, e.Datum_toekenning, + IFNULL(e.Status, 0) AS locked, (e.Eigendom_ID IS NOT NULL) AS heeft_toestel, + (SELECT GROUP_CONCAT(o.Opmerking ORDER BY o.Timestamp SEPARATOR ' | ') + FROM Opmerkingen o WHERE o.Toestel_ID = t.Toestel_ID) AS opmerkingen + FROM Leerlingen l + LEFT JOIN Eigendom e ON e.Internnummer = l.Internnummer AND e.Datum_inlevering IS NULL + LEFT JOIN Toestellen t ON t.Toestel_ID = e.Toestel_ID + WHERE {vertrokken}e.Eigendom_ID IS NOT NULL + ) x + """ + woorden = query.split()[:5] + if woorden: + sql += " WHERE " + " AND ".join( + ["LOWER(CONCAT_WS(' ', internnummer, Voornaam, Naam, Gebruikersnaam, SS_nummer, IFNULL(kamxm_nummer, ''), " + "IFNULL(Serienummer, ''), IFNULL(opmerkingen, ''))) LIKE %s"] * len(woorden)) + sql += " ORDER BY heeft_toestel DESC, Datum_toekenning DESC, Naam, Voornaam, internnummer" + results = execute_query(sql, tuple(f"%{w.lower()}%" for w in woorden)) + + return render_template("inventaris.html", results=results, query=query) + +@devices_bp.route("/eigendom/historie/", methods=["GET"]) +@login_required +@recht_vereist('eigendom_bekijken') +def eigendom_historie(internnummer): + """Alle toestellen die een leerling ooit gehad heeft (ook ingeleverde), nieuwste eerst.""" + from datetime import date + rows = execute_query(""" + SELECT e.Eigendom_ID, e.Datum_toekenning, e.Datum_inlevering, IFNULL(e.Status, 0) AS locked, + t.Schooleigen_ID, t.Serienummer, t.Type, + (SELECT GROUP_CONCAT(o.Opmerking ORDER BY o.Timestamp SEPARATOR ' | ') + FROM Opmerkingen o WHERE o.Toestel_ID = t.Toestel_ID) AS opmerkingen + FROM Eigendom e INNER JOIN Toestellen t ON t.Toestel_ID = e.Toestel_ID + WHERE e.Internnummer = %s + ORDER BY e.Datum_inlevering IS NOT NULL, e.Datum_toekenning DESC, e.Eigendom_ID DESC""", (internnummer,)) or [] + leerling = (execute_query("SELECT Voornaam, Naam, Gebruikersnaam FROM Leerlingen WHERE Internnummer = %s", + (internnummer,)) or [{}])[0] + + def d(x): + return x.strftime('%d-%m-%Y') if hasattr(x, 'strftime') else (str(x) if x else '') + + uit = [] + for r in rows: + begin, einde = r['Datum_toekenning'], r['Datum_inlevering'] + dagen = None + if hasattr(begin, 'toordinal'): + dagen = ((einde if hasattr(einde, 'toordinal') else date.today()) - begin).days + uit.append({'toestel': r['Schooleigen_ID'] or '', 'serienummer': r['Serienummer'] or '', 'type': r['Type'] or '', + 'van': d(begin), 'tot': d(einde), 'huidig': not einde, 'dagen': dagen, + 'geblokkeerd': int(r['locked'] or 0) == 1, 'opmerkingen': r['opmerkingen'] or ''}) + return jsonify(ok=True, internnummer=internnummer, + naam=f"{leerling.get('Voornaam') or ''} {leerling.get('Naam') or ''}".strip(), + gebruikersnaam=leerling.get('Gebruikersnaam') or '', toestellen=uit) + + +@devices_bp.route("/inventaris/historie/", methods=["GET"]) +@login_required +@recht_vereist('toestellen_beheren', 'eigendom_bekijken') +def toestel_historie(toestel_id): + """Alle leerlingen die dit toestel ooit gehad hebben, nieuwste eerst.""" + from datetime import date + rows = execute_query(""" + SELECT e.Internnummer, e.Datum_toekenning, e.Datum_inlevering, IFNULL(e.Status, 0) AS locked, + l.Voornaam, l.Naam, l.Gebruikersnaam + FROM Eigendom e LEFT JOIN Leerlingen l ON l.Internnummer = e.Internnummer + WHERE e.Toestel_ID = %s + ORDER BY e.Datum_inlevering IS NOT NULL, e.Datum_toekenning DESC, e.Eigendom_ID DESC""", (toestel_id,)) or [] + + def d(x): + return x.strftime('%d-%m-%Y') if hasattr(x, 'strftime') else (str(x) if x else '') + + uit = [] + for r in rows: + begin, einde = r['Datum_toekenning'], r['Datum_inlevering'] + dagen = ((einde if hasattr(einde, 'toordinal') else date.today()) - begin).days if hasattr(begin, 'toordinal') else None + uit.append({'internnummer': r['Internnummer'], 'naam': f"{r['Voornaam'] or ''} {r['Naam'] or ''}".strip(), + 'gebruikersnaam': r['Gebruikersnaam'] or '', 'van': d(begin), 'tot': d(einde), 'huidig': not einde, + 'dagen': dagen, 'geblokkeerd': int(r['locked'] or 0) == 1}) + return jsonify(ok=True, eigenaars=uit) + + +#------------------------------------------------- +# --- ROUTE UITDELEN --- +#------------------------------------------------- +@devices_bp.route('/uitdelen', methods=['GET']) +@login_required +@recht_vereist('toestellen_uitdelen') +def uitdelen_page(): + return render_template('uitdelen.html', message=None) + +@devices_bp.route('/zoek_leerlingen', methods=['GET']) +@login_required +@recht_vereist('toestellen_uitdelen', 'toestellen_beheren') +def zoek_leerlingen(): + """Suggesties voor het veld 'Internnummer' (max. 15): op internnummer, naam, voornaam of gebruikersnaam. + Geeft ook het toestel dat de leerling nu heeft.""" + q = (request.args.get('q') or '').strip() + if not q: + return jsonify([]) + woorden = q.split()[:4] + # Elk woord moet voorkomen in internnummer, gebruikersnaam of naam (in eender welke volgorde) + # LOWER(): zoeken zonder onderscheid tussen hoofd- en kleine letters, ongeacht de collation van CONCAT_WS + voorwaarden = " AND ".join(["LOWER(CONCAT_WS(' ', l.Internnummer, l.SS_nummer, l.Gebruikersnaam, l.Voornaam, l.Naam)) LIKE %s"] * len(woorden)) + rows = execute_query( + "SELECT l.Internnummer, l.Voornaam, l.Naam, l.Gebruikersnaam, " + " GROUP_CONCAT(COALESCE(t.Schooleigen_ID, t.Serienummer) SEPARATOR ', ') AS Toestellen " + "FROM Leerlingen l " + "LEFT JOIN Eigendom e ON e.Internnummer = l.Internnummer AND e.Datum_inlevering IS NULL " + "LEFT JOIN Toestellen t ON t.Toestel_ID = e.Toestel_ID " + f"WHERE {voorwaarden} " + "GROUP BY l.Internnummer, l.Voornaam, l.Naam, l.Gebruikersnaam " + "ORDER BY (l.Internnummer LIKE %s) DESC, l.Naam, l.Voornaam LIMIT 15", + tuple(f"%{w.lower()}%" for w in woorden) + (f"{q}%",)) + return jsonify([{'intern': r['Internnummer'], 'naam': f"{r['Voornaam'] or ''} {r['Naam'] or ''}".strip(), + 'gebruiker': r['Gebruikersnaam'] or '', 'toestellen': r['Toestellen'] or ''} for r in rows]) + + +@devices_bp.route('/zoek_toestellen', methods=['GET']) +@login_required +@recht_vereist('toestellen_uitdelen', 'toestellen_beheren') +def zoek_toestellen(): + """Suggesties voor het zoekveld 'Toestelnummer' (max. 15): op toestelnummer of serienummer.""" + q = (request.args.get('q') or '').strip() + if len(q) < 1: + return jsonify([]) + # Uitdelen: beschikbare toestellen eerst; inleveren: uitgeleende toestellen eerst + voorkeur = {'uitgeleend': "e.Internnummer IS NULL, ", 'beschikbaar': "e.Internnummer IS NOT NULL, "}.get( + request.args.get('voorkeur'), "") + rows = execute_query( + "SELECT t.Schooleigen_ID, t.Serienummer, t.Type, t.Status, e.Internnummer " + "FROM Toestellen t LEFT JOIN Eigendom e ON e.Toestel_ID = t.Toestel_ID AND e.Datum_inlevering IS NULL " + "WHERE t.Schooleigen_ID LIKE %s OR t.Serienummer LIKE %s " + f"ORDER BY {voorkeur}t.Schooleigen_ID IS NULL, (t.Schooleigen_ID LIKE %s) DESC, t.Schooleigen_ID, t.Serienummer " + "LIMIT 15", + (f"%{q}%", f"%{q}%", f"{q}%")) + return jsonify([{'nummer': r['Schooleigen_ID'] or '', 'serie': r['Serienummer'] or '', 'type': r['Type'] or '', + 'status': r['Status'] or '', 'bij': r['Internnummer'] or ''} for r in rows]) + +# Functie van knop Ingeven (Uitdelen) +@devices_bp.route('/uitdelen_submit', methods=['POST']) +@login_required +@recht_vereist('toestellen_uitdelen') +def uitdelen_submit(): + internnummer = request.form.get('internnummer') + #TODO-------------------------------------------- + try: + internnummer= int(internnummer) + + except: + internnummer = str(internnummer) + #-------------------------------------------- + serienummer = request.form.get('serienummer') + action_type = request.form.get('action') + + success = CIP_uitdelen.uitdelen(internnummer, serienummer) + + if success: + flash(f"Toestel met nummer {serienummer} succesvol uitgedeeld!", "success") + else: + # Als het mislukt, tonen we de foutmelding die in de service is gezet + flash(CIP_uitdelen.foutmelding, "error") + + return redirect(url_for('devices.uitdelen_page')) + +#------------------------------------------------- +# --- ROUTE INLEVEREN --- +#------------------------------------------------- +@devices_bp.route('/inleveren', methods=['GET']) +@login_required +@recht_vereist('toestellen_uitdelen') +def inleveren_page(): + return render_template('inleveren.html', message=None) + +# Functie van knop Ingeven (Inleveren) +@devices_bp.route('/inleveren_submit', methods=['POST']) +@login_required +@recht_vereist('toestellen_uitdelen') +def inleveren_submit(): + internnummer = request.form.get('internnummer') + serienummer = request.form.get('serienummer') + tab2_schade_text = request.form.get('schade_type', "") + action_type = request.form.get('action') + try: + internnummer= int(internnummer) + + except: + internnummer = str(internnummer) + if action_type: + CIP_inleveren.Inleveren(internnummer, serienummer, action_type, tab2_schade_text) + + return render_template('inleveren.html', message=CIP_inleveren.foutmelding) + +#--------------------------------- +# --- STATUS UPDATES --- +#--------------------------------- +@devices_bp.route("/update_toestel_status", methods=["POST"]) +@login_required +@recht_vereist('toestellen_beheren') +def wijzig_status(): + toestel_id = request.form.get("toestel_id") + new_status = request.form.get("new_status") + query = request.form.get("query", "") + + if toestel_id and new_status in ["Beschikbaar", "Uitgeleend", "Defect"]: + execute_query("UPDATE Toestellen SET Status = %s WHERE Toestel_ID = %s", (new_status, toestel_id), commit=True) + rij = execute_query("SELECT Schooleigen_ID, Serienummer FROM Toestellen WHERE Toestel_ID = %s", (toestel_id,)) + label = (rij[0]['Schooleigen_ID'] or rij[0]['Serienummer']) if rij else toestel_id + flash(f"Status van {label} gewijzigd naar {new_status}", "success") + + return redirect(url_for("devices.inventaris_toestellen", query=query)) + +#------------------------------------------------- +# --- ROUTE BLOKKEREN / DEBLOKKEREN --- +#------------------------------------------------- +@devices_bp.route('/eigendom/bewerken', methods=['POST']) +@login_required +@recht_vereist('toestellen_uitdelen') +def eigendom_bewerken(): + """Een lopende toekenning aanpassen: andere leerling en/of ander toestel.""" + query = request.form.get('query', '') + terug = redirect(url_for('devices.inventaris_eigendom', query=query or None)) + eigendom_id = request.form.get('eigendom_id', type=int) + rows = execute_query("SELECT * FROM Eigendom WHERE Eigendom_ID = %s AND Datum_inlevering IS NULL", (eigendom_id,)) + if not rows: + flash("Deze toekenning bestaat niet (meer) of is al ingeleverd.", "error") + return terug + oud = rows[0] + + leerling = tst.zoek_leerling((request.form.get('internnummer') or '').strip()) + if not leerling: + flash("Internnummer niet gevonden in de leerlingenlijst.", "error") + return terug + toestel = tst.zoek_toestel((request.form.get('toestelnummer') or '').strip()) + if not toestel: + flash("Toestelnummer (of serienummer) niet gevonden in de toestellenlijst.", "error") + return terug + + nieuw_toestel = toestel['Toestel_ID'] != oud['Toestel_ID'] + if nieuw_toestel: + bezet = execute_query("SELECT Internnummer FROM Eigendom WHERE Toestel_ID = %s AND Datum_inlevering IS NULL " + "AND Eigendom_ID <> %s", (toestel['Toestel_ID'], eigendom_id)) + if bezet: + flash(f"Toestel {toestel.get('Schooleigen_ID') or toestel.get('Serienummer')} is al uitgeleend aan " + f"{bezet[0]['Internnummer']}. Lever het eerst in.", "error") + return terug + if not nieuw_toestel and str(leerling['Internnummer']) == str(oud['Internnummer']): + flash("Er is niets gewijzigd.", "info") + return terug + + execute_query("UPDATE Eigendom SET Internnummer = %s, Toestel_ID = %s WHERE Eigendom_ID = %s", + (leerling['Internnummer'], toestel['Toestel_ID'], eigendom_id), commit=True) + if nieuw_toestel: + # Het vorige toestel is weer vrij, het nieuwe staat op uitgeleend + execute_query("UPDATE Toestellen SET Status = 'Beschikbaar' WHERE Toestel_ID = %s AND Status = 'Uitgeleend'", + (oud['Toestel_ID'],), commit=True) + execute_query("UPDATE Toestellen SET Status = 'Uitgeleend' WHERE Toestel_ID = %s", (toestel['Toestel_ID'],), + commit=True) + naam = f"{leerling.get('Voornaam') or ''} {leerling.get('Naam') or ''}".strip() or leerling['Internnummer'] + flash(f"Toekenning aangepast: {toestel.get('Schooleigen_ID') or toestel.get('Serienummer')} → {naam} " + f"({leerling['Internnummer']}).", "success") + return terug + + +@devices_bp.route('/toggle_lock', methods=['POST']) +@login_required +@recht_vereist('toestel_blokkeren') +def toggle_lock(): + # Haal de gegevens op uit het formulier en strip ze direct + internnummer = request.form.get('internnummer', '').strip() + query = request.form.get('query', '') + + # 1. Haal de huidige leerling/toestel koppeling op + rows = execute_query( + "SELECT e.Eigendom_ID, e.Status, e.Toestel_ID, t.Schooleigen_ID, t.Serienummer FROM Eigendom e " + "JOIN Toestellen t ON t.Toestel_ID = e.Toestel_ID " + "WHERE e.Internnummer = %s AND e.Datum_inlevering IS NULL ORDER BY e.Datum_toekenning DESC", + (internnummer,)) + + if not rows: + flash("Geen gegevens gevonden in de Eigendom tabel.", "error") + return redirect(url_for('devices.inventaris_eigendom', query=query)) + + current_status = int(rows[0]['Status']) if rows[0]['Status'] is not None else 0 + eigendom_id = rows[0]['Eigendom_ID'] + kamxm_nummer = str(rows[0]['Schooleigen_ID'] or '').strip() + + # 2. Serienummer van het toestel + serienummer = str(rows[0]['Serienummer']).strip() if rows[0]['Serienummer'] else None + + if not serienummer: + flash(f"Kan geen serienummer vinden voor toestel {kamxm_nummer}.", "error") + return redirect(url_for('devices.inventaris_eigendom', query=query)) + + # 3. Vraag het Device ID op bij Google met een 'gecleand' serienummer + # We gebruiken strip() om de \t (tab) en spaties te verwijderen + clean_serial = serienummer.strip() + device_id, error = google_service.get_device_id_by_serial(clean_serial) + + if device_id: + # Als status 0 is (unlocked) -> moet hij naar disable (True) + should_lock = (current_status == 0) + success, api_message = google_service.toggle_device_status(device_id, lock=should_lock) + + if success: + new_status = 1 if should_lock else 0 + execute_query("UPDATE Eigendom SET Status=%s WHERE Eigendom_ID=%s", (new_status, eigendom_id), commit=True) + try: + tst.zet_geblokkeerd(rows[0]['Toestel_ID'], should_lock) + except Exception as e: + sys.stderr.write(f"Toestellen.Geblokkeerd bijwerken: {e}\n") + flash(api_message, "success") + else: + flash(f"Google API Fout: {api_message}", "error") + else: + # Hier wordt de 'Invalid Input' nu voorkomen of getoond als het serienummer echt fout is + flash(f"Google Zoekfout: {error}", "error") + + return redirect(url_for('devices.inventaris_eigendom', query=query)) + +@devices_bp.route('/inventaris/blokkeren', methods=['POST']) +@login_required +@recht_vereist('toestel_blokkeren') +def toestel_blokkeren(): + """Blokkeert of deblokkeert één Chromebook in Google (knop in Alle toestellen). + actie = 'blokkeren' of 'deblokkeren'. Met fetch (X-Requested-With) komt er JSON terug, anders een redirect.""" + from rechten import log + ajax = request.headers.get('X-Requested-With') == 'fetch' + query = request.form.get('query', '') + actie = request.form.get('actie', '') + + def klaar(ok, melding, geblokkeerd=None): + if ajax: + return jsonify(ok=ok, melding=melding, geblokkeerd=geblokkeerd) + flash(melding, "success" if ok else "error") + return redirect(url_for('devices.inventaris_toestellen', query=query)) + + if actie not in ('blokkeren', 'deblokkeren'): + return klaar(False, "Onbekende actie.") + blokkeren = actie == 'blokkeren' + try: + toestel_id = int(request.form.get('toestel_id', '')) + except ValueError: + return klaar(False, "Onbekend toestel.") + rows = execute_query("SELECT Toestel_ID, Schooleigen_ID, Serienummer FROM Toestellen WHERE Toestel_ID = %s", + (toestel_id,)) + if not rows: + return klaar(False, "Toestel niet gevonden.") + t = rows[0] + label = t['Schooleigen_ID'] or t['Serienummer'] or str(toestel_id) + if not (t['Serienummer'] or '').strip(): + return klaar(False, f"Toestel {label} heeft geen serienummer; vul het eerst in via ✏️ Bewerken.") + try: + toestel, fout = google_service.zoek_chromebook(t['Serienummer']) + except Exception as e: + toestel, fout = None, f"Google gaf een fout: {e}" + if not toestel: + return klaar(False, fout) + status = toestel['status'] + if status == 'DEPROVISIONED': + return klaar(False, f"Toestel {label} is uitgeschreven in Google Admin en kan niet (ge)blokkeerd worden.") + gewenst = 'DISABLED' if blokkeren else 'ACTIVE' + if status != gewenst: + ok, melding = google_service.toggle_device_status(toestel['id'], lock=blokkeren) + if not ok: + return klaar(False, melding) + try: + tst.zet_geblokkeerd(toestel_id, blokkeren) + except Exception as e: + sys.stderr.write(f"Toestellen.Geblokkeerd bijwerken: {e}\n") + log(f"Chromebook {label} {'geblokkeerd' if blokkeren else 'gedeblokkeerd'}") + if status == gewenst: + return klaar(True, f"Toestel {label} was in Google al {'geblokkeerd' if blokkeren else 'actief'}.", blokkeren) + return klaar(True, f"Toestel {label} is {'geblokkeerd' if blokkeren else 'gedeblokkeerd'}.", blokkeren) + + +#------------------------------------------------- +# --- HELPER gebruikt in Toggle lock functie --- +#------------------------------------------------- +def get_serienummer_from_kamxm(kamxm_nummer): + if not kamxm_nummer: + return None + result = execute_query("SELECT Serienummer FROM Toestellen WHERE Schooleigen_ID=%s", (kamxm_nummer,)) + if result and result[0]['Serienummer']: + # Alvast een basis strip() + return str(result[0]['Serienummer']).strip() + return None + + + diff --git a/blueprints/facturatie_bp.py b/blueprints/facturatie_bp.py new file mode 100644 index 0000000..730119a --- /dev/null +++ b/blueprints/facturatie_bp.py @@ -0,0 +1,96 @@ +"""Leerlingfacturatie: facturen en creditnota's van de leerlingen van de actieve school (Informat Rekeningen API).""" +import csv +import io +import time +from datetime import date + +from flask import Blueprint, render_template, request, Response, redirect, url_for, flash + +from blueprints.auth import login_required +from rechten import recht_vereist +from services.facturatie_service import FacturatieService, FacturatieFout, schooljaren +from tenancy import huidige_school + +facturatie_bp = Blueprint('facturatie', __name__) + +STATUS_LABELS = {'open': 'Open', 'gedeeltelijk': 'Gedeeltelijk betaald', 'betaald': 'Betaald', 'credit': 'Creditnota'} + + +def _schooljaar(): + jaren = schooljaren() + gekozen = request.args.get('schooljaar') or '' + return gekozen if gekozen in jaren else jaren[0], jaren + + +@facturatie_bp.route("/", methods=["GET"]) +@login_required +@recht_vereist('leerlingfacturatie') +def overzicht(): + school = huidige_school() + schooljaar, jaren = _schooljaar() + rijen, groepen, fout, opgehaald = [], [], None, None + if not school.heeft('INFORMAT_ID', 'INFORMAT_SECRET'): + fout = "Informat is nog niet ingesteld voor deze school (🔌 Koppelingen › Informat)." + else: + try: + rijen, groepen, t = FacturatieService().facturen(schooljaar, vernieuw=bool(request.args.get('vernieuw'))) + opgehaald = time.strftime('%d-%m-%Y %H:%M', time.localtime(t)) + except FacturatieFout as e: + fout = str(e) + except Exception as e: + fout = f"Facturen ophalen mislukt: {e}" + return render_template("facturatie.html", rijen=rijen, groepen=groepen, fout=fout, opgehaald=opgehaald, + schooljaar=schooljaar, jaren=jaren, school_naam=school.naam, labels=STATUS_LABELS, + today=date.today()) + + +@facturatie_bp.route("/pdf//", methods=["GET"]) +@login_required +@recht_vereist('leerlingfacturatie') +def pdf(toegangsgroep, invoice_id): + try: + inhoud = FacturatieService().pdf(toegangsgroep, invoice_id) + except FacturatieFout as e: + flash(str(e), "error") + return redirect(url_for('facturatie.overzicht', schooljaar=request.args.get('schooljaar'))) + except Exception as e: + flash(f"De PDF kon niet opgehaald worden: {e}", "error") + return redirect(url_for('facturatie.overzicht', schooljaar=request.args.get('schooljaar'))) + naam = (request.args.get('naam') or 'factuur').replace('"', '') + return Response(inhoud, mimetype='application/pdf', + headers={'Content-Disposition': f'inline; filename="{naam}.pdf"'}) + + +@facturatie_bp.route("/export.csv", methods=["GET"]) +@login_required +@recht_vereist('leerlingfacturatie') +def export(): + """CSV met dezelfde filters als de tabel: ?schooljaar=&groep=&status=&zoek=""" + schooljaar, _ = _schooljaar() + try: + rijen, _, _ = FacturatieService().facturen(schooljaar) + except Exception as e: + flash(str(e), "error") + return redirect(url_for('facturatie.overzicht', schooljaar=schooljaar)) + groep, status = request.args.get('groep') or '', request.args.get('status') or '' + zoek = (request.args.get('zoek') or '').strip().lower() + if groep: + rijen = [r for r in rijen if str(r['groep_id']) == groep] + if status == 'onbetaald': + rijen = [r for r in rijen if r['status'] in ('open', 'gedeeltelijk')] + elif status: + rijen = [r for r in rijen if r['status'] == status] + if zoek: + rijen = [r for r in rijen if zoek in ' '.join(str(r[k]) for k in ('naam', 'voornaam', 'stamnummer', 'klas', 'groep', 'ogm')).lower()] + bedrag = lambda x: f"{x:.2f}".replace('.', ',') + datum = lambda d: d.strftime('%d/%m/%Y') if d else '' + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') + w.writerow(['Naam', 'Voornaam', 'Stamnummer', 'Klas', 'Factuurgroep', 'Soort', 'Datum', 'Vervaldag', 'Totaal', 'Betaald', + 'Open', 'Status', 'Gestructureerde mededeling']) + for r in rijen: + w.writerow([r['naam'], r['voornaam'], r['stamnummer'], r['klas'], r['groep'], 'Creditnota' if r['type'] == 'CREDIT_NOTE' else 'Factuur', + datum(r['datum']), datum(r['vervaldag']), bedrag(r['totaal'] * r['teken']), bedrag(r['betaald'] * r['teken']), bedrag(r['open'] * r['teken']), + STATUS_LABELS.get(r['status'], r['status']), r['ogm']]) + return Response('' + buf.getvalue(), mimetype='text/csv; charset=utf-8', headers={ + 'Content-Disposition': f"attachment; filename=Facturen_{huidige_school().code}_{schooljaar}_{date.today():%Y%m%d}.csv"}) diff --git a/blueprints/gedeelde_drives_bp.py b/blueprints/gedeelde_drives_bp.py new file mode 100644 index 0000000..481cdeb --- /dev/null +++ b/blueprints/gedeelde_drives_bp.py @@ -0,0 +1,116 @@ +"""Google › Gedeelde drives: overzicht, leden en rechten beheren.""" +import time + +from flask import Blueprint, render_template, request, redirect, url_for, flash + +from blueprints.auth import login_required +from rechten import recht_vereist, log +from services import gedeelde_drives_service as gd + +gedeelde_drives_bp = Blueprint('gedeelde_drives', __name__) + + +@gedeelde_drives_bp.route('/', methods=['GET']) +@login_required +@recht_vereist('gedeelde_drives') +def overzicht(): + drives, fout, opgehaald, gekozen, leden = [], None, None, None, [] + did = request.args.get('drive') or '' + vervang, lid, lid_van = None, (request.args.get('lid') or '').strip().lower(), None + try: + if lid: + lid_van = gd.drives_van(lid) + elif request.args.get('oud'): + oud, nieuw = request.args.get('oud').strip().lower(), (request.args.get('nieuw') or '').strip().lower() + vervang = {'oud': oud, 'nieuw': nieuw, 'drives': gd.drives_van(oud)} + elif did: + gekozen, leden = gd.drive(did) + else: + drives, t = gd.overzicht(vernieuw=bool(request.args.get('vernieuw'))) + opgehaald = time.strftime('%d-%m-%Y %H:%M', time.localtime(t)) + if request.args.get('vernieuw'): + return redirect(url_for('gedeelde_drives.overzicht')) + except gd.DriveFout as e: + fout = str(e) + except Exception as e: + fout = gd.vriendelijk(e) + return render_template('gedeelde_drives.html', drives=drives, fout=fout, opgehaald=opgehaald, gekozen=gekozen, + leden=leden, rollen=gd.ROLLEN, vervang=vervang, resultaat=None, lid=lid, lid_van=lid_van) + + +@gedeelde_drives_bp.route('/vervangen', methods=['POST']) +@login_required +@recht_vereist('gedeelde_drives') +def vervangen(): + oud, nieuw = request.form.get('oud'), request.form.get('nieuw') + try: + res = gd.vervang(oud, nieuw, request.form.getlist('drive'), request.form.get('verwijderen') == '1', + request.form.get('melding') == '1') + except gd.DriveFout as e: + flash(str(e), "error") + return redirect(url_for('gedeelde_drives.overzicht', oud=oud, nieuw=nieuw)) + ok = sum(1 for r in res if r['ok']) + log(f"Gedeelde drives: {oud} vervangen door {nieuw} op {ok} drive(s)") + return render_template('gedeelde_drives.html', drives=[], fout=None, opgehaald=None, gekozen=None, leden=[], + rollen=gd.ROLLEN, vervang={'oud': oud, 'nieuw': nieuw, 'drives': []}, resultaat=res, + lid='', lid_van=None) + + +def _terug(): + return redirect(url_for('gedeelde_drives.overzicht', drive=request.form.get('drive'))) + + +@gedeelde_drives_bp.route('/lid/toevoegen', methods=['POST']) +@login_required +@recht_vereist('gedeelde_drives') +def lid_toevoegen(): + did, email, rol = request.form.get('drive'), request.form.get('email'), request.form.get('rol') + try: + gd.lid_toevoegen(did, email, rol, request.form.get('melding') == '1') + log(f"Gedeelde drive {request.form.get('naam')}: {email} toegevoegd als {gd.ROL_NAAM.get(rol)}") + flash(f"{email} toegevoegd als {gd.ROL_NAAM.get(rol)}.", "success") + except gd.DriveFout as e: + flash(str(e), "error") + return _terug() + + +@gedeelde_drives_bp.route('/lid/wijzigen', methods=['POST']) +@login_required +@recht_vereist('gedeelde_drives') +def lid_wijzigen(): + rol = request.form.get('rol') + try: + gd.lid_wijzigen(request.form.get('drive'), request.form.get('perm'), rol) + log(f"Gedeelde drive {request.form.get('naam')}: {request.form.get('email')} → {gd.ROL_NAAM.get(rol)}") + flash(f"{request.form.get('email')} is nu {gd.ROL_NAAM.get(rol)}.", "success") + except gd.DriveFout as e: + flash(str(e), "error") + return _terug() + + +@gedeelde_drives_bp.route('/lid/verwijderen', methods=['POST']) +@login_required +@recht_vereist('gedeelde_drives') +def lid_verwijderen(): + try: + gd.lid_verwijderen(request.form.get('drive'), request.form.get('perm')) + log(f"Gedeelde drive {request.form.get('naam')}: {request.form.get('email')} verwijderd") + flash(f"{request.form.get('email')} verwijderd uit de drive.", "success") + except gd.DriveFout as e: + flash(str(e), "error") + return _terug() + + +@gedeelde_drives_bp.route('/nieuw', methods=['POST']) +@login_required +@recht_vereist('gedeelde_drives') +def nieuw(): + naam = request.form.get('naam') + try: + did = gd.drive_maken(naam, (request.form.get('beheerder') or '').strip() or None) + log(f"Gedeelde drive {naam} aangemaakt") + flash(f"Gedeelde drive '{naam}' aangemaakt.", "success") + return redirect(url_for('gedeelde_drives.overzicht', drive=did)) + except gd.DriveFout as e: + flash(str(e), "error") + return redirect(url_for('gedeelde_drives.overzicht')) diff --git a/blueprints/gmail_delegatie_bp.py b/blueprints/gmail_delegatie_bp.py new file mode 100644 index 0000000..816aed5 --- /dev/null +++ b/blueprints/gmail_delegatie_bp.py @@ -0,0 +1,156 @@ +from flask import Blueprint, render_template, request, redirect, url_for, flash, session, jsonify +from tenancy import huidige_school, per_school +from blueprints.auth import login_required +from rechten import recht_vereist +from services.gmail_delegation_service import GmailDelegationService, DelegationError, MAX_DELEGATES +from services.gmail_delegatie_overzicht import DelegatieOverzicht + +gmail_delegatie_bp = Blueprint('gmail_delegatie', __name__) +delegation_service = per_school(GmailDelegationService) + + +_table_ready = set() # scholen waarvoor de tabellen al gecontroleerd zijn + + +def _ensure_table(): + if huidige_school().code not in _table_ready: + try: + delegation_service.ensure_table() + _table_ready.add(huidige_school().code) + except Exception as e: + flash(f"Kon tabel gmail_delegatie_log niet aanmaken: {e}", "error") + + +def _safe_log(actie, mailbox, gedelegeerde): + try: + delegation_service.log(session.get('user'), actie, mailbox, gedelegeerde) + except Exception as e: + flash(f"Wijziging is uitgevoerd, maar kon niet gelogd worden: {e}", "warning") + + +#--------------------------------------------- +# Overzicht: mailbox zoeken en gedelegeerden tonen +#--------------------------------------------- +@gmail_delegatie_bp.route('/', methods=['GET']) +@login_required +@recht_vereist('gmail_delegatie') +def overzicht(): + _ensure_table() + zoek = (request.args.get('zoek') or '').strip() + mailbox_param = (request.args.get('mailbox') or '').strip() + + zoekresultaten, mailbox, delegates, fout = [], None, [], None + + # Zoekterm zonder @ = zoeken op naam; met @ = direct die mailbox openen + if zoek and '@' not in zoek: + zoekresultaten = delegation_service.search_users(zoek) + if not zoekresultaten: + fout = f"Geen gebruikers gevonden voor '{zoek}'." + elif zoek and not mailbox_param: + mailbox_param = zoek + + if mailbox_param: + try: + mailbox = delegation_service.resolve_user(mailbox_param) + delegates = delegation_service.list_delegates(mailbox['email']) + DelegatieOverzicht().bewaar_mailbox(mailbox['email'], mailbox['naam'], delegates) # overzicht actueel houden + except DelegationError as e: + fout = str(e) + + try: + geschiedenis = delegation_service.history(mailbox['email'] if mailbox else None) + except Exception: + geschiedenis = [] + + # Alle lopende machtigingen (achtergrondtaak, vanzelf vernieuwd als ze ouder zijn dan een dag) + ov = DelegatieOverzicht() + machtigingen, laatst, ov_fout = [], None, None + try: + ov.ensure_table() + if ov.verouderd(): + ov.sync_op_achtergrond() + machtigingen, laatst = ov.alle(), ov.laatst_opgehaald() + except Exception as e: + ov_fout = f"Het overzicht kon niet gelezen worden: {e}" + + return render_template('gmail_delegatie.html', zoek=zoek, zoekresultaten=zoekresultaten, + mailbox=mailbox, delegates=delegates, fout=fout, + geschiedenis=geschiedenis, max_delegates=MAX_DELEGATES, + machtigingen=machtigingen, laatst=laatst, ov_fout=ov_fout, ov_status=ov.status) + + +@gmail_delegatie_bp.route('/overzicht/vernieuwen', methods=['POST']) +@login_required +@recht_vereist('gmail_delegatie') +def overzicht_vernieuwen(): + if DelegatieOverzicht().sync_op_achtergrond(): + flash("Alle mailboxen worden nagekeken. Dit kan enkele minuten duren; de tabel vernieuwt vanzelf.", "info") + else: + flash("Er loopt al een ophaling.", "warning") + return redirect(url_for('gmail_delegatie.overzicht')) + + +@gmail_delegatie_bp.route('/overzicht/status.json', methods=['GET']) +@login_required +@recht_vereist('gmail_delegatie') +def overzicht_status(): + s = DelegatieOverzicht().status + return jsonify(bezig=s['bezig'], voortgang=s['voortgang'], totaal=s['totaal'], fout=s['fout'], resultaat=s['resultaat']) + + +def _ververs_mailbox(mailbox): + """Na een wijziging: de rijen van deze mailbox in het overzicht opnieuw opvragen.""" + try: + m = delegation_service.resolve_user(mailbox) + DelegatieOverzicht().bewaar_mailbox(m['email'], m['naam'], delegation_service.list_delegates(m['email'])) + except Exception: + pass + + +#--------------------------------------------- +# Gedelegeerde toevoegen +#--------------------------------------------- +@gmail_delegatie_bp.route('/toevoegen', methods=['POST']) +@login_required +@recht_vereist('gmail_delegatie') +def toevoegen(): + _ensure_table() + mailbox_in = request.form.get('mailbox', '') + delegate_in = request.form.get('delegate', '') + try: + mailbox = delegation_service.resolve_user(mailbox_in) + delegate = delegation_service.resolve_user(delegate_in) + if delegate['geschorst']: + raise DelegationError(f"{delegate['email']} is geschorst en kan geen toegang krijgen.") + if len(delegation_service.list_delegates(mailbox['email'])) >= MAX_DELEGATES: + raise DelegationError(f"{mailbox['email']} heeft al het maximum van {MAX_DELEGATES} gedelegeerden.") + delegation_service.add_delegate(mailbox['email'], delegate['email']) + _safe_log('toegevoegd', mailbox['email'], delegate['email']) + _ververs_mailbox(mailbox['email']) + extra = f" (alias {delegate_in.strip()} omgezet naar hoofdadres)" if delegate['is_alias'] else "" + flash(f"{delegate['email']} heeft nu toegang tot {mailbox['email']}{extra}. " + "Het kan tot een minuut duren voor de mailbox zichtbaar is.", "success") + return redirect(url_for('gmail_delegatie.overzicht', mailbox=mailbox['email'])) + except DelegationError as e: + flash(str(e), "error") + return redirect(url_for('gmail_delegatie.overzicht', mailbox=mailbox_in.strip())) + + +#--------------------------------------------- +# Gedelegeerde verwijderen +#--------------------------------------------- +@gmail_delegatie_bp.route('/verwijderen', methods=['POST']) +@login_required +@recht_vereist('gmail_delegatie') +def verwijderen(): + _ensure_table() + mailbox = (request.form.get('mailbox') or '').strip().lower() + delegate = (request.form.get('delegate') or '').strip().lower() + try: + delegation_service.remove_delegate(mailbox, delegate) + _safe_log('verwijderd', mailbox, delegate) + _ververs_mailbox(mailbox) + flash(f"Toegang van {delegate} tot {mailbox} is ingetrokken.", "success") + except DelegationError as e: + flash(str(e), "error") + return redirect(url_for('gmail_delegatie.overzicht', mailbox=mailbox)) diff --git a/blueprints/gmail_labels_bp.py b/blueprints/gmail_labels_bp.py new file mode 100644 index 0000000..a7cdc4b --- /dev/null +++ b/blueprints/gmail_labels_bp.py @@ -0,0 +1,84 @@ +"""Google › E-mails met een label verplaatsen of kopiëren naar een andere mailbox.""" +from flask import Blueprint, render_template, request, redirect, url_for, flash, session, jsonify + +from blueprints.auth import login_required +from rechten import recht_vereist, log +from services import gmail_label_service as gl +from services.gmail_delegation_service import GmailDelegationService, DelegationError + +gmail_labels_bp = Blueprint('gmail_labels', __name__) + + +def _mailbox(waarde): + """E-mailadres → {'email', 'naam', ...} via Google (hoofdadres, ook als er een alias ingegeven werd).""" + return GmailDelegationService().resolve_user(waarde) + + +@gmail_labels_bp.route('/', methods=['GET']) +@login_required +@recht_vereist('gmail_labels') +def overzicht(): + bron_in = (request.args.get('bron') or '').strip() + doel_in = (request.args.get('doel') or '').strip() + label_id = (request.args.get('label') or '').strip() + bron = doel = None + labels, fout, gekozen = [], None, None + if bron_in: + try: + bron = _mailbox(bron_in) + labels = gl.labels(bron['email']) + gekozen = next((l for l in labels if l['id'] == label_id), None) + except (DelegationError, gl.LabelFout) as e: + fout = str(e) + except Exception as e: + fout = gl.vriendelijk(e) + if doel_in and not fout: + try: + doel = _mailbox(doel_in) + if bron and doel['email'] == bron['email']: + fout, doel = "De doelmailbox moet een andere mailbox zijn dan de bronmailbox.", None + except DelegationError as e: + fout = str(e) + try: + geschiedenis = gl.geschiedenis() + except Exception: + geschiedenis = [] + return render_template('gmail_labels.html', bron_in=bron_in, doel_in=doel_in, bron=bron, doel=doel, + labels=labels, gekozen=gekozen, fout=fout, status=gl.LabelVerplaatser().status, + geschiedenis=geschiedenis, scope=gl.SCOPE) + + +@gmail_labels_bp.route('/start', methods=['POST']) +@login_required +@recht_vereist('gmail_labels') +def start(): + f = request.form + terug = dict(bron=f.get('bron'), doel=f.get('doel'), label=f.get('label')) + modus = 'verplaatsen' if f.get('modus') == 'verplaatsen' else 'kopieren' + try: + bron, doel = _mailbox(f.get('bron')), _mailbox(f.get('doel')) + if bron['email'] == doel['email']: + raise DelegationError("De doelmailbox moet een andere mailbox zijn dan de bronmailbox.") + label = next((l for l in gl.labels(bron['email']) if l['id'] == f.get('label')), None) + if not label: + raise gl.LabelFout("Dat label bestaat niet (meer) in de bronmailbox.") + except (DelegationError, gl.LabelFout) as e: + flash(str(e), "error") + return redirect(url_for('gmail_labels.overzicht', **terug)) + door = session.get('naam') or session.get('user') + if gl.LabelVerplaatser().start(bron['email'], label['id'], label['naam'], doel['email'], modus, door): + log(f"Gmail: label '{label['naam']}' {modus} van {bron['email']} naar {doel['email']}") + flash(f"Gestart: de berichten met label '{label['naam']}' worden {'verplaatst' if modus == 'verplaatsen' else 'gekopieerd'} " + f"naar {doel['email']}. Je mag deze pagina sluiten; het gaat verder op de achtergrond.", "info") + else: + flash("Er loopt al een opdracht. Wacht tot die klaar is.", "warning") + return redirect(url_for('gmail_labels.overzicht', **terug)) + + +@gmail_labels_bp.route('/status.json', methods=['GET']) +@login_required +@recht_vereist('gmail_labels') +def status(): + s = gl.LabelVerplaatser().status + return jsonify({k: s.get(k) for k in ('bezig', 'voortgang', 'totaal', 'gelukt', 'overgeslagen', 'fouten', 'fout', + 'resultaat', 'opdracht', 'foutvoorbeelden')}) diff --git a/blueprints/google_admin.py b/blueprints/google_admin.py new file mode 100644 index 0000000..af03787 --- /dev/null +++ b/blueprints/google_admin.py @@ -0,0 +1,112 @@ +from flask import Blueprint, request, flash, redirect, url_for, render_template, make_response, jsonify +from services.google_service import GoogleAdminService +from blueprints.auth import login_required +from rechten import recht_vereist +import rechten +from config import Config +from tenancy import per_school +from datetime import datetime +import io +from xhtml2pdf import pisa + +google_bp = Blueprint('google', __name__) +google_service = per_school(GoogleAdminService) + +#------------------------------------------------- +# Passwoord reset route +#------------------------------------------------- +@google_bp.route('/reset_pw', methods=['POST']) +@login_required +@recht_vereist('google_wachtwoord') +def reset_pw(): + email = request.form.get('email') + nieuw_wachtwoord = Config.STANDAARD_WACHTWOORD + + if not email: + flash("Geen e-mailadres opgegeven.", "error") + return redirect(url_for('google.password_reset')) + + success, message = google_service.change_password(email, nieuw_wachtwoord) + + if success: + rechten.log(actie=f"PW Reset voor {email}") # tabel Logs (centrale database) + flash(f"Wachtwoord voor {email} is gereset naar {nieuw_wachtwoord}", "success") + else: + flash(f"Google API Fout: {message}", "error") + + return redirect(url_for('google.password_reset')) + +#-------------------------------------------------- +# Route voor pagina google gebruikers +#-------------------------------------------------- + +@google_bp.route('/google_account_beheer', methods=['GET', 'POST']) +@login_required +@recht_vereist('google_wachtwoord', 'google_accounts') +def password_reset(): + results = [] + query = "" + if request.method == 'POST': + query = request.form.get('query') + results = google_service.search_users(query) + return render_template('google_beheer.html', results=results, query=query) + + +# Logica voor apply password +@google_bp.route('/apply_password', methods=['POST']) +@login_required +@recht_vereist('google_wachtwoord') +def apply_password(): + email = request.form.get('email') + new_password = request.form.get('new_password') + + success, message = google_service.change_password(email, new_password) + if success: + return "OK", 200 + else: + return message, 500 + +# Logica voor google account aanmaken +@google_bp.route('/aanmaken_google_account', methods=['POST']) +@login_required +@recht_vereist('google_accounts') +def aanmaken_google_account(): + first_name = request.form.get('first_name') + last_name = request.form.get('last_name') + password = request.form.get('password') + account_type = request.form.get('account_type') + + + # Gebruik de config vanuit de service + target_ou = Config.OU_NIEUWE_LEERKRACHTEN if account_type == "Leerkracht" else f"/{google_service.conf.OU_NEW_STUDENTS}" + + template_html = "pdf_template_leerkracht.html" if account_type == "Leerkracht" else "pdf_template_leerling.html" + + success, result = google_service.create_user(first_name, last_name, password, target_ou) + + if success: + context = { + 'naam': f"{first_name} {last_name}", + 'email': result, + 'wachtwoord': password, + 'datum': datetime.now().strftime("%d/%m/%Y") + } + html_string = render_template(template_html, **context) + pdf_buffer = io.BytesIO() + + # Gebruik pisa om de HTML om te zetten naar PDF + pisa_status = pisa.CreatePDF(io.StringIO(html_string), dest=pdf_buffer) + + if pisa_status.err: + flash("Fout bij het genereren van PDF", "error") + return redirect(url_for('google.password_reset')) + + pdf_buffer.seek(0) + response = make_response(pdf_buffer.read()) + response.headers['Content-Type'] = 'application/pdf' + response.headers['Content-Disposition'] = f'inline; filename=account_{first_name}.pdf' + return response + else: + flash(f"Google Fout: {result}", "error") + return redirect(url_for('google.password_reset')) + diff --git a/blueprints/google_licenties_bp.py b/blueprints/google_licenties_bp.py new file mode 100644 index 0000000..1df6fa3 --- /dev/null +++ b/blueprints/google_licenties_bp.py @@ -0,0 +1,95 @@ +import csv +import io +from datetime import datetime +from flask import Blueprint, render_template, request, redirect, url_for, flash, session, Response +from tenancy import huidige_school, per_school +from blueprints.auth import login_required +from rechten import recht_vereist +from services.google_license_service import GoogleLicenseService, SKU_NAMES + +google_licenties_bp = Blueprint('google_licenties', __name__) +license_service = per_school(GoogleLicenseService) + +# Tabel aanmaken bij de eerste request (niet bij import, zodat de app ook start zonder DB) +_table_ready = set() # scholen waarvoor de tabellen al gecontroleerd zijn + + +def _ensure_table(): + if huidige_school().code not in _table_ready: + try: + license_service.ensure_table() + _table_ready.add(huidige_school().code) + except Exception as e: + flash(f"Kon tabel google_licenties niet aanmaken: {e}", "error") + + +#--------------------------------------------- +# Overzichtspagina +#--------------------------------------------- +@google_licenties_bp.route('/', methods=['GET']) +@login_required +@recht_vereist('google_licenties') +def overzicht(): + _ensure_table() + data, fout = license_service.get_overview(force=request.args.get('vernieuw') == '1') + if request.args.get('vernieuw') == '1': + return redirect(url_for('google_licenties.overzicht')) + + opgehaald = None + if data: + opgehaald = datetime.fromtimestamp(data['opgehaald']).strftime('%d-%m-%Y %H:%M') + return render_template('google_licenties.html', data=data, fout=fout, + opgehaald=opgehaald, sku_names=SKU_NAMES) + + +#--------------------------------------------- +# Aangekochte aantallen opslaan +#--------------------------------------------- +@google_licenties_bp.route('/aangekocht', methods=['POST']) +@login_required +@recht_vereist('google_licenties') +def aangekocht_opslaan(): + _ensure_table() + gewijzigd = 0 + for key, waarde in request.form.items(): + if not key.startswith('aangekocht_'): + continue + sku_id = key.replace('aangekocht_', '', 1) + if sku_id not in SKU_NAMES: + continue + waarde = (waarde or '').strip() + if waarde == '': + continue + if not waarde.isdigit(): + flash(f"Ongeldig aantal voor {SKU_NAMES[sku_id]}: '{waarde}'", "error") + continue + license_service.set_purchased(sku_id, int(waarde), session.get('user')) + gewijzigd += 1 + + license_service.clear_cache() + if gewijzigd: + flash("Aangekochte aantallen opgeslagen.", "success") + return redirect(url_for('google_licenties.overzicht')) + + +#--------------------------------------------- +# Export van alle toegewezen licenties +#--------------------------------------------- +@google_licenties_bp.route('/export.csv', methods=['GET']) +@login_required +@recht_vereist('google_licenties') +def export_csv(): + data, fout = license_service.get_overview() + if fout or not data: + flash(fout or "Geen gegevens om te exporteren.", "error") + return redirect(url_for('google_licenties.overzicht')) + + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') + w.writerow(['E-mail', 'Naam', 'Organisatie-eenheid', 'Licentie', 'SKU', 'Geschorst', 'Gearchiveerd', 'Laatste login']) + for u in data['users']: + w.writerow([u['email'], u['naam'], u['ou'], u['sku_naam'], u['sku_id'], + 'ja' if u['geschorst'] else 'nee', 'ja' if u['gearchiveerd'] else 'nee', u['laatste_login']]) + bestandsnaam = f"google_licenties_{datetime.now():%Y%m%d}.csv" + return Response('' + buf.getvalue(), mimetype='text/csv', + headers={'Content-Disposition': f'attachment; filename={bestandsnaam}'}) diff --git a/blueprints/gopro_bp.py b/blueprints/gopro_bp.py new file mode 100644 index 0000000..4573426 --- /dev/null +++ b/blueprints/gopro_bp.py @@ -0,0 +1,378 @@ +""" +Scholengroep › GO! Pro: personeelsleden van de actieve school uit Informat, met een rol per personeelslid en +functie, en een export in de kolommen van het GO! Pro-importbestand. +""" +import csv +import io +import time +from datetime import date + +from flask import Blueprint, render_template, request, jsonify, Response, session, redirect, url_for, flash + +from blueprints.auth import login_required +from config import Config +from rechten import recht_vereist +from services import gopro_service as gp +from tenancy import huidige_school + +gopro_bp = Blueprint('gopro', __name__) + +CACHE_SECONDEN = 15 * 60 # Informat niet bij elke klik opnieuw bevragen + + +def _rijen(vernieuw=False): + """Personeel van de actieve school (15 minuten bewaard per school). De rollen komen altijd vers uit de database.""" + school = huidige_school() + bewaard = school.cache.get('gopro') + if vernieuw or not bewaard or time.time() - bewaard[0] > CACHE_SECONDEN: + rijen = gp.GoProService().personeel(school.domein, Config.INSTELLINGSNUMMER) + bewaard = (time.time(), rijen) + school.cache['gopro'] = bewaard + gekozen = gp.keuzes() + for r in bewaard[1]: + gp.pas_keuzes_toe(r, gekozen) + gp.markeer_dubbel(bewaard[1]) + return bewaard[1], bewaard[0] + + +def _niet_verzameld(rijen, per_soort=False): + """Laat de personeelsleden weg die al in de verzameltabel of in de rode lijst (genegeerd) staan. + Geeft (rijen, aantal weggelaten) of met per_soort=True (rijen, {'groen': n, 'genegeerd': m}).""" + sleutels = gp.verzameld_sleutels() + code = huidige_school().code + over, weg = [], {'groen': 0, 'genegeerd': 0} + for r in rijen: + soort = gp.is_verzameld(r, code, sleutels) + if soort: + weg[soort] = weg.get(soort, 0) + 1 + else: + over.append(r) + return over, (weg if per_soort else len(rijen) - len(over)) + + +@gopro_bp.route("/", methods=["GET"]) +@login_required +@recht_vereist('gopro') +def overzicht(): + school = huidige_school() + rijen, fout, opgehaald, verzameld_hier = [], None, None, {'groen': 0, 'genegeerd': 0, 'verzonden': 0} + if not school.heeft('INFORMAT_INST_NUMBER', 'INFORMAT_ID', 'INFORMAT_SECRET'): + fout = "Informat is nog niet ingesteld voor deze school (🔌 Koppelingen › Informat)." + else: + try: + rijen, t = _rijen(vernieuw=bool(request.args.get('vernieuw'))) + rijen, verzameld_hier = _niet_verzameld(rijen, per_soort=True) # verzameld of genegeerd: niet meer tonen + opgehaald = time.strftime('%d-%m-%Y %H:%M', time.localtime(t)) + except Exception as e: + fout = str(e) + return render_template("gopro.html", rijen=rijen, fout=fout, opgehaald=opgehaald, rollen=gp.ROLLEN, + domein=school.domein, school_naam=school.naam, + dubbel=sum(1 for r in rijen if r['dubbel']), verzameld_hier=verzameld_hier, + verzameld_totaal=len(gp.verzameld_alle()), + genegeerd_totaal=len(gp.verzameld_alle(soort='genegeerd')), + verzonden_school=gp.aantal_verzonden(school.code), + nacht=gp.nacht_instelling(), periode=gp.schooljaar_periode()) + + +@gopro_bp.route("/verplaats", methods=["POST"]) +@login_required +@recht_vereist('gopro') +def verplaats(): + """Eén personeelslid met de gegevens uit het venster (aangepast of niet) naar de verzameltabel.""" + from datetime import datetime as _dt + data = request.get_json(silent=True) or {} + pid = str(data.get('person_id') or '') + try: + rijen, _ = _rijen() + except Exception as e: + return jsonify(ok=False, fout=str(e)), 400 + rij = next((r for r in rijen if str(r['person_id']) == pid), None) + if not rij: + return jsonify(ok=False, fout="Personeelslid niet gevonden (haal de lijst opnieuw op)."), 404 + + def tekst(veld, maxlen): + return str(data.get(veld) or '').strip()[:maxlen] + + def datum(veld): + w = tekst(veld, 10) + if not w: + return None + try: + return _dt.strptime(w, '%Y-%m-%d').date() + except ValueError: + raise ValueError(f"Ongeldige datum: {w}") + + try: + nieuw = dict(rij) + nieuw.update(voornaam=tekst('voornaam', 100), achternaam=tekst('achternaam', 100), + email=tekst('email', 255).lower(), upn=tekst('upn', 255).lower(), + instellingsnummer=tekst('instellingsnummer', 20), functie=tekst('functie', 100), + rol=tekst('rol', 100), start=datum('start'), einde=datum('einde'), telefoon=tekst('telefoon', 50)) + except ValueError as e: + return jsonify(ok=False, fout=str(e)), 400 + if not nieuw['voornaam'] or not nieuw['achternaam']: + return jsonify(ok=False, fout="Voornaam en achternaam zijn verplicht."), 400 + if nieuw['email'] and '@' not in nieuw['email']: + return jsonify(ok=False, fout="Het e-mailadres is niet geldig."), 400 + if nieuw['start'] and nieuw['einde'] and nieuw['einde'] < nieuw['start']: + return jsonify(ok=False, fout="De einddatum ligt voor de startdatum."), 400 + toegevoegd, _ = gp.verzamel_toevoegen([nieuw], huidige_school(), session.get('naam') or session.get('user')) + if not toegevoegd: + return jsonify(ok=False, fout=f"{nieuw['email']} staat al in de verzameltabel of op de rode lijst."), 409 + return jsonify(ok=True, totaal=len(gp.verzameld_alle())) + + +@gopro_bp.route("/nachtelijk", methods=["POST"]) +@login_required +@recht_vereist('gopro') +def nachtelijk(): + """Schakelaar: elke nacht van alle scholen de groene naar de verzameltabel (of ?nu=1: meteen één keer).""" + door = session.get('naam') or session.get('user') + if request.form.get('nu') == '1': + if gp.verzamel_alle_scholen_op_achtergrond(door): + flash("De groene personeelsleden van alle scholen worden nu verzameld. Dit kan enkele minuten duren; " + "het resultaat verschijnt onder de schakelaar.", "info") + else: + flash("Er loopt al een verzameling.", "warning") + return redirect(url_for('gopro.overzicht')) + aan = request.form.get('aan') == '1' + gp.zet_nacht(aan, door) + from rechten import log + log(f"GO! Pro: nachtelijk verzamelen {'aangezet' if aan else 'uitgezet'}") + flash("Elke nacht (tussen 2 en 6 uur) worden de groene personeelsleden van alle scholen automatisch naar de " + "verzameltabel gezet." if aan else "Het automatisch verzamelen 's nachts staat uit.", "success") + return redirect(url_for('gopro.overzicht')) + + +@gopro_bp.route("/negeer", methods=["POST"]) +@login_required +@recht_vereist('gopro') +def negeer(): + """Eén personeelslid naar de rode lijst: wordt genegeerd (niet geëxporteerd en niet meer getoond).""" + data = request.get_json(silent=True) or request.form + pid = str(data.get('person_id') or '') + try: + rijen, _ = _rijen() + except Exception as e: + return jsonify(ok=False, fout=str(e)), 400 + rij = next((r for r in rijen if str(r['person_id']) == pid), None) + if not rij: + return jsonify(ok=False, fout="Personeelslid niet gevonden (haal de lijst opnieuw op)."), 404 + toegevoegd, _ = gp.verzamel_toevoegen([rij], huidige_school(), session.get('naam') or session.get('user'), + soort='genegeerd') + return jsonify(ok=True, toegevoegd=toegevoegd, totaal=len(gp.verzameld_alle(soort='genegeerd'))) + + +@gopro_bp.route("/keuze", methods=["POST"]) +@login_required +@recht_vereist('gopro') +def keuze(): + """Bewaart de gekozen functie of rol van één personeelslid (veld = functie | rol).""" + data = request.get_json(silent=True) or request.form + pid, veld = data.get('person_id') or '', data.get('veld') or '' + try: + gp.keuze_opslaan(pid, veld, data.get('waarde') or '', session.get('user')) + except ValueError as e: + return jsonify(ok=False, fout=str(e)), 400 + # De waarde die nu geldt (bij een leeg gemaakt e-mail/UPN-veld: weer het standaardadres) + waarde = data.get('waarde') + bewaard = huidige_school().cache.get('gopro') + if bewaard and veld in ('email', 'upn'): + rij = next((r for r in bewaard[1] if r['person_id'] == pid), None) + if rij: + gp.pas_keuzes_toe(rij, gp.keuzes()) + waarde = rij[veld] + return jsonify(ok=True, waarde=waarde) + + +@gopro_bp.route("/google.json", methods=["POST"]) +@login_required +@recht_vereist('gopro') +def google_check(): + """Welke van de doorgestuurde adressen bestaan in Google Workspace: {adres: 'primair' | 'alias'}.""" + data = request.get_json(silent=True) or {} + gevraagd = [str(a).strip().lower() for a in data.get('adressen') or [] if a][:5000] + try: + bestaand = gp.google_adressen(vernieuw=bool(data.get('vernieuw'))) + except Exception as e: + return jsonify(ok=False, fout=f"Google kon niet bevraagd worden: {e}"), 200 + return jsonify(ok=True, adressen={a: bestaand[a] for a in set(gevraagd) if a in bestaand}) + + +@gopro_bp.route("/export.csv", methods=["GET"]) +@login_required +@recht_vereist('gopro') +def export(): + """CSV in de kolommen van het GO! Pro-importbestand (; als scheidingsteken, UTF-8, datums dd/mm/jjjj).""" + try: + rijen, _ = _rijen() + rijen, _ = _niet_verzameld(rijen) + except Exception as e: + flash(str(e), "error") + return redirect(url_for('gopro.overzicht')) + # ?kleur=account|alias|geen → enkel die rijen, net als de kleurfilter op de pagina + kleur = request.args.get('kleur') or '' + if kleur in ('account', 'alias', 'geen'): + try: + google = gp.google_adressen() + except Exception as e: + flash(f"Google kon niet bevraagd worden, dus de kleurfilter kan niet toegepast worden: {e}", "error") + return redirect(url_for('gopro.overzicht')) + rijen = [r for r in rijen if gp.google_kleur(r, google) == kleur] + datum = lambda d: d.strftime('%d/%m/%Y') if d else '' + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') + w.writerow(gp.EXPORT_KOLOMMEN) + for r in rijen: + w.writerow([r['voornaam'], r['achternaam'], r['email'], r['upn'], r['email'], r['instellingsnummer'], + r['functie'], r['rol'], datum(r['start']), datum(r['einde']), r['telefoon']]) + return Response('\ufeff' + buf.getvalue(), mimetype='text/csv; charset=utf-8', headers={ + 'Content-Disposition': f"attachment; filename=GO_Pro_{huidige_school().code}" + f"{'_' + {'account': 'met_account', 'alias': 'alias', 'geen': 'zonder_account'}[kleur] if kleur in ('account', 'alias', 'geen') else ''}" + f"_{date.today():%Y%m%d}.csv"}) + + +def _csv(rijen, bestandsnaam): + """CSV in de kolommen van het GO! Pro-importbestand. `rijen` = [(voornaam, achternaam, email, upn, instelling, + functie, rol, start, einde, telefoon)].""" + datum = lambda d: d.strftime('%d/%m/%Y') if d else '' + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') + w.writerow(gp.EXPORT_KOLOMMEN) + for vn, an, em, upn, inst, fu, rol, st, ei, tel in rijen: + w.writerow([vn, an, em, upn, em, inst, fu, rol, datum(st), datum(ei), tel]) + return Response('\ufeff' + buf.getvalue(), mimetype='text/csv; charset=utf-8', + headers={'Content-Disposition': f"attachment; filename={bestandsnaam}"}) + + +# --------------------------------------------------------------------- +# Verzameltabel: de groene personeelsleden van alle scholen samen +# --------------------------------------------------------------------- +@gopro_bp.route("/verzamel", methods=["POST"]) +@login_required +@recht_vereist('gopro') +def verzamel(): + """Zet alle personeelsleden met een account in Google (groen) van de actieve school in de verzameltabel.""" + school = huidige_school() + try: + rijen, _ = _rijen() + rijen, _ = _niet_verzameld(rijen) + google = gp.google_adressen() + except Exception as e: + flash(f"Kon niet verzamelen: {e}", "error") + return redirect(url_for('gopro.overzicht')) + groen = [r for r in rijen if gp.google_kleur(r, google) == 'account'] + if not groen: + flash("Er zijn geen (nieuwe) groene personeelsleden om toe te voegen.", "warning") + return redirect(url_for('gopro.overzicht')) + toegevoegd, overgeslagen = gp.verzamel_toevoegen(groen, school, session.get('naam') or session.get('user')) + from rechten import log + log(f"GO! Pro: {toegevoegd} personeelsleden van {school.code} naar de verzameltabel") + flash(f"{toegevoegd} personeelsleden van {school.naam} toegevoegd aan de verzameltabel" + f"{f' ({overgeslagen} stonden er al in met hetzelfde e-mailadres)' if overgeslagen else ''}. " + "Ze worden hier niet meer getoond.", "success") + return redirect(url_for('gopro.overzicht')) + + +LIJSTEN = {'groen': 'groen', 'rood': 'genegeerd', 'verzonden': 'verzonden'} +LIJSTNAMEN = {'groen': 'de verzameltabel', 'rood': 'de rode lijst', 'verzonden': 'de lijst met verzonden personeelsleden'} + + +def _lijst(waarde): + return waarde if waarde in LIJSTEN else 'groen' + + +@gopro_bp.route("/verzameltabel", methods=["GET"]) +@login_required +@recht_vereist('gopro') +def verzameltabel(): + """?lijst=rood → de rode lijst (genegeerd), ?lijst=verzonden → al verzonden, anders de groene verzameltabel.""" + lijst = _lijst(request.args.get('lijst')) + rijen = gp.verzameld_alle(soort=LIJSTEN[lijst]) + scholen = sorted({(r['School_code'], r['School_naam'] or r['School_code']) for r in rijen}, key=lambda x: x[1].lower()) + per_soort = gp.aantallen() + aantal = {k: (len(rijen) if k == lijst else per_soort.get(v, 0)) for k, v in LIJSTEN.items()} + from collections import Counter + per_school = Counter(r['School_code'] for r in rijen) + return render_template("gopro_verzameld.html", rijen=rijen, scholen=scholen, rollen=gp.ROLLEN, per_school=per_school, + huidige=huidige_school().code, lijst=lijst, rood=lijst == 'rood', + verzonden=lijst == 'verzonden', aantal=aantal, + aantal_groen=aantal['groen'], aantal_rood=aantal['rood']) + + +@gopro_bp.route("/verzameltabel/naar-rood", methods=["POST"]) +@login_required +@recht_vereist('gopro') +def verzameltabel_naar_rood(): + """Eén personeelslid uit de verzameltabel naar de rode lijst (genegeerd: niet exporteren, nooit meer tonen).""" + from database import central_query + from rechten import log + gp.verzamel_ensure() + n = central_query("UPDATE GoPro_verzameltabel SET Soort = 'genegeerd', Door = %s, Toegevoegd = NOW() " + "WHERE ID = %s AND Soort = 'groen'", + (session.get('naam') or session.get('user'), request.form.get('id')), commit=True) + if n: + log(f"GO! Pro: {request.form.get('naam')} van de verzameltabel naar de rode lijst") + melding = (f"{request.form.get('naam')} staat nu op de rode lijst." if n + else "Dit personeelslid staat niet (meer) in de verzameltabel.") + if request.headers.get('X-Requested-With') == 'fetch': # vanuit de tabel: zoekopdracht blijft staan + return jsonify(ok=bool(n), melding=melding) + flash(melding, "success" if n else "error") + return redirect(url_for('gopro.verzameltabel')) + + +@gopro_bp.route("/verzameltabel/verzonden", methods=["POST"]) +@login_required +@recht_vereist('gopro') +def verzameltabel_verzonden(): + """De verzameltabel (of één school, school=...) markeren als verzonden naar GO! Pro.""" + from rechten import log + code = request.form.get('school') or None + n = gp.markeer_verzonden(session.get('naam') or session.get('user'), code) + log(f"GO! Pro: {n} personeelsleden{' van ' + code if code else ''} gemarkeerd als verzonden") + flash(f"{n} personeelsleden gemarkeerd als verzonden. Ze worden niet meer aan de verzameltabel toegevoegd.", "success") + return redirect(url_for('gopro.verzameltabel')) + + +@gopro_bp.route("/verzameltabel/export.csv", methods=["GET"]) +@login_required +@recht_vereist('gopro') +def verzameltabel_export(): + """Eén CSV voor GO! Pro met alle scholen (of ?school=code voor één school).""" + code = request.args.get('school') or None + lijst = 'verzonden' if request.args.get('lijst') == 'verzonden' else 'groen' + rijen = gp.verzameld_alle(code, LIJSTEN[lijst]) + return _csv([(r['Voornaam'], r['Achternaam'], r['Email'], r['UPN'], r['Instellingsnummer'], r['Functie'], r['Rol'], + r['Startdatum'], r['Einddatum'], r['Telefoon']) for r in rijen], + f"GO_Pro_{'verzonden_' if lijst == 'verzonden' else ''}{code or 'alle_scholen'}_{date.today():%Y%m%d}.csv") + + +@gopro_bp.route("/verzameltabel/verwijderen", methods=["POST"]) +@login_required +@recht_vereist('gopro') +def verzameltabel_verwijderen(): + """Eén rij (id=...), alle rijen van één school (school=...) of alles (alles=1) uit de verzameltabel halen. + Die personeelsleden verschijnen dan weer op de GO! Pro-pagina van hun school.""" + from database import central_query + from rechten import log + gp.verzamel_ensure() + lijst = _lijst(request.form.get('lijst')) + soort, naam = LIJSTEN[lijst], LIJSTNAMEN[lijst] + if request.form.get('id'): + n = central_query("DELETE FROM GoPro_verzameltabel WHERE ID = %s AND Soort = %s", + (request.form.get('id'), soort), commit=True) + if request.headers.get('X-Requested-With') == 'fetch': # vanuit de tabel: zoekopdracht blijft staan + return jsonify(ok=bool(n), melding=f"Personeelslid uit {naam} gehaald." if n else "Niet (meer) gevonden.") + flash(f"Personeelslid uit {naam} gehaald.", "success") + elif request.form.get('school'): + code = request.form.get('school') + n = len(gp.verzameld_alle(code, soort)) + central_query("DELETE FROM GoPro_verzameltabel WHERE School_code = %s AND Soort = %s", (code, soort), commit=True) + log(f"GO! Pro: {n} rijen van {code} uit {naam} gehaald") + flash(f"{n} personeelsleden van deze school uit {naam} gehaald.", "success") + elif request.form.get('alles') == '1': + n = len(gp.verzameld_alle(soort=soort)) + central_query("DELETE FROM GoPro_verzameltabel WHERE Soort = %s", (soort,), commit=True) + log(f"GO! Pro: {naam} leeggemaakt ({n} rijen)") + flash(f"{naam[0].upper() + naam[1:]} leeggemaakt ({n} personeelsleden).", "success") + return redirect(url_for('gopro.verzameltabel', lijst=None if lijst == 'groen' else lijst)) diff --git a/blueprints/handleidingen_bp.py b/blueprints/handleidingen_bp.py new file mode 100644 index 0000000..989e150 --- /dev/null +++ b/blueprints/handleidingen_bp.py @@ -0,0 +1,273 @@ +""" +📘 Handleidingen: stappenplannen voor het beheer (bv. Google Admin). + +- Lezen: iedereen met een PIVOT-account (handleidingen met Zichtbaar = 'admins' enkel administrators). + Leerkrachten die enkel met Google inloggen (zonder PIVOT-account) zien ze niet. +- Aanmaken, bewerken, verwijderen, vorige versie terugzetten: enkel administrators. + +Handleidingen staan in de centrale database: ze gelden voor alle scholen. +Elke opslag bewaart de vorige tekst in Handleidingen_versies. +""" +import re +import unicodedata + +from flask import Blueprint, render_template, request, redirect, url_for, flash, session, abort + +import rechten +from blueprints.auth import login_required +from database import central_query, central_insert +from rechten import admin_vereist, is_admin +from services.html_schoon import schoon + +handleidingen_bp = Blueprint('handleidingen', __name__) + +ZICHTBAAR = {'iedereen': 'Iedereen met een PIVOT-account', 'admins': 'Enkel administrators'} +MAX_VERSIES = 30 + + +def mag_lezen(): + return is_admin() or bool(session.get('gebruiker_id')) + + +def _zichtbaar_filter(): + return ("Zichtbaar IN ('iedereen', 'admins')" if is_admin() else "Zichtbaar = 'iedereen'") + + +def lijst(): + """Zichtbare handleidingen voor de ingelogde gebruiker (ook gebruikt door het dashboard).""" + if not mag_lezen(): + return [] + try: + return central_query(f"SELECT Handleiding_ID, Slug, Titel, Categorie, Samenvatting, Zichtbaar, Gewijzigd_op, " + f"Gewijzigd_door FROM Handleidingen WHERE {_zichtbaar_filter()} " + f"ORDER BY Volgorde, Titel") + except Exception: + return [] + + +def _maak_slug(titel, behalve=None): + s = unicodedata.normalize('NFKD', titel).encode('ascii', 'ignore').decode().lower() + s = re.sub(r'[^a-z0-9]+', '-', s).strip('-')[:80] or 'handleiding' + if s == 'nieuw': # botst met de route /handleidingen/nieuw + s = 'nieuw-1' + kandidaat, n = s, 2 + while central_query("SELECT 1 FROM Handleidingen WHERE Slug = %s AND Handleiding_ID <> %s", + (kandidaat, behalve or 0)): + kandidaat, n = f"{s}-{n}", n + 1 + return kandidaat + + +def _haal(slug): + rows = central_query(f"SELECT * FROM Handleidingen WHERE Slug = %s AND {_zichtbaar_filter()}", (slug,)) + return rows[0] if rows else None + + +def _inhoudstafel(html): + """[(id, tekst, niveau)] van de h2/h3-koppen; koppen zonder id krijgen er een.""" + gezien, toc = set(), [] + + def vervang(m): + tag, attrs, tekst = m.group(1), m.group(2) or '', m.group(3) + platte = re.sub(r'<[^>]+>', '', tekst).strip() + idm = re.search(r'id="([^"]+)"', attrs) + hid = idm.group(1) if idm else (re.sub(r'[^a-z0-9]+', '-', platte.lower()).strip('-') or 'kop') + basis, n = hid, 2 + while hid in gezien: + hid, n = f"{basis}-{n}", n + 1 + gezien.add(hid) + toc.append((hid, platte, int(tag[1]))) + attrs = re.sub(r'\s*id="[^"]*"', '', attrs) + return f'<{tag} id="{hid}"{attrs}>{tekst}' + + html = re.sub(r'<(h[23])((?:\s[^>]*)?)>(.*?)', vervang, schoon(html or ''), flags=re.S) + return html, toc + + +# ------------------------------------------------------------------ +# Lezen +# ------------------------------------------------------------------ +@handleidingen_bp.route('/', methods=['GET']) +@login_required +def overzicht(): + if not mag_lezen(): + flash("Handleidingen zijn enkel beschikbaar voor PIVOT-gebruikers.", "error") + return redirect(url_for('main.dashboard')) + q = (request.args.get('q') or '').strip() + items = lijst() + if q: + treffers = {r['Handleiding_ID'] for r in central_query( + f"SELECT Handleiding_ID FROM Handleidingen WHERE {_zichtbaar_filter()} AND " + "(Titel LIKE %s OR Samenvatting LIKE %s OR Inhoud LIKE %s)", (f"%{q}%",) * 3)} + items = [h for h in items if h['Handleiding_ID'] in treffers] + per_cat = {} + for h in items: + per_cat.setdefault(h['Categorie'] or 'Algemeen', []).append(h) + return render_template('handleidingen.html', per_cat=per_cat, q=q, ZICHTBAAR=ZICHTBAAR) + + +@handleidingen_bp.route('/', methods=['GET']) +@login_required +def bekijk(slug): + if not mag_lezen(): + return redirect(url_for('main.dashboard')) + h = _haal(slug) + if not h: + flash("Deze handleiding bestaat niet (meer).", "error") + return redirect(url_for('handleidingen.overzicht')) + inhoud, toc = _inhoudstafel(h['Inhoud']) + return render_template('handleiding.html', h=h, inhoud=inhoud, toc=toc, ZICHTBAAR=ZICHTBAAR) + + +# ------------------------------------------------------------------ +# Bewerken (enkel administrators) +# ------------------------------------------------------------------ +def _formulier(): + titel = (request.form.get('titel') or '').strip()[:200] + return { + 'Titel': titel, + 'Categorie': (request.form.get('categorie') or '').strip()[:100] or None, + 'Samenvatting': (request.form.get('samenvatting') or '').strip()[:300] or None, + 'Inhoud': schoon(request.form.get('inhoud') or ''), + 'Zichtbaar': request.form.get('zichtbaar') if request.form.get('zichtbaar') in ZICHTBAAR else 'iedereen', + 'Volgorde': request.form.get('volgorde', type=int) or 0, + } + + +def _te_groot(e): + t = str(e) + if 'max_allowed_packet' in t or 'too large' in t.lower() or '1153' in t: + return (": de handleiding is te groot voor de database (te veel of te grote afbeeldingen). Verdeel ze over " + "meerdere handleidingen, of verhoog max_allowed_packet in MySQL.") + return f": {t}" + + +def _categorieen(): + return [r['Categorie'] for r in central_query( + "SELECT DISTINCT Categorie FROM Handleidingen WHERE Categorie IS NOT NULL AND Zichtbaar <> 'weg' ORDER BY Categorie")] + + +@handleidingen_bp.route('/nieuw', methods=['GET', 'POST']) +@login_required +@admin_vereist +def nieuw(): + if request.method == 'POST': + f = _formulier() + if not f['Titel']: + flash("Geef de handleiding een titel.", "error") + return render_template('handleiding_bewerken.html', h=f, nieuw=True, categorieen=_categorieen(), + ZICHTBAAR=ZICHTBAAR, versies=[]) + slug = _maak_slug(f['Titel']) + try: + central_insert("INSERT INTO Handleidingen (Slug, Titel, Categorie, Samenvatting, Inhoud, Zichtbaar, " + "Volgorde, Gewijzigd_op, Gewijzigd_door) VALUES (%s, %s, %s, %s, %s, %s, %s, NOW(), %s)", + (slug, f['Titel'], f['Categorie'], f['Samenvatting'], f['Inhoud'], f['Zichtbaar'], + f['Volgorde'], session.get('user'))) + except Exception as e: + flash(f"Opslaan mislukt{_te_groot(e)}", "error") + return render_template('handleiding_bewerken.html', h=f, nieuw=True, categorieen=_categorieen(), + ZICHTBAAR=ZICHTBAAR, versies=[]) + rechten.log(actie=f"Handleiding '{f['Titel']}' aangemaakt") + flash("Handleiding aangemaakt.", "success") + return redirect(url_for('handleidingen.bekijk', slug=slug)) + leeg = {'Titel': '', 'Categorie': request.args.get('categorie') or '', 'Samenvatting': '', 'Inhoud': '', + 'Zichtbaar': 'iedereen', 'Volgorde': 100} + return render_template('handleiding_bewerken.html', h=leeg, nieuw=True, categorieen=_categorieen(), + ZICHTBAAR=ZICHTBAAR, versies=[]) + + +@handleidingen_bp.route('//bewerken', methods=['GET', 'POST']) +@login_required +@admin_vereist +def bewerken(slug): + h = _haal(slug) + if not h: + abort(404) + if request.method == 'POST': + f = _formulier() + if not f['Titel']: + flash("De titel mag niet leeg zijn.", "error") + return redirect(url_for('handleidingen.bewerken', slug=slug)) + if f['Titel'] != h['Titel'] or f['Inhoud'] != (h['Inhoud'] or ''): + central_query("INSERT INTO Handleidingen_versies (Handleiding_ID, Titel, Inhoud, Opgeslagen_op, Door) " + "VALUES (%s, %s, %s, %s, %s)", + (h['Handleiding_ID'], h['Titel'], h['Inhoud'], h['Gewijzigd_op'], h['Gewijzigd_door']), + commit=True) + _versies_opruimen(h['Handleiding_ID']) + try: + central_query("UPDATE Handleidingen SET Titel = %s, Categorie = %s, Samenvatting = %s, Inhoud = %s, " + "Zichtbaar = %s, Volgorde = %s, Gewijzigd_op = NOW(), Gewijzigd_door = %s " + "WHERE Handleiding_ID = %s", + (f['Titel'], f['Categorie'], f['Samenvatting'], f['Inhoud'], f['Zichtbaar'], f['Volgorde'], + session.get('user'), h['Handleiding_ID']), commit=True) + except Exception as e: + flash(f"Opslaan mislukt{_te_groot(e)}", "error") + return redirect(url_for('handleidingen.bewerken', slug=slug)) + rechten.log(actie=f"Handleiding '{f['Titel']}' bewerkt") + flash("Handleiding opgeslagen.", "success") + if request.form.get('verder'): + return redirect(url_for('handleidingen.bewerken', slug=slug)) + return redirect(url_for('handleidingen.bekijk', slug=slug)) + versies = central_query("SELECT Versie_ID, Titel, Opgeslagen_op, Door FROM Handleidingen_versies " + "WHERE Handleiding_ID = %s ORDER BY Opgeslagen_op DESC, Versie_ID DESC", + (h['Handleiding_ID'],)) + h['Inhoud'] = schoon(h['Inhoud'] or '') + return render_template('handleiding_bewerken.html', h=h, nieuw=False, categorieen=_categorieen(), + ZICHTBAAR=ZICHTBAAR, versies=versies) + + +def _versies_opruimen(hid): + oud = central_query("SELECT Versie_ID FROM Handleidingen_versies WHERE Handleiding_ID = %s " + "ORDER BY Opgeslagen_op DESC, Versie_ID DESC", (hid,))[MAX_VERSIES:] + for r in oud: + central_query("DELETE FROM Handleidingen_versies WHERE Versie_ID = %s", (r['Versie_ID'],), commit=True) + + +@handleidingen_bp.route('//versie/', methods=['GET']) +@login_required +@admin_vereist +def versie(slug, vid): + h = _haal(slug) + rows = central_query("SELECT * FROM Handleidingen_versies WHERE Versie_ID = %s AND Handleiding_ID = %s", + (vid, h['Handleiding_ID'] if h else 0)) + if not h or not rows: + abort(404) + v = rows[0] + inhoud, toc = _inhoudstafel(v['Inhoud']) + return render_template('handleiding.html', h=h, inhoud=inhoud, toc=toc, versie=v, ZICHTBAAR=ZICHTBAAR) + + +@handleidingen_bp.route('//versie//terugzetten', methods=['POST']) +@login_required +@admin_vereist +def terugzetten(slug, vid): + h = _haal(slug) + rows = central_query("SELECT * FROM Handleidingen_versies WHERE Versie_ID = %s AND Handleiding_ID = %s", + (vid, h['Handleiding_ID'] if h else 0)) + if not h or not rows: + abort(404) + v = rows[0] + central_query("INSERT INTO Handleidingen_versies (Handleiding_ID, Titel, Inhoud, Opgeslagen_op, Door) " + "VALUES (%s, %s, %s, %s, %s)", + (h['Handleiding_ID'], h['Titel'], h['Inhoud'], h['Gewijzigd_op'], h['Gewijzigd_door']), commit=True) + central_query("UPDATE Handleidingen SET Titel = %s, Inhoud = %s, Gewijzigd_op = NOW(), Gewijzigd_door = %s " + "WHERE Handleiding_ID = %s", (v['Titel'], v['Inhoud'], session.get('user'), h['Handleiding_ID']), + commit=True) + _versies_opruimen(h['Handleiding_ID']) + rechten.log(actie=f"Handleiding '{v['Titel']}': versie van {v['Opgeslagen_op']:%d-%m-%Y %H:%M} teruggezet") + flash(f"Versie van {v['Opgeslagen_op']:%d-%m-%Y %H:%M} teruggezet. De vorige tekst staat bij de versies.", "success") + return redirect(url_for('handleidingen.bekijk', slug=slug)) + + +@handleidingen_bp.route('//verwijderen', methods=['POST']) +@login_required +@admin_vereist +def verwijderen(slug): + h = _haal(slug) + if not h: + abort(404) + # Verbergen i.p.v. wissen: zo komt een meegeleverde handleiding niet terug bij het opstarten + central_query("UPDATE Handleidingen SET Zichtbaar = 'weg', Gewijzigd_op = NOW(), Gewijzigd_door = %s " + "WHERE Handleiding_ID = %s", (session.get('user'), h['Handleiding_ID']), commit=True) + rechten.log(actie=f"Handleiding '{h['Titel']}' verwijderd") + flash(f"Handleiding '{h['Titel']}' verwijderd.", "success") + return redirect(url_for('handleidingen.overzicht')) diff --git a/blueprints/handtekeningen_bp.py b/blueprints/handtekeningen_bp.py new file mode 100644 index 0000000..f78110f --- /dev/null +++ b/blueprints/handtekeningen_bp.py @@ -0,0 +1,179 @@ +"""Gmail › Handtekeningen: sjabloon, logo, OU's, functie/telefoon (Google) en toepassen in Gmail.""" +import time + +from flask import Blueprint, render_template, request, redirect, url_for, flash, session, jsonify, Response, abort + +from blueprints.auth import login_required +from rechten import recht_vereist, log +from services import handtekening_service as hs +from tenancy import huidige_school, school_op_code, in_school + +handtekeningen_bp = Blueprint('handtekeningen', __name__) +handtekening_logo_bp = Blueprint('handtekening_logo', __name__) # publiek (Gmail haalt het logo op) + +CACHE_SECONDEN = 5 * 60 + + +def _door(): + return session.get('naam') or session.get('user') + + +def _gebruikers(inst, vernieuw=False): + school = huidige_school() + sleutel = ('handtekening_gebruikers', tuple(inst['ous']), bool(inst.get('Met_sub_ous'))) + bewaard = school.cache.get('handtekening_gebruikers') + if bewaard and not vernieuw and bewaard[0] == sleutel and time.time() - bewaard[1] < CACHE_SECONDEN: + return bewaard[2] + lijst = hs.gebruikers(inst['ous'], bool(inst.get('Met_sub_ous'))) + school.cache['handtekening_gebruikers'] = (sleutel, time.time(), lijst) + return lijst + + +@handtekeningen_bp.route('/', methods=['GET']) +@login_required +@recht_vereist('gmail_handtekeningen') +def overzicht(): + inst = hs.instellingen() + fout_ou = fout_gebruikers = None + try: + ous = hs.ou_lijst() + except hs.HandtekeningFout as e: + ous, fout_ou = inst['ous'], str(e) + gebruikers = [] + if inst['ous']: + try: + gebruikers = _gebruikers(inst, vernieuw=bool(request.args.get('vernieuw'))) + except Exception as e: + fout_gebruikers = str(e) + if request.args.get('vernieuw'): + return redirect(url_for('handtekeningen.overzicht')) + logboek = hs.logboek() + return render_template('handtekeningen.html', inst=inst, ous=ous, fout_ou=fout_ou, gebruikers=gebruikers, + fout_gebruikers=fout_gebruikers, logboek=logboek, velden=hs.VELDEN, + standaard_sjabloon=hs.STANDAARD_SJABLOON, max_tekens=hs.MAX_TEKENS, + publiek_voorstel=request.host_url.rstrip('/'), status=hs.Toepasser().status, + school_gegevens=hs.gegevens({})) + + +@handtekeningen_bp.route('/sjabloon', methods=['POST']) +@login_required +@recht_vereist('gmail_handtekeningen') +def sjabloon(): + hs.ensure_tables() + try: + hs.bewaar(request.form.get('sjabloon'), request.form.getlist('ou'), request.form.get('met_sub') == '1', + request.form.get('logo_url'), request.form.get('logo_breedte') or 120, + request.form.get('publiek_adres'), _door()) + bestand = request.files.get('logo') + if bestand and bestand.filename: + hs.bewaar_logo(bestand.read(), bestand.mimetype) + elif request.form.get('logo_wissen') == '1': + hs.verwijder_logo() + huidige_school().cache.pop('handtekening_gebruikers', None) + log("Gmail-handtekening: sjabloon en instellingen bewaard") + flash("Handtekening en instellingen bewaard. Klik op ▶ Toepassen om ze in Gmail te zetten.", "success") + except hs.HandtekeningFout as e: + flash(str(e), "error") + except Exception as e: + flash(f"Bewaren mislukt: {e}", "error") + return redirect(url_for('handtekeningen.overzicht')) + + +@handtekeningen_bp.route('/voorbeeld', methods=['POST']) +@login_required +@recht_vereist('gmail_handtekeningen') +def voorbeeld(): + """Live voorbeeld met het (nog niet bewaarde) sjabloon uit de editor en de gegevens van één gebruiker.""" + d = request.get_json(silent=True) or {} + inst = hs.instellingen() + if d.get('logo_url') is not None: + inst['Logo_url'] = (d.get('logo_url') or '').strip() or None + if d.get('publiek_adres') is not None: + inst['Publiek_adres'] = (d.get('publiek_adres') or '').strip().rstrip('/') or None + try: + inst['Logo_breedte'] = int(d.get('logo_breedte') or inst.get('Logo_breedte') or 120) + except ValueError: + pass + inst['logo_link'] = hs.logo_link(inst) + # In het voorbeeld het geüploade logo via de eigen (ingelogde) sessie tonen, ook als het publiek adres nog niet klopt + if not inst.get('Logo_url') and inst.get('heeft_logo') and inst.get('Logo_sleutel'): + inst['logo_link'] = url_for('handtekening_logo.logo', code=huidige_school().code, sleutel=inst['Logo_sleutel'], + ext=hs.LOGO_TYPES.get(inst.get('Logo_type'), 'png')) + g = d.get('gebruiker') or {} + tekst = hs.vul_in(d.get('sjabloon') if d.get('sjabloon') is not None else inst.get('Sjabloon'), hs.gegevens(g), inst) + return jsonify(ok=True, html=tekst, tekens=len(tekst)) + + +@handtekeningen_bp.route('/gebruiker', methods=['POST']) +@login_required +@recht_vereist('gmail_handtekeningen') +def gebruiker(): + """Functie en telefoon van één gebruiker in Google bewaren.""" + d = request.get_json(silent=True) or {} + email = (d.get('email') or '').strip().lower() + functie, telefoon = (d.get('functie') or '').strip()[:100], (d.get('telefoon') or '').strip()[:40] + if not email: + return jsonify(ok=False, fout="Geen gebruiker."), 400 + try: + hs.bewaar_in_google(email, functie, telefoon) + except hs.HandtekeningFout as e: + return jsonify(ok=False, fout=str(e)), 400 + bewaard = huidige_school().cache.get('handtekening_gebruikers') + if bewaard: + for u in bewaard[2]: + if u['email'] == email: + u.update(functie=functie, telefoon=telefoon) + log(f"Gmail-handtekening: functie/telefoon van {email} aangepast in Google") + return jsonify(ok=True) + + +@handtekeningen_bp.route('/toepassen', methods=['POST']) +@login_required +@recht_vereist('gmail_handtekeningen') +def toepassen(): + d = request.get_json(silent=True) or {} + emails = None if d.get('alle') else [e for e in (d.get('emails') or []) if isinstance(e, str)] + if emails is not None and not emails: + return jsonify(ok=False, fout="Niemand geselecteerd."), 400 + if not hs.Toepasser().start(emails, _door()): + return jsonify(ok=False, fout="Er loopt al een opdracht."), 409 + log(f"Gmail-handtekening toepassen ({'iedereen' if emails is None else len(emails)})") + return jsonify(ok=True) + + +@handtekeningen_bp.route('/status.json', methods=['GET']) +@login_required +@recht_vereist('gmail_handtekeningen') +def status(): + s = dict(hs.Toepasser().status) + if not s['bezig']: + s['logboek'] = {k: {'ok': bool(v['Ok']), 'melding': v['Melding'] or '', + 'op': v['Toegepast'].strftime('%d-%m-%Y %H:%M')} for k, v in hs.logboek().items()} + return jsonify(s) + + +@handtekeningen_bp.route('/nachtelijk', methods=['POST']) +@login_required +@recht_vereist('gmail_handtekeningen') +def nachtelijk(): + aan = request.form.get('aan') == '1' + hs.zet_nacht(aan, _door()) + log(f"Gmail-handtekening: nachtelijk opnieuw toepassen {'aan' if aan else 'uit'}") + flash("Elke nacht wordt de handtekening opnieuw gezet bij wie ze gewijzigd heeft." if aan + else "Het nachtelijk opnieuw toepassen staat uit.", "success") + return redirect(url_for('handtekeningen.overzicht')) + + +# --------------------------------------------------------------------- +# Publiek: het logo (Gmail haalt het op via een link; geen aanmelding) +# --------------------------------------------------------------------- +@handtekening_logo_bp.route('/handtekening-logo//.', methods=['GET']) +def logo(code, sleutel, ext): + school = school_op_code(code) + if not school or not sleutel.isalnum(): + abort(404) + with in_school(school): + data, soort = hs.logo_bestand(sleutel) + if not data: + abort(404) + return Response(bytes(data), mimetype=soort, headers={'Cache-Control': 'public, max-age=86400'}) diff --git a/blueprints/internaat_bp.py b/blueprints/internaat_bp.py new file mode 100644 index 0000000..a8a3f9e --- /dev/null +++ b/blueprints/internaat_bp.py @@ -0,0 +1,229 @@ +"""Internaat: lijst van alle internen van de actieve school (Informat Internaat WEB API).""" +import csv +import io +import time +from datetime import date + +from flask import Blueprint, render_template, request, Response, redirect, url_for, flash + +from blueprints.auth import login_required +from rechten import recht_vereist +from services.facturatie_service import schooljaren +from services.internaat_service import InternaatService, InternaatFout +from tenancy import huidige_school + +internaat_bp = Blueprint('internaat', __name__) + + +def _keuzes(): + jaren = schooljaren() + schooljaar = request.args.get('schooljaar') if request.args.get('schooljaar') in jaren else jaren[0] + try: + peildatum = date.fromisoformat(request.args.get('peildatum') or '') + except ValueError: + peildatum = date.today() + return schooljaar, jaren, peildatum + + +@internaat_bp.route("/internen", methods=["GET"]) +@login_required +@recht_vereist('internen') +def internen(): + school = huidige_school() + schooljaar, jaren, peildatum = _keuzes() + rijen, fout, opgehaald = [], None, None + if not school.heeft('INFORMAT_ID', 'INFORMAT_SECRET'): + fout = "Informat is nog niet ingesteld voor deze school (🔌 Koppelingen › Informat)." + else: + try: + rijen, t = InternaatService().internen(schooljaar, peildatum, vernieuw=bool(request.args.get('vernieuw'))) + opgehaald = time.strftime('%d-%m-%Y %H:%M', time.localtime(t)) + except InternaatFout as e: + fout = str(e) + except Exception as e: + fout = f"Internen ophalen mislukt: {e}" + internaten = sorted({r['internaat'] for r in rijen}) + return render_template("internen.html", rijen=rijen, fout=fout, opgehaald=opgehaald, schooljaar=schooljaar, + jaren=jaren, peildatum=peildatum, internaten=internaten, school_naam=school.naam) + + +@internaat_bp.route("/internen/smartschool.json", methods=["POST"]) +@login_required +@recht_vereist('internen') +def internen_smartschool(): + """Welke internen bestaan als gebruiker in Smartschool? {pid: gebruikersnaam | null}""" + from flask import jsonify + from services.internaat_service import smartschool_status + personen = (request.get_json(silent=True) or {}).get('personen') or [] + try: + return jsonify(ok=True, status=smartschool_status(personen[:2000])) + except InternaatFout as e: + return jsonify(ok=False, fout=str(e)) + except Exception as e: + return jsonify(ok=False, fout=f"Smartschool kon niet bevraagd worden: {e}") + + +@internaat_bp.route("/internen/export.csv", methods=["GET"]) +@login_required +@recht_vereist('internen') +def export(): + schooljaar, _, peildatum = _keuzes() + try: + rijen, _ = InternaatService().internen(schooljaar, peildatum) + except Exception as e: + flash(str(e), "error") + return redirect(url_for('internaat.internen', schooljaar=schooljaar)) + internaat = request.args.get('internaat') or '' + zoek = (request.args.get('zoek') or '').strip().lower() + if internaat: + rijen = [r for r in rijen if r['internaat'] == internaat] + if zoek: + rijen = [r for r in rijen if zoek in ' '.join(str(r[k]) for k in ('naam', 'voornaam', 'stamnummer', 'kamer', 'vestiging', 'gemeente')).lower()] + datum = lambda d: d.strftime('%d/%m/%Y') if d else '' + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') + w.writerow(['Naam', 'Voornaam', 'Geboortedatum', 'Geslacht', 'Stamnummer', 'Internaat', 'Vestiging', 'Kamer', + 'Ingeschreven van', 'Ingeschreven tot', 'Financiering', 'Woonplaats', 'Contact 1', 'Gsm 1', 'E-mail 1', + 'Contact 2', 'Gsm 2', 'E-mail 2', 'Smartschool']) + ss_cache = huidige_school().cache.get('ss_internen') or {} + def ss(r): + hit = ss_cache.get((str(r['id']), r['voornaam'], r['naam'])) + return '' if not hit else (hit[1] or 'niet gevonden') + for r in rijen: + o = (r['ouders'] + [{}, {}])[:2] + w.writerow([r['naam'], r['voornaam'], datum(r['geboortedatum']), r['geslacht'], r['stamnummer'], r['internaat'], + r['vestiging'], r['kamer'], datum(r['begin']), datum(r['einde']), r['financiering'], r['gemeente']] + + sum(([f"{x.get('naam', '')} ({x['type']})" if x.get('type') else x.get('naam', ''), x.get('gsm', ''), + x.get('email', '')] for x in o), []) + [ss(r)]) + return Response('' + buf.getvalue(), mimetype='text/csv; charset=utf-8', headers={ + 'Content-Disposition': f"attachment; filename=Internen_{huidige_school().code}_{peildatum:%Y%m%d}.csv"}) + + +# --------------------------------------------------------------------- +# Aanwezigheden (register per week: ochtend en avond) +# --------------------------------------------------------------------- +from datetime import timedelta +from flask import jsonify, session +from services import aanwezigheid_service as aw + + +def _week(): + try: + d = date.fromisoformat(request.args.get('week') or '') + except ValueError: + d = date.today() + return aw.maandag_van(d) + + +def _internen_van_week(maandag): + """Internen die in de week ingeschreven zijn (peildatum: vandaag als die in de week valt, anders woensdag).""" + vandaag = date.today() + peildatum = vandaag if maandag <= vandaag <= maandag + timedelta(days=6) else maandag + timedelta(days=2) + rijen, _ = InternaatService().internen(aw.schooljaar_van(peildatum), peildatum) + meerdere = len({r['internaat'] for r in rijen}) > 1 + for r in rijen: + r['groep'] = aw.groep_van(r, meerdere) + r['pid'] = str(r['id']) + return rijen + + +@internaat_bp.route("/aanwezigheden", methods=["GET"]) +@login_required +@recht_vereist('internaat_aanwezigheid') +def aanwezigheden(): + school = huidige_school() + maandag = _week() + rijen, fout, data = [], None, {} + try: + rijen = _internen_van_week(maandag) + data = aw.week(maandag) + except InternaatFout as e: + fout = str(e) + except Exception as e: + fout = f"Internen ophalen mislukt: {e}" + groepen = {} + for r in sorted(rijen, key=lambda r: (r['groep'].lower(), r['naam'].lower(), r['voornaam'].lower())): + groepen.setdefault(r['groep'], []).append(r) + dagen = [maandag + timedelta(days=i) for i in range(7)] + return render_template("aanwezigheden.html", groepen=groepen, data=data, dagen=dagen, maandag=maandag, + fout=fout, school_naam=school.naam, vandaag=date.today(), dagnamen=aw.DAGEN, + dagnamen_voluit=aw.DAGEN_VOLUIT, aantal=len(rijen), + vorige=maandag - timedelta(days=7), volgende=maandag + timedelta(days=7), + weeknr=maandag.isocalendar()[1]) + + +@internaat_bp.route("/aanwezigheden/zet", methods=["POST"]) +@login_required +@recht_vereist('internaat_aanwezigheid') +def aanwezigheid_zet(): + d = request.get_json(silent=True) or {} + try: + datum = date.fromisoformat(str(d.get('datum') or '')) + aw.zet(datum, str(d.get('persoon') or '')[:64], d.get('moment'), d.get('status'), d.get('naam'), + session.get('naam') or session.get('user')) + except ValueError as e: + return jsonify(ok=False, fout=str(e) or 'Ongeldige gegevens.'), 400 + except Exception as e: + return jsonify(ok=False, fout=f"Bewaren mislukt: {e}"), 500 + return jsonify(ok=True) + + +@internaat_bp.route("/aanwezigheden/export.xlsx", methods=["GET"]) +@login_required +@recht_vereist('internaat_aanwezigheid') +def aanwezigheden_export(): + """Excel van de week, met dezelfde filters als op het scherm (?groep=&zoek=).""" + from openpyxl import Workbook + from openpyxl.styles import Font, PatternFill, Alignment + maandag = _week() + try: + rijen = _internen_van_week(maandag) + data = aw.week(maandag) + except Exception as e: + flash(str(e), "error") + return redirect(url_for('internaat.aanwezigheden', week=maandag.isoformat())) + groep, zoek = request.args.get('groep') or '', (request.args.get('zoek') or '').strip().lower() + rijen = [r for r in rijen if (not groep or r['groep'] == groep) + and (not zoek or zoek in f"{r['naam']} {r['voornaam']}".lower())] + rijen.sort(key=lambda r: (r['groep'].lower(), r['naam'].lower(), r['voornaam'].lower())) + labels = {'aanwezig': 'Aanwezig', 'afwezig': 'Afwezig'} + kleur = {'aanwezig': PatternFill('solid', fgColor='D7EDDF'), 'afwezig': PatternFill('solid', fgColor='F6D5CF')} + wb = Workbook() + ws = wb.active + ws.title = f"Week {maandag.isocalendar()[1]}" + kop = ['Naam', 'Voornaam', 'Groep', 'Kamer'] + for i, dag in enumerate(aw.DAGEN_VOLUIT): + d = maandag + timedelta(days=i) + kop += [f"{dag} {d:%d/%m} ochtend", f"{dag} {d:%d/%m} avond"] + ws.append(kop) + for c in ws[1]: + c.font = Font(bold=True) + c.alignment = Alignment(wrap_text=True, vertical='top') + vorige_groep = None + for r in rijen: + if r['groep'] != vorige_groep: + ws.append([f"Groep: {r['groep']}"]) + ws.cell(ws.max_row, 1).font = Font(bold=True) + vorige_groep = r['groep'] + rij = [r['naam'], r['voornaam'], r['groep'], r['kamer']] + for i in range(7): + for m in aw.MOMENTEN: + rij.append(labels.get(data.get(f"{r['pid']}:{i}:{m}"), '')) + ws.append(rij) + for c in ws[ws.max_row][4:]: + for k, f in kleur.items(): + if c.value == labels[k]: + c.fill = f + ws.column_dimensions['A'].width = 22 + ws.column_dimensions['B'].width = 16 + ws.column_dimensions['C'].width = 16 + ws.column_dimensions['D'].width = 22 + from openpyxl.utils import get_column_letter + for i in range(5, 5 + 14): + ws.column_dimensions[get_column_letter(i)].width = 13 + ws.freeze_panes = 'C2' + buf = io.BytesIO() + wb.save(buf) + return Response(buf.getvalue(), mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + headers={'Content-Disposition': f"attachment; filename=Aanwezigheden_{huidige_school().code}_" + f"{maandag:%Y}-W{maandag.isocalendar()[1]:02d}.xlsx"}) diff --git a/blueprints/ipblokkade_bp.py b/blueprints/ipblokkade_bp.py new file mode 100644 index 0000000..9354acb --- /dev/null +++ b/blueprints/ipblokkade_bp.py @@ -0,0 +1,285 @@ +""" +Beheer › IP-blokkades. Geldt voor alle scholen. + +- Administrators zien en beheren alles (blokkeren, altijd toestaan, schakelaar, testen). +- Een gewone gebruiker met het recht 'ip_whitelist' ziet enkel de toegestane adressen van de actieve school, + kan een adres toevoegen (school = actieve school, opmerking = zijn naam) en enkel zijn eigen regels verwijderen. +""" +import functools + +from flask import Blueprint, render_template, request, flash, redirect, url_for, session + +from blueprints.auth import login_required +from database import central_query +from rechten import admin_vereist, recht_vereist, is_admin, log +from services import ipblokkade as ipb +from tenancy import alle_scholen, school_op_code, huidige_school + +ipblokkade_bp = Blueprint('ipblokkade', __name__) + + +def _schoolnaam(code): + s = school_op_code(code, ook_inactief=True) + return s.naam if s else code + + +def admin_of_whitelist(view): + """Administrators altijd (ook zonder gekozen school); anderen met het recht 'ip_whitelist' in de actieve school.""" + beschermd = recht_vereist('ip_whitelist')(view) + + @functools.wraps(view) + def wrapped(*a, **kw): + return view(*a, **kw) if session.get('auth') and is_admin() else beschermd(*a, **kw) + return wrapped + + +# Gewone gebruikers mogen hoogstens zo'n reeks toestaan (een ruimere reeks laat te veel adressen altijd binnen) +MAX_PREFIX_GEBRUIKER = {4: 24, 6: 64} + + +def _eigen(r): + """Mag de ingelogde (gewone) gebruiker deze regel verwijderen? Enkel als hij hem zelf toevoegde.""" + gid = session.get('gebruiker_id') + return bool(gid) and r.get('Gebruiker_ID') == gid and r.get('Soort') == 'toestaan' + + +def _gekozen_scholen(): + """De aangevinkte scholen uit het formulier (enkel bestaande schoolcodes).""" + return ipb.scholen_waarde(c for c in request.form.getlist('scholen') if school_op_code(c, ook_inactief=True)) + + +@ipblokkade_bp.route("/", methods=["GET"]) +@login_required +@admin_of_whitelist +def overzicht(): + ipb.ensure_table() + rijen = central_query("SELECT * FROM IP_blokkades ORDER BY Soort, Reeks") or [] + if not is_admin(): + return _overzicht_gebruiker(rijen) + import ipaddress + for r in rijen: # sorteersleutel: numeriek op adres (zodat 9.x vóór 85.x komt), dan op grootte van de reeks + try: + net = ipaddress.ip_network(r['Reeks'], strict=False) + r['Sorteer'] = f"{net.version}-{int(net.network_address):040d}-{net.prefixlen:03d}" + except ValueError: + r['Sorteer'] = r['Reeks'] + r['Scholen_codes'] = ipb.scholen_codes(r.get('Scholen')) + r['Scholen_namen'] = sorted((_schoolnaam(c) for c in r['Scholen_codes']), key=str.lower) + test_ip = (request.args.get('test') or '').strip() + test = None + if test_ip: + try: + lijst = ipb.regels(vers=True) + geweigerd, rid = ipb.beoordeel(test_ip, lijst) + regel = next((r for r in rijen if r['ID'] == rid), None) + test = {'ip': test_ip, 'geweigerd': geweigerd, 'regel': regel} + except Exception as e: + flash(f"Test mislukt: {e}", "error") + modus = ipb.instelling(ipb.MODUS_SLEUTEL) + teller = ipb.instelling(ipb.TELLER_SLEUTEL) + scholen = sorted(alle_scholen(ook_inactief=True), key=lambda s: s.naam.lower()) + return render_template("ipblokkade.html", rijen=rijen, mijn_ip=request.remote_addr, test=test, scholen=scholen, + blokkeren=[r for r in rijen if r['Soort'] == 'blokkeren'], + toestaan=[r for r in rijen if r['Soort'] == 'toestaan'], + enkel_toegestaan=bool(modus and modus['Waarde'] == '1'), modus=modus, + lokaal=ipb.is_lokaal(request.remote_addr), + modus_geweigerd=int(teller['Waarde']) if teller and str(teller['Waarde']).isdigit() else 0) + + +def _overzicht_gebruiker(rijen): + """Gewone gebruiker: enkel de toegestane adressen van de actieve school.""" + school = huidige_school() + eigen_school = [r for r in rijen if r['Soort'] == 'toestaan' and school.code in ipb.scholen_codes(r.get('Scholen'))] + import ipaddress + for r in eigen_school: + try: + net = ipaddress.ip_network(r['Reeks'], strict=False) + r['Sorteer'] = f"{net.version}-{int(net.network_address):040d}-{net.prefixlen:03d}" + except ValueError: + r['Sorteer'] = r['Reeks'] + r['Eigen'] = _eigen(r) + return render_template("ipblokkade_school.html", rijen=eigen_school, school_naam=school.naam, + mijn_ip=request.remote_addr, lokaal=ipb.is_lokaal(request.remote_addr), + naam=session.get('naam') or session.get('user')) + + +@ipblokkade_bp.route("/modus", methods=["POST"]) +@login_required +@admin_vereist +def modus(): + """Schakelaar: enkel nog adressen uit "Altijd toestaan" binnenlaten.""" + ipb.ensure_table() + aan = request.form.get('aan') == '1' + if aan: + mijn = request.remote_addr + if ipb.is_lokaal(mijn): + flash(f"PIVOT ziet jouw adres als {mijn}. Dan draait PIVOT achter een reverse proxy (of test je lokaal) en " + "lijkt elke bezoeker van dat adres te komen: de witte lijst zou dan niets tegenhouden of iedereen " + "buitensluiten. Zet eerst in config.ini › [algemeen] proxy_aantal = 1 en herstart PIVOT; bij " + "'Jouw IP-adres' moet je echte adres verschijnen.", "error") + return redirect(url_for('ipblokkade.overzicht')) + lijst = ipb.regels(vers=True) + if not any(sz == 'toestaan' for _, sz, _ in lijst): + flash("Voeg eerst minstens één adres of reeks toe bij 'Altijd toestaan'.", "error") + return redirect(url_for('ipblokkade.overzicht')) + if ipb.beoordeel(mijn, lijst, enkel_toe=True)[0]: + flash(f"Jouw eigen adres ({mijn}) staat niet bij 'Altijd toestaan': dan sluit je jezelf buiten. " + "Voeg het eerst toe.", "error") + return redirect(url_for('ipblokkade.overzicht')) + ipb.zet_enkel_toegestaan(aan, session.get('user')) + flash("Enkel nog adressen uit 'Altijd toestaan' worden binnengelaten." if aan + else "Iedereen wordt weer binnengelaten, behalve de geblokkeerde adressen.", "success" if not aan else "warning") + return redirect(url_for('ipblokkade.overzicht')) + + +@ipblokkade_bp.route("/toevoegen", methods=["POST"]) +@login_required +@admin_of_whitelist +def toevoegen(): + if not is_admin(): + return _toevoegen_gebruiker() + soort = 'toestaan' if request.form.get('soort') == 'toestaan' else 'blokkeren' + try: + net = ipb.normaliseer(request.form.get('reeks')) + except ipb.OngeldigeReeks as e: + flash(str(e), "error") + return redirect(url_for('ipblokkade.overzicht')) + ipb.ensure_table() + if soort == 'blokkeren': + # Niet jezelf buitensluiten: weigeren als je eigen adres erin valt (tenzij het uitdrukkelijk toegestaan is) + lijst = ipb.regels(vers=True) + [(0, 'blokkeren', net)] + if ipb.beoordeel(request.remote_addr, lijst)[0]: + flash(f"Deze reeks bevat je eigen IP-adres ({request.remote_addr}): dan sluit je jezelf buiten. " + "Voeg eerst je eigen adres toe als uitzondering (toestaan), of kies een kleinere reeks.", "error") + return redirect(url_for('ipblokkade.overzicht')) + bestaat = central_query("SELECT ID FROM IP_blokkades WHERE Reeks = %s AND Soort = %s", (str(net), soort)) + if bestaat: + flash(f"{net} staat al in de lijst.", "warning") + return redirect(url_for('ipblokkade.overzicht')) + # Bij "Altijd toestaan" kan je aanduiden bij welke school/scholen het adres hoort (enkel ter info in de tabel) + scholen = _gekozen_scholen() if soort == 'toestaan' else None + central_query("INSERT INTO IP_blokkades (Reeks, Soort, Opmerking, Scholen, Aangemaakt, Door, Gebruiker_ID) " + "VALUES (%s, %s, %s, %s, NOW(), %s, %s)", + (str(net), soort, (request.form.get('opmerking') or '').strip()[:255] or None, + scholen, session.get('user'), session.get('gebruiker_id')), + commit=True) + ipb.vergeet_cache() + aantal = net.num_addresses + getal = f"{aantal:,}".replace(',', '.') + flash(f"{net} toegevoegd ({'geblokkeerd' if soort == 'blokkeren' else 'altijd toegestaan'}" + f"{', ' + ', '.join(_schoolnaam(c) for c in ipb.scholen_codes(scholen)) if scholen else ''}, {getal} adres{'sen' if aantal != 1 else ''}).", "success") + return redirect(url_for('ipblokkade.overzicht')) + + +def _toevoegen_gebruiker(): + """Gewone gebruiker: enkel 'Altijd toestaan', school = actieve school, opmerking = zijn naam.""" + terug = redirect(url_for('ipblokkade.overzicht')) + try: + net = ipb.normaliseer(request.form.get('reeks')) + except ipb.OngeldigeReeks as e: + flash(str(e), "error") + return terug + grens = MAX_PREFIX_GEBRUIKER[net.version] + if net.prefixlen < grens: + flash(f"{net} is een te grote reeks. Je kan één adres toevoegen of hoogstens een /{grens}-reeks " + f"(bv. {'85.12.3.' if net.version == 4 else 'een /64'}). Vraag een administrator voor een grotere reeks.", "error") + return terug + ipb.ensure_table() + school = huidige_school() + naam = (session.get('naam') or session.get('user') or '').strip()[:255] or None + bestaat = central_query("SELECT ID, Scholen FROM IP_blokkades WHERE Reeks = %s AND Soort = 'toestaan'", (str(net),)) + if bestaat: + codes = ipb.scholen_codes(bestaat[0]['Scholen']) + if school.code in codes: + flash(f"{net} staat al in de lijst van {school.naam}.", "warning") + else: + # Al toegestaan voor een andere school: deze school erbij zetten (de regel blijft van wie hem maakte) + central_query("UPDATE IP_blokkades SET Scholen = %s WHERE ID = %s", + (ipb.scholen_waarde(codes + [school.code]), bestaat[0]['ID']), commit=True) + flash(f"{net} was al toegestaan voor een andere school en staat nu ook bij {school.naam}.", "success") + return terug + central_query("INSERT INTO IP_blokkades (Reeks, Soort, Opmerking, Scholen, Aangemaakt, Door, Gebruiker_ID) " + "VALUES (%s, 'toestaan', %s, %s, NOW(), %s, %s)", + (str(net), naam, school.code, session.get('user'), session.get('gebruiker_id')), commit=True) + ipb.vergeet_cache() + log(f"IP toegestaan voor {school.code}: {net}") + flash(f"{net} toegevoegd aan de toegestane adressen van {school.naam}.", "success") + return terug + + +@ipblokkade_bp.route("/leegmaken", methods=["POST"]) +@login_required +@admin_vereist +def leegmaken(): + """Verwijdert alle 'blokkeren'-regels. 'Altijd toestaan' en de schakelaar blijven ongemoeid.""" + ipb.ensure_table() + rij = central_query("SELECT COUNT(*) AS n FROM IP_blokkades WHERE Soort = 'blokkeren'") + aantal = int(rij[0]['n']) if rij else 0 + if not aantal: + flash("De bloklijst is al leeg.", "warning") + return redirect(url_for('ipblokkade.overzicht')) + central_query("DELETE FROM IP_blokkades WHERE Soort = 'blokkeren'", commit=True) + ipb.vergeet_cache() + try: + from rechten import log + log(f"Bloklijst IP-blokkades leeggemaakt ({aantal} regels)") + except Exception: + pass + flash(f"Bloklijst leeggemaakt: {aantal} regel{'s' if aantal != 1 else ''} verwijderd.", "success") + return redirect(url_for('ipblokkade.overzicht')) + + +@ipblokkade_bp.route("//bewerken", methods=["POST"]) +@login_required +@admin_vereist +def bewerken(regel_id): + """Reeks, scholen en opmerking van een bestaande regel aanpassen (de soort blijft dezelfde).""" + terug = redirect(url_for('ipblokkade.overzicht')) + ipb.ensure_table() + rij = central_query("SELECT ID, Soort FROM IP_blokkades WHERE ID = %s", (regel_id,)) + if not rij: + flash("Deze regel bestaat niet meer.", "error") + return terug + soort = rij[0]['Soort'] + try: + net = ipb.normaliseer(request.form.get('reeks')) + except ipb.OngeldigeReeks as e: + flash(str(e), "error") + return terug + if central_query("SELECT ID FROM IP_blokkades WHERE Reeks = %s AND Soort = %s AND ID <> %s", (str(net), soort, regel_id)): + flash(f"{net} staat al in de lijst.", "warning") + return terug + # Niet jezelf buitensluiten: met de aangepaste regel moet je eigen adres nog binnen mogen + mijn = request.remote_addr + nieuw = [r for r in ipb.regels(vers=True) if r[0] != regel_id] + [(regel_id, soort, net)] + if ipb.beoordeel(mijn, nieuw, enkel_toe=ipb.enkel_toegestaan())[0] and not ipb.beoordeel(mijn, ipb.regels())[0]: + flash(f"Met deze aanpassing zou je eigen IP-adres ({mijn}) geweigerd worden: dan sluit je jezelf buiten.", "error") + return terug + central_query("UPDATE IP_blokkades SET Reeks = %s, Opmerking = %s, Scholen = %s WHERE ID = %s", + (str(net), (request.form.get('opmerking') or '').strip()[:255] or None, + _gekozen_scholen() if soort == 'toestaan' else None, regel_id), commit=True) + ipb.vergeet_cache() + flash(f"{net} bijgewerkt.", "success") + return terug + + +@ipblokkade_bp.route("//verwijderen", methods=["POST"]) +@login_required +@admin_of_whitelist +def verwijderen(regel_id): + if not is_admin(): + rij = central_query("SELECT ID, Soort, Gebruiker_ID FROM IP_blokkades WHERE ID = %s", (regel_id,)) + if not rij or not _eigen(rij[0]): + flash("Je kan enkel adressen verwijderen die je zelf toegevoegd hebt.", "error") + return redirect(url_for('ipblokkade.overzicht')) + # Staat de witte-lijstmodus aan, dan mag je de regel die jou zelf binnenlaat niet verwijderen + if ipb.enkel_toegestaan(vers=True): + rest = [r for r in ipb.regels(vers=True) if r[0] != regel_id] + if ipb.beoordeel(request.remote_addr, rest, enkel_toe=True)[0]: + flash("Deze regel laat jou zelf binnen terwijl enkel 'Altijd toestaan' geldt: verwijderen zou je " + "buitensluiten. Zet eerst de schakelaar uit of voeg je adres apart toe.", "error") + return redirect(url_for('ipblokkade.overzicht')) + central_query("DELETE FROM IP_blokkades WHERE ID = %s", (regel_id,), commit=True) + ipb.vergeet_cache() + flash("Regel verwijderd.", "success") + return redirect(url_for('ipblokkade.overzicht')) diff --git a/blueprints/leerlingenaantal_bp.py b/blueprints/leerlingenaantal_bp.py new file mode 100644 index 0000000..b255e88 --- /dev/null +++ b/blueprints/leerlingenaantal_bp.py @@ -0,0 +1,273 @@ +""" +Scholengroep: leerlingenaantallen van alle scholen in PIVOT. + +Elke school wordt geteld met haar EIGEN Informat-koppeling (instellingsnummer, +client-ID en secret uit het scholenregister). Het resultaat wordt bewaard in de +centrale database, zodat elke school het overzicht van de scholengroep ziet. + +- Huidig aantal: peildatum vandaag + 1 maand (kolommen in Scholen). +- Telling op peildatum: een gekozen datum (bv. 1 februari), bewaard in Leerlingenaantal_tellingen, + zodat je ze later opnieuw kan bekijken en exporteren. +""" +import csv +import io +import json +from datetime import date, datetime + +from flask import Blueprint, render_template, request, flash, redirect, url_for, session, Response +from blueprints.auth import login_required +from database import central_query +from rechten import recht_vereist +from services.sync_service import SyncService +from tenancy import alle_scholen, school_op_code, in_school, herlaad, ONDERWIJSNIVEAUS + +leerlingenaantal_bp = Blueprint('leerlingenaantal', __name__) + +INFORMAT_VELDEN = ('INFORMAT_INST_NUMBER', 'INFORMAT_ID', 'INFORMAT_SECRET') + +# Teksten en routes voor het gedeelde sjabloon leerlingenaantal.html (ook gebruikt door de personeelsaantallen) +WEERGAVE = dict(ep='leerlingenaantal', pagina='leerlingenaantal_page', titel='Leerlingenaantallen', + eenheid='Leerlingen', kort='lln.') + + +def _datum(waarde): + try: + return datetime.strptime((waarde or '').strip(), '%Y-%m-%d').date() + except ValueError: + return None + + +def _fmt(dt, leeg=''): + if not dt: + return leeg + return dt.strftime('%d-%m-%Y %H:%M') if hasattr(dt, 'strftime') else str(dt) + + +def _detail(tekst): + try: + return json.loads(tekst) if tekst else [] + except ValueError: + return [] + + +NIVEAUS = list(ONDERWIJSNIVEAUS) + [('', 'Onderwijsniveau niet ingesteld')] +NIVEAU_LABEL = dict(NIVEAUS) + + +def _niveau(school): + n = school.waarden.get('ONDERWIJSNIVEAU') or '' + return n if n in NIVEAU_LABEL else '' + + +def _som(rijen, veld): + return sum(r[veld] for r in rijen if isinstance(r[veld], int)) + + +def _groepen(rows, veld): + """Rijen per onderwijsniveau (basis, secundair, niet ingesteld) met subtotaal; lege groepen vallen weg.""" + uit = [] + for code, label in NIVEAUS: + rijen = [r for r in rows if r['Niveau'] == code] + if rijen: + uit.append({'code': code, 'label': label, 'rijen': rijen, 'subtotaal': _som(rijen, veld)}) + return uit + + +def _huidig(query=''): + rows = [] + for s in alle_scholen(): + if query and query.lower() not in s.naam.lower(): + continue + rows.append({ + 'Code': s.code, + 'Naam_school': s.naam, + 'Niveau': _niveau(s), + 'Leerlingenaantal': s.leerlingenaantal if s.leerlingenaantal is not None else '–', + 'Huidig': s.leerlingenaantal if s.leerlingenaantal is not None else '–', + 'Laatste_synchronisatie': s.leerlingenaantal_sync, + 'Informat': s.heeft(*INFORMAT_VELDEN), + 'Campussen': s.leerlingenaantal_detail or [], # [{'naam', 'nummer', 'aantal'}] bij meerdere campussen + }) + return rows + + +def _telling(peildatum, query=''): + """Alle actieve scholen met hun aantal op de peildatum (None = niet geteld).""" + per = {r['School_ID']: r for r in central_query( + "SELECT School_ID, Aantal, Detail, Schooljaar, Opgevraagd_op, Door FROM Leerlingenaantal_tellingen " + "WHERE Peildatum = %s", (peildatum,))} + rows = [] + for s in alle_scholen(): + if query and query.lower() not in s.naam.lower(): + continue + t = per.get(s.id) or {} + rows.append({'Code': s.code, 'Naam_school': s.naam, 'Niveau': _niveau(s), 'Aantal': t.get('Aantal'), + 'Schooljaar': t.get('Schooljaar'), 'Opgevraagd_op': t.get('Opgevraagd_op'), + 'Door': t.get('Door'), 'Informat': s.heeft(*INFORMAT_VELDEN), + 'Campussen': _detail(t.get('Detail'))}) + return rows + + +def _peildata(): + return central_query("SELECT Peildatum, COUNT(*) AS Scholen, SUM(Aantal) AS Totaal, MAX(Opgevraagd_op) AS Laatst " + "FROM Leerlingenaantal_tellingen GROUP BY Peildatum ORDER BY Peildatum DESC") + + +@leerlingenaantal_bp.route("/leerlingenaantal", methods=["GET", "POST"]) +@login_required +@recht_vereist('leerlingenaantal') +def leerlingenaantal_page(): + query = (request.values.get("query") or "").strip() + herlaad(force=True) + results = _huidig(query) + totaal = _som(results, 'Leerlingenaantal') + + peildatum = _datum(request.args.get('peildatum')) + telling = _telling(peildatum, query) if peildatum else None + telling_totaal = _som(telling, 'Aantal') if telling else 0 + return render_template("leerlingenaantal.html", results=results, query=query, totaal=totaal, + groepen=_groepen(results, 'Leerlingenaantal'), + telling_groepen=_groepen(telling, 'Aantal') if telling else [], + peildatum=peildatum, telling=telling, telling_totaal=telling_totaal, + peildata=_peildata(), vandaag=date.today(), **WEERGAVE) + + +@leerlingenaantal_bp.route("/sync-aanvragen", methods=["POST"]) +@login_required +@recht_vereist('leerlingenaantal') +def sync_aanvragen(): + codes = [s.code for s in alle_scholen()] if request.form.get("alle") else [request.form.get("school_code")] + for code in codes: + school = school_op_code(code) + if not school: + continue + if not school.heeft(*INFORMAT_VELDEN): + flash(f"{school.naam}: Informat is nog niet ingesteld.", "error") + continue + with in_school(school): + success, message = SyncService().sync_student_count() + flash(f"{school.naam}: {message}", "success" if success else "error") + return redirect(url_for('leerlingenaantal.leerlingenaantal_page')) + + +@leerlingenaantal_bp.route("/leerlingenaantal/peildatum", methods=["POST"]) +@login_required +@recht_vereist('leerlingenaantal') +def tel_peildatum(): + """Telt de leerlingen op de gekozen datum, voor alle scholen of één school.""" + peildatum = _datum(request.form.get('peildatum')) + if not peildatum: + flash("Kies een geldige datum.", "error") + return redirect(url_for('leerlingenaantal.leerlingenaantal_page')) + code = request.form.get('school_code') + scholen = [school_op_code(code)] if code else alle_scholen() + door = session.get('user') + gelukt = 0 + for school in scholen: + if not school: + continue + if not school.heeft(*INFORMAT_VELDEN): + if code: + flash(f"{school.naam}: Informat is nog niet ingesteld.", "error") + continue + with in_school(school): + ok, res = SyncService().tel_op_peildatum(peildatum, door) + if ok: + gelukt += 1 + else: + flash(f"{school.naam}: {res}", "error") + if gelukt: + flash(f"Leerlingen geteld op {peildatum:%d-%m-%Y} voor {gelukt} school/scholen.", "success") + return redirect(url_for('leerlingenaantal.leerlingenaantal_page', peildatum=peildatum.isoformat())) + + +@leerlingenaantal_bp.route("/leerlingenaantal/peildatum/verwijderen", methods=["POST"]) +@login_required +@recht_vereist('leerlingenaantal') +def verwijder_peildatum(): + peildatum = _datum(request.form.get('peildatum')) + if peildatum: + central_query("DELETE FROM Leerlingenaantal_tellingen WHERE Peildatum = %s", (peildatum,), commit=True) + flash(f"Telling van {peildatum:%d-%m-%Y} verwijderd.", "success") + return redirect(url_for('leerlingenaantal.leerlingenaantal_page')) + + +# ------------------------------------------------------------------ +# CSV +# ------------------------------------------------------------------ +def _csv(naam, kop, rijen): + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') # ; zodat Excel (Belgische instellingen) de kolommen meteen splitst + w.writerow(kop) + w.writerows(rijen) + return Response('' + buf.getvalue(), mimetype='text/csv', + headers={'Content-Disposition': f'attachment; filename={naam}'}) + + +@leerlingenaantal_bp.route("/leerlingenaantal/export.csv", methods=["GET"]) +@login_required +@recht_vereist('leerlingenaantal') +def export_csv(): + """?peildatum=YYYY-MM-DD → die telling; ?alle=1 → alle peildata naast elkaar; anders het huidige aantal.""" + query = (request.args.get('query') or '').strip() + + if request.args.get('alle'): + data = central_query("SELECT School_ID, Peildatum, Aantal, Detail FROM Leerlingenaantal_tellingen ORDER BY Peildatum") + datums = sorted({r['Peildatum'] for r in data}) + per = {(r['School_ID'], r['Peildatum']): r['Aantal'] for r in data} + # campus-aantallen: {(school_id, campusnaam, datum): aantal} + campus, campusnamen = {}, {} + for r in data: + for d in _detail(r['Detail']): + campus[(r['School_ID'], d['naam'], r['Peildatum'])] = d['aantal'] + campusnamen.setdefault(r['School_ID'], []) + if d['naam'] not in campusnamen[r['School_ID']]: + campusnamen[r['School_ID']].append(d['naam']) + scholen = [s for s in alle_scholen() if not query or query.lower() in s.naam.lower()] + rijen = [] + for code, label in NIVEAUS: + groep = [s for s in scholen if _niveau(s) == code] + if not groep: + continue + for s in groep: + rijen.append([label, s.naam, ''] + [per.get((s.id, d), '') for d in datums]) + for naam in campusnamen.get(s.id, []): + rijen.append([label, s.naam, naam] + [campus.get((s.id, naam, d), '') for d in datums]) + if code: + rijen.append([f"Subtotaal {label}", '', ''] + [sum(per.get((s.id, d)) or 0 for s in groep) for d in datums]) + rijen.append(['Totaal', '', ''] + [sum(per.get((s.id, d)) or 0 for s in scholen) for d in datums]) + return _csv(f"leerlingenaantallen_alle_peildata_{date.today():%Y%m%d}.csv", + ['Onderwijsniveau', 'School', 'Campus'] + [f"{d:%d-%m-%Y}" for d in datums], rijen) + + peildatum = _datum(request.args.get('peildatum')) + if peildatum: + rows = _telling(peildatum, query) + rijen = [] + for g in _groepen(rows, 'Aantal'): + for r in g['rijen']: + rijen.append([g['label'], r['Naam_school'], '', '' if r['Aantal'] is None else r['Aantal'], + r['Schooljaar'] or '', _fmt(r['Opgevraagd_op'], 'niet geteld'), r['Door'] or '']) + for c in r['Campussen']: + rijen.append([g['label'], r['Naam_school'], c['naam'], c['aantal'], r['Schooljaar'] or '', '', '']) + if g['code']: + rijen.append([f"Subtotaal {g['label']}", '', '', g['subtotaal'], '', '', '']) + rijen.append(['Totaal', '', '', _som(rows, 'Aantal'), '', '', '']) + return _csv(f"leerlingenaantallen_{peildatum:%Y%m%d}.csv", + ['Onderwijsniveau', 'School', 'Campus', f"Leerlingen op {peildatum:%d-%m-%Y}", 'Schooljaar', + 'Opgevraagd op', 'Door'], rijen) + + rows = _huidig(query) + rijen = [] + for g in _groepen(rows, 'Leerlingenaantal'): + for r in g['rijen']: + rijen.append([g['label'], r['Naam_school'], '', + r['Leerlingenaantal'] if isinstance(r['Leerlingenaantal'], int) else '', + _fmt(r['Laatste_synchronisatie'], 'nog nooit')]) + for c in r['Campussen']: + rijen.append([g['label'], r['Naam_school'], c['naam'], c['aantal'], '']) + if g['code']: + rijen.append([f"Subtotaal {g['label']}", '', '', g['subtotaal'], '']) + rijen.append(['Totaal', '', '', _som(rows, 'Leerlingenaantal'), '']) + return _csv(f"leerlingenaantallen_{date.today():%Y%m%d}.csv", + ['Onderwijsniveau', 'School', 'Campus', 'Leerlingen', 'Laatste synchronisatie'], rijen) + diff --git a/blueprints/nieuw_schooljaar_accounts_bp.py b/blueprints/nieuw_schooljaar_accounts_bp.py new file mode 100644 index 0000000..2eb7599 --- /dev/null +++ b/blueprints/nieuw_schooljaar_accounts_bp.py @@ -0,0 +1,51 @@ +from flask import Blueprint, render_template, request, session, redirect, url_for, flash +from services.google_service import GoogleAdminService +from blueprints.auth import login_required +from rechten import recht_vereist +from tenancy import per_school + +account_verplaatsen_bp = Blueprint('accounts_verplaatsen', __name__) +google = per_school(GoogleAdminService) + +@account_verplaatsen_bp.route('/beheer/verplaatsen', methods=['GET', 'POST']) +@login_required +@recht_vereist('nieuw_schooljaar') +def accounts_verplaatsen(): + if request.method == 'POST': + huidige_ou = request.form.get('huidige_ou') + nieuwe_ou = request.form.get('nieuwe_ou') + move_type = request.form.get('move_type') # 'current' of 'all' + + # Als move_type 'current' is, zou je hier je database/Informat lijst ophalen + enrolled_list = [] + if move_type == 'current': + # Voorbeeld: enrolled_list = db.get_active_students_emails() + pass + + only_enrolled = (move_type == 'current') + + success, message = google.move_users_ou( + huidige_ou, + nieuwe_ou, + only_enrolled=only_enrolled, + enrolled_emails=enrolled_list + ) + + flash(message) + return redirect(url_for('accounts_verplaatsen.accounts_verplaatsen')) + + # Voor de GET: vul de dropdowns + org_units = google.list_org_units() + return render_template('nieuw_schooljaar_accounts.html', ous=org_units) + +@account_verplaatsen_bp.route('/beheer/archiveren-inactief', methods=['POST']) +@login_required +@recht_vereist('nieuw_schooljaar') +def archiveren_inactief(): + source_ou = request.form.get('bron_ou') + days_inactive = int(request.form.get('inactief_periode')) + + success, message = google.archive_inactive_users(source_ou, days_inactive) + + flash(message, "success" if success else "danger") + return redirect(url_for('accounts_verplaatsen.accounts_verplaatsen')) \ No newline at end of file diff --git a/blueprints/nieuw_schooljaar_toestellen_bp.py b/blueprints/nieuw_schooljaar_toestellen_bp.py new file mode 100644 index 0000000..1c2e4c8 --- /dev/null +++ b/blueprints/nieuw_schooljaar_toestellen_bp.py @@ -0,0 +1,39 @@ +from flask import Blueprint, render_template, request, flash, redirect, url_for +from services.google_service import GoogleAdminService +from blueprints.auth import login_required +from rechten import recht_vereist + +# We noemen de blueprint 'toestellen_verplaatsen' +toestellen_verplaatsen_bp = Blueprint('toestellen_verplaatsen', __name__) + +@toestellen_verplaatsen_bp.route('/toestellen', methods=['GET', 'POST']) +@login_required +@recht_vereist('nieuw_schooljaar') +def move_toestellen(): + google_service = GoogleAdminService() + org_units = google_service.list_org_units() + + # Standaard is de verplaatsen tab actief + return render_template('nieuw_schooljaar_toestellen.html', + org_units=org_units, + active_tab='verplaatsen') + +@toestellen_verplaatsen_bp.route('/blokkeren', methods=['POST']) +@login_required +@recht_vereist('nieuw_schooljaar') +def blokkeer_toestellen(): + google_service = GoogleAdminService() + selected_ou = request.form.get('ou_select_blokkeer') + actie = request.form.get('actie') + + success, message = google_service.toggle_ou_devices_status(selected_ou, block=(actie == 'blokkeer')) + + flash(message, "success" if success else "danger") + + # Haal opnieuw de OU's op voor de template + org_units = google_service.list_org_units() + + # Cruciaal: we geven 'blokkeren' mee als actieve tab + return render_template('nieuw_schooljaar_toestellen.html', + org_units=org_units, + active_tab='blokkeren') \ No newline at end of file diff --git a/blueprints/personeel_bp.py b/blueprints/personeel_bp.py new file mode 100644 index 0000000..89701c1 --- /dev/null +++ b/blueprints/personeel_bp.py @@ -0,0 +1,318 @@ +from datetime import date, datetime, timedelta +from decimal import Decimal, InvalidOperation +from functools import wraps + +from flask import Blueprint, render_template, request, redirect, url_for, flash, session, abort +from tenancy import huidige_school, per_school +from blueprints.auth import login_required +from services import personeel_service as P + +personeel_bp = Blueprint('personeel', __name__) + +_tables_ready = set() # scholen waarvoor de tabellen al gecontroleerd zijn + + +def _ensure_tables(): + if huidige_school().code not in _tables_ready: + try: + P.ensure_tables() + _tables_ready.add(huidige_school().code) + except Exception as e: + flash(f"Kon de personeelstabellen niet aanmaken: {e}", "error") + + +def _me(): + return (session.get('user') or '').lower(), session.get('naam') or session.get('user') + + +def rol_vereist(rol): + def deco(f): + @wraps(f) + def wrapped(*a, **kw): + if rol not in P.rollen(session): + flash("Je hebt geen toegang tot deze pagina.", "error") + return redirect(url_for('personeel.mijn')) + return f(*a, **kw) + return wrapped + return deco + + +@personeel_bp.context_processor +def _ctx(): + r = P.rollen(session) if session.get('auth') else set() + return {'p_rollen': r, 'SOORTEN': P.SOORTEN, 'STATUS': P.STATUS, 'DAGDELEN': P.DAGDELEN, + 'p_te_beoordelen': P.aantal_te_beoordelen() if 'directie' in r else 0} + + +def _link(aid): + return url_for('personeel.detail', aid=aid, _external=True) + + +def _mag_zien(item): + me, _ = _me() + r = P.rollen(session) + return (item['Email'] == me or 'secretariaat' in r + or ('directie' in r and P.SOORTEN[item['Soort']]['goedkeuring'])) + + +def _laad(aid): + item = P.get(aid) + if not item: + abort(404) + if not _mag_zien(item): + flash("Je hebt geen toegang tot deze aanvraag.", "error") + return None + return item + + +#--------------------------------------------- +# Mijn meldingen en aanvragen +#--------------------------------------------- +@personeel_bp.route('/', methods=['GET']) +@login_required +def mijn(): + _ensure_tables() + me, _ = _me() + try: + items = P.mijn(me) + except Exception as e: + items = [] + flash(f"Kon je aanvragen niet ophalen: {e}", "error") + return render_template('personeel_mijn.html', items=items, vandaag=date.today()) + + +#--------------------------------------------- +# Nieuwe melding / aanvraag +#--------------------------------------------- +@personeel_bp.route('/nieuw', methods=['GET', 'POST']) +@login_required +def nieuw(): + _ensure_tables() + soort = request.values.get('soort', 'afwezigheid') + if soort not in P.SOORTEN: + soort = 'afwezigheid' + me, mijn_naam = _me() + is_secr = 'secretariaat' in P.rollen(session) + form = request.form + + if request.method == 'POST': + fouten = [] + try: + van = datetime.strptime(form.get('van', ''), '%Y-%m-%d').date() + tot = datetime.strptime(form.get('tot') or form.get('van', ''), '%Y-%m-%d').date() + if tot < van: + fouten.append("De einddatum ligt voor de begindatum.") + except ValueError: + van = tot = None + fouten.append("Kies een geldige datum.") + + titel = (form.get('titel') or '').strip() + if soort == 'afwezigheid' and not titel: + titel = 'Afwezig' + if not titel: + fouten.append("Geef een titel op.") + + dagdeel = form.get('dagdeel', 'dag') + if dagdeel not in P.DAGDELEN: + dagdeel = 'dag' + lesuren = (form.get('lesuren') or '').strip() + if dagdeel == 'uren' and not lesuren: + fouten.append("Vul in welke lesuren het gaat (bv. 3-5).") + + klassen = form.getlist('klassen') + extra = [k.strip() for k in (form.get('klassen_extra') or '').split(',') if k.strip()] + klassen = list(dict.fromkeys(klassen + extra)) + if soort == 'uitstap' and not klassen: + fouten.append("Kies welke klassen mee op uitstap gaan.") + + kost = None + if (form.get('kost') or '').strip(): + try: + kost = Decimal(form['kost'].replace(',', '.').replace('€', '').strip()) + except InvalidOperation: + fouten.append("De kost is geen geldig bedrag.") + + # Secretariaat kan melden namens een leerkracht + email, naam = me, mijn_naam + namens = (form.get('namens') or '').strip().lower() + if namens and namens != me: + if not is_secr: + fouten.append("Je kan enkel voor jezelf een melding maken.") + else: + email, naam = namens, namens + try: + from services.google_service import GoogleAdminService + u = GoogleAdminService().get_user_info(namens) + if not u: + fouten.append(f"{namens} bestaat niet in Google Workspace.") + else: + email = u['primaryEmail'].lower() + naam = (u.get('name') or {}).get('fullName') or email + except Exception: + pass + + if fouten: + for f in fouten: + flash(f, "error") + else: + data = dict(soort=soort, email=email, naam=naam, titel=titel[:255], + omschrijving=(form.get('omschrijving') or '').strip() or None, + locatie=(form.get('locatie') or '').strip()[:255] or None, + van=van, tot=tot, dagdeel=dagdeel, lesuren=lesuren[:50] or None, + klassen=klassen, begeleiders=(form.get('begeleiders') or '').strip() or None, kost=kost) + aid = P.aanmaken(data, me, mijn_naam) + P.mail_nieuw(P.get(aid), _link(aid)) + if P.SOORTEN[soort]['goedkeuring']: + flash("Je aanvraag is ingediend. De directie krijgt een melding; je ontvangt een mail zodra er een beslissing is.", "success") + else: + flash("De afwezigheid is gemeld aan het secretariaat.", "success") + return redirect(url_for('personeel.detail', aid=aid)) + + return render_template('personeel_nieuw.html', soort=soort, form=form, klassen=P.klassen(), + is_secr=is_secr, vandaag=date.today()) + + +#--------------------------------------------- +# Detail + acties +#--------------------------------------------- +@personeel_bp.route('/', methods=['GET']) +@login_required +def detail(aid): + _ensure_tables() + item = _laad(aid) + if item is None: + return redirect(url_for('personeel.mijn')) + me, _ = _me() + return render_template('personeel_detail.html', item=item, reacties=P.reacties(aid), + is_eigenaar=item['Email'] == me, vandaag=date.today()) + + +@personeel_bp.route('//beslissing', methods=['POST']) +@login_required +@rol_vereist('directie') +def beslissing(aid): + item = _laad(aid) + if item is None: + return redirect(url_for('personeel.mijn')) + actie = request.form.get('actie') + tekst = (request.form.get('tekst') or '').strip() + if actie not in ('goedgekeurd', 'geweigerd', 'vraag'): + abort(400) + if not P.SOORTEN[item['Soort']]['goedkeuring'] or item['Status'] not in ('ingediend', 'vraag'): + flash("Over deze aanvraag kan geen beslissing (meer) genomen worden.", "error") + return redirect(url_for('personeel.detail', aid=aid)) + if actie in ('geweigerd', 'vraag') and not tekst: + flash("Geef wat uitleg mee bij een weigering of vraag.", "error") + return redirect(url_for('personeel.detail', aid=aid)) + me, naam = _me() + P.wijzig_status(aid, actie, me, naam, actie, tekst or None) + P.mail_beslissing(P.get(aid), actie, tekst, _link(aid)) + flash({'goedgekeurd': "Aanvraag goedgekeurd.", 'geweigerd': "Aanvraag geweigerd.", + 'vraag': "Je vraag is naar de leerkracht gestuurd."}[actie], "success") + nxt = request.form.get('volgende') + return redirect(url_for('personeel.beoordelen') if nxt else url_for('personeel.detail', aid=aid)) + + +@personeel_bp.route('//antwoord', methods=['POST']) +@login_required +def antwoord(aid): + item = _laad(aid) + if item is None: + return redirect(url_for('personeel.mijn')) + me, naam = _me() + tekst = (request.form.get('tekst') or '').strip() + if item['Email'] != me or item['Status'] != 'vraag' or not tekst: + flash("Antwoorden kan enkel op je eigen aanvraag met een openstaande vraag.", "error") + return redirect(url_for('personeel.detail', aid=aid)) + P.wijzig_status(aid, 'ingediend', me, naam, 'antwoord', tekst) + P.mail_antwoord(P.get(aid), tekst, _link(aid)) + flash("Je antwoord is verstuurd; de aanvraag wacht opnieuw op de directie.", "success") + return redirect(url_for('personeel.detail', aid=aid)) + + +@personeel_bp.route('//commentaar', methods=['POST']) +@login_required +def commentaar(aid): + item = _laad(aid) + if item is None: + return redirect(url_for('personeel.mijn')) + tekst = (request.form.get('tekst') or '').strip() + if tekst: + me, naam = _me() + P.commentaar(aid, me, naam, tekst) + return redirect(url_for('personeel.detail', aid=aid)) + + +@personeel_bp.route('//annuleren', methods=['POST']) +@login_required +def annuleren(aid): + item = _laad(aid) + if item is None: + return redirect(url_for('personeel.mijn')) + me, naam = _me() + if not (item['Email'] == me or 'secretariaat' in P.rollen(session)): + flash("Je kan deze aanvraag niet annuleren.", "error") + elif item['Status'] in ('geannuleerd', 'geweigerd'): + flash("Deze aanvraag is al afgesloten.", "error") + else: + P.mail_geannuleerd(item, _link(aid)) + P.wijzig_status(aid, 'geannuleerd', me, naam, 'geannuleerd', (request.form.get('tekst') or '').strip() or None) + flash("Geannuleerd.", "success") + return redirect(url_for('personeel.detail', aid=aid)) + + +@personeel_bp.route('//vervanging', methods=['POST']) +@login_required +@rol_vereist('secretariaat') +def vervanging(aid): + item = _laad(aid) + if item is None: + return redirect(url_for('personeel.mijn')) + me, naam = _me() + P.vervanging(aid, request.form.get('ok') == '1', request.form.get('info'), me, naam) + terug = request.form.get('terug') + return redirect(terug if terug and terug.startswith('/') else url_for('personeel.detail', aid=aid)) + + +#--------------------------------------------- +# Directie: te beoordelen +#--------------------------------------------- +@personeel_bp.route('/beoordelen', methods=['GET']) +@login_required +@rol_vereist('directie') +def beoordelen(): + _ensure_tables() + return render_template('personeel_beoordelen.html', open_items=P.te_beoordelen(), recent=P.recent_beslist()) + + +#--------------------------------------------- +# Secretariaat: dagoverzicht +#--------------------------------------------- +@personeel_bp.route('/dagoverzicht', methods=['GET']) +@login_required +@rol_vereist('secretariaat') +def dagoverzicht(): + _ensure_tables() + try: + dag = datetime.strptime(request.args.get('datum', ''), '%Y-%m-%d').date() + except ValueError: + dag = date.today() + weergave = request.args.get('weergave', 'dag') + if weergave == 'week': + van = dag - timedelta(days=dag.weekday()) + tot = van + timedelta(days=4) + stap = timedelta(days=7) + else: + weergave = 'dag' + if dag.weekday() >= 5: # weekend → volgende maandag + dag = dag + timedelta(days=7 - dag.weekday()) + van = tot = dag + stap = timedelta(days=1) + vorige, volgende = van - stap, van + stap + if weergave == 'dag': + while vorige.weekday() >= 5: + vorige -= timedelta(days=1) + while volgende.weekday() >= 5: + volgende += timedelta(days=1) + return render_template('personeel_dagoverzicht.html', dagen=P.dagoverzicht(van, tot), weergave=weergave, + dag=dag, van=van, tot=tot, vorige=vorige, volgende=volgende, vandaag=date.today()) diff --git a/blueprints/personeelsaantal_bp.py b/blueprints/personeelsaantal_bp.py new file mode 100644 index 0000000..cbabf81 --- /dev/null +++ b/blueprints/personeelsaantal_bp.py @@ -0,0 +1,232 @@ +""" +Personeel › Personeelsaantallen: hetzelfde overzicht als de leerlingenaantallen, maar voor het personeel. + +Elke school wordt geteld met haar eigen Informat-koppeling (Personeel-API, zie services/gopro_service.py): +een personeelslid telt mee als het op de peildatum een lopende opdracht heeft (één keer per persoon). +- Huidig aantal: vandaag, bewaard in Personeelsaantal_huidig. +- Telling op peildatum: bewaard in Personeelsaantal_tellingen, later opnieuw te bekijken en te exporteren. +Het sjabloon is gedeeld met de leerlingenaantallen (leerlingenaantal.html). +""" +import csv +import io +import json +from datetime import date + +from flask import Blueprint, render_template, request, flash, redirect, url_for, session, Response +from blueprints.auth import login_required +from blueprints.leerlingenaantal_bp import (INFORMAT_VELDEN, NIVEAUS, _datum, _detail, _fmt, _groepen, _niveau, + _som) +from database import central_query +from rechten import recht_vereist +from services.gopro_service import GoProService +from tenancy import alle_scholen, school_op_code, in_school, _automatisch_schooljaar + +personeelsaantal_bp = Blueprint('personeelsaantal', __name__) + +WEERGAVE = dict(ep='personeelsaantal', pagina='personeelsaantal_page', titel='Personeelsaantallen', + eenheid='Personeelsleden', kort='pers.') + + +def _huidig(query=''): + per = {r['School_ID']: r for r in central_query( + "SELECT School_ID, Aantal, Detail, Gesynchroniseerd FROM Personeelsaantal_huidig")} + rows = [] + for s in alle_scholen(): + if query and query.lower() not in s.naam.lower(): + continue + h = per.get(s.id) or {} + rows.append({'Code': s.code, 'Naam_school': s.naam, 'Niveau': _niveau(s), + 'Huidig': h['Aantal'] if h else '–', 'Laatste_synchronisatie': h.get('Gesynchroniseerd'), + 'Informat': s.heeft(*INFORMAT_VELDEN), 'Campussen': _detail(h.get('Detail'))}) + return rows + + +def _telling(peildatum, query=''): + per = {r['School_ID']: r for r in central_query( + "SELECT School_ID, Aantal, Detail, Schooljaar, Opgevraagd_op, Door FROM Personeelsaantal_tellingen " + "WHERE Peildatum = %s", (peildatum,))} + rows = [] + for s in alle_scholen(): + if query and query.lower() not in s.naam.lower(): + continue + t = per.get(s.id) or {} + rows.append({'Code': s.code, 'Naam_school': s.naam, 'Niveau': _niveau(s), 'Aantal': t.get('Aantal'), + 'Schooljaar': t.get('Schooljaar'), 'Opgevraagd_op': t.get('Opgevraagd_op'), + 'Door': t.get('Door'), 'Informat': s.heeft(*INFORMAT_VELDEN), + 'Campussen': _detail(t.get('Detail'))}) + return rows + + +def _peildata(): + return central_query("SELECT Peildatum, COUNT(*) AS Scholen, SUM(Aantal) AS Totaal, MAX(Opgevraagd_op) AS Laatst " + "FROM Personeelsaantal_tellingen GROUP BY Peildatum ORDER BY Peildatum DESC") + + +def _tel(school, peildatum): + """(ok, aantal of foutmelding, detail) voor één school.""" + try: + with in_school(school): + totaal, detail = GoProService().tel(peildatum) + return True, totaal, detail + except Exception as e: + return False, str(e), None + + +@personeelsaantal_bp.route("/", methods=["GET"]) +@login_required +@recht_vereist('personeelsaantal') +def personeelsaantal_page(): + query = (request.values.get("query") or "").strip() + results = _huidig(query) + peildatum = _datum(request.args.get('peildatum')) + telling = _telling(peildatum, query) if peildatum else None + return render_template("leerlingenaantal.html", results=results, query=query, totaal=_som(results, 'Huidig'), + groepen=_groepen(results, 'Huidig'), + telling_groepen=_groepen(telling, 'Aantal') if telling else [], + peildatum=peildatum, telling=telling, + telling_totaal=_som(telling, 'Aantal') if telling else 0, + peildata=_peildata(), vandaag=date.today(), **WEERGAVE) + + +@personeelsaantal_bp.route("/sync-aanvragen", methods=["POST"]) +@login_required +@recht_vereist('personeelsaantal') +def sync_aanvragen(): + codes = [s.code for s in alle_scholen()] if request.form.get("alle") else [request.form.get("school_code")] + for code in codes: + school = school_op_code(code) + if not school: + continue + if not school.heeft(*INFORMAT_VELDEN): + if not request.form.get("alle"): + flash(f"{school.naam}: Informat is nog niet ingesteld.", "error") + continue + ok, res, detail = _tel(school, date.today()) + if not ok: + flash(f"{school.naam}: {res}", "error") + continue + central_query( + "INSERT INTO Personeelsaantal_huidig (School_ID, Aantal, Detail, Gesynchroniseerd) VALUES (%s, %s, %s, NOW()) " + "ON DUPLICATE KEY UPDATE Aantal = VALUES(Aantal), Detail = VALUES(Detail), Gesynchroniseerd = NOW()", + (school.id, res, json.dumps(detail) if detail else None), commit=True) + flash(f"{school.naam}: {res} personeelsleden" + (" (" + ", ".join(f"{d['naam']}: {d['aantal']}" for d in detail) + + ")" if detail else "") + ".", "success") + return redirect(url_for('personeelsaantal.personeelsaantal_page')) + + +@personeelsaantal_bp.route("/peildatum", methods=["POST"]) +@login_required +@recht_vereist('personeelsaantal') +def tel_peildatum(): + peildatum = _datum(request.form.get('peildatum')) + if not peildatum: + flash("Kies een geldige datum.", "error") + return redirect(url_for('personeelsaantal.personeelsaantal_page')) + code = request.form.get('school_code') + scholen = [school_op_code(code)] if code else alle_scholen() + gelukt = 0 + for school in scholen: + if not school or not school.heeft(*INFORMAT_VELDEN): + if school and code: + flash(f"{school.naam}: Informat is nog niet ingesteld.", "error") + continue + ok, res, detail = _tel(school, peildatum) + if not ok: + flash(f"{school.naam}: {res}", "error") + continue + central_query( + "INSERT INTO Personeelsaantal_tellingen (School_ID, Peildatum, Schooljaar, Aantal, Detail, Opgevraagd_op, Door) " + "VALUES (%s, %s, %s, %s, %s, NOW(), %s) ON DUPLICATE KEY UPDATE Schooljaar = VALUES(Schooljaar), " + "Aantal = VALUES(Aantal), Detail = VALUES(Detail), Opgevraagd_op = NOW(), Door = VALUES(Door)", + (school.id, peildatum, _automatisch_schooljaar(peildatum), res, json.dumps(detail) if detail else None, + session.get('user')), commit=True) + gelukt += 1 + if gelukt: + flash(f"Personeel geteld op {peildatum:%d-%m-%Y} voor {gelukt} school/scholen.", "success") + return redirect(url_for('personeelsaantal.personeelsaantal_page', peildatum=peildatum.isoformat())) + + +@personeelsaantal_bp.route("/peildatum/verwijderen", methods=["POST"]) +@login_required +@recht_vereist('personeelsaantal') +def verwijder_peildatum(): + peildatum = _datum(request.form.get('peildatum')) + if peildatum: + central_query("DELETE FROM Personeelsaantal_tellingen WHERE Peildatum = %s", (peildatum,), commit=True) + flash(f"Telling van {peildatum:%d-%m-%Y} verwijderd.", "success") + return redirect(url_for('personeelsaantal.personeelsaantal_page')) + + +def _csv(naam, kop, rijen): + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') + w.writerow(kop) + w.writerows(rijen) + return Response('' + buf.getvalue(), mimetype='text/csv', + headers={'Content-Disposition': f'attachment; filename={naam}'}) + + +@personeelsaantal_bp.route("/export.csv", methods=["GET"]) +@login_required +@recht_vereist('personeelsaantal') +def export_csv(): + """?peildatum=YYYY-MM-DD → die telling; ?alle=1 → alle peildata naast elkaar; anders het huidige aantal.""" + query = (request.args.get('query') or '').strip() + + if request.args.get('alle'): + data = central_query("SELECT School_ID, Peildatum, Aantal, Detail FROM Personeelsaantal_tellingen ORDER BY Peildatum") + datums = sorted({r['Peildatum'] for r in data}) + per = {(r['School_ID'], r['Peildatum']): r['Aantal'] for r in data} + campus, campusnamen = {}, {} + for r in data: + for d in _detail(r['Detail']): + campus[(r['School_ID'], d['naam'], r['Peildatum'])] = d['aantal'] + campusnamen.setdefault(r['School_ID'], []) + if d['naam'] not in campusnamen[r['School_ID']]: + campusnamen[r['School_ID']].append(d['naam']) + scholen = [s for s in alle_scholen() if not query or query.lower() in s.naam.lower()] + rijen = [] + for code, label in NIVEAUS: + groep = [s for s in scholen if _niveau(s) == code] + if not groep: + continue + for s in groep: + rijen.append([label, s.naam, ''] + [per.get((s.id, d), '') for d in datums]) + for naam in campusnamen.get(s.id, []): + rijen.append([label, s.naam, naam] + [campus.get((s.id, naam, d), '') for d in datums]) + if code: + rijen.append([f"Subtotaal {label}", '', ''] + [sum(per.get((s.id, d)) or 0 for s in groep) for d in datums]) + rijen.append(['Totaal', '', ''] + [sum(per.get((s.id, d)) or 0 for s in scholen) for d in datums]) + return _csv(f"personeelsaantallen_alle_peildata_{date.today():%Y%m%d}.csv", + ['Onderwijsniveau', 'School', 'Instelling'] + [f"{d:%d-%m-%Y}" for d in datums], rijen) + + peildatum = _datum(request.args.get('peildatum')) + if peildatum: + rows = _telling(peildatum, query) + rijen = [] + for g in _groepen(rows, 'Aantal'): + for r in g['rijen']: + rijen.append([g['label'], r['Naam_school'], '', '' if r['Aantal'] is None else r['Aantal'], + r['Schooljaar'] or '', _fmt(r['Opgevraagd_op'], 'niet geteld'), r['Door'] or '']) + for c in r['Campussen']: + rijen.append([g['label'], r['Naam_school'], c['naam'], c['aantal'], r['Schooljaar'] or '', '', '']) + if g['code']: + rijen.append([f"Subtotaal {g['label']}", '', '', g['subtotaal'], '', '', '']) + rijen.append(['Totaal', '', '', _som(rows, 'Aantal'), '', '', '']) + return _csv(f"personeelsaantallen_{peildatum:%Y%m%d}.csv", + ['Onderwijsniveau', 'School', 'Instelling', f"Personeelsleden op {peildatum:%d-%m-%Y}", 'Schooljaar', + 'Opgevraagd op', 'Door'], rijen) + + rows = _huidig(query) + rijen = [] + for g in _groepen(rows, 'Huidig'): + for r in g['rijen']: + rijen.append([g['label'], r['Naam_school'], '', r['Huidig'] if isinstance(r['Huidig'], int) else '', + _fmt(r['Laatste_synchronisatie'], 'nog nooit')]) + for c in r['Campussen']: + rijen.append([g['label'], r['Naam_school'], c['naam'], c['aantal'], '']) + if g['code']: + rijen.append([f"Subtotaal {g['label']}", '', '', g['subtotaal'], '']) + rijen.append(['Totaal', '', '', _som(rows, 'Huidig'), '']) + return _csv(f"personeelsaantallen_{date.today():%Y%m%d}.csv", + ['Onderwijsniveau', 'School', 'Instelling', 'Personeelsleden', 'Laatste synchronisatie'], rijen) diff --git a/blueprints/qr_code_bp.py b/blueprints/qr_code_bp.py new file mode 100644 index 0000000..5e97b1e --- /dev/null +++ b/blueprints/qr_code_bp.py @@ -0,0 +1,125 @@ +import io +import zipfile +import qrcode +import pandas as pd +from flask import Blueprint, render_template, request, send_file, flash, redirect, url_for +from PIL import Image, ImageDraw, ImageFont +from blueprints.auth import login_required +from rechten import recht_vereist # Zorg dat dit pad klopt naar je auth_utils.py + +# definieren blueprint +qr_code_bp = Blueprint('qr_generator', __name__, template_folder='templates') + +def generate_qr_images(excel_file, show_top, show_bottom): + # Overslaan van de header rij + df = pd.read_excel(excel_file, header=0) + + zip_buffer = io.BytesIO() + + try: + # Try loading your local or system Arial font + font = ImageFont.truetype("arial.ttf", 20) + except IOError: + try: + + font = ImageFont.load_default_font(size=20) + except AttributeError: + # Absolute fallback if Pillow is outdated, but textbbox WILL fail if this hits + font = ImageFont.load_default() + + with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED) as zip_file: + for index, row in df.iterrows(): + # Gebruik .iloc voor veiligheid tegen kolomnamen + qr_text = str(row.iloc[0]) if not pd.isna(row.iloc[0]) else "" + top_text = str(row.iloc[1]) if not pd.isna(row.iloc[1]) else "" + bottom_text = str(row.iloc[2]) if not pd.isna(row.iloc[2]) else "" + + if qr_text.strip() == "": + continue + + qr = qrcode.QRCode(error_correction=qrcode.constants.ERROR_CORRECT_H) + qr.add_data(qr_text) + qr.make(fit=True) + qr_img = qr.make_image(fill_color="black", back_color="white").convert("RGB") + + qr_width, qr_height = qr_img.size + padding = 40 + total_height = qr_height + (2 * padding) + + canvas = Image.new("RGB", (qr_width + 40, total_height + 40), "white") + draw = ImageDraw.Draw(canvas) + + qr_x = (canvas.width - qr_width) // 2 + qr_y = padding + canvas.paste(qr_img, (qr_x, qr_y)) + + if show_top and top_text: + bbox = draw.textbbox((0, 0), top_text, font=font) + text_w = bbox[2] - bbox[0] + draw.text(((canvas.width - text_w) / 2, 5), top_text, fill="black", font=font) + + if show_bottom and bottom_text: + bbox = draw.textbbox((0, 0), bottom_text, font=font) + text_w = bbox[2] - bbox[0] + draw.text(((canvas.width - text_w) / 2, qr_y + qr_height + 5), bottom_text, fill="black", font=font) + + img_io = io.BytesIO() + canvas.save(img_io, 'PNG') + img_io.seek(0) + zip_file.writestr(f"qr_{index+1}.png", img_io.getvalue()) + + zip_buffer.seek(0) + return zip_buffer + +@qr_code_bp.route('/') +@login_required +@recht_vereist('qr_codes') +def qr_generator(): + + return render_template('qr_code.html') + +@qr_code_bp.route('/download-template') +@login_required +@recht_vereist('qr_codes') +def download_template(): + df = pd.DataFrame(columns=["QR-Code (Link/ID)", "Koptekst", "Voettekst"]) + + buffer = io.BytesIO() + with pd.ExcelWriter(buffer, engine='openpyxl') as writer: + df.to_excel(writer, index=False) + + buffer.seek(0) + + return send_file( + buffer, + as_attachment=True, + download_name='sjabloon_qr.xlsx', + mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ) + +@qr_code_bp.route('/upload', methods=['POST']) +@login_required +@recht_vereist('qr_codes') +def upload_file(): + if 'file' not in request.files: + flash("Geen bestand geselecteerd", "warning") + return redirect(url_for('qr_generator.qr_generator')) + + file = request.files['file'] + show_top = request.form.get('show_top') == 'on' + show_bottom = request.form.get('show_bottom') == 'on' + + if file and file.filename != '': + try: + zip_data = generate_qr_images(file, show_top, show_bottom) + return send_file( + zip_data, + mimetype='application/zip', + as_attachment=True, + download_name='qr_codes.zip' + ) + except Exception as e: + flash(f"Fout bij verwerken: {str(e)}", "danger") + return redirect(url_for('qr_generator.qr_generator')) + + return redirect(url_for('qr_generator.qr_generator')) \ No newline at end of file diff --git a/blueprints/repairs.py b/blueprints/repairs.py new file mode 100644 index 0000000..9f4df57 --- /dev/null +++ b/blueprints/repairs.py @@ -0,0 +1,145 @@ +from flask import Blueprint, render_template, request, session, redirect, url_for, flash +from database import execute_query +from blueprints.auth import login_required +from rechten import recht_vereist +from services import CIP_inleveren # Voor de Ingeven_herstelling logica +from services.signpost_byod_service import get_cases_by_serial +from services import toestellen as tst + +# Herstellingen met de kolomnamen die herstellingen.html verwacht +HERSTELLINGEN_SQL = """ + SELECT h.Incident_ID AS Incident_nr, t.Schooleigen_ID AS KAMXM_nummer, t.Serienummer, + h.Omschrijving AS Soort_herstelling, h.Status_herstelling AS Status, h.Datum, h.Kostprijs, + l.Internnummer + FROM Signpost_herstellingen_DB h + JOIN Toestellen t ON t.Toestel_ID = h.Toestel_ID + LEFT JOIN Leerlingen l ON l.Leerling_ID = h.Leerling_ID +""" + +# Definieer de blueprint +repairs_bp = Blueprint('repairs', __name__) + +#--------------------------------------------------- +# --- ROUTE: OVERZICHT & ZOEKEN --- +#---------------------------------------------------- +@repairs_bp.route('/herstellingen', methods=['GET', 'POST']) +@login_required +@recht_vereist('herstellingen') +def herstellingen(): + query = None + results = [] + + # Haal de zoekterm op bij een POST request + if request.method == 'POST': + query = request.form.get('query') + sql = HERSTELLINGEN_SQL + " WHERE t.Schooleigen_ID LIKE %s OR h.Omschrijving LIKE %s ORDER BY h.Incident_ID DESC" + results = execute_query(sql, (f'%{query}%', f'%{query}%')) + else: + # Toon standaard alle herstellingen + results = execute_query(HERSTELLINGEN_SQL + " ORDER BY h.Incident_ID DESC") + + return render_template('herstellingen.html', results=results, query=query) + +#------------------------------------------------ +# --- ROUTE: TOEVOEGEN HERSTELLING --- +#------------------------------------------------ +@repairs_bp.route('/repairs.add_herstelling', methods=['POST']) +@login_required +@recht_vereist('herstellingen') +def add_herstelling(): + kamxm_nummer = request.form.get('kamxm_nummer') + soort_herstelling = request.form.get('soort_herstelling') + + if not kamxm_nummer or not soort_herstelling: + flash("Vul alle velden in!", "error") + return redirect(url_for('repairs.herstellingen')) + + try: + # Gebruik de logica uit de CIP_inleveren module + CIP_inleveren.Ingeven_herstelling(kamxm_nummer, soort_herstelling) + if CIP_inleveren.foutmelding: + flash(CIP_inleveren.foutmelding) + except Exception as e: + flash(f"Er is een fout opgetreden: {str(e)}", "error") + + return redirect(url_for('repairs.herstellingen')) + +#functie achter wijzig herstellingen +@repairs_bp.route('/wijzig_status_herstelling', methods=['POST']) +@login_required +@recht_vereist('herstellingen') +def wijzig_status_herstelling(): + # Haal alle gegevens op uit het formulier + kamxm_nummer = request.form.get('kamxm_nummer') + nieuwe_status = request.form.get('new_status') + incident_nr = request.form.get("incident_nr") # Zorg dat dit uit je modal komt + + # Validatie: we hebben nu alle drie de velden nodig voor een unieke update + if not kamxm_nummer or not nieuwe_status or not incident_nr: + flash("Fout: Ontbrekende gegevens (Toestel, Status of Incident nr).", "error") + return redirect(url_for('repairs.herstellingen')) + + try: + # Update alleen de rij waar zowel KAMXM als Incident_nr overeenkomen + execute_query("UPDATE Signpost_herstellingen_DB SET Status_herstelling = %s WHERE Incident_ID = %s", + (nieuwe_status, incident_nr), commit=True) + + flash(f"Status van incident {incident_nr} ({kamxm_nummer}) is nu: {nieuwe_status}", "success") + except Exception as err: + flash(f"Database fout: {err}", "error") + + return redirect(url_for('repairs.herstellingen')) + +#----------------------------------------------- +# --- ROUTE: GEGEVENS BEWERKEN --- +#----------------------------------------------- +@repairs_bp.route('/bewerk_herstelling', methods=['POST']) +@login_required +@recht_vereist('herstellingen') +def bewerk_herstelling(): + # Haal de originele sleutels op om de juiste rij te vinden + old_kamxm = request.form.get('kamxm_nummer_original') + incident_nr = request.form.get('incident_nr') # Dit is essentieel voor de unieke selectie + + # Haal de nieuwe waarden op + new_kamxm = request.form.get('kamxm_nummer') + soort = request.form.get('soort_herstelling') + datum = request.form.get('datum') + + try: + toestel = tst.zoek_toestel(new_kamxm) + if not toestel: + flash(f"Toestel {new_kamxm} niet gevonden.", "error") + return redirect(url_for('repairs.herstellingen')) + execute_query("UPDATE Signpost_herstellingen_DB SET Toestel_ID = %s, Omschrijving = %s, Datum = %s " + "WHERE Incident_ID = %s", + (toestel['Toestel_ID'], soort, datum or None, incident_nr), commit=True) + flash(f"Herstelling {incident_nr} voor {new_kamxm} succesvol bijgewerkt!", "success") + except Exception as err: + flash(f"Fout bij bijwerken: {err}", "error") + + return redirect(url_for('repairs.herstellingen')) + +#-------------------------------------------------- +#--- ROUTE: Signpost herstelling +#-------------------------------------------------- +@repairs_bp.route('/herstellingen/signpost_search', methods=['POST']) +@login_required +@recht_vereist('herstellingen') +def signpost_search(): + serial = request.form.get('serial_number') + signpost_results = [] + + if serial: + signpost_results = get_cases_by_serial(serial) + if not signpost_results: + flash(f"Geen Signpost cases gevonden voor {serial}", "info") + + # We sturen de gebruiker terug naar de tab, maar met de resultaten + # Tip: Om de tab 'active' te houden na een POST, kun je een parameter meesturen + results = execute_query(HERSTELLINGEN_SQL + " ORDER BY h.Incident_ID DESC") + return render_template('herstellingen.html', + results=results, + signpost_results=signpost_results, + active_tab='signpost-tab', + searched_serial=serial) \ No newline at end of file diff --git a/blueprints/scholen_bp.py b/blueprints/scholen_bp.py new file mode 100644 index 0000000..78bd6d5 --- /dev/null +++ b/blueprints/scholen_bp.py @@ -0,0 +1,683 @@ +""" +Scholenbeheer. + +- Superbeheerders (administrators in Gebruikers, of config.ini › superbeheerders via Google): + scholen toevoegen, alle instellingen wijzigen, tussen alle scholen wisselen. +- Gebruikers met het recht 'koppelingen' in een school: de koppelingen van DIE school wijzigen + (wachtwoorden, Informat, Google, ...), maar niet de code, domeinen of database. +- Iedereen kan wisselen naar een school waarin hij rechten heeft. +""" +import functools +import json +import os +import re +import sys + +import requests +from flask import Blueprint, render_template, request, redirect, url_for, flash, session, g + +import tenancy +from tenancy import VELDEN, VELD, GROEPEN, alle_scholen, school_op_code, in_school +from database import central_query, execute_query, get_central_connection, vergeet_pools +import rechten + +scholen_bp = Blueprint('scholen', __name__) + +CODE_RE = re.compile(r'^[a-z0-9_-]{2,32}$') +DB_RE = re.compile(r'^[A-Za-z0-9_-]{1,64}$') +# Velden die enkel een superbeheerder mag wijzigen +ENKEL_SUPER_GROEPEN = {'database'} + + +def superbeheerder_required(f): + @functools.wraps(f) + def wrapped(*a, **kw): + if not session.get('auth') or not session.get('superbeheerder'): + flash("Enkel voor superbeheerders van de scholengroep.", "error") + return redirect(url_for('auth.login')) + return f(*a, **kw) + return wrapped + + +# Koppelingen van de eigen school: recht 'koppelingen' in die school +schoolbeheerder_required = rechten.recht_vereist('koppelingen') + + +# ------------------------------------------------------------------ +# Overzicht en wisselen +# ------------------------------------------------------------------ +@scholen_bp.route('/') +@superbeheerder_required +def overzicht(): + tenancy.herlaad(force=True) + scholen = alle_scholen(ook_inactief=True) + # Onderverdeeld per onderwijsniveau; scholen zonder (geldig) niveau komen in de laatste groep + niveaus = list(tenancy.ONDERWIJSNIVEAUS) + [('', 'Onderwijsniveau niet gekozen')] + codes = {c for c, _ in tenancy.ONDERWIJSNIVEAUS} + niveau = lambda sch: sch.waarden.get('ONDERWIJSNIVEAU') if sch.waarden.get('ONDERWIJSNIVEAU') in codes else '' + groepen = [{'code': code or 'geen', 'label': label, 'scholen': [x for x in scholen if niveau(x) == code]} + for code, label in niveaus] + tests = laatste_tests() + return render_template('scholen.html', scholen=scholen, groepen=[g for g in groepen if g['scholen']], + badges={x.code: koppeling_badges(x, tests.get(x.id, {})) for x in scholen}) + + +# ------------------------------------------------------------------ +# Resultaten van de koppelingstest (voor de badges in het overzicht) +# ------------------------------------------------------------------ +# Badge in het overzicht → onderdelen uit test_school() die erbij horen +BADGES = [ + ('Smartschool', ('SS_API_PLATFORM', 'SS_API_PW'), ('Smartschool webservices', 'Smartschool OneRoster')), + ('Informat', ('INFORMAT_INST_NUMBER', 'INFORMAT_ID', 'INFORMAT_SECRET'), ('Informat',)), + ('Google', None, ('Google Workspace',)), + ('Signpost', ('M4S_CLIENT_ID', 'M4S_CLIENT_SECRET'), ('Signpost / M4S',)), +] + + +def _informat_ingesteld(school): + """Informat telt als ingesteld met client-ID/secret en een instellingsnummer van de school óf van het internaat.""" + return school.heeft('INFORMAT_ID', 'INFORMAT_SECRET') and ( + school.heeft('INFORMAT_INST_NUMBER') or school.heeft('INFORMAT_INTERNAAT_NUMMER')) + + +def bewaar_test(school, resultaten): + for onderdeel, ok, detail in resultaten: + central_query( + "INSERT INTO Koppeling_tests (School_ID, Onderdeel, Ok, Detail, Getest_op) VALUES (%s, %s, %s, %s, NOW()) " + "ON DUPLICATE KEY UPDATE Ok = VALUES(Ok), Detail = VALUES(Detail), Getest_op = NOW()", + (school.id, onderdeel, None if ok is None else int(bool(ok)), (detail or '')[:500]), commit=True) + + +def laatste_tests(): + """{school_id: {onderdeel: rij}}""" + uit = {} + try: + for r in central_query("SELECT School_ID, Onderdeel, Ok, Detail, Getest_op FROM Koppeling_tests") or []: + uit.setdefault(r['School_ID'], {})[r['Onderdeel']] = r + except Exception: + pass + return uit + + +def koppeling_badges(school, tests): + """[{label, toestand: ok|fout|ongetest|niet, titel}] volgens de laatste test. Een test van vóór de laatste + wijziging aan de school telt niet meer (dan 'ongetest').""" + from datetime import datetime + try: + gewijzigd = datetime.fromisoformat(school.versie).replace(microsecond=0) if school.versie else None + except ValueError: + gewijzigd = None + uit = [] + for label, velden, onderdelen in BADGES: + if label == 'Informat': + ingesteld = _informat_ingesteld(school) + else: + ingesteld = school.google_sleutel is not None if velden is None else school.heeft(*velden) + if not ingesteld: + uit.append({'label': label, 'toestand': 'niet', 'titel': 'niet ingesteld'}) + continue + rijen = [tests[o] for o in onderdelen if o in tests and tests[o]['Ok'] is not None] + if not rijen or (gewijzigd and any(r['Getest_op'] < gewijzigd for r in rijen)): + uit.append({'label': label, 'toestand': 'ongetest', + 'titel': 'ingesteld, maar nog niet getest sinds de laatste wijziging – klik op Testen'}) + continue + fout = [r for r in rijen if not r['Ok']] + wanneer = max(r['Getest_op'] for r in rijen).strftime('%d-%m-%Y %H:%M') + if fout: + uit.append({'label': label, 'toestand': 'fout', + 'titel': f"test mislukt op {wanneer}: " + ' · '.join(r['Detail'] for r in fout)[:300]}) + else: + uit.append({'label': label, 'toestand': 'ok', 'titel': f"test geslaagd op {wanneer}"}) + return uit + + +@scholen_bp.route('/wissel/') +def wissel(code): + """Naar een andere school gaan: superbeheerders overal, anderen waar ze rechten hebben.""" + if not session.get('auth'): + return redirect(url_for('auth.login')) + school = school_op_code(code) + if not school: + flash("Onbekende of inactieve school.", "error") + return redirect(url_for('main.dashboard')) + if not session.get('superbeheerder'): + gid = session.get('gebruiker_id') + if not gid or school.id not in rechten.scholen_met_rechten(gid): + flash(f"Je hebt geen rechten in {school.naam}.", "error") + return redirect(url_for('main.dashboard')) + session['school'] = school.code + rechten.bewaar_laatste_school(session.get('gebruiker_id'), school.code) # volgende keer meteen deze school + flash(f"Je werkt nu in {school.naam}.", "success") + from blueprints.auth import _onthoud_school + return _onthoud_school(redirect(url_for('main.dashboard')), school) + + +# ------------------------------------------------------------------ +# Formulier +# ------------------------------------------------------------------ +# Velden die een uur van de dag zijn (0–23) +UUR_VELDEN = {'AFWEZIGHEID_SYNC_UUR'} + + +def _controleer_waarden(waarden): + """Geeft een foutmelding als een getal-veld ongeldig is, anders None.""" + for v in VELDEN: + w = str(waarden.get(v.key) or '').strip() + if v.soort != 'getal' or not w: + continue + if not w.isdigit(): + return f"'{v.label}' moet een getal zijn (nu: {w})." + if v.key in UUR_VELDEN and not 0 <= int(w) <= 23: + return f"'{v.label}' moet een uur tussen 0 en 23 zijn (nu: {w})." + return None + + +def _form_waarden(school, mag_alles): + """Leest het formulier. Lege geheimen = ongewijzigd laten (tenzij 'wissen' aangevinkt).""" + oud = dict(school.waarden) if school else {} + nieuw = dict(oud) + for v in VELDEN: + if v.groep in ENKEL_SUPER_GROEPEN and not mag_alles: + continue + naam = f"v_{v.key}" + if v.soort == 'janee': + nieuw[v.key] = 'ja' if request.form.get(naam) else 'nee' + continue + waarde = (request.form.get(naam) or '').strip() + if v.soort == 'geheim': + if request.form.get(f"wis_{v.key}"): + nieuw.pop(v.key, None) + elif waarde: + nieuw[v.key] = waarde + continue + if waarde: + nieuw[v.key] = waarde + else: + nieuw.pop(v.key, None) + return nieuw + + +def _google_sleutel_uit_form(): + """Geeft (sleutel_dict | None, foutmelding | None).""" + bestand = request.files.get('google_sleutel') + tekst = '' + if bestand and bestand.filename: + tekst = bestand.read().decode('utf-8', errors='replace') + elif (request.form.get('google_sleutel_tekst') or '').strip(): + tekst = request.form['google_sleutel_tekst'].strip() + if not tekst: + return None, None + try: + data = json.loads(tekst) + except ValueError: + return None, "De Google-sleutel is geen geldig JSON-bestand." + if data.get('type') != 'service_account' or not data.get('private_key') or not data.get('client_email'): + return None, "Dit is geen sleutel van een Google-serviceaccount (type 'service_account')." + return data, None + + +def database_status(school): + """'ok' (PIVOT-tabellen aanwezig), 'leeg' (database bestaat, tabellen ontbreken) of 'ontbreekt'.""" + import mysql.connector + cfg = school.db_config() + from config import Config + try: + conn = mysql.connector.connect(host=cfg['host'], port=Config.DB_PORT, user=cfg['user'], + password=cfg['password'], connection_timeout=5) + except Exception: + return 'onbekend' + try: + cur = conn.cursor() + cur.execute("SELECT COUNT(*) FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = %s", (school.db_naam,)) + if not cur.fetchone()[0]: + return 'ontbreekt' + cur.execute("SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = %s " + "AND LOWER(TABLE_NAME) = 'toestellen'", (school.db_naam,)) + return 'ok' if cur.fetchone()[0] else 'leeg' + except Exception: + return 'onbekend' + finally: + conn.close() + + +def _render_form(school, nieuw, mag_alles, form=None): + return render_template('school_bewerken.html', school=school, nieuw=nieuw, mag_alles=mag_alles, + db_status=database_status(school) if school else None, + groepen=GROEPEN, velden=VELDEN, enkel_super=ENKEL_SUPER_GROEPEN, + form=form or {}, andere_scholen=[s for s in alle_scholen(ook_inactief=True) if not school or s.code != school.code]) + + +@scholen_bp.route('/nieuw', methods=['GET', 'POST']) +@superbeheerder_required +def nieuw(): + if request.method == 'GET': + return _render_form(None, True, True) + + code = (request.form.get('code') or '').strip().lower() + naam = (request.form.get('naam') or '').strip() + db_naam = (request.form.get('db_naam') or '').strip() + fouten = [] + if not CODE_RE.match(code): + fouten.append("De code mag enkel kleine letters, cijfers, - en _ bevatten (2-32 tekens).") + elif school_op_code(code, ook_inactief=True): + fouten.append(f"Er bestaat al een school met code '{code}'.") + if not naam: + fouten.append("Vul de naam van de school in.") + if not DB_RE.match(db_naam): + fouten.append("Ongeldige databasenaam.") + domeinen, fout = _domeinen(request.form.get('domeinen')) + if fout: + fouten.append(fout) + sleutel, fout = _google_sleutel_uit_form() + if fout: + fouten.append(fout) + if fouten: + for f in fouten: + flash(f, "error") + return _render_form(None, True, True, form=request.form) + + waarden = _form_waarden(None, True) + fout = _controleer_waarden(waarden) + if fout: + flash(fout, "error") + return _render_form(None, True, True, form=request.form) + + # Optioneel: database aanmaken (standaardstructuur, of een volledige kopie van een bestaande school) + keuze = request.form.get('kopieer_schema_van') + bron = school_op_code(keuze, ook_inactief=True) if keuze and keuze != STANDAARD else None + if keuze == STANDAARD: + ok, msg = maak_schooldatabase(db_naam, waarden) + flash(msg, "success" if ok else "error") + if not ok: + return _render_form(None, True, True, form=request.form) + elif bron: + if request.form.get('kopie_koppelingen'): + # Koppelingen en instellingen van de bron overnemen (database-server blijft dezelfde); + # aanpassen kan meteen daarna op de pagina Bewerken. + waarden = dict(bron.waarden) + sleutel = sleutel or bron.google_sleutel + ok, msg = kopieer_school_db(bron, db_naam, waarden) + flash(msg, "success" if ok else "error") + if not ok: + return _render_form(None, True, True, form=request.form) + + tenancy.opslaan(code, naam, ','.join(domeinen), _hostnamen(request.form.get('hostnamen')), db_naam, + bool(request.form.get('actief')), waarden, sleutel, gebruiker=session.get('user'), nieuw=True) + flash(f"School {naam} toegevoegd.", "success") + if bron: + if request.form.get('kopie_koppelingen'): + flash(f"Koppelingen en instellingen van {bron.naam} overgenomen. Kijk ze hieronder na" + + (" (de school staat actief: geplande synchronisaties lopen ook voor de kopie)." + if request.form.get('actief') else "."), "info") + if request.form.get('kopie_rechten'): + n = kopieer_rechten(bron, code, session.get('user')) + flash(f"Rechten van {n} gebruiker(s) overgenomen van {bron.naam}.", "success") + return redirect(url_for('scholen.bewerken', code=code)) + + +@scholen_bp.route('//bewerken', methods=['GET', 'POST']) +@superbeheerder_required +def bewerken(code): + return _bewerk(code, mag_alles=True) + + +@scholen_bp.route('//database-aanmaken', methods=['POST']) +@superbeheerder_required +def database_aanmaken(code): + """Database van een bestaande school (alsnog) aanmaken met de standaardstructuur. + Veilig om te herhalen: bestaande tabellen en gegevens blijven behouden.""" + school = school_op_code(code, ook_inactief=True) + if not school: + flash("Onbekende school.", "error") + return redirect(url_for('scholen.overzicht')) + ok, msg = maak_schooldatabase(school.db_naam, school.waarden) + vergeet_pools(school.db_naam) + flash(msg, "success" if ok else "error") + return redirect(url_for('scholen.bewerken', code=school.code)) + + +@scholen_bp.route('/mijn-school', methods=['GET', 'POST']) +@schoolbeheerder_required +def mijn_school(): + return _bewerk(session['school'], mag_alles=bool(session.get('superbeheerder'))) + + +def _bewerk(code, mag_alles): + school = school_op_code(code, ook_inactief=True) + if not school: + flash("Onbekende school.", "error") + return redirect(url_for('main.dashboard')) + if request.method == 'GET': + return _render_form(school, False, mag_alles) + + if request.form.get('wis_google_sleutel'): + tenancy.wis_google_sleutel(school.code, session.get('user')) + school = school_op_code(code, ook_inactief=True) + + sleutel, fout = _google_sleutel_uit_form() + if fout: + flash(fout, "error") + return _render_form(school, False, mag_alles, form=request.form) + + if mag_alles: + naam = (request.form.get('naam') or '').strip() or school.naam + domeinen, fout = _domeinen(request.form.get('domeinen'), school.code) + db_naam = (request.form.get('db_naam') or '').strip() + if fout or not DB_RE.match(db_naam): + flash(fout or "Ongeldige databasenaam.", "error") + return _render_form(school, False, mag_alles, form=request.form) + hostnamen = _hostnamen(request.form.get('hostnamen')) + actief = bool(request.form.get('actief')) + else: + naam, domeinen, db_naam = school.naam, school.domeinen, school.db_naam + hostnamen, actief = ','.join(school.hostnamen), school.actief + + waarden = _form_waarden(school, mag_alles) + fout = _controleer_waarden(waarden) + if fout: + flash(fout, "error") + return _render_form(school, False, mag_alles, form=request.form) + tenancy.opslaan(school.code, naam, ','.join(domeinen), hostnamen, db_naam, actief, waarden, sleutel, + gebruiker=session.get('user')) + vergeet_pools() + flash(f"Instellingen van {naam} opgeslagen.", "success") + if request.endpoint == 'scholen.bewerken': + return redirect(url_for('scholen.bewerken', code=school.code)) + return redirect(url_for('scholen.mijn_school')) + + +def _domeinen(tekst, eigen_code=None): + domeinen = [d.strip().lower().lstrip('@') for d in re.split(r'[,;\s]+', tekst or '') if d.strip()] + if not domeinen: + return [], "Geef minstens één e-maildomein op (bv. school.be)." + for d in domeinen: + if not re.match(r'^[a-z0-9.-]+\.[a-z]{2,}$', d): + return [], f"'{d}' is geen geldig domein." + # Meerdere scholen mogen hetzelfde domein delen (bv. basis- en secundaire school van één campus). + # Wie zich met Google aanmeldt, komt dan in de school waar hij toegang toe heeft (zie auth.callback). + return domeinen, None + + +def _hostnamen(tekst): + return ','.join(h.strip().lower() for h in re.split(r'[,;\s]+', tekst or '') if h.strip()) + + +# ------------------------------------------------------------------ +# Database aanmaken +# ------------------------------------------------------------------ +STANDAARD = '__standaard__' +SCHOOL_SQL = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'sql', 'school.sql') + + +def sql_statements(pad): + """Leest een .sql-bestand en geeft de afzonderlijke statements (commentaar weggelaten).""" + with open(pad, encoding='utf-8') as f: + regels = [r for r in f.read().split('\n') if not r.strip().startswith('--')] + return [st.strip() for st in re.split(r';\s*\n', '\n'.join(regels) + '\n') if st.strip()] + + +def maak_schooldatabase(db_naam, waarden=None): + """Maakt db_naam aan met de standaardstructuur uit sql/school.sql (lege tabellen).""" + import mysql.connector + from config import Config + waarden = waarden or {} + if not DB_RE.match(db_naam or ''): + return False, "Ongeldige databasenaam." + try: + conn = mysql.connector.connect( + host=waarden.get('DB_HOST') or Config.DB_HOST, port=Config.DB_PORT, + user=waarden.get('DB_USER') or Config.DB_USER, + password=waarden.get('DB_PASSWORD') or Config.DB_PASSWORD, connection_timeout=10, + charset='utf8mb4', collation='utf8mb4_unicode_ci') + except Exception as e: + return False, f"Kan niet verbinden met de databaseserver: {e}" + cur = conn.cursor() + try: + cur.execute(f"CREATE DATABASE IF NOT EXISTS `{db_naam}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci") + cur.execute(f"USE `{db_naam}`") + stmts = sql_statements(SCHOOL_SQL) + for st in stmts: + cur.execute(st) + conn.commit() + n = sum(1 for st in stmts if st.upper().startswith('CREATE TABLE')) + return True, f"Database {db_naam} aangemaakt met de standaardstructuur ({n} tabellen)." + except Exception as e: + conn.rollback() + return False, f"Database aanmaken mislukt: {e}" + finally: + cur.close() + conn.close() +def kopieer_school_db(bron, db_naam, waarden): + """Maakt db_naam aan (zelfde server) als volledige kopie van de database van `bron`: alle tabellen mét gegevens. + De doeldatabase moet nieuw of leeg zijn. Mislukt het, dan wordt een database die we zelf aanmaakten weer verwijderd.""" + bron_db = bron.db_naam + if waarden.get('DB_HOST') and waarden.get('DB_HOST') != (bron.waarden.get('DB_HOST') or ''): + return False, "Een school kopiëren kan enkel binnen dezelfde databaseserver." + if db_naam == bron_db: + return False, "Kies een andere databasenaam dan die van de school die je kopieert." + conn = get_central_connection() + cur = conn.cursor() + zelf_aangemaakt = False + try: + cur.execute("SELECT 1 FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = %s", (db_naam,)) + bestond = bool(cur.fetchall()) + if bestond: + cur.execute(f"SHOW FULL TABLES FROM `{db_naam}` WHERE Table_type = 'BASE TABLE'") + if cur.fetchall(): + return False, (f"De database {db_naam} bestaat al en bevat tabellen. Kies een nieuwe databasenaam " + "om er een kopie in te zetten.") + else: + cur.execute(f"CREATE DATABASE `{db_naam}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci") + zelf_aangemaakt = True + cur.execute(f"SHOW FULL TABLES FROM `{bron_db}` WHERE Table_type = 'BASE TABLE'") + tabellen = [r[0] for r in cur.fetchall()] + cur.execute("SET FOREIGN_KEY_CHECKS = 0") + rijen = 0 + for t in tabellen: + cur.execute(f"CREATE TABLE `{db_naam}`.`{t}` LIKE `{bron_db}`.`{t}`") + cur.execute(f"INSERT INTO `{db_naam}`.`{t}` SELECT * FROM `{bron_db}`.`{t}`") + rijen += max(cur.rowcount or 0, 0) + cur.execute("SET FOREIGN_KEY_CHECKS = 1") + conn.commit() + return True, (f"Database {db_naam} aangemaakt als kopie van {bron.naam}: " + f"{len(tabellen)} tabellen, {rijen} rijen gegevens.") + except Exception as e: + try: + conn.rollback() + cur.execute("SET FOREIGN_KEY_CHECKS = 1") + if zelf_aangemaakt: + cur.execute(f"DROP DATABASE IF EXISTS `{db_naam}`") + except Exception: + pass + return False, f"School kopiëren mislukt: {e}" + finally: + cur.close() + conn.close() + + +def kopieer_rechten(bron, nieuwe_code, door=None): + """Geeft iedereen die rechten heeft in `bron` dezelfde rechten in de nieuwe school.""" + nieuw = school_op_code(nieuwe_code, ook_inactief=True) + if not nieuw: + return 0 + central_query("INSERT IGNORE INTO Gebruiker_rechten (Gebruiker_ID, School_ID, Onderdeel_ID, Toegekend_op, Toegekend_door) " + "SELECT Gebruiker_ID, %s, Onderdeel_ID, NOW(), %s FROM Gebruiker_rechten WHERE School_ID = %s", + (nieuw.id, door, bron.id), commit=True) + return central_query("SELECT COUNT(DISTINCT Gebruiker_ID) AS n FROM Gebruiker_rechten WHERE School_ID = %s", + (nieuw.id,))[0]['n'] + + +# ------------------------------------------------------------------ +# Verbindingstest +# ------------------------------------------------------------------ +def test_school(school): + """Test elke ingestelde koppeling. Geeft een lijst (onderdeel, ok|None, detail).""" + res = [] + with in_school(school): + # Database (eerst tabelnamen met hoofdletters herstellen, voor een database die van Windows komt) + try: + from services.tabelnamen import herstel_school + for m in herstel_school(school): + res.append(('Tabelnamen', 'mislukt' not in m and 'samen' not in m, m)) + except Exception as e: + res.append(('Tabelnamen', False, str(e)[:200])) + try: + n = execute_query("SELECT COUNT(*) AS n FROM information_schema.tables WHERE table_schema = DATABASE()")[0]['n'] + heeft = execute_query("SHOW TABLES LIKE 'Toestellen'") + res.append(('Database', bool(heeft), f"{school.db_naam}: {n} tabellen" + + ('' if heeft else " – tabel Toestellen ontbreekt (python beheer.py nieuwe-schooldatabase)"))) + except Exception as e: + res.append(('Database', False, str(e))) + + # Smartschool webservices + if school.heeft('SS_API_PLATFORM', 'SS_API_PW'): + try: + from services.smartschool_api import SmartschoolService + from config import Config + ss = SmartschoolService(Config.SS_API_PLATFORM, Config.SS_API_PW) + raw = ss.client.service.getClassListJson(Config.SS_API_PW) + if isinstance(raw, (int, float)) or (isinstance(raw, str) and raw.strip().lstrip('-').isdigit()): + res.append(('Smartschool webservices', False, f"foutcode {raw} (wachtwoord of rechten)")) + else: + res.append(('Smartschool webservices', True, Config.SS_API_PLATFORM)) + except Exception as e: + res.append(('Smartschool webservices', False, str(e)[:200])) + else: + res.append(('Smartschool webservices', None, 'niet ingesteld')) + + # Smartschool OneRoster + if school.heeft('SS_API_PLATFORM', 'SS_CLIENT_ID', 'SS_CLIENT_SECRET'): + try: + from config import Config + r = requests.post(Config.SS_TOKEN_URL, data={"grant_type": "client_credentials"}, + auth=(Config.SS_CLIENT_ID, Config.SS_CLIENT_SECRET), timeout=10) + res.append(('Smartschool OneRoster', r.ok and bool(r.json().get('access_token')), + 'token ontvangen' if r.ok else f"HTTP {r.status_code}")) + except Exception as e: + res.append(('Smartschool OneRoster', False, str(e)[:200])) + else: + res.append(('Smartschool OneRoster', None, 'niet ingesteld')) + + # Informat: eerst de leerlingen-API; lukt die niet, dan de Internaat-API (een internaat gebruikt in + # Informat geen leerlingen maar internen, dus de leerlingen-scope wordt daar geweigerd) + if _informat_ingesteld(school): + fout = None + if school.heeft('INFORMAT_INST_NUMBER'): + try: + from services.sync_service import SyncService + if SyncService().get_informat_token(): + res.append(('Informat', True, 'token ontvangen (leerlingen)')) + else: + fout = 'authenticatie mislukt' + except Exception as e: + fout = str(e)[:200] + else: + fout = 'geen instellingsnummer voor leerlingen' + if fout is not None: + try: + from services.internaat_service import InternaatService + svc = InternaatService() + if not svc.nummers: + raise RuntimeError('geen instellingsnummer') + for nr in svc.nummers: + svc._token(nr) + res.append(('Informat', True, f"token ontvangen (internaat {', '.join(svc.nummers)})")) + except Exception as e: + res.append(('Informat', False, f"{fout}; internaat: {str(e)[:150]}")) + else: + res.append(('Informat', None, 'niet ingesteld')) + + # Google + if school.google_sleutel and not school.heeft('ADMIN_EMAIL'): + res.append(('Google Workspace', False, "Sleutel staat erin, maar 'Beheerder (Google-admin)' is nog niet " + "ingevuld (Algemeen). PIVOT moet weten namens welk beheerdersaccount het werkt.")) + elif school.google_sleutel: + try: + from services.google_service import GoogleAdminService + svc = GoogleAdminService() + svc.service.users().list(customer='my_customer', maxResults=1).execute() + res.append(('Google Workspace', True, f"namens {school.get('ADMIN_EMAIL')}")) + except Exception as e: + res.append(('Google Workspace', False, google_fout_uitleg(str(e), school))) + else: + res.append(('Google Workspace', None, 'geen serviceaccount-sleutel')) + + # Signpost + if school.heeft('M4S_CLIENT_ID', 'M4S_CLIENT_SECRET'): + from services.signpost_byod_service import get_signpost_token + ok = bool(get_signpost_token()) + res.append(('Signpost / M4S', ok, 'token ontvangen' if ok else 'authenticatie mislukt')) + else: + res.append(('Signpost / M4S', None, 'niet ingesteld')) + return res + + +def google_fout_uitleg(fout, school): + """Vertaalt de meest voorkomende Google-fouten naar wat je moet nakijken.""" + admin = school.get('ADMIN_EMAIL') + f = fout.lower() + # Bij een HttpError staat de eigenlijke reden na 'returned "...": die tonen i.p.v. de lange URL + m = re.search(r'returned "([^"]+)"', fout) + reden = m.group(1) if m else fout + if 'has not been used' in f or 'is disabled' in f or 'accessnotconfigured' in f or 'service_disabled' in f: + uitleg = ("De Admin SDK API staat nog niet aan in het Google Cloud-project van het serviceaccount " + "(console.cloud.google.com › API's en services › Bibliotheek › Admin SDK API › Inschakelen).") + elif 'unauthorized_client' in f: + uitleg = ("De domeinbrede delegatie is (nog) niet in orde: controleer in admin.google.com › Beveiliging › " + "API-beheer › Domeinbrede delegatie de client-ID (Unieke ID van het serviceaccount) en de OAuth-bereiken. " + "Een nieuwe instelling kan tot een uur duren.") + elif 'invalid_grant' in f: + uitleg = (f"Google kent het beheerdersaccount '{admin}' niet of het is geschorst. " + "Vul bij 'Beheerder (Google-admin)' een bestaand account van dit domein in.") + elif 'not authorized' in f or '403' in f: + uitleg = (f"'{admin}' mag de gebruikerslijst niet lezen in Google. Controleer in admin.google.com › Account › " + "Beheerdersrollen dat dit account superbeheerder is (een gewone gebruiker of een beheerder met een " + "beperkte rol volstaat niet), en dat het in dezelfde Google-organisatie zit als de domeinbrede delegatie.") + elif 'invalid input' in f: + uitleg = (f"Google aanvaardt '{admin}' niet als beheerder van dit domein. Controleer of 'Beheerder (Google-admin)' " + "een echt beheerdersaccount is (geen groep of alias) van hetzelfde domein als het serviceaccount.") + else: + return fout[:300] + return f"{uitleg} (Google: {reden[:200]})" + + +@scholen_bp.route('//test', methods=['POST']) +def test(code): + if not session.get('auth'): + return redirect(url_for('auth.login')) + if not session.get('superbeheerder') and not rechten.heeft_recht('koppelingen'): + flash("Onvoldoende rechten voor deze actie.", "error") + return redirect(url_for('main.dashboard')) + if not session.get('superbeheerder') and code != session.get('school'): + flash("Je kan enkel je eigen school testen.", "error") + return redirect(url_for('main.dashboard')) + school = school_op_code(code, ook_inactief=True) + if not school: + flash("Onbekende school.", "error") + return redirect(url_for('main.dashboard')) + resultaten = test_school(school) + try: + bewaar_test(school, resultaten) + except Exception as e: + sys.stderr.write(f"PIVOT: testresultaat bewaren mislukt: {e}\n") + return render_template('school_test.html', school=school, resultaten=resultaten) + + +@scholen_bp.route('/alles-testen', methods=['POST']) +@superbeheerder_required +def alles_testen(): + """Test de koppelingen van alle actieve scholen en werkt de badges in het overzicht bij.""" + goed, fout = 0, [] + for school in alle_scholen(): + try: + res = test_school(school) + bewaar_test(school, res) + if any(ok is False for _, ok, _ in res): + fout.append(school.naam) + else: + goed += 1 + except Exception as e: + fout.append(f"{school.naam} ({e})") + flash(f"{goed} school/scholen zonder fouten." + (f" Met fouten: {', '.join(fout)}." if fout else ""), + "warning" if fout else "success") + return redirect(url_for('scholen.overzicht')) diff --git a/blueprints/sgr_groepen_bp.py b/blueprints/sgr_groepen_bp.py new file mode 100644 index 0000000..ee0e084 --- /dev/null +++ b/blueprints/sgr_groepen_bp.py @@ -0,0 +1,65 @@ +"""Smartschool › SGR groepen: subgroepen van de hoofdgroep (standaard 'groepen GO-Antwerpen') met hun leden.""" +import csv +import io +import time +from datetime import date + +from flask import Blueprint, render_template, request, Response, redirect, url_for, flash + +from blueprints.auth import login_required +from rechten import recht_vereist +from services import sgr_groepen_service as sgr +from tenancy import huidige_school + +sgr_groepen_bp = Blueprint('sgr_groepen', __name__) + + +def _gevraagd(): + return (request.args.get('groep') or '').strip() or None + + +@sgr_groepen_bp.route("/", methods=["GET"]) +@login_required +@recht_vereist('sgr_groepen') +def overzicht(): + school = huidige_school() + standaard = (school.get('SS_SGR_GROEP') or sgr.STANDAARD_GROEP).strip() + gevraagd = _gevraagd() + hoofd, groepen, fout, opgehaald = None, [], None, None + try: + hoofd, groepen, t = sgr.overzicht(gevraagd, vernieuw=bool(request.args.get('vernieuw'))) + opgehaald = time.strftime('%d-%m-%Y %H:%M', time.localtime(t)) + except sgr.SgrFout as e: + fout = str(e) + except Exception as e: + fout = f"Groepen ophalen uit Smartschool mislukt: {e}" + if request.args.get('vernieuw'): + return redirect(url_for('sgr_groepen.overzicht', groep=gevraagd)) + leden = [l for g in groepen for l in g['leden']] + return render_template("sgr_groepen.html", hoofd=hoofd, groepen=groepen, fout=fout, opgehaald=opgehaald, + groep=gevraagd or standaard, standaard=standaard, school_naam=school.naam, + aantal_leden=len(leden), + uniek=len({l['gebruikersnaam'] or (l['naam'], l['voornaam']) for l in leden})) + + +@sgr_groepen_bp.route("/export.csv", methods=["GET"]) +@login_required +@recht_vereist('sgr_groepen') +def export(): + try: + hoofd, groepen, _ = sgr.overzicht(_gevraagd()) + except Exception as e: + flash(f"Kon niet exporteren: {e}", "error") + return redirect(url_for('sgr_groepen.overzicht', groep=_gevraagd())) + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') + w.writerow(['Groep', 'Pad', 'Groepscode', 'Naam', 'Voornaam', 'Gebruikersnaam', 'Rol', 'E-mail']) + for g in groepen: + pad = ' › '.join(g['pad'] + [g['naam']]) + if not g['leden']: + w.writerow([g['naam'], pad, g['code'], '', '', '', '', '']) + for l in g['leden']: + w.writerow([g['naam'], pad, g['code'], l['naam'], l['voornaam'], l['gebruikersnaam'], l['rol'], l['email']]) + naam = ''.join(c if c.isalnum() else '_' for c in hoofd['naam'])[:40] + return Response('' + buf.getvalue(), mimetype='text/csv', + headers={'Content-Disposition': f'attachment; filename=SGR_{naam}_{date.today():%Y%m%d}.csv'}) diff --git a/blueprints/signpost_devices_bp.py b/blueprints/signpost_devices_bp.py new file mode 100644 index 0000000..f44b6eb --- /dev/null +++ b/blueprints/signpost_devices_bp.py @@ -0,0 +1,135 @@ +import requests +from flask import Blueprint, render_template, request, flash, redirect, url_for +from database import execute_query +from services import toestellen as tst +from blueprints.auth import login_required +from rechten import recht_vereist +# Importeer de benodigdheden uit je bestaande service-bestand +from services.signpost_byod_service import BASE_DATA_URL, get_signpost_token, signpost_token_met_reden + +signpost_devices_bp = Blueprint('signpost_devices', __name__) + +def sync_signpost_devices_to_db(): + """ + Haalt alle toestellen op via de Signpost-API en voegt toestellen die + nog niet bestaan (op basis van serienummer) toe aan Signpost_database. + """ + token, fout = signpost_token_met_reden() + if not token: + return False, fout + + headers = { + "Authorization": f"Bearer {token}", + "Accept": "application/json" + } + + page_number = 1 + page_size = 100 + toegevoegd_teller = 0 + overgeslagen_teller = 0 + + print("Starten met synchroniseren van toestellen naar Signpost_database...") + + while True: + params = { + "$top": page_size, + "$skip": (page_number - 1) * page_size + } + + url = "https://byod-api.signpost.be/v1/devices" + + try: + res = requests.get(url, headers=headers, params=params, timeout=15) + if res.status_code != 200: + print(f"Fout bij pagina {page_number}: {res.status_code}") + return False, f"Signpost API gaf foutcode {res.status_code} op pagina {page_number}." + + data = res.json() + items = data.get("items", []) + + if not items: + break + + for item in items: + signpost_nummer = item.get("signpostLabel") + serienummer = item.get("serialNumber") + model = item.get("modelName") + warranty_void_raw = item.get("warrantyVoidAt") + + garantie = warranty_void_raw.split("T")[0] if warranty_void_raw else None + + if not serienummer: + continue + + # Bestaat het toestel al (op serienummer)? Zo niet: aanmaken in Toestellen. + bestaand = execute_query( + "SELECT t.Toestel_ID, sp.Toestel_ID AS heeft_signpost FROM Toestellen t " + "LEFT JOIN Signpost_DB sp ON sp.Toestel_ID = t.Toestel_ID WHERE t.Serienummer = %s LIMIT 1", + (serienummer,)) + if bestaand and bestaand[0]['heeft_signpost']: + overgeslagen_teller += 1 + continue + toestel_id = bestaand[0]['Toestel_ID'] if bestaand else tst.nieuw_toestel( + serienummer=serienummer, type_toestel=model) + execute_query( + "INSERT INTO Signpost_DB (Toestel_ID, Signpostnummer, Garantie) VALUES (%s, %s, %s) " + "ON DUPLICATE KEY UPDATE Signpostnummer = VALUES(Signpostnummer), Garantie = VALUES(Garantie)", + (toestel_id, signpost_nummer or None, garantie), commit=True) + toegevoegd_teller += 1 + + if len(items) < page_size: + break + + page_number += 1 + + except Exception as e: + import traceback + print(f"Fout tijdens database/API sync: {e}") + traceback.print_exc() # Dit print de échte boosdoener in je terminal (bijv. IndexError of MySQL-fout) + return False, f"Er is een fout opgetreden tijdens de synchronisatie: {str(e)}" + + return True, f"Synchronisatie voltooid! {toegevoegd_teller} nieuw(e) toestel(len) toegevoegd. {overgeslagen_teller} bestaand(e) toestel(len) overgeslagen." + +@signpost_devices_bp.route('/signpost_database', methods=['GET', 'POST']) +@login_required +@recht_vereist('signpost') +def signpost_database_overzicht(): + # Komt overeen met jouw methode om de query op te vangen bij GET of POST + query = request.form.get('query') if request.method == 'POST' else request.args.get('query') + + # De basis-query aangepast naar de tabel Signpost_database en de gevraagde kolommen + basis_sql = """ + SELECT sp.Signpostnummer, t.Serienummer AS Device_serienummer, t.Type AS Device_model, sp.Garantie, + sp.Aankoopbedrag, sp.Aankoopdatum, t.Schooleigen_ID + FROM Signpost_DB sp + JOIN Toestellen t ON t.Toestel_ID = sp.Toestel_ID + """ + + if query: + # Als er gezocht wordt, zoeken we veilig op serienummer of signpostnummer + sql = basis_sql + " WHERE t.Serienummer LIKE %s OR sp.Signpostnummer LIKE %s ORDER BY Signpostnummer DESC" + params = (f"%{query}%", f"%{query}%") + results = execute_query(sql, params) + else: + # Als er geen zoekterm is, halen we alles op + sql = basis_sql + " ORDER BY Signpostnummer DESC" + results = execute_query(sql) + + # We sturen de resultaten door naar de HTML-pagina + return render_template('signpost_devices.html', results=results, query=query) + + +@signpost_devices_bp.route('/sync_signpost', methods=['POST']) +@login_required +@recht_vereist('signpost') +def sync_signpost(): + # Voer de vernieuwde synchronisatie uit + succes, melding = sync_signpost_devices_to_db() + + if succes: + flash(melding, 'success') + else: + flash(melding, 'danger') + + # Stuur de gebruiker terug naar het overzicht + return redirect(url_for('signpost_devices.signpost_database_overzicht')) \ No newline at end of file diff --git a/blueprints/skore_bp.py b/blueprints/skore_bp.py new file mode 100644 index 0000000..b0bff51 --- /dev/null +++ b/blueprints/skore_bp.py @@ -0,0 +1,66 @@ +"""Skore-synchronisatie in Smartschool: manueel starten, planning instellen en logboek bekijken.""" +from flask import Blueprint, render_template, request, redirect, url_for, flash, session + +from blueprints.auth import login_required +from rechten import recht_vereist +import rechten +from services import skore_service as skore + +skore_bp = Blueprint('skore', __name__) + + +@skore_bp.route('/', methods=['GET']) +@login_required +@recht_vereist('skore') +def overzicht(): + try: + p = skore.planning() + log = skore.logboek() + except Exception as e: + flash(f"Kon de Skore-gegevens niet lezen: {e}", "error") + p, log = None, [] + try: + loopt = skore.bezig() + except Exception: + loopt = False + return render_template('skore.html', planning=p, log=log, frequenties=skore.FREQUENTIES, loopt=loopt, + weekdagen=skore.WEEKDAGEN, volgende=skore.volgende_moment(p) if p else None) + + +@skore_bp.route('/start', methods=['POST']) +@login_required +@recht_vereist('skore') +def start(): + rij = skore.start(session.get('user'), manier='manueel') + rechten.log(actie="Skore-synchronisatie gestart") + if rij['Status'] == 'mislukt': + flash(rij['Melding'], "error") + else: + flash("Skore-synchronisatie gestart bij Smartschool. PIVOT volgt de status automatisch op; " + "deze pagina ververst vanzelf tot ze klaar is.", "success") + return redirect(url_for('skore.overzicht')) + + +@skore_bp.route('/status/', methods=['POST']) +@login_required +@recht_vereist('skore') +def status(log_id): + rij = skore.controleer(log_id) + if rij: + flash(f"Status: {rij['Status']}", "info") + return redirect(url_for('skore.overzicht')) + + +@skore_bp.route('/planning', methods=['POST']) +@login_required +@recht_vereist('skore') +def planning(): + f = request.form + try: + skore.bewaar_planning(f.get('frequentie', 'uit'), f.get('uur', 6), f.get('minuut', 0), + f.get('weekdag', 0), f.get('dag_van_maand', 1), session.get('user')) + rechten.log(actie=f"Skore-planning: {f.get('frequentie')}") + flash("Planning opgeslagen.", "success") + except (ValueError, TypeError) as e: + flash(str(e) or "Ongeldige planning.", "error") + return redirect(url_for('skore.overzicht')) diff --git a/blueprints/smartschool_activiteit_bp.py b/blueprints/smartschool_activiteit_bp.py new file mode 100644 index 0000000..0d8d302 --- /dev/null +++ b/blueprints/smartschool_activiteit_bp.py @@ -0,0 +1,104 @@ +from flask import Blueprint, render_template, request, flash, jsonify, redirect, url_for, Response +from services.smartschool_api import SmartschoolService +from config import Config +from services.google_service import GoogleAdminService +from blueprints.auth import login_required +from rechten import recht_vereist +from services.coaccounts_service import CoAccountsService +from tenancy import huidige_school +# Definieer de blueprint +ss_bp = Blueprint('smartschool', __name__) + + + + +@ss_bp.route('/coaccount-overzicht', methods=['GET']) +@login_required +@recht_vereist('smartschool_activiteit') +def coaccount_overzicht(): + """Alle co-accounts van alle leerlingen (klas, leerling, laatste aanmelding). Standaard enkel wie nog nooit + aanmeldde. De gegevens worden op de achtergrond opgehaald als ze ouder zijn dan een dag.""" + svc = CoAccountsService() + rows, fout, laatst = [], None, None + ingesteld = huidige_school().heeft('SS_API_PLATFORM', 'SS_API_PW') + try: + svc.ensure_tables() + if ingesteld and svc.verouderd(): + svc.sync_op_achtergrond() + rows, laatst = svc.alle(), svc.laatst_opgehaald() + except Exception as e: + fout = f"Gegevens konden niet gelezen worden: {e}" + return render_template('smartschool_activiteit.html', rows=rows, fout=fout, laatst=laatst, + ingesteld=ingesteld, status=svc.status, + nooit=sum(1 for r in rows if not r['Laatste_login']), + leerlingen=len({r['Internnummer'] for r in rows})) + + +@ss_bp.route('/coaccount-overzicht/ophalen', methods=['POST']) +@login_required +@recht_vereist('smartschool_activiteit') +def coaccount_ophalen(): + if not huidige_school().heeft('SS_API_PLATFORM', 'SS_API_PW'): + flash("Smartschool is nog niet ingesteld voor deze school (🔌 Koppelingen › Smartschool).", "error") + elif CoAccountsService().sync_op_achtergrond(): + flash("Co-accounts worden opgehaald uit Smartschool. Dit kan enkele minuten duren.", "info") + else: + flash("Er loopt al een ophaling.", "warning") + return redirect(url_for('smartschool.coaccount_overzicht')) + + +@ss_bp.route('/coaccount-overzicht/status.json', methods=['GET']) +@login_required +@recht_vereist('smartschool_activiteit') +def coaccount_status(): + s = CoAccountsService().status + return jsonify(bezig=s['bezig'], voortgang=s['voortgang'], totaal=s['totaal'], fout=s['fout'], + resultaat=s['resultaat']) + + +@ss_bp.route('/coaccount-overzicht/export.csv', methods=['GET']) +@login_required +@recht_vereist('smartschool_activiteit') +def coaccount_export(): + """CSV met dezelfde filters als de tabel: ?nooit=1 (enkel nog nooit aangemeld) en ?zoek=...""" + import csv, io + from datetime import date + rows = CoAccountsService().alle() + if request.args.get('nooit') == '1': + rows = [r for r in rows if not r['Laatste_login']] + zoek = (request.args.get('zoek') or '').strip().lower() + if zoek: + velden = ('Klas', 'Leerling_voornaam', 'Leerling_naam', 'Gebruikersnaam', 'Internnummer', 'Voornaam', 'Naam', 'Email') + rows = [r for r in rows if zoek in ' '.join(str(r[v] or '') for v in velden).lower()] + buf = io.StringIO() + w = csv.writer(buf, delimiter=';') # ; zodat Excel (Belgische instellingen) de kolommen meteen splitst + w.writerow(['Klas', 'Leerling naam', 'Leerling voornaam', 'Internnummer', 'Co-account voornaam', 'Co-account naam', + 'Type', 'E-mail', 'Laatste aanmelding']) + for r in rows: + w.writerow([r['Klas'] or '', r['Leerling_naam'] or '', r['Leerling_voornaam'] or '', r['Internnummer'], + r['Voornaam'] or '', r['Naam'] or '', r['Type'] or '', r['Email'] or '', + r['Laatste_login'].strftime('%d-%m-%Y %H:%M') if r['Laatste_login'] else 'Nooit']) + naam = f"co-accounts{'_nooit_aangemeld' if request.args.get('nooit') == '1' else ''}_{date.today():%Y%m%d}.csv" + return Response('\ufeff' + buf.getvalue(), mimetype='text/csv; charset=utf-8', + headers={'Content-Disposition': f'attachment; filename={naam}'}) + + +@ss_bp.route('/send-reminder-email', methods=['POST']) +@login_required +@recht_vereist('smartschool_activiteit') +def send_reminder(): + data = request.json + email = data.get('email') + subject = data.get('subject') + message_body = data.get('message') + + if not email or "@" not in email: + return jsonify({"status": "error", "message": "Geen geldig e-mailadres gevonden voor dit co-account."}), 400 + + email_service = GoogleAdminService() + success, msg = email_service.send_custom_mail(email, subject, message_body) + + if success: + return jsonify({"status": "success", "message": msg}) + else: + return jsonify({"status": "error", "message": f"Fout bij verzenden: {msg}"}), 500 \ No newline at end of file diff --git a/blueprints/smartschool_bp.py b/blueprints/smartschool_bp.py new file mode 100644 index 0000000..57ff223 --- /dev/null +++ b/blueprints/smartschool_bp.py @@ -0,0 +1,108 @@ +from flask import Blueprint, render_template, request, jsonify, make_response, flash +from io import BytesIO # <-- Deze regel lost de NameError op +from xhtml2pdf import pisa +from datetime import datetime +from services.smartschool_api import SmartschoolService +from config import Config +from database import execute_query +from tenancy import per_school +from blueprints.auth import login_required +from rechten import recht_vereist + +smartschool_bp = Blueprint("/ss",__name__) + +# Eén Smartschool-client per school (met het webservice-wachtwoord van die school) +ss_service = per_school(lambda: SmartschoolService( + platform=Config.SS_API_PLATFORM, + webservice_pwd=Config.SS_API_PW +)) + +@smartschool_bp.route('/smartschool', methods=['GET', 'POST']) +@login_required +@recht_vereist('smartschool') +def smartschool(): + results = [] + query = (request.form.get('query') or '').strip() + if request.method == 'POST' and query: + # 1) Exact internnummer of gebruikersnaam: rechtstreeks bij Smartschool + try: + user_data = ss_service.get_student_details(query) + except Exception as e: + user_data = None + flash(f"Smartschool is niet bereikbaar of nog niet ingesteld voor deze school ({e}).", "error") + if user_data: + results = [user_data] + else: + # 2) Deel van een naam, voornaam of gebruikersnaam: zoeken in de leerlingen van PIVOT + results = zoek_leerlingen_lokaal(query) + return render_template('smartschool_beheer.html', results=results, query=query) + + +MAX_RESULTATEN = 25 + + +def zoek_leerlingen_lokaal(query): + """Leerlingen uit de tabel Leerlingen (gevuld door de Informat-sync) die op de zoekterm lijken. + Geeft dicts met dezelfde sleutels als Smartschool (internnummer, voornaam, naam, gebruikersnaam).""" + zoek = f"%{query}%" + rows = execute_query( + "SELECT Internnummer, Voornaam, Naam, Gebruikersnaam FROM Leerlingen " + "WHERE Internnummer = %s OR Gebruikersnaam LIKE %s OR Voornaam LIKE %s OR Naam LIKE %s " + " OR CONCAT_WS(' ', Voornaam, Naam) LIKE %s OR CONCAT_WS(' ', Naam, Voornaam) LIKE %s " + "ORDER BY Naam, Voornaam LIMIT %s", + (query, zoek, zoek, zoek, zoek, zoek, MAX_RESULTATEN)) + return [{'internnummer': r['Internnummer'], 'voornaam': r['Voornaam'] or '', 'naam': r['Naam'] or '', + 'gebruikersnaam': r['Gebruikersnaam'] or ''} for r in rows] + +@smartschool_bp.route('/smartschool/reset', methods=['POST']) +@login_required +@recht_vereist('smartschool') +def smartschool_reset(): + identifier = request.form.get('username') + new_pass = request.form.get('new_password') + acc_type = int(request.form.get('account_type', 0)) + generate_pdf = request.form.get('generate_pdf') == 'true' + display_name = request.form.get('display_name') # Ontvang de naam uit de browser + + result = ss_service.reset_password(identifier, new_pass, acc_type) + + if result == "0": + if generate_pdf: + # We gebruiken de display_name die we van de frontend hebben gekregen + # Voor de e-mail label kunnen we nog steeds student details ophalen indien nodig + student_data = ss_service.get_student_details(identifier) + + email_label = student_data.get('gebruikersnaam') if acc_type == 0 else f"Co-account van {student_data['voornaam']}" + + rendered_html = render_template( + 'pdf_template_leerling.html', + naam=display_name, + datum=datetime.now().strftime("%d/%m/%Y"), + email=email_label, + wachtwoord=new_pass + ) + + pdf_out = BytesIO() + pisa_status = pisa.CreatePDF(rendered_html, dest=pdf_out) + + if pisa_status.err: + return jsonify({"status": "error", "message": "PDF generatie mislukt"}) + + pdf_out.seek(0) + response = make_response(pdf_out.read()) + response.headers['Content-Type'] = 'application/pdf' + response.headers['Content-Disposition'] = f'attachment; filename=Account_{identifier}.pdf' + return response + + return jsonify({"status": "success"}) + + return jsonify({"status": "error", "message": f"Code {result}"}) + +@smartschool_bp.route('/smartschool/coaccounts', methods=['POST']) +@login_required +@recht_vereist('smartschool') +def smartschool_coaccounts(): + username = request.form.get('username') + # Gebruik de nieuwe parser functie + co_accounts = ss_service.get_co_accounts_from_details(username) + return jsonify({"status": "success", "accounts": co_accounts}) \ No newline at end of file diff --git a/blueprints/students.py b/blueprints/students.py new file mode 100644 index 0000000..dfd5cc4 --- /dev/null +++ b/blueprints/students.py @@ -0,0 +1,190 @@ +from flask import Blueprint, render_template, request, session, redirect, url_for, flash +from database import execute_query, get_db_connection +from blueprints.auth import login_required +from rechten import recht_vereist +from services.google_service import GoogleAdminService +from services.sync_service import SyncService, InformatSmartschoolSync +from config import Config +students_bp = Blueprint('students', __name__) + +#----------------------------------------------- +# --- ROUTE: INVENTARIS LEERLINGEN --- +#----------------------------------------------- +@students_bp.route('/inventaris', methods=["GET", "POST"]) +@login_required +@recht_vereist('leerlingen_bekijken') +def inventaris_leerlingen(): + query = request.form.get('query') if request.method == 'POST' else request.args.get('query') + toon_vertrokken = (request.form.get('vertrokken') if request.method == 'POST' else request.args.get('vertrokken')) == '1' + from services.sync_service import zorg_vertrokken_kolom + zorg_vertrokken_kolom() + + # De basis-query waarin we de tabellen 'Leerlingen' (l) en 'Schooljaar' (s) aan elkaar koppelen + basis_sql = """ + SELECT + l.Internnummer, + l.Gebruikersnaam, + l.Voornaam, + l.Naam, + l.SS_nummer, + l.Google_adres, + l.Vertrokken_op, + s.Schooljaar AS Schooljaar -- Hier halen we de tekst (bijv. '2025-2026') op! + FROM Leerlingen l + LEFT JOIN Schooljaar s ON l.Schooljaar_ID = s.Schooljaar_ID + """ + + voorwaarden, params = [], [] + if query: + voorwaarden.append("(l.Gebruikersnaam LIKE %s OR l.Internnummer LIKE %s OR l.Naam LIKE %s OR l.Voornaam LIKE %s)") + params += [f"%{query}%"] * 4 + if not toon_vertrokken: + voorwaarden.append("l.Vertrokken_op IS NULL") + sql = basis_sql + (" WHERE " + " AND ".join(voorwaarden) if voorwaarden else "") + data = execute_query(sql, tuple(params)) + vertrokken = (execute_query("SELECT COUNT(*) AS n FROM Leerlingen WHERE Vertrokken_op IS NOT NULL") or [{'n': 0}])[0]['n'] + + return render_template('Inventaris_Leerlingen.html', results=data, query=query, + toon_vertrokken=toon_vertrokken, aantal_vertrokken=vertrokken) + +#---------------------------------------- +# --- ROUTE: BEWERK GEBRUIKER --- +#---------------------------------------- +@students_bp.route("/bewerk_gebruiker", methods=["POST"]) +@login_required +@recht_vereist('leerlingen_bekijken') +def bewerk_gebruiker(): + print("bewerken wordt uitgevoerd") + internnummer = request.form.get("internnummer") + gebruikersnaam = request.form.get("gebruikersnaam") + ss_nummer = request.form.get("ss_nummer") + google_adres = request.form.get('google_adres') + naam= request.form.get('naam') + voornaam= request.form.get('voornaam') + query = request.form.get("query", "") + + if not internnummer: + flash("Fout: Geen internnummer ontvangen.", "error") + return redirect(url_for("students.inventaris_leerlingen")) + + sql = "UPDATE Leerlingen SET Gebruikersnaam = %s, SS_nummer = %s, Google_adres = %s, Naam = %s, Voornaam= %s WHERE Internnummer = %s" + rows_affected = execute_query(sql, (gebruikersnaam, ss_nummer, google_adres, naam, voornaam, internnummer ), commit=True) + + if rows_affected: + flash(f"Gegevens voor {internnummer} succesvol bijgewerkt!", "success") + else: + flash("Er zijn geen wijzigingen opgeslagen.", "info") + + return redirect(url_for("students.inventaris_leerlingen", query=query)) + +#---------------------------------------------------- +# --- ROUTE: SYNC GOOGLE ACCOUNTS --- +#---------------------------------------------------- +@students_bp.route("/sync_google_accounts", methods=["GET", "POST"]) +@login_required +@recht_vereist('leerlingen_synchroniseren') +def sync_google_accounts(): + """Maakt Google accounts aan voor leerlingen die er nog geen hebben.""" + google = GoogleAdminService() + + # Haal leerlingen op die nog geen email (SS_nummer) hebben + lln_zonder_mail = execute_query("SELECT Internnummer, Gebruikersnaam FROM Leerlingen WHERE SS_nummer IS NULL OR SS_nummer = ''") + + created_count = 0 + error_count = 0 + + for lln in lln_zonder_mail: + gebruikersnaam_db = lln['Gebruikersnaam'] + # Splits naam (bijv: "Janssens.Jan") + if "." in gebruikersnaam_db: + achternaam, voornaam = gebruikersnaam_db.split(".", 1) + else: + achternaam, voornaam = gebruikersnaam_db, "lln" + + # Genereer wachtwoord (bijv: 12345Jan) + password = f"{lln['Internnummer']}{voornaam.capitalize()}" + + # Gebruik je service om de gebruiker aan te maken + success, message = google.create_user( + first_name=voornaam, + last_name=achternaam, + password=password, + org_unit_path=google.conf.OU_NEW_STUDENTS + ) + + if success: + # Update database met het nieuwe emailadres + email = f"{voornaam.lower()}.{achternaam.lower()}@{google.conf.SCHOOL_DOMAIN}" + execute_query("UPDATE Leerlingen SET SS_nummer = %s WHERE Internnummer = %s", + (email, lln['Internnummer']), commit=True) + created_count += 1 + else: + print(f"Fout voor {gebruikersnaam_db}: {message}") + error_count += 1 + + flash(f"Sync voltooid: {created_count} accounts aangemaakt, {error_count} fouten.", "success") + return redirect(url_for("students.inventaris_leerlingen")) + +#------------------------------------------------------------------- +# --- ROUTE: SYNC INFORMAT (Gebruikmakend van SyncService) --- +#------------------------------------------------------------------- +@students_bp.route("/sync_informat", methods=["GET", "POST"]) +@login_required +@recht_vereist('leerlingen_synchroniseren') +def sync_informat(): + """Haalt de nieuwste leerlinggegevens op uit Informat.""" + #syncer = SyncService() + syncer = InformatSmartschoolSync() + #success, result = syncer.sync_leerlingen_informat() + success, result = syncer.sync_actieve_leerlingen() + + if success: + flash(f"Synchronisatie gelukt: {result['melding']}", "success") + if result.get('smartschool_fout'): + flash("Smartschool kon niet bevraagd worden, dus gebruikersnamen en Smartschool-nummers zijn niet " + f"aangepast (enkel de gegevens uit Informat). Reden: {result['smartschool_fout']}", "warning") + else: + flash(f"Synchronisatie mislukt: {result}", "error") + + return redirect(url_for("students.inventaris_leerlingen")) + +#------------------------------------------------------------------- +# --- Leerling manueel toevoegen +#------------------------------------------------------------------- + +@students_bp.route('/registreer_leerling', methods=['POST']) +@login_required +@recht_vereist('leerlingen_synchroniseren') +def registreer_leerling(): + print('Toevoegen gestart') + # 1. Haal de gegevens uit het formulier op + internnummer = request.form.get('inter_id') + gebruikersnaam = request.form.get('gebruikersnaam') + ss_nummer = request.form.get('ss_nummer') + google_adres = request.form.get('google_adres') + schooljaar_id= Config.SCHOOLYEAR[:4] + naam= request.form.get('naam') + voornaam= request.form.get('voornaam') + + # 2. Validatie + if not internnummer or not gebruikersnaam: + flash('Zowel Internnummer als Gebruikersnaam zijn vereist.', 'danger') + return redirect(url_for('students.inventaris_leerlingen')) + + # 3. Opslaan in de database + try: + # We gebruiken geparametriseerde queries (%s) om SQL-injectie te voorkomen + sql = "INSERT INTO Leerlingen (Internnummer, Gebruikersnaam, Naam, Voornaam, SS_nummer, Google_adres, Schooljaar_ID) " \ + "VALUES (%s, %s, %s, %s, %s, %s, %s)" + params = (internnummer, gebruikersnaam,naam, voornaam, ss_nummer,google_adres, schooljaar_id) + + execute_query(sql, params, commit=True) + + flash(f'Leerling {gebruikersnaam} (ID: {internnummer}) succesvol toegevoegd aan de database!', 'success') + except Exception as e: + # Als bijvoorbeeld het internnummer al bestaat (Duplicate Entry) + print(f"Database error: {e}") + flash('Fout bij het registreren: Mogelijk bestaat dit Internnummer al.', 'danger') + + # 4. Keer terug naar het overzicht + return redirect(url_for('students.inventaris_leerlingen')) \ No newline at end of file diff --git a/blueprints/tools.py b/blueprints/tools.py new file mode 100644 index 0000000..913cf2f --- /dev/null +++ b/blueprints/tools.py @@ -0,0 +1,44 @@ +from flask import Blueprint, render_template, request, session, redirect, url_for, flash +from blueprints.auth import login_required +from tenancy import huidige_school + +tools_bp = Blueprint('tools', __name__) + + +def _staat(): + """Internetstatus en notitie: per school bijgehouden (in het geheugen).""" + return huidige_school().object('internet_status', lambda: {'status': 1, 'notitie': ''}) + + +@tools_bp.route('/internet') +def internet_status(): + """Toont de huidige status van de internetverbinding.""" + staat = _staat() + return render_template( + 'internet_connection.html', + current_status=staat['status'], + current_note=staat['notitie'], + current_user=session.get('user') + ) + + +@tools_bp.route('/toggle_internet', methods=['POST']) +def toggle_internet(): + """Wijzigt de status van de internetverbinding.""" + new_status = request.form.get('new_status', type=int) + + if new_status in [0, 1]: + _staat()['status'] = new_status + flash(f"Status gewijzigd naar {'Online' if new_status == 1 else 'Offline'}", "success") + else: + flash("Ongeldige statuswaarde.", "error") + + return redirect(url_for('tools.internet_status')) + + +@tools_bp.route('/save_note', methods=['POST']) +def save_note(): + """Slaat de korte tekst op.""" + _staat()['notitie'] = request.form.get('status_note', '') + flash("Notitie bijgewerkt!", "success") + return redirect(url_for('tools.internet_status')) diff --git a/blueprints/tweestaps_bp.py b/blueprints/tweestaps_bp.py new file mode 100644 index 0000000..d9c4a38 --- /dev/null +++ b/blueprints/tweestaps_bp.py @@ -0,0 +1,177 @@ +from datetime import datetime +from flask import Blueprint, render_template, request, redirect, url_for, flash, session +from tenancy import huidige_school, per_school +from blueprints.auth import login_required +from rechten import recht_vereist +from config import Config +from services.tweestaps_service import TweestapsService, TweestapsError + +tweestaps_bp = Blueprint('tweestaps', __name__) +LOG_PER_PAGINA = 25 # standaard; te kiezen: 10 / 25 / 50 / 100 / alles (0) +LOG_KEUZES = (10, 25, 50, 100, 0) +service = per_school(TweestapsService) + +_tables_ready = set() # scholen waarvoor de tabellen al gecontroleerd zijn + + +def _ensure_tables(): + if huidige_school().code not in _tables_ready: + try: + service.ensure_tables() + _tables_ready.add(huidige_school().code) + except Exception as e: + flash(f"Kon de 2FA-tabellen niet aanmaken: {e}", "error") + + +def _render(email=None, codes=None, code_actie=None, fout=None): + """Bouwt de pagina op; codes worden enkel in deze response getoond, nooit bewaard of gelogd.""" + tab = request.args.get('tab', 'hulp') + zoek = (request.args.get('zoek') or '').strip() + email = email or (request.args.get('email') or '').strip() + gebruiker, uitzondering, zoekresultaten, reset_wacht = None, None, [], None + + if zoek and '@' not in zoek: + zoekresultaten = service.search_users(zoek) + if not zoekresultaten: + fout = fout or f"Geen gebruikers gevonden voor '{zoek}'." + elif zoek: + email = zoek + + if email: + try: + gebruiker = service.get_user(email) + uitzondering = service.active_for(gebruiker['email']) + reset_wacht = service.reset_bezig(gebruiker['email']) + except TweestapsError as e: + fout = fout or str(e) + + try: + actief = service.active_exceptions() + # Aantal per pagina: uit ?logper=..., anders de vorige keuze (sessie), anders 25 + per = request.args.get('logper', type=int) + if per in LOG_KEUZES: + session['tweestaps_logper'] = per + per = session.get('tweestaps_logper', LOG_PER_PAGINA) + grootte = per or 100000 # 0 = alles + log_pagina = max(1, request.args.get('logpagina', 1, type=int) or 1) + logboek, log_totaal = service.recent_log(log_pagina, grootte) + log_paginas = max(1, -(-log_totaal // grootte)) + if log_pagina > log_paginas: + log_pagina = log_paginas + logboek, log_totaal = service.recent_log(log_pagina, grootte) + except Exception: + actief, logboek, log_totaal, log_pagina, log_paginas, per = [], [], 0, 1, 1, LOG_PER_PAGINA + + lijst, lijst_fout = None, None + if tab == 'lijst': + try: + lijst = service.niet_ingesteld(force=request.args.get('vernieuw') == '1') + lijst_fout = service.ou_melding() # sommige OU's bestaan niet: lijst tonen + waarschuwing + except TweestapsError as e: + lijst_fout = str(e) + except Exception as e: + lijst_fout = TweestapsService._friendly(e) + + return render_template('tweestaps.html', tab=tab, zoek=zoek, zoekresultaten=zoekresultaten, + gebruiker=gebruiker, uitzondering=uitzondering, reset_wacht=reset_wacht, codes=codes, code_actie=code_actie, + fout=fout, actief=actief, logboek=logboek, log_totaal=log_totaal, log_pagina=log_pagina, log_per=per, log_keuzes=LOG_KEUZES, + log_paginas=log_paginas, lijst=lijst, lijst_fout=lijst_fout, + einde=service.einde_vandaag(), groep=service.exception_group, + ous=Config.TWEESTAPS_OUS, nu=datetime.now()) + + +@tweestaps_bp.route('/', methods=['GET']) +@login_required +@recht_vereist('tweestaps_codes', 'tweestaps_uitzetten') +def overzicht(): + _ensure_tables() + return _render() + + +#--------------------------------------------- +# Back-upcodes +#--------------------------------------------- +@tweestaps_bp.route('/codes', methods=['POST']) +@login_required +@recht_vereist('tweestaps_codes') +def codes(): + _ensure_tables() + email = request.form.get('email', '') + actie = request.form.get('actie', 'tonen') + door = session.get('user') + try: + user = service.get_user(email) + if actie == 'ongeldig': + service.invalidate_codes(user['email']) + service.log(door, 'codes ongeldig gemaakt', user['email']) + flash(f"Alle back-upcodes van {user['email']} zijn ongeldig gemaakt.", "success") + return redirect(url_for('tweestaps.overzicht', email=user['email'])) + + bestaand = [] if actie == 'nieuw' else service.list_codes(user['email']) + if bestaand: + lijst = bestaand + service.log(door, 'code getoond', user['email']) + else: + lijst = service.generate_codes(user['email']) + service.log(door, 'nieuwe codes', user['email'], f"{len(lijst)} codes") + return _render(email=user['email'], codes=lijst, code_actie='nieuw' if not bestaand else 'bestaand') + except TweestapsError as e: + return _render(email=email, fout=str(e)) + + +#--------------------------------------------- +# Tijdelijke uitzondering +#--------------------------------------------- +@tweestaps_bp.route('/uitzondering', methods=['POST']) +@login_required +@recht_vereist('tweestaps_uitzetten') +def uitzondering(): + _ensure_tables() + email = request.form.get('email', '') + reden = (request.form.get('reden') or '').strip() + eindtijd = service.einde_vandaag() + try: + user = service.grant_exception(email, eindtijd, session.get('user'), reden) + flash(f"{user['email']} kan tot {eindtijd:%H:%M} zonder 2FA inloggen. Daarna zet PIVOT 2FA automatisch " + "terug aan. Let op: het kan enkele minuten duren voor Google de uitzondering toepast.", "success") + except TweestapsError as e: + flash(str(e), "error") + return redirect(url_for('tweestaps.overzicht', email=email.strip())) + + +@tweestaps_bp.route('/reset', methods=['POST']) +@login_required +@recht_vereist('tweestaps_uitzetten') +def reset(): + """2FA resetten voor iemand met een nieuwe of verloren telefoon.""" + _ensure_tables() + email = request.form.get('email', '') + eindtijd = service.einde_vandaag() + try: + user = service.reset_2fa(email, eindtijd, session.get('user'), (request.form.get('reden') or '').strip()) + if user.get('wacht'): + flash(f"{user['email']} staat nu in de uitzonderingsgroep, maar Google past dat pas na enkele minuten toe. " + "PIVOT probeert de 2FA-reset elke minuut opnieuw (tot de uitzondering afloopt om " + f"{eindtijd:%H:%M}). Je hoeft niets meer te doen; vernieuw deze pagina om de status te zien.", "info") + return redirect(url_for('tweestaps.overzicht', email=email.strip())) + tekst = f"2FA is uitgezet voor {user['email']}. Hij kan nu inloggen en 2FA opnieuw instellen met zijn nieuwe telefoon" + if user.get('uitzondering'): + tekst += f" (vóór {eindtijd:%H:%M}; daarna is 2FA weer verplicht)" + flash(tekst + ". Het kan enkele minuten duren voor Google dit toepast.", "success") + except TweestapsError as e: + flash(str(e), "error") + return redirect(url_for('tweestaps.overzicht', email=email.strip())) + + +@tweestaps_bp.route('/uitzondering//stop', methods=['POST']) +@login_required +@recht_vereist('tweestaps_uitzetten') +def stop_uitzondering(uitz_id): + _ensure_tables() + try: + email = service.end_exception(uitz_id, session.get('user')) + flash(f"2FA is opnieuw verplicht voor {email}.", "success") + except TweestapsError as e: + flash(str(e), "error") + terug = request.form.get('terug') + return redirect(url_for('tweestaps.overzicht', email=terug) if terug else url_for('tweestaps.overzicht')) diff --git a/blueprints/verzendlijsten_bp.py b/blueprints/verzendlijsten_bp.py new file mode 100644 index 0000000..68c3826 --- /dev/null +++ b/blueprints/verzendlijsten_bp.py @@ -0,0 +1,124 @@ +"""Google › Verzendlijsten: Google Groepen van de school bekijken, aanmaken en aanpassen (leden en rollen).""" +from flask import Blueprint, render_template, request, flash, redirect, url_for, session + +from blueprints.auth import login_required +from rechten import recht_vereist, log +from services.verzendlijsten_service import (VerzendlijstenService, VerzendlijstFout, ROLLEN, WIE_MAILT, adressen) +from tenancy import huidige_school + +verzendlijsten_bp = Blueprint('verzendlijsten', __name__) + + +@verzendlijsten_bp.route("/", methods=["GET"]) +@login_required +@recht_vereist('verzendlijsten') +def overzicht(): + lijsten, fout = [], None + try: + lijsten = VerzendlijstenService().alle() + except Exception as e: + fout = str(e) + return render_template("verzendlijsten.html", lijsten=lijsten, fout=fout, + domeinen=huidige_school().domeinen, wie_mailt=WIE_MAILT) + + +@verzendlijsten_bp.route("/nieuw", methods=["POST"]) +@login_required +@recht_vereist('verzendlijsten') +def nieuw(): + deel = (request.form.get('adres') or '').strip().lower() + domein = (request.form.get('domein') or '').strip().lower() + email = deel if '@' in deel else f"{deel}@{domein}" + svc = VerzendlijstenService() + try: + svc.aanmaken(email, request.form.get('naam'), request.form.get('beschrijving')) + except VerzendlijstFout as e: + flash(str(e), "error") + return redirect(url_for('verzendlijsten.overzicht')) + log(f"Verzendlijst aangemaakt: {email}") + melding = f"Verzendlijst {email} aangemaakt." + wie = request.form.get('wie_mailt') + if wie: + try: + svc.zet_wie_mailt(email, wie) + except VerzendlijstFout as e: + melding += f" 'Wie mag mailen' kon niet ingesteld worden: {e}" + flash(melding + " Google kan er een minuutje over doen voor ze overal zichtbaar is.", "success") + return redirect(url_for('verzendlijsten.detail', email=email)) + + +@verzendlijsten_bp.route("/", methods=["GET"]) +@login_required +@recht_vereist('verzendlijsten') +def detail(email): + svc = VerzendlijstenService() + try: + groep = svc.groep(email) + leden = svc.leden(email) + except VerzendlijstFout as e: + flash(str(e), "error") + return redirect(url_for('verzendlijsten.overzicht')) + return render_template("verzendlijst.html", groep=groep, leden=leden, rollen=ROLLEN, + wie_mailt=WIE_MAILT, huidig_wie=svc.wie_mailt(email)) + + +@verzendlijsten_bp.route("//bewerken", methods=["POST"]) +@login_required +@recht_vereist('verzendlijsten') +def bewerken(email): + svc = VerzendlijstenService() + try: + svc.bijwerken(email, request.form.get('naam'), request.form.get('beschrijving')) + if request.form.get('wie_mailt'): + svc.zet_wie_mailt(email, request.form.get('wie_mailt')) + log(f"Verzendlijst aangepast: {email}") + flash("Verzendlijst bijgewerkt.", "success") + except VerzendlijstFout as e: + flash(str(e), "error") + return redirect(url_for('verzendlijsten.detail', email=email)) + + +@verzendlijsten_bp.route("//leden/toevoegen", methods=["POST"]) +@login_required +@recht_vereist('verzendlijsten') +def leden_toevoegen(email): + goed, ongeldig = adressen(request.form.get('adressen')) + if ongeldig: + flash("Geen geldig e-mailadres, overgeslagen: " + ", ".join(ongeldig), "warning") + if goed: + gelukt, fouten = VerzendlijstenService().leden_toevoegen(email, goed, request.form.get('rol') or 'MEMBER') + if gelukt: + log(f"Verzendlijst {email}: {gelukt} lid/leden toegevoegd") + flash(f"{gelukt} lid/leden toegevoegd.", "success") + for adres, fout in fouten: + flash(f"{adres}: {fout}", "error") + elif not ongeldig: + flash("Vul minstens één e-mailadres in.", "error") + return redirect(url_for('verzendlijsten.detail', email=email)) + + +@verzendlijsten_bp.route("//leden/rol", methods=["POST"]) +@login_required +@recht_vereist('verzendlijsten') +def lid_rol(email): + lid = request.form.get('lid') or '' + try: + VerzendlijstenService().lid_rol(email, lid, request.form.get('rol')) + flash(f"Rol van {lid} aangepast.", "success") + except VerzendlijstFout as e: + flash(str(e), "error") + return redirect(url_for('verzendlijsten.detail', email=email)) + + +@verzendlijsten_bp.route("//leden/verwijderen", methods=["POST"]) +@login_required +@recht_vereist('verzendlijsten') +def lid_verwijderen(email): + lid = request.form.get('lid') or '' + try: + VerzendlijstenService().lid_verwijderen(email, lid) + log(f"Verzendlijst {email}: {lid} verwijderd") + flash(f"{lid} uit de verzendlijst gehaald.", "success") + except VerzendlijstFout as e: + flash(str(e), "error") + return redirect(url_for('verzendlijsten.detail', email=email)) diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..fabf3de --- /dev/null +++ b/compose.yaml @@ -0,0 +1,27 @@ +# PIVOT – één container voor alle scholen. +# +# Vóór de eerste start: +# 1. config.ini invullen (database-server, superbeheerders, gedeelde Google-login) +# 2. .env aanmaken naast dit bestand met minstens: +# PIVOT_DB_PASSWORD=... +# PIVOT_SLEUTEL=... (python beheer.py nieuwe-sleutel) ← BACK-UP NEMEN +# FLASK_SECRET_KEY=... (willekeurige lange tekst) +# 3. docker compose up -d --build +# 4. bestaande school overzetten: +# docker compose exec server python beheer.py importeer-config /app/import/config.ini \ +# --google-sleutel /app/import/kamxm_api_key.json +services: + server: + build: + context: . + ports: + - 5001:5001 + env_file: + - .env + environment: + - PIVOT_GEHEIMEN=/app/geheimen + volumes: + - ./config.ini:/app/config.ini:ro + - ./geheimen:/app/geheimen + - ./import:/app/import:ro + restart: unless-stopped diff --git a/config.py b/config.py new file mode 100644 index 0000000..8c8fb05 --- /dev/null +++ b/config.py @@ -0,0 +1,107 @@ +""" +Instellingen. + +config.ini bevat enkel nog wat voor ALLE scholen geldt (database-server, centrale +database, gedeelde Google-login, superbeheerders). Alles wat per school verschilt +staat in de centrale database (zie tenancy.py) en wordt beheerd via /scholen. + +`Config.SS_API_PW`, `Config.SCHOOL_DOMAIN`, ... geven de waarde van de school +waarvoor de huidige request (of achtergrondtaak) loopt. + +Geheimen kunnen ook via omgevingsvariabelen gezet worden (handig voor Docker): + PIVOT_DB_PASSWORD, FLASK_SECRET_KEY, PIVOT_SLEUTEL, PIVOT_SSO_CLIENT_SECRET +""" +import os +import configparser + +base_dir = os.path.dirname(os.path.abspath(__file__)) +config_path = os.environ.get('PIVOT_CONFIG', os.path.join(base_dir, 'config.ini')) + +config_file = configparser.ConfigParser() +config_file.read(config_path, encoding='utf-8') + + +def _get(section, key, fallback='', env=None): + if env and os.environ.get(env): + return os.environ[env] + return config_file.get(section, key, fallback=fallback) + + +def _secret_key(): + """FLASK_SECRET_KEY, config.ini, of anders een willekeurige sleutel die bewaard wordt in geheimen/flask.key. + (Nooit een vaste standaardsleutel: daarmee kan iemand een sessie voor eender welke school vervalsen.)""" + sleutel = os.environ.get("FLASK_SECRET_KEY") or _get('algemeen', 'secret_key') + if sleutel: + return sleutel + import secrets + pad = os.path.join(os.environ.get('PIVOT_GEHEIMEN', os.path.join(base_dir, 'geheimen')), 'flask.key') + if os.path.exists(pad): + with open(pad) as f: + return f.read().strip() + os.makedirs(os.path.dirname(pad), exist_ok=True) + sleutel = secrets.token_hex(32) + with open(pad, 'w') as f: + f.write(sleutel) + return sleutel + + +class _SchoolConfigMeta(type): + """Onbekende attributen op de klasse → instelling van de huidige school.""" + def __getattr__(cls, naam): + if naam.startswith('__'): + raise AttributeError(naam) + if naam == 'GOOGLE_API_LOCATION': + raise AttributeError("GOOGLE_API_LOCATION bestaat niet meer: gebruik tenancy.google_credentials()") + from tenancy import huidige_school, VELD, AFGELEID + if naam not in VELD and naam not in AFGELEID: + raise AttributeError(naam) + return huidige_school().get(naam) + + +class Config(metaclass=_SchoolConfigMeta): + """Algemene instellingen (klasse-attributen) + per-school instellingen (via de metaclass).""" + + # Flask + SECRET_KEY = _secret_key() + DEBUG = _get('algemeen', 'debug', 'nee').strip().lower() in ('ja', 'yes', 'true', '1', 'on') + SESSION_COOKIE_PATH = '/' + SESSION_PERMANENT = True + + # Database-server: standaard voor alle schooldatabases + de centrale database + DB_HOST = _get('database', 'host', 'localhost', env='PIVOT_DB_HOST') + DB_PORT = int(_get('database', 'port', '3306', env='PIVOT_DB_PORT')) + DB_USER = _get('database', 'user', '', env='PIVOT_DB_USER') + DB_PASSWORD = _get('database', 'password', '', env='PIVOT_DB_PASSWORD') + DB_CENTRAAL = _get('database', 'centrale_database', 'pivot_centraal', env='PIVOT_DB_CENTRAAL') + # Verbindingen per database in de pool. Elke pool opent die meteen allemaal: aantal scholen x pool_size + # (+ centraal) moet onder max_connections van MySQL blijven (standaard 151). + DB_POOL_SIZE = max(1, min(32, int(_get('database', 'pool_size', '3', env='PIVOT_DB_POOL_SIZE') or 3))) + + # Gedeelde Google-login (één OAuth-client voor alle scholen; per school te overschrijven) + SSO_CLIENT_ID = _get('google_sso', 'client_id', env='PIVOT_SSO_CLIENT_ID') + SSO_CLIENT_SECRET = _get('google_sso', 'client_secret', env='PIVOT_SSO_CLIENT_SECRET') + + # Superbeheerders: mogen scholen beheren en tussen scholen wisselen (Google-login) + SUPERBEHEERDERS = [x.strip().lower() for x in + _get('algemeen', 'superbeheerders', env='PIVOT_SUPERBEHEERDERS').replace(';', ',').split(',') + if x.strip()] + + APP_VERSION = _get('algemeen', 'app_version', '1.1.0') + + # Elke bezochte pagina bewaren in de tabel Logs (centrale database) + LOGBOEK = _get('algemeen', 'logboek', 'ja').strip().lower() in ('ja', 'yes', 'true', '1', 'on') + # Aantal reverse proxies (nginx, IIS, firewall met https, ...) vóór PIVOT. 0 = PIVOT staat rechtstreeks op het net. + # Nodig om het echte IP-adres van de bezoeker te kennen (IP-blokkades, logboek, inlogbeveiliging). + try: + PROXY_AANTAL = max(0, int(_get('algemeen', 'proxy_aantal', '0') or 0)) + except ValueError: + PROXY_AANTAL = 0 + + def __getattr__(self, naam): + # Config().SS_API_PW werkt ook (zoals in de bestaande services) + return getattr(type(self), naam) + + @property + def DB_CONFIG(self): + from tenancy import huidige_school + return huidige_school().db_config() diff --git a/database.py b/database.py new file mode 100644 index 0000000..c600afa --- /dev/null +++ b/database.py @@ -0,0 +1,106 @@ +""" +Databaseverbindingen. + +- execute_query / get_db_connection → de database van de HUIDIGE school +- central_query / get_central_connection → de centrale database (Scholen, Gebruikers, rechten, Logs, Bugs) + +Per database wordt lui een connection pool aangemaakt. +""" +import threading + +import mysql.connector +from mysql.connector import pooling + +from config import Config + +_pools = {} +_lock = threading.Lock() +POOL_SIZE = Config.DB_POOL_SIZE # config.ini › [database] › pool_size (standaard 3) + + +def _pool(host, user, password, database, port=None): + key = (host, port or Config.DB_PORT, user, database) + pool = _pools.get(key) + if pool is None: + with _lock: + pool = _pools.get(key) + if pool is None: + naam = f"p{len(_pools)}_{database}"[:60] + pool = pooling.MySQLConnectionPool( + pool_name=naam, pool_size=POOL_SIZE, + host=host, port=port or Config.DB_PORT, user=user, password=password, database=database, + connection_timeout=10, + # zelfde collatie als de tabellen (sql/*.sql); anders geeft MySQL 8 bij vergelijkingen + # "Illegal mix of collations (utf8mb4_0900_ai_ci / utf8mb4_unicode_ci)" + charset='utf8mb4', collation='utf8mb4_unicode_ci', + # autocommit: elke query ziet meteen de laatste gegevens (ook na wijzigingen via een + # andere verbinding uit de pool). Wie meerdere statements samen wil, gebruikt + # conn.start_transaction() ... conn.commit(). + autocommit=True) + _pools[key] = pool + return pool + + +def vergeet_pools(database=None): + """Na het wijzigen van de DB-gegevens van een school: pools opnieuw laten opbouwen.""" + with _lock: + for k in [k for k in _pools if database is None or k[3] == database]: + _pools.pop(k, None) + + +def get_db_connection(): + """Verbinding met de database van de huidige school.""" + from tenancy import huidige_school + cfg = huidige_school().db_config() + return _pool(cfg['host'], cfg['user'], cfg['password'], cfg['database']).get_connection() + + +def get_central_connection(): + return _pool(Config.DB_HOST, Config.DB_USER, Config.DB_PASSWORD, Config.DB_CENTRAAL).get_connection() + + +def _run(conn, query, params, commit): + cursor = conn.cursor(dictionary=True) + try: + cursor.execute(query, params) + if commit: + conn.commit() + return cursor.rowcount + return cursor.fetchall() + finally: + cursor.close() + conn.close() # terug naar de pool + + +def execute_query(query, params=(), commit=False): + return _run(get_db_connection(), query, params, commit) + + +def execute_insert(query, params=()): + """INSERT in de database van de huidige school; geeft het nieuwe AUTO_INCREMENT-id terug.""" + conn = get_db_connection() + cursor = conn.cursor() + try: + cursor.execute(query, params) + conn.commit() + return cursor.lastrowid + finally: + cursor.close() + conn.close() + + +def central_query(query, params=(), commit=False): + return _run(get_central_connection(), query, params, commit) + + +def central_insert(query, params=()): + """INSERT in de centrale database; geeft het nieuwe AUTO_INCREMENT-id terug.""" + conn = get_central_connection() + cursor = conn.cursor() + try: + cursor.execute(query, params) + conn.commit() + return cursor.lastrowid + finally: + cursor.close() + conn.close() diff --git a/rechten.py b/rechten.py new file mode 100644 index 0000000..a1b85c1 --- /dev/null +++ b/rechten.py @@ -0,0 +1,475 @@ +""" +Rechtensysteem: wie mag wat, in welke school. + +Gebruikers staan in de CENTRALE database (één account voor alle scholen). +Per gebruiker wordt per school bijgehouden op welke onderdelen hij rechten heeft: + + Gebruiker_rechten (Gebruiker_ID, School_ID, Onderdeel_ID) + +Zo kan iemand in school A '2FA tijdelijk uitzetten' mogen en in school B niet. + +Veiligheidsgroepen: + 1 = Administrator : alle rechten in alle scholen, beheert gebruikers, rechten en scholen + 2 = Gebruiker : enkel de rechten die per school zijn aangevinkt + 5 = Leerkracht : (geen account) personeelslid dat met Google inlogt → enkel de personeelsmodule + +Gebruik in de code: + @recht_vereist('herstellingen') # route + if heeft_recht('tweestaps_uitzetten'): ... # in Python + {% if mag('co2') %} ... {% endif %} # in templates +""" +import functools +import sys +from collections import OrderedDict + +from flask import session, g, flash, redirect, url_for, request, has_request_context + +ADMIN = 1 +GEBRUIKER = 2 + +VEILIGHEIDSGROEPEN = OrderedDict([ + (ADMIN, 'Administrator'), + (GEBRUIKER, 'Gebruiker'), +]) + +# (code, naam, categorie). De volgorde hier is de volgorde op het scherm. +# Nieuwe onderdelen worden bij het opstarten automatisch in de tabel Onderdelen gezet. +ONDERDELEN = [ + # --- Chromebooks --- + ('eigendom_bekijken', 'Eigendom bekijken', 'Chromebooks'), + ('toestellen_uitdelen', 'Toestellen uitdelen en inleveren', 'Chromebooks'), + ('toestellen_beheren', 'Toestelleninventaris beheren', 'Chromebooks'), + ('toestel_blokkeren', 'Chromebook blokkeren / deblokkeren', 'Chromebooks'), + ('herstellingen', 'Herstellingen', 'Chromebooks'), + ('signpost', 'Signpost-toestellen', 'Chromebooks'), + # --- Leerlingen --- + ('leerlingen_bekijken', 'Leerlingen bekijken en bewerken', 'Leerlingen'), + ('leerlingen_synchroniseren', 'Leerlingen toevoegen en synchroniseren', 'Leerlingen'), + ('leerlingenaantal', 'Leerlingenaantallen (alle scholen)', 'Leerlingen'), + # --- Basisonderwijs (blok enkel zichtbaar bij een basisschool) --- + ('bingel', 'Bingel: leerlingenlijst (Excel)', 'Basisonderwijs'), + # --- Internaat --- + ('internen', 'Internaat: internen bekijken', 'Internaat'), + ('internaat_aanwezigheid', 'Internaat: aanwezigheden registreren', 'Internaat'), + # --- Leerlingfacturatie --- + ('leerlingfacturatie', 'Leerlingfacturatie: facturen bekijken', 'Leerlingfacturatie'), + # --- Google --- + ('google_wachtwoord', 'Google-wachtwoord resetten', 'Google'), + ('google_accounts', 'Google-accounts aanmaken', 'Google'), + ('tweestaps_codes', '2FA: back-upcodes tonen / aanmaken', 'Google'), + ('tweestaps_uitzetten', '2FA tijdelijk uitzetten (uitzondering)', 'Google'), + ('google_licenties', 'Google-licenties', 'Google'), + ('gmail_delegatie', 'Mailbox-delegatie', 'Google'), + ('verzendlijsten', 'Verzendlijsten (Google Groepen) beheren', 'Google'), + ('gmail_labels', 'E-mails met een label naar een andere mailbox', 'Google'), + ('gmail_handtekeningen', 'Gmail-handtekeningen instellen (functie/telefoon)', 'Google'), + ('gedeelde_drives', 'Gedeelde drives: leden en rechten beheren', 'Google'), + ('gmail_contacten', 'Contacten: contactlijsten in mailboxen, adresboek', 'Google'), + # --- Smartschool --- + ('smartschool', 'Smartschool-wachtwoorden & info', 'Smartschool'), + ('smartschool_activiteit', 'Activiteit co-accounts & berichten', 'Smartschool'), + ('afwezigheden', 'Afwezigheden leerlingen (B-codes)', 'Smartschool'), + ('laatkomers', 'Laatkomers', 'Smartschool'), + ('skore', 'Skore-synchronisatie (starten en plannen)', 'Smartschool'), + ('sgr_groepen', 'SGR groepen: subgroepen en leden bekijken', 'Smartschool'), + # --- Personeel --- + ('personeel_directie', 'Personeel: aanvragen goedkeuren (directie)', 'Personeel'), + ('personeel_secretariaat', 'Personeel: dagoverzicht (secretariaat)', 'Personeel'), + ('gopro', 'GO! Pro: personeel en rollen', 'Personeel'), + ('personeelsaantal', 'Personeelsaantallen (alle scholen)', 'Personeel'), + # --- Tools --- + ('qr_codes', 'QR-code generator', 'Tools'), + # --- IoT --- + ('co2', 'CO2-sensoren', 'IoT'), + # --- Scholengroep --- + # --- Beheer --- + ('bugs_bekijken', 'Bugs bekijken', 'Beheer'), + ('bugs_beheren', 'Status van bugs wijzigen', 'Beheer'), + ('nieuw_schooljaar', 'Nieuw schooljaar (accounts & toestellen)', 'Beheer'), + ('ip_whitelist', 'IP-adressen toestaan voor deze school', 'Beheer'), + ('database_toestellen', 'Database: toestellen importeren uit Excel', 'Beheer'), + # --- PIVOT --- + ('gebruikersbeheer', 'Gebruikers & rechten van deze school', 'PIVOT'), + ('koppelingen', 'Koppelingen van deze school', 'PIVOT'), +] +CODES = [o[0] for o in ONDERDELEN] + + +# ===================================================================== +# Tabellen (centrale database) +# ===================================================================== +SCHEMA = [ + """CREATE TABLE IF NOT EXISTS Veiligheidsgroepen ( + Veiligheidsgroep TINYINT NOT NULL PRIMARY KEY, + Naam VARCHAR(50) NOT NULL, + Omschrijving VARCHAR(255) NULL + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Gebruikers ( + Gebruiker_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Gebruikersnaam VARCHAR(100) NOT NULL, + Veiligheidsgroep TINYINT NOT NULL DEFAULT 2, + Passwoordhash VARCHAR(255) NULL, + Emailadres VARCHAR(255) NULL, + Last_login DATETIME NULL, + IP_laatste_login VARCHAR(45) NULL, + Laatste_school VARCHAR(32) NULL, + Actief TINYINT NOT NULL DEFAULT 1, + UNIQUE KEY uq_gebruikersnaam (Gebruikersnaam), + UNIQUE KEY uq_emailadres (Emailadres), + CONSTRAINT fk_gebruikers_groep FOREIGN KEY (Veiligheidsgroep) + REFERENCES Veiligheidsgroepen (Veiligheidsgroep) + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Onderdelen ( + Onderdeel_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Code VARCHAR(50) NOT NULL, + Naam VARCHAR(255) NOT NULL, + Categorie VARCHAR(50) NOT NULL, + Volgorde INT NOT NULL DEFAULT 0, + UNIQUE KEY uq_onderdeel_code (Code) + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Gebruiker_rechten ( + Gebruiker_ID INT NOT NULL, + School_ID INT NOT NULL, + Onderdeel_ID INT NOT NULL, + Toegekend_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Toegekend_door VARCHAR(100) NULL, + PRIMARY KEY (Gebruiker_ID, School_ID, Onderdeel_ID), + KEY idx_rechten_school (School_ID), + KEY idx_rechten_onderdeel (Onderdeel_ID), + CONSTRAINT fk_rechten_gebruiker FOREIGN KEY (Gebruiker_ID) + REFERENCES Gebruikers (Gebruiker_ID) ON DELETE CASCADE, + CONSTRAINT fk_rechten_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE, + CONSTRAINT fk_rechten_onderdeel FOREIGN KEY (Onderdeel_ID) + REFERENCES Onderdelen (Onderdeel_ID) ON DELETE CASCADE + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Handleidingen ( + Handleiding_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Slug VARCHAR(100) NOT NULL, + Titel VARCHAR(200) NOT NULL, + Categorie VARCHAR(100) NULL, + Samenvatting VARCHAR(300) NULL, + Inhoud MEDIUMTEXT NULL, + Zichtbaar VARCHAR(10) NOT NULL DEFAULT 'iedereen', + Volgorde INT NOT NULL DEFAULT 0, + Gewijzigd_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Gewijzigd_door VARCHAR(100) NULL, + UNIQUE KEY uq_handleiding_slug (Slug) + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Handleidingen_versies ( + Versie_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Handleiding_ID INT NOT NULL, + Titel VARCHAR(200) NOT NULL, + Inhoud MEDIUMTEXT NULL, + Opgeslagen_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Door VARCHAR(100) NULL, + KEY idx_versie_handleiding (Handleiding_ID, Opgeslagen_op), + CONSTRAINT fk_versie_handleiding FOREIGN KEY (Handleiding_ID) + REFERENCES Handleidingen (Handleiding_ID) ON DELETE CASCADE + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Leerlingenaantal_tellingen ( + Telling_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_ID INT NOT NULL, + Peildatum DATE NOT NULL, + Schooljaar VARCHAR(10) NOT NULL, + Aantal INT NOT NULL, + Detail TEXT NULL, + Opgevraagd_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Door VARCHAR(100) NULL, + UNIQUE KEY uq_telling (School_ID, Peildatum), + KEY idx_telling_datum (Peildatum), + CONSTRAINT fk_telling_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Personeelsaantal_tellingen ( + Telling_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_ID INT NOT NULL, + Peildatum DATE NOT NULL, + Schooljaar VARCHAR(10) NOT NULL, + Aantal INT NOT NULL, + Detail TEXT NULL, + Opgevraagd_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Door VARCHAR(100) NULL, + UNIQUE KEY uq_ptelling (School_ID, Peildatum), + KEY idx_ptelling_datum (Peildatum), + CONSTRAINT fk_ptelling_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Personeelsaantal_huidig ( + School_ID INT NOT NULL PRIMARY KEY, + Aantal INT NOT NULL, + Detail TEXT NULL, + Gesynchroniseerd DATETIME NOT NULL, + CONSTRAINT fk_phuidig_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS PIVOT_instellingen ( + Sleutel VARCHAR(50) NOT NULL PRIMARY KEY, + Waarde VARCHAR(255) NULL, + Bijgewerkt DATETIME NULL, + Door VARCHAR(100) NULL + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS IP_blokkades ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Reeks VARCHAR(64) NOT NULL, + Soort VARCHAR(10) NOT NULL DEFAULT 'blokkeren', + Opmerking VARCHAR(255) NULL, + Scholen VARCHAR(1000) NULL, + Aangemaakt DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Gebruiker_ID INT NULL, + Aantal_geweigerd INT NOT NULL DEFAULT 0, + Laatst_geweigerd DATETIME NULL, + UNIQUE KEY uq_ip_reeks (Reeks, Soort) + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Koppeling_tests ( + School_ID INT NOT NULL, + Onderdeel VARCHAR(50) NOT NULL, + Ok TINYINT NULL, + Detail VARCHAR(500) NULL, + Getest_op DATETIME NOT NULL, + PRIMARY KEY (School_ID, Onderdeel), + CONSTRAINT fk_ktest_school FOREIGN KEY (School_ID) REFERENCES Scholen (School_ID) ON DELETE CASCADE + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Logs ( + Log_ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Bezochte_url VARCHAR(2048) NOT NULL, + Gebruiker_ID INT NULL, + School_ID INT NULL, + Actie VARCHAR(255) NULL, + IP VARCHAR(45) NULL, + KEY idx_logs_tijd (Timestamp), + KEY idx_logs_gebruiker (Gebruiker_ID), + CONSTRAINT fk_logs_gebruiker FOREIGN KEY (Gebruiker_ID) + REFERENCES Gebruikers (Gebruiker_ID) ON DELETE SET NULL, + CONSTRAINT fk_logs_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE SET NULL + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Status ( + Bugstatus_ID TINYINT NOT NULL PRIMARY KEY, + Omschrijving VARCHAR(50) NOT NULL, + UNIQUE KEY uq_status_omschrijving (Omschrijving) + ) ENGINE=InnoDB""", + """CREATE TABLE IF NOT EXISTS Bugs ( + Bug_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Timestamp DATETIME NOT NULL, + Omschrijving TEXT NOT NULL, + Foutcode VARCHAR(100) NULL, + Bugstatus_ID TINYINT NOT NULL DEFAULT 1, + Gebruiker_ID INT NULL, + Gebruikersnaam VARCHAR(255) NULL, + School_ID INT NULL, + Gemeld_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + KEY idx_bugs_status (Bugstatus_ID), + CONSTRAINT fk_bugs_status FOREIGN KEY (Bugstatus_ID) REFERENCES Status (Bugstatus_ID), + CONSTRAINT fk_bugs_gebruiker FOREIGN KEY (Gebruiker_ID) + REFERENCES Gebruikers (Gebruiker_ID) ON DELETE SET NULL, + CONSTRAINT fk_bugs_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE SET NULL + ) ENGINE=InnoDB""", +] + +BUGSTATUS = [(1, 'Nieuw'), (2, 'In behandeling'), (3, 'Fixed')] + + +def ensure_schema(): + """Maakt de tabellen aan en zet de vaste lijsten (groepen, onderdelen, bugstatussen) goed.""" + from database import central_query + for sql in SCHEMA: + central_query(sql, commit=True) + # Bestaande tabel Gebruikers van vóór "laatst actieve school" (het aanmeldscherm vraagt geen school meer) + if 'laatste_school' not in {r['Field'].lower() for r in central_query("SHOW COLUMNS FROM Gebruikers") or []}: + central_query("ALTER TABLE Gebruikers ADD COLUMN Laatste_school VARCHAR(32) NULL AFTER IP_laatste_login", commit=True) + for nr, naam in VEILIGHEIDSGROEPEN.items(): + central_query("INSERT INTO Veiligheidsgroepen (Veiligheidsgroep, Naam) VALUES (%s, %s) " + "ON DUPLICATE KEY UPDATE Naam = VALUES(Naam)", (nr, naam), commit=True) + for i, (code, naam, cat) in enumerate(ONDERDELEN, start=1): + central_query("INSERT INTO Onderdelen (Code, Naam, Categorie, Volgorde) VALUES (%s, %s, %s, %s) " + "ON DUPLICATE KEY UPDATE Naam = VALUES(Naam), Categorie = VALUES(Categorie), " + "Volgorde = VALUES(Volgorde)", (code, naam, cat, i * 10), commit=True) + for nr, oms in BUGSTATUS: + central_query("INSERT INTO Status (Bugstatus_ID, Omschrijving) VALUES (%s, %s) " + "ON DUPLICATE KEY UPDATE Omschrijving = VALUES(Omschrijving)", (nr, oms), commit=True) + # Standaardhandleidingen die nog niet bestaan (daarna beheer je ze in PIVOT; verwijderen = verbergen) + from services.handleidingen_standaard import STANDAARD + bestaand = {r['Slug'] for r in central_query("SELECT Slug FROM Handleidingen")} + for i, h in enumerate(STANDAARD, start=1): + if h['slug'] not in bestaand: + central_query("INSERT IGNORE INTO Handleidingen (Slug, Titel, Categorie, Samenvatting, Inhoud, Volgorde, " + "Gewijzigd_door) VALUES (%s, %s, %s, %s, %s, %s, 'PIVOT')", + (h['slug'], h['titel'], h['categorie'], h['samenvatting'], h['inhoud'].strip(), i * 10), + commit=True) + + +# ===================================================================== +# Gebruikers +# ===================================================================== +def zoek_gebruiker(naam_of_email): + """Actieve of inactieve gebruiker op gebruikersnaam of e-mailadres (hoofdletterongevoelig).""" + from database import central_query + w = (naam_of_email or '').strip() + if not w: + return None + rows = central_query("SELECT * FROM Gebruikers WHERE Gebruikersnaam = %s OR Emailadres = %s " + "ORDER BY Gebruikersnaam = %s DESC LIMIT 1", (w, w.lower(), w)) + return rows[0] if rows else None + + +def gebruiker_op_id(gid): + from database import central_query + rows = central_query("SELECT * FROM Gebruikers WHERE Gebruiker_ID = %s", (gid,)) + return rows[0] if rows else None + + +def registreer_login(gid, ip): + from database import central_query + try: + central_query("UPDATE Gebruikers SET Last_login = NOW(), IP_laatste_login = %s WHERE Gebruiker_ID = %s", + (ip, gid), commit=True) + except Exception as e: + sys.stderr.write(f"PIVOT: laatste login niet bewaard: {e}\n") + + +def bewaar_laatste_school(gid, code): + """Onthoudt de school waarin de gebruiker het laatst werkte (die wordt bij de volgende aanmelding geladen).""" + from database import central_query + if not gid or not code: + return + try: + central_query("UPDATE Gebruikers SET Laatste_school = %s WHERE Gebruiker_ID = %s", (code, gid), commit=True) + except Exception as e: + sys.stderr.write(f"PIVOT: laatst actieve school niet bewaard: {e}\n") + + +def rechten_van(gid, school_id): + """Set met codes van onderdelen waarop gebruiker `gid` rechten heeft in school `school_id`.""" + from database import central_query + rows = central_query( + "SELECT o.Code FROM Gebruiker_rechten r JOIN Onderdelen o ON o.Onderdeel_ID = r.Onderdeel_ID " + "WHERE r.Gebruiker_ID = %s AND r.School_ID = %s", (gid, school_id)) + return {r['Code'] for r in rows} + + +def scholen_met_rechten(gid): + """School_ID's waar de gebruiker minstens één recht heeft.""" + from database import central_query + rows = central_query("SELECT DISTINCT School_ID FROM Gebruiker_rechten WHERE Gebruiker_ID = %s", (gid,)) + return {r['School_ID'] for r in rows} + + +def mag_in_school(gebruiker, school): + """Mag deze gebruiker (rij uit Gebruikers) in deze school inloggen?""" + if not gebruiker or not school: + return False + if int(gebruiker['Veiligheidsgroep']) == ADMIN: + return True + return school.id in scholen_met_rechten(gebruiker['Gebruiker_ID']) + + +def zet_rechten(gid, school_id, codes, door=None): + """Vervangt alle rechten van gebruiker `gid` in school `school_id` door `codes`.""" + from database import get_central_connection + codes = [c for c in codes if c in CODES] + conn = get_central_connection() + cur = conn.cursor() + try: + conn.start_transaction() + cur.execute("DELETE FROM Gebruiker_rechten WHERE Gebruiker_ID = %s AND School_ID = %s", (gid, school_id)) + if codes: + plek = ','.join(['%s'] * len(codes)) + cur.execute( + f"INSERT INTO Gebruiker_rechten (Gebruiker_ID, School_ID, Onderdeel_ID, Toegekend_door) " + f"SELECT %s, %s, Onderdeel_ID, %s FROM Onderdelen WHERE Code IN ({plek})", + (gid, school_id, door, *codes)) + conn.commit() + except Exception: + conn.rollback() + raise + finally: + cur.close() + conn.close() + + +# ===================================================================== +# Huidige gebruiker +# ===================================================================== +def is_admin(): + return bool(session.get('admin')) or bool(session.get('superbeheerder')) + + +def huidige_rechten(): + """Rechten van de ingelogde gebruiker in de huidige school (één keer per request opgehaald).""" + if not has_request_context() or not session.get('auth'): + return set() + if is_admin(): + return set(CODES) + if '_rechten' in g: + return g._rechten + gid = session.get('gebruiker_id') + school = g.get('school') + rechten = set() + if gid and school: + try: + rechten = rechten_van(gid, school.id) + except Exception as e: + sys.stderr.write(f"PIVOT: rechten ophalen mislukt: {e}\n") + g._rechten = rechten + return rechten + + +def heeft_recht(*codes): + """True als de ingelogde gebruiker in de huidige school minstens één van deze rechten heeft.""" + rechten = huidige_rechten() + return any(c in rechten for c in codes) + + +def recht_vereist(*codes): + """Decorator voor routes: de gebruiker moet in de huidige school één van deze rechten hebben.""" + for c in codes: + if c not in CODES: + raise ValueError(f"Onbekend onderdeel '{c}'") + + def decorator(view): + @functools.wraps(view) + def wrapped(*a, **kw): + if not session.get('auth') or not session.get('school'): + return redirect(url_for('auth.login')) + if not heeft_recht(*codes): + flash("Je hebt geen rechten voor dit onderdeel in deze school.", "error") + return redirect(url_for('main.dashboard')) + return view(*a, **kw) + return wrapped + return decorator + + +def admin_vereist(view): + @functools.wraps(view) + def wrapped(*a, **kw): + if not session.get('auth'): + return redirect(url_for('auth.login')) + if not is_admin(): + flash("Enkel voor administrators.", "error") + return redirect(url_for('main.dashboard')) + return view(*a, **kw) + return wrapped + + +# ===================================================================== +# Logboek (tabel Logs) +# ===================================================================== +def log(actie=None, url=None): + """Schrijft een regel in Logs. Fouten worden genegeerd (loggen mag PIVOT nooit blokkeren).""" + from database import central_query + try: + school = g.get('school') if has_request_context() else None + central_query( + "INSERT INTO Logs (Bezochte_url, Gebruiker_ID, School_ID, Actie, IP) VALUES (%s, %s, %s, %s, %s)", + ((url or (request.full_path.rstrip('?') if has_request_context() else ''))[:2048], + session.get('gebruiker_id') if has_request_context() else None, + school.id if school else None, + (actie or '')[:255] or None, + request.remote_addr if has_request_context() else None), + commit=True) + except Exception as e: + sys.stderr.write(f"PIVOT: loggen mislukt: {e}\n") diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..0ff42a9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,17 @@ +# Getest met Python 3.11 – 3.13 +Flask>=3.0,<4 +Authlib>=1.3,<2 +google-auth>=2.25 +google-auth-oauthlib>=1.1 +google-auth-httplib2>=0.2 +google-api-python-client>=2.100 +requests>=2.32 +mysql-connector-python>=8.4 +xhtml2pdf>=0.2.16 +python-dateutil>=2.8.2 +# zeep 4.3+ nodig voor Python 3.13 (oudere versies gebruiken de verwijderde module 'cgi') +zeep>=4.3.1 +qrcode>=8.1 +pandas>=2.2.3 +openpyxl>=3.1.2 +cryptography>=41 \ No newline at end of file diff --git a/services/CIP_inleveren.py b/services/CIP_inleveren.py new file mode 100644 index 0000000..c2e3cdc --- /dev/null +++ b/services/CIP_inleveren.py @@ -0,0 +1,66 @@ +# CIP_inleveren.py – toestel terug inleveren (en eventueel herstelling registreren) +from database import execute_query +from datetime import date +from services import toestellen as tst + +foutmelding = "" + + +def Inleveren(internnummer, toestelnummer, action_type, tab2_schade_text): + global foutmelding + + # 1. Zoek leerling op (zet om naar officieel Internnummer) + leerling = tst.zoek_leerling(internnummer) + if not leerling: + foutmelding = "Error: Internnummer niet gevonden." + return + + # 2. Zoek het toestel en de huidige toekenning aan deze leerling + toestel = tst.zoek_toestel(toestelnummer) + if not toestel: + foutmelding = "Error: Toestelnummer niet gevonden in de toestellenlijst." + return + eigendom = execute_query( + "SELECT Eigendom_ID FROM Eigendom WHERE Toestel_ID = %s AND Internnummer = %s AND Datum_inlevering IS NULL", + (toestel['Toestel_ID'], leerling['Internnummer'])) + if not eigendom: + foutmelding = "Error: Dit toestel staat niet als 'uitgeleend' aan deze leerling in de database." + return + + # 3. Verwerk de inlevering + try: + _verwerk_inlevering(eigendom[0]['Eigendom_ID'], leerling, toestel['Toestel_ID'], action_type, tab2_schade_text) + foutmelding = "Toestel succesvol ingeleverd." + except Exception as e: + foutmelding = f"Systeemfout: {str(e)}" + + +def _verwerk_inlevering(eigendom_id, leerling, toestel_id, action_type, schade_text): + vandaag = date.today() + + # A. Toekenning afsluiten (blijft bewaard als geschiedenis) + execute_query("UPDATE Eigendom SET Datum_inlevering = %s WHERE Eigendom_ID = %s", (vandaag, eigendom_id), commit=True) + + # B. Status en eventueel herstelling + if action_type == "Schade": + execute_query( + "INSERT INTO Signpost_herstellingen_DB (Toestel_ID, Omschrijving, Status_herstelling, Datum, Leerling_ID) " + "VALUES (%s, %s, 'geregistreerd', %s, %s)", + (toestel_id, schade_text, vandaag, leerling['Leerling_ID']), commit=True) + execute_query("UPDATE Toestellen SET Status = 'Defect' WHERE Toestel_ID = %s", (toestel_id,), commit=True) + else: + execute_query("UPDATE Toestellen SET Status = 'Beschikbaar' WHERE Toestel_ID = %s", (toestel_id,), commit=True) + + +def Ingeven_herstelling(toestelnummer, soort_herstelling): + """Herstelling registreren zonder inlevering door een leerling.""" + global foutmelding + toestel = tst.zoek_toestel(toestelnummer) + if not toestel: + foutmelding = f"Toestel {toestelnummer} niet gevonden." + return + execute_query( + "INSERT INTO Signpost_herstellingen_DB (Toestel_ID, Omschrijving, Status_herstelling, Datum) " + "VALUES (%s, %s, 'In afwachting', %s)", + (toestel['Toestel_ID'], soort_herstelling, date.today()), commit=True) + foutmelding = "Herstelling ingegeven" diff --git a/services/CIP_uitdelen.py b/services/CIP_uitdelen.py new file mode 100644 index 0000000..485e6ba --- /dev/null +++ b/services/CIP_uitdelen.py @@ -0,0 +1,51 @@ +# CIP_uitdelen.py – toestel uitdelen aan een leerling +from database import execute_query +from datetime import date +from services import toestellen as tst + +foutmelding = "" + + +def uitdelen(internnummer, toestelnummer): + """`toestelnummer` = eigen toestelnummer van de school (Schooleigen_ID) of serienummer.""" + global foutmelding + + # 1. Validatie van input + if not internnummer or not toestelnummer: + foutmelding = "Error: Vul zowel het Internnummer als het toestelnummer in." + return False + + # 2. Check of leerling bestaat + leerling = tst.zoek_leerling(internnummer) + if not leerling: + foutmelding = "Error: Internnummer niet gevonden in de leerlingenlijst." + return False + + # 3. Check of toestel bestaat + toestel = tst.zoek_toestel(toestelnummer) + if not toestel: + foutmelding = "Error: Toestelnummer niet gevonden in de toestellenlijst." + return False + + # 4. Check of toestel al is uitgegeven + huidig = tst.actieve_eigendom(toestel['Toestel_ID']) + if huidig: + foutmelding = f"Error: Toestel is al toegekend aan {huidig['Internnummer']}" + return False + + # 5. Alles OK -> Uitvoeren + try: + _verwerk_uitdeling(leerling['Internnummer'], toestel['Toestel_ID']) + foutmelding = "Toestel succesvol uitgedeeld!" + return True + except Exception as e: + foutmelding = f"Systeemfout: {str(e)}" + return False + + +def _verwerk_uitdeling(internnummer, toestel_id): + """Nieuwe rij in Eigendom (zonder Datum_inlevering) en toestel op 'Uitgeleend'.""" + execute_query( + "INSERT INTO Eigendom (Internnummer, Toestel_ID, Status, Datum_toekenning) VALUES (%s, %s, %s, %s)", + (internnummer, toestel_id, 1 if tst.is_geblokkeerd(toestel_id) else 0, date.today()), commit=True) + execute_query("UPDATE Toestellen SET Status = 'Uitgeleend' WHERE Toestel_ID = %s", (toestel_id,), commit=True) diff --git a/services/__init__.py b/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/services/aanwezigheid_service.py b/services/aanwezigheid_service.py new file mode 100644 index 0000000..00ef3a0 --- /dev/null +++ b/services/aanwezigheid_service.py @@ -0,0 +1,69 @@ +""" +Internaat › Aanwezigheden: per intern, per dag een ochtend- en een avondcontrole (aanwezig / afwezig / nog niet +gecontroleerd). De internen komen uit Informat (Internaat-API); de registraties staan in de schooldatabase +(tabel internaat_aanwezigheid) en zijn dus gedeeld met alle opvoeders. +""" +from datetime import date, timedelta + +from database import execute_query + +MOMENTEN = ('ochtend', 'avond') +STATUSSEN = ('aanwezig', 'afwezig') # 'leeg' = geen rij +DAGEN = ['Ma', 'Di', 'Wo', 'Do', 'Vr', 'Za', 'Zo'] +DAGEN_VOLUIT = ['Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag', 'Zondag'] + + +def ensure_table(): + execute_query(""" + CREATE TABLE IF NOT EXISTS internaat_aanwezigheid ( + Datum DATE NOT NULL, + Persoon_ID VARCHAR(64) NOT NULL, + Moment VARCHAR(10) NOT NULL, + Status VARCHAR(10) NOT NULL, + Naam VARCHAR(200) NULL, + Bijgewerkt DATETIME NOT NULL, + Door VARCHAR(255) NULL, + PRIMARY KEY (Datum, Persoon_ID, Moment), + KEY idx_aanw_persoon (Persoon_ID) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", commit=True) + + +def maandag_van(d): + return d - timedelta(days=d.weekday()) + + +def schooljaar_van(d): + start = d.year if d.month >= 9 else d.year - 1 + return f"{start}-{str(start + 1)[-2:]}" + + +def week(maandag): + """{'::': status} voor de week vanaf `maandag`.""" + ensure_table() + rijen = execute_query("SELECT Datum, Persoon_ID, Moment, Status FROM internaat_aanwezigheid " + "WHERE Datum BETWEEN %s AND %s", (maandag, maandag + timedelta(days=6))) or [] + return {f"{r['Persoon_ID']}:{(r['Datum'] - maandag).days}:{r['Moment']}": r['Status'] for r in rijen} + + +def zet(datum, persoon_id, moment, status, naam=None, door=None): + """Bewaart één controle. status 'leeg' wist de registratie.""" + if moment not in MOMENTEN: + raise ValueError("Onbekend moment.") + ensure_table() + if status == 'leeg': + execute_query("DELETE FROM internaat_aanwezigheid WHERE Datum = %s AND Persoon_ID = %s AND Moment = %s", + (datum, persoon_id, moment), commit=True) + return + if status not in STATUSSEN: + raise ValueError("Onbekende status.") + execute_query("INSERT INTO internaat_aanwezigheid (Datum, Persoon_ID, Moment, Status, Naam, Bijgewerkt, Door) " + "VALUES (%s, %s, %s, %s, %s, NOW(), %s) ON DUPLICATE KEY UPDATE Status = VALUES(Status), " + "Naam = VALUES(Naam), Bijgewerkt = NOW(), Door = VALUES(Door)", + (datum, persoon_id, moment, status, (naam or '')[:200] or None, door), commit=True) + + +def groep_van(r, meerdere_internaten=False): + """Groep in het register: het blok van de kamer, anders de vestiging (met het internaat ervoor als er meerdere zijn).""" + blok = (r.get('kamer') or '').split(' verd.')[0].split(' nr.')[0] + groep = blok.replace('blok', 'Blok') if blok.startswith('blok') else (r.get('vestiging') or 'Zonder kamer') + return f"{r['internaat']} · {groep}" if meerdere_internaten else groep diff --git a/services/afwezigheden_service.py b/services/afwezigheden_service.py new file mode 100644 index 0000000..3880728 --- /dev/null +++ b/services/afwezigheden_service.py @@ -0,0 +1,296 @@ +""" +Afwezigheden (o.a. B-codes) uit Smartschool ophalen en bewaren. + +Werking +- Per schooldag wordt `getAbsentsWithInternalNumberByDate` aangeroepen. + Smartschool geeft per leerling (internnummer) de code van de voormiddag (am) + en namiddag (pm) terug. +- Enkel de codes uit config.ini (standaard: B) worden bewaard in de tabel + `smartschool_afwezigheden`. Andere codes worden genegeerd. +- Eén keer per dag (standaard 06:00) synchroniseert een achtergrondtaak. + De laatste 14 dagen worden telkens opnieuw opgehaald, zodat correcties + in Smartschool ook in PIVOT terechtkomen. + +Vereist in Smartschool: + Beheer › Webservices › het webservice-wachtwoord moet het recht + 'Afwezigheden' hebben. +""" +import json +import sys +import threading +import time +from datetime import date, datetime, timedelta + +from config import Config +from database import execute_query +from tenancy import school_singleton, alle_scholen, in_school, met_school + +HERHAAL_DAGEN = 14 # laatste X dagen altijd opnieuw ophalen +DAGDEEL = {'am': 'VM', 'pm': 'NM'} + + +def schooljaar_start(vandaag=None): + vandaag = vandaag or date.today() + jaar = vandaag.year if vandaag.month >= 9 else vandaag.year - 1 + return date(jaar, 9, 1) + + +class AfwezighedenService: + _scheduler = None # één achtergrondtaak voor alle scholen + + def __new__(cls): + # één instantie per school (eigen status, lock en Smartschool-client) + def init(inst): + inst._lock = threading.Lock() + inst._client = None + inst.status = {'bezig': False, 'gestart': None, 'voortgang': 0, 'totaal': 0, + 'laatste_fout': None, 'laatste_resultaat': None} + return school_singleton(cls, init) + + # ---------------- configuratie ---------------- + @property + def codes(self): + return [c.strip().upper() for c in Config.AFWEZIGHEID_CODES.split(',') if c.strip()] + + @property + def laat_codes(self): + """Codes die 'te laat' betekenen (Laatkomers). Ze worden samen met de afwezigheidscodes opgehaald.""" + return [c.strip().upper() for c in str(Config.LAATKOMER_CODES or '').split(',') if c.strip()] + + def _ss(self): + if self._client is None: + from services.smartschool_api import SmartschoolService + if not (Config.SS_API_PLATFORM and Config.SS_API_PW): + raise RuntimeError("Smartschool is nog niet ingesteld voor deze school " + "(platform en webservice-wachtwoord via 🔌 Koppelingen van deze school).") + self._client = SmartschoolService(platform=Config.SS_API_PLATFORM, + webservice_pwd=Config.SS_API_PW) + return self._client + + # ---------------- database ---------------- + @staticmethod + def ensure_tables(): + execute_query(""" + CREATE TABLE IF NOT EXISTS smartschool_afwezigheden ( + Datum DATE NOT NULL, + Internnummer VARCHAR(32) NOT NULL, + Dagdeel CHAR(2) NOT NULL, + Code VARCHAR(8) NOT NULL, + PRIMARY KEY (Datum, Internnummer, Dagdeel), + INDEX idx_intern (Internnummer), + INDEX idx_code (Code) + )""", commit=True) + execute_query(""" + CREATE TABLE IF NOT EXISTS smartschool_afwezigheden_sync ( + Datum DATE NOT NULL PRIMARY KEY, + Opgehaald DATETIME NOT NULL, + Aantal INT NOT NULL DEFAULT 0 + )""", commit=True) + + # ---------------- Smartschool ---------------- + def fetch_day(self, dag): + """Geeft {internnummer: {'VM': code, 'NM': code}} voor één dag (alleen de gezochte codes).""" + raw = self._ss().client.service.getAbsentsWithInternalNumberByDate( + Config.SS_API_PW, dag.strftime('%Y-%m-%d')) + + if raw is None or raw == '': + return {} + if isinstance(raw, (int, float)) or (isinstance(raw, str) and raw.strip().lstrip('-').isdigit()): + # Smartschool geeft bij fouten een numerieke foutcode terug + raise RuntimeError(f"Smartschool foutcode {raw} (controleer het recht 'Afwezigheden' " + "voor het webservice-wachtwoord).") + data = json.loads(raw) if isinstance(raw, str) else raw + if not isinstance(data, dict): + return {} + + gezocht = set(self.codes) | set(self.laat_codes) + result = {} + for intern, delen in data.items(): + if not isinstance(delen, dict): + continue + for key, label in DAGDEEL.items(): + val = delen.get(key) + if isinstance(val, dict): # variant met alias: {'code': 'B', 'alias': ...} + val = val.get('code') + code = (val or '').strip().upper() + if code in gezocht: + result.setdefault(str(intern).strip(), {})[label] = code + return result + + def _store_day(self, dag, per_leerling): + execute_query("DELETE FROM smartschool_afwezigheden WHERE Datum = %s", (dag,), commit=True) + aantal = 0 + for intern, delen in per_leerling.items(): + for dagdeel, code in delen.items(): + execute_query( + "INSERT INTO smartschool_afwezigheden (Datum, Internnummer, Dagdeel, Code) " + "VALUES (%s, %s, %s, %s)", (dag, intern, dagdeel, code), commit=True) + aantal += 1 + execute_query( + "INSERT INTO smartschool_afwezigheden_sync (Datum, Opgehaald, Aantal) VALUES (%s, NOW(), %s) " + "ON DUPLICATE KEY UPDATE Opgehaald = NOW(), Aantal = VALUES(Aantal)", (dag, aantal), commit=True) + return aantal + + # ---------------- synchronisatie ---------------- + def dagen_te_synchroniseren(self, vandaag=None, volledig=False): + vandaag = vandaag or date.today() + start = schooljaar_start(vandaag) + alle = [start + timedelta(days=i) for i in range((vandaag - start).days + 1)] + schooldagen = [d for d in alle if d.weekday() < 5] # ma–vr + if volledig: + return schooldagen + rows = execute_query("SELECT Datum FROM smartschool_afwezigheden_sync WHERE Datum >= %s", (start,)) + gehad = {r['Datum'] for r in rows} + grens = vandaag - timedelta(days=HERHAAL_DAGEN) + return [d for d in schooldagen if d not in gehad or d >= grens] + + def sync(self, volledig=False): + """Synchroniseert (blokkerend). Geeft (ok, bericht) terug.""" + if not self._lock.acquire(blocking=False): + return False, "Er loopt al een synchronisatie." + try: + self.ensure_tables() + dagen = self.dagen_te_synchroniseren(volledig=volledig) + self.status.update(bezig=True, gestart=datetime.now(), voortgang=0, + totaal=len(dagen), laatste_fout=None) + gevonden, fouten = 0, 0 + for i, dag in enumerate(dagen, 1): + try: + gevonden += self._store_day(dag, self.fetch_day(dag)) + except Exception as e: + fouten += 1 + self.status['laatste_fout'] = str(e) + sys.stderr.write(f"Afwezigheden {dag}: {e}\n") + self.status['voortgang'] = i + if fouten >= 3 and fouten == i: # eerste 3 dagen allemaal fout → stoppen + break + if fouten and fouten == self.status['voortgang']: + msg = f"Synchronisatie mislukt: {self.status['laatste_fout']}" + ok = False + else: + msg = (f"{len(dagen)} schooldag(en) gecontroleerd, {gevonden} halve dag(en) met code " + f"{'/'.join(self.codes)} op die dagen" + (f", {fouten} dag(en) met fouten." if fouten else ".")) + ok = True + self.status['laatste_resultaat'] = msg + return ok, msg + finally: + self.status['bezig'] = False + self._lock.release() + + def sync_in_background(self, volledig=False): + if self.status['bezig']: + return False + self.status.update(bezig=True, voortgang=0, totaal=0) # meteen tonen op de pagina + threading.Thread(target=met_school(self.sync), kwargs={'volledig': volledig}, daemon=True).start() + return True + + def dagelijkse_controle(self, nu=None): + """Start de synchronisatie als het sync-uur van deze school voorbij is en er vandaag nog niet gesynchroniseerd werd.""" + nu = nu or datetime.now() + if nu.hour < Config.AFWEZIGHEID_SYNC_UUR: + return + self.ensure_tables() + rows = execute_query("SELECT MAX(Opgehaald) AS m FROM smartschool_afwezigheden_sync") + laatst = rows[0]['m'] if rows else None + if not laatst or laatst.date() < nu.date(): + print(f"[{Config.SCHOOLNAME_SHORT}] Afwezigheden: dagelijkse synchronisatie gestart.", flush=True) + ok, msg = self.sync() + print(f"[{Config.SCHOOLNAME_SHORT}] Afwezigheden: {msg}", flush=True) + + @classmethod + def start_scheduler(cls): + """Eén achtergrondtaak die elk kwartier alle scholen met een Smartschool-koppeling overloopt.""" + if AfwezighedenService._scheduler: + return + + def loop(): + time.sleep(30) # app eerst laten opstarten + gedaan = {} # school → laatste dag waarop gecontroleerd + while True: + nu = datetime.now() + for school in alle_scholen(): + if not school.heeft('SS_API_PLATFORM', 'SS_API_PW') or gedaan.get(school.code) == nu.date(): + continue + try: + with in_school(school): + if nu.hour >= Config.AFWEZIGHEID_SYNC_UUR: + cls().dagelijkse_controle(nu) + gedaan[school.code] = nu.date() + except Exception as e: + sys.stderr.write(f"[{school.code}] Afwezigheden scheduler: {e}\n") + time.sleep(15 * 60) + + AfwezighedenService._scheduler = threading.Thread(target=loop, daemon=True) + AfwezighedenService._scheduler.start() + + # ---------------- opvragen ---------------- + def laatste_sync(self): + rows = execute_query("SELECT MAX(Opgehaald) AS m, MAX(Datum) AS d FROM smartschool_afwezigheden_sync") + return rows[0] if rows else {'m': None, 'd': None} + + def overzicht(self, van, tot, code=None, zoek=None, minimum=1): + params = [van, tot] + where = "a.Datum BETWEEN %s AND %s" + codes = [code] if code else self.codes # laatkomerscodes horen niet bij de afwezigheden + where += f" AND a.Code IN ({', '.join(['%s'] * len(codes))})" + params.extend(codes) + sql = f""" + SELECT a.Internnummer, + MAX(l.Voornaam) AS Voornaam, MAX(l.Naam) AS Naam, MAX(l.Gebruikersnaam) AS Gebruikersnaam, + COUNT(*) AS Halve_dagen, + COUNT(DISTINCT a.Datum) AS Dagen, + MIN(a.Datum) AS Eerste, MAX(a.Datum) AS Laatste + FROM smartschool_afwezigheden a + LEFT JOIN Leerlingen l ON l.Internnummer = a.Internnummer + WHERE {where} + GROUP BY a.Internnummer + HAVING COUNT(*) >= %s + ORDER BY Halve_dagen DESC, Laatste DESC + """ + params.append(int(minimum or 1)) + rows = execute_query(sql, tuple(params)) + if zoek: + z = zoek.lower() + rows = [r for r in rows if z in ' '.join(str(r.get(k) or '') for k in + ('Internnummer', 'Voornaam', 'Naam', 'Gebruikersnaam')).lower()] + return rows + + def detail(self, internnummer, van, tot, code=None): + params = [internnummer, van, tot] + codes = [code] if code else self.codes + extra = f" AND Code IN ({', '.join(['%s'] * len(codes))})" + params.extend(codes) + rows = execute_query( + "SELECT Datum, Dagdeel, Code FROM smartschool_afwezigheden " + f"WHERE Internnummer = %s AND Datum BETWEEN %s AND %s{extra} ORDER BY Datum DESC, Dagdeel", + tuple(params)) + # samenvoegen per dag + per_dag = {} + for r in rows: + d = per_dag.setdefault(r['Datum'], {'Datum': r['Datum'], 'VM': None, 'NM': None}) + d[r['Dagdeel']] = r['Code'] + return list(per_dag.values()) + + def laatkomers(self, van, tot): + """Alle leerlingen die tussen van en tot te laat waren: aantal keer, eerste en laatste datum en de lijst + van data (nieuwste eerst). Eén keer te laat = één halve dag met een laatkomerscode.""" + codes = self.laat_codes + if not codes: + return [] + rows = execute_query( + f"""SELECT a.Internnummer, a.Datum, a.Dagdeel, + l.Voornaam, l.Naam, l.Gebruikersnaam + FROM smartschool_afwezigheden a + LEFT JOIN Leerlingen l ON l.Internnummer = a.Internnummer + WHERE a.Datum BETWEEN %s AND %s AND a.Code IN ({', '.join(['%s'] * len(codes))}) + ORDER BY a.Datum DESC, a.Dagdeel""", (van, tot, *codes)) + per = {} + for r in rows: + l = per.setdefault(r['Internnummer'], { + 'Internnummer': r['Internnummer'], 'Voornaam': r['Voornaam'], 'Naam': r['Naam'], + 'Gebruikersnaam': r['Gebruikersnaam'], 'Aantal': 0, 'Laatste': r['Datum'], 'Eerste': r['Datum'], + 'Data': []}) + l['Aantal'] += 1 + l['Eerste'] = r['Datum'] + l['Data'].append((r['Datum'], r['Dagdeel'])) + return sorted(per.values(), key=lambda x: (-x['Aantal'], -x['Laatste'].toordinal())) diff --git a/services/bingel_service.py b/services/bingel_service.py new file mode 100644 index 0000000..ca2851f --- /dev/null +++ b/services/bingel_service.py @@ -0,0 +1,186 @@ +""" +Basisonderwijs › Bingel: leerlingenlijst uit Informat (alle instellingsnummers/campussen van de school) voor de import +in Bingel. Kolommen: Klas, Voornaam, Familienaam, Wachtwoord (leeg), Klasnummer, Geslacht (M/V). + +Informat-leerlingen-API: + GET /students?schoolYear=&refdate= → de leerlingen (naam, voornaam, geslacht, inschrijvingsId) + GET /registrations?schoolYear=&refdate= → de inschrijvingen, met de klas +Het klasnummer haalt PIVOT niet uit Informat: binnen elke klas nummert het alfabetisch (familienaam, voornaam). +Gekoppeld op inschrijvingsId (anders op pPersoon). De velden worden op verschillende plaatsen en namen gezocht +(zie KANDIDATEN), bij een lijst (bv. klassen in de loop van het jaar) eerst de lopende. +""" +import json +import time +from datetime import date + +from config import Config + +KANDIDATEN = { + 'klas': ('klascode', 'klasCode', 'klas', 'klasnaam', 'klasNaam', 'className', 'class'), + 'geslacht': ('geslacht', 'gender', 'sex'), + 'voornaam': ('voornaam', 'firstName', 'roepnaam'), + 'naam': ('naam', 'lastName', 'familienaam'), +} +CACHE_SECONDEN = 10 * 60 + + +class BingelFout(Exception): + pass + + +def _datum(w): + try: + return date.fromisoformat(str(w)[:10]) + except (TypeError, ValueError): + return None + + +def _lopend(item, vandaag): + """Is deze inschrijving lopend op `vandaag` (begin/einde onder verschillende namen)?""" + if not isinstance(item, dict): + return True + begin = next((_datum(item[k]) for k in ('begindatum', 'beginDatum', 'startDate', 'van') if item.get(k)), None) + einde = next((_datum(item[k]) for k in ('einddatum', 'eindDatum', 'endDate', 'tot') if item.get(k)), None) + return (not begin or begin <= vandaag) and (not einde or einde >= vandaag) + + +def _zoek(obj, namen, vandaag, diepte=0): + """Eerste niet-lege waarde voor een van `namen`: eerst op dit niveau, dan in (lopende) geneste lijsten/dicts.""" + if not isinstance(obj, dict) or diepte > 3: + return None + for n in namen: + w = obj.get(n) + if isinstance(w, dict): # bv. "klas": {"code": "3A", "naam": "3de leerjaar A"} + w = w.get('code') or w.get('naam') or w.get('name') + if w not in (None, '') and not isinstance(w, (dict, list)): + return w + for w in obj.values(): + kinderen = [x for x in w if isinstance(x, dict)] if isinstance(w, list) else ([w] if isinstance(w, dict) else []) + kinderen.sort(key=lambda x: not _lopend(x, vandaag)) # lopende inschrijving eerst + for k in kinderen: + gevonden = _zoek(k, namen, vandaag, diepte + 1) + if gevonden not in (None, ''): + return gevonden + return None + + +def _geslacht(w): + t = str(w or '').strip().upper() + if t in ('M', 'MAN', 'MANNELIJK', 'JONGEN', 'MALE', '1'): + return 'M' + if t in ('V', 'F', 'VROUW', 'VROUWELIJK', 'MEISJE', 'FEMALE', '2'): + return 'V' + return t[:1] + + +def _nummer(w): + try: + return int(str(w).strip()) + except (TypeError, ValueError): + return str(w).strip() if w not in (None, '') else None + + +def _inschrijvingen(svc, nummer, refdate): + """Inschrijvingen (met klas) van één instellingsnummer. Geeft (lijst, fout).""" + import requests + from datetime import datetime, timezone + token = svc.get_informat_token(nummer) + if not token: + return [], f"Informat-authenticatie mislukt ({nummer})" + headers = {'Authorization': f'BEARER {token}', 'InstituteNo': nummer, 'Api-Version': '1', 'Accept': 'application/json', + 'Timestamp': datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.000Z')} + url = f"{svc.api_base.strip().rstrip('/')}/registrations" + params = {'schoolYear': Config.SCHOOLYEAR, 'refdate': refdate} + try: + r = requests.get(url, params=params, headers=headers, timeout=60) + if r.status_code == 405: + r = requests.post(url, params=params, headers=headers, timeout=60) + except Exception as e: + return [], f"inschrijvingen niet bereikbaar: {e}" + if r.status_code == 404: + return [], None + if r.status_code != 200: + return [], f"inschrijvingen: HTTP {r.status_code} {r.text[:150]}" + data = r.json() + return (data if isinstance(data, list) else (data.get('registrations') or data.get('items') or data.get('data') or [])), None + + +def leerlingen(vernieuw=False): + """[{'klas','voornaam','naam','klasnummer','geslacht'}] gesorteerd op klas en klasnummer (alfabetisch), plus een voorbeeld + van de ruwe velden van de eerste leerling (om te controleren). Bewaard voor 10 minuten.""" + from tenancy import huidige_school + from services.sync_service import SyncService + school = huidige_school() + bewaard = school.cache.get('bingel') + if bewaard and not vernieuw and time.time() - bewaard[0] < CACHE_SECONDEN: + return bewaard[1], bewaard[2], bewaard[3] + if not school.heeft('INFORMAT_INST_NUMBER', 'INFORMAT_ID', 'INFORMAT_SECRET'): + raise BingelFout("Informat is nog niet ingesteld voor deze school (🔌 Koppelingen › Informat).") + svc, vandaag = SyncService(), date.today() + ruw, gezien, inschr, waarschuwing = [], set(), {}, None + for nummer, naam in (svc.campussen or [(svc.institute_no, '')]): + ok, lijst = svc.informat_lijst(vandaag.isoformat(), Config.SCHOOLYEAR, nummer) + if not ok: + raise BingelFout(f"{naam + ': ' if naam else ''}{lijst}") + reg, fout = _inschrijvingen(svc, nummer, vandaag.isoformat()) + if fout: + waarschuwing = f"Klassen konden niet opgehaald worden ({fout})." + for ins in sorted(reg, key=lambda x: _lopend(x, vandaag)): # lopende inschrijving wint + for k in ('inschrijvingsId', 'pInschrijving', 'id'): + if ins.get(k) not in (None, ''): + inschr[('i', str(ins[k]))] = ins + if ins.get('pPersoon') not in (None, ''): + inschr[('p', str(ins['pPersoon']))] = ins + for st in lijst: + sleutel = str(st.get('pPersoon') or st.get('internNummer') or st.get('id') or id(st)) + if sleutel not in gezien: + gezien.add(sleutel) + ruw.append(st) + uit = [] + for st in ruw: + ins = inschr.get(('i', str(st.get('inschrijvingsId')))) or inschr.get(('p', str(st.get('pPersoon')))) or {} + uit.append({'klas': str(_zoek(ins, KANDIDATEN['klas'], vandaag) or _zoek(st, KANDIDATEN['klas'], vandaag) or '').strip(), + 'voornaam': str(_zoek(st, KANDIDATEN['voornaam'], vandaag) or '').strip(), + 'naam': str(_zoek(st, KANDIDATEN['naam'], vandaag) or '').strip(), + 'klasnummer': None, + 'geslacht': _geslacht(_zoek(st, KANDIDATEN['geslacht'], vandaag))}) + # Klasnummer: alfabetisch binnen de klas (familienaam, dan voornaam) + uit.sort(key=lambda r: (not r['klas'], r['klas'].lower(), r['naam'].lower(), r['voornaam'].lower())) + vorige, nr = None, 0 + for r in uit: + nr = nr + 1 if r['klas'] == vorige else 1 + vorige = r['klas'] + r['klasnummer'] = nr if r['klas'] else None + # Om na te kijken: de velden van een inschrijving en een voorbeeld van een klas-item (eerste niet-lege) + alle_ins = list({id(v): v for v in inschr.values()}.values()) + met_klas = next((i for i in alle_ins if _klas_items(i, vandaag)), None) + klas_item = _klas_items(met_klas, vandaag)[0] if met_klas else None + voorbeeld = {'leerling': _velden(ruw[0]) if ruw else [], + 'inschrijving': _velden(met_klas or (alle_ins[0] if alle_ins else {})), + 'klas_item': json.dumps(klas_item, ensure_ascii=False, default=str)[:600] if klas_item else ''} + school.cache['bingel'] = (time.time(), uit, voorbeeld, waarschuwing) + return uit, voorbeeld, waarschuwing + + +def _klas_items(ins, vandaag): + """De klas-items van een inschrijving (bv. inschrKlassen), lopende eerst.""" + items = [] + for k, v in (ins or {}).items(): + if 'klas' in k.lower() and isinstance(v, list): + items += [x for x in v if isinstance(x, dict)] + return sorted(items, key=lambda x: not _lopend(x, vandaag)) + + +def _velden(obj, prefix=''): + """Namen van de velden van één leerling (met geneste velden als a.b), om te zien wat Informat teruggeeft.""" + uit = [] + if isinstance(obj, dict): + for k, v in obj.items(): + pad = f"{prefix}{k}" + if isinstance(v, dict): + uit += _velden(v, pad + '.') + elif isinstance(v, list) and v and isinstance(v[0], dict): + uit += _velden(v[0], pad + '.') + else: + uit.append(pad) + return uit diff --git a/services/co2_service.py b/services/co2_service.py new file mode 100644 index 0000000..db2f55d --- /dev/null +++ b/services/co2_service.py @@ -0,0 +1,81 @@ +import threading +import time +import requests +import re +from database import execute_query +from config import Config +from tenancy import school_singleton, met_school + + +def lokaal_id(naam): + """Lokaal_ID voor een lokaalnaam; maakt het lokaal aan (zonder campus) als het nog niet bestaat.""" + from database import execute_insert + rows = execute_query("SELECT Lokaal_ID FROM Lokalen WHERE Naam = %s ORDER BY Lokaal_ID LIMIT 1", (naam,)) + if rows: + return rows[0]['Lokaal_ID'] + return execute_insert("INSERT INTO Lokalen (Naam) VALUES (%s)", (naam,)) + + +class CO2Scanner: + def __new__(cls): + # één scanner per school (elke school heeft een eigen netwerkbereik) + def init(inst): + inst.active = False + inst.thread = None + inst.auto_delete = False + inst.conf = Config() + return school_singleton(cls, init) + #start service + def start(self): + if not self.active: + self.active = True + self.thread = threading.Thread(target=met_school(self._run_scan_loop), daemon=True) + self.thread.start() + print("CO2 Scanner Service gestart.") + + #killswitch + def stop(self): + self.active = False + print("CO2 Scanner Service gestopt.") + #houd service in actie + def _run_scan_loop(self): + while self.active: + self.perform_scan() + # Wacht het aantal minuten uit je config.ini (bijv. 5) + time.sleep(self.conf.CO2_INTERVAL * 60) + #functie die effectieve taak uitvoerd + def perform_scan(self): + """De logica uit je originele script om IP's af te gaan.""" + start_ip = self.conf.CO2_START_ADDR + end_ip = self.conf.CO2_END_ADDR + network = self.conf.CO2_NETWORK + if not network: + return + + for i in range(start_ip, end_ip + 1): + if not self.active and threading.current_thread() == self.thread: + break + + ip = f"{network}{i}" + url = f"http://{ip}/v1/constellation" + + try: + # Time-out kort houden zodat de scan niet uren duurt + response = requests.get(url, timeout=1.5) + if response.status_code == 200: + data = response.text + # Regex uit je originele script + conc_match = re.search(r'"concentration":\s*{\s*"unit":\s*"ppm",\s*"value":\s*(\d+)', data) + name_match = re.search(r'"device_name":\s*{\s*"value":\s*"(.*?)"', data) + + if conc_match: + ppm = int(conc_match.group(1)) + lokaal = name_match.group(1) if name_match else ip + + # Opslaan in DB (lokaal wordt aangemaakt als het nog niet bestaat) + execute_query( + "INSERT INTO CO2_Metingen (Lokaal_ID, ppm, Timestamp) VALUES (%s, %s, NOW())", + (lokaal_id(lokaal), ppm), commit=True + ) + except: + continue \ No newline at end of file diff --git a/services/coaccounts_service.py b/services/coaccounts_service.py new file mode 100644 index 0000000..3e5ad11 --- /dev/null +++ b/services/coaccounts_service.py @@ -0,0 +1,200 @@ +""" +Co-accounts van alle leerlingen uit Smartschool, met klas en laatste aanmelding. + +Werking (achtergrondtaak, per school): +1. getClassListJson → de officiële klassen +2. getAllAccountsExtended → de leerlingen per klas (met hun co-accountvelden, als Smartschool die meegeeft) +3. getUserDetailsByUsername → enkel voor leerlingen waarvan de co-accountvelden ontbraken +Het resultaat komt in de tabel smartschool_coaccounts (telkens volledig vervangen). +Wordt opnieuw opgehaald als de gegevens ouder zijn dan VERVERS_UREN, of met de knop op de pagina. +""" +import json +import sys +import threading +from datetime import datetime + +from config import Config +from database import execute_query +from tenancy import school_singleton, met_school + +VERVERS_UREN = 24 +MAX_CO = 6 + + +def _json(raw): + if raw is None or raw == '': + return None + if isinstance(raw, (int, float)) or (isinstance(raw, str) and raw.strip().lstrip('-').isdigit()): + raise RuntimeError(f"Smartschool foutcode {raw}") + return json.loads(raw) if isinstance(raw, str) else raw + + +def _lijst(data): + if isinstance(data, dict): + for k in ('accounts', 'users', 'items'): + if isinstance(data.get(k), list): + return data[k] + return list(data.values()) + return data or [] + + +def _login(waarde): + """'2026-09-12 08:01:22' → datetime; leeg, '0000-00-00…' of ongeldig → None.""" + t = str(waarde or '').strip() + if not t or t.startswith('0000') or t.lower() in ('none', 'nooit', 'never'): + return None + for fmt in ('%Y-%m-%d %H:%M:%S', '%Y-%m-%dT%H:%M:%S', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%d-%m-%Y %H:%M:%S', '%d/%m/%Y %H:%M'): + try: + return datetime.strptime(t[:19], fmt) + except ValueError: + continue + return None + + +def co_accounts_uit(data): + """Co-accounts (1-6) uit de gegevens van één leerling. Lege lijst als er geen co-accountvelden zijn.""" + uit = [] + for i in range(1, MAX_CO + 1): + voornaam = str(data.get(f"voornaam_coaccount{i}") or '').strip() + naam = str(data.get(f"naam_coaccount{i}") or '').strip() + if not (voornaam or naam): + continue + uit.append({'nr': i, 'voornaam': voornaam, 'naam': naam, + 'type': str(data.get(f"type_coaccount{i}") or '').strip(), + 'email': str(data.get(f"email_coaccount{i}") or '').strip(), + 'login': _login(data.get(f"last_successful_login_coaccount{i}"))}) + return uit + + +def heeft_co_velden(data): + return any(k.startswith('voornaam_coaccount') for k in data) + + +class CoAccountsService: + def __new__(cls): + def init(inst): + inst._lock = threading.Lock() + inst.status = {'bezig': False, 'voortgang': 0, 'totaal': 0, 'fout': None, 'resultaat': None} + return school_singleton(cls, init) + + @staticmethod + def ensure_tables(): + execute_query(""" + CREATE TABLE IF NOT EXISTS smartschool_coaccounts ( + Internnummer VARCHAR(32) NOT NULL, + Nr TINYINT NOT NULL, + Gebruikersnaam VARCHAR(100) NULL, + Leerling_naam VARCHAR(100) NULL, + Leerling_voornaam VARCHAR(100) NULL, + Klas VARCHAR(50) NULL, + Voornaam VARCHAR(100) NULL, + Naam VARCHAR(100) NULL, + Type VARCHAR(50) NULL, + Email VARCHAR(255) NULL, + Laatste_login DATETIME NULL, + Opgehaald DATETIME NOT NULL, + PRIMARY KEY (Internnummer, Nr), + KEY idx_coacc_klas (Klas) + )""", commit=True) + + # ---------------- opvragen ---------------- + def laatst_opgehaald(self): + rows = execute_query("SELECT MAX(Opgehaald) AS m FROM smartschool_coaccounts") + return rows[0]['m'] if rows else None + + def alle(self): + return execute_query( + "SELECT * FROM smartschool_coaccounts ORDER BY Klas, Leerling_naam, Leerling_voornaam, Nr") or [] + + def verouderd(self): + laatst = self.laatst_opgehaald() + return not laatst or (datetime.now() - laatst).total_seconds() > VERVERS_UREN * 3600 + + # ---------------- ophalen uit Smartschool ---------------- + def _leerlingen(self, ss): + """[(account-dict, klasnaam)] voor alle leerlingen in een officiële klas (elke leerling één keer).""" + klassen = [] + for k in _lijst(_json(ss.client.service.getClassListJson(Config.SS_API_PW))): + if not isinstance(k, dict): + continue + if str(k.get('isKlas', k.get('isOfficial', True))).lower() in ('false', '0', 'none'): + continue + code = str(k.get('code') or '').strip() + if code: + klassen.append((code, str(k.get('name') or code).strip())) + klassen.sort(key=lambda x: x[1]) + self.status.update(totaal=len(klassen), voortgang=0) + gezien, uit = set(), [] + for i, (code, naam) in enumerate(klassen, 1): + try: + leden = _lijst(_json(ss.client.service.getAllAccountsExtended(Config.SS_API_PW, code, '0'))) + except Exception as e: + sys.stderr.write(f"Co-accounts: klas {naam}: {e}\n") + leden = [] + for a in leden: + if not isinstance(a, dict): + continue + rol = str(a.get('basisrol') or a.get('basisRol') or '').lower() + if rol and rol not in ('1', 'leerling', 'student'): + continue + sleutel = str(a.get('internnummer') or a.get('gebruikersnaam') or '').strip() + if sleutel and sleutel not in gezien: + gezien.add(sleutel) + uit.append((a, naam)) + self.status['voortgang'] = i + return uit + + def sync(self): + if not self._lock.acquire(blocking=False): + return False, "Er loopt al een ophaling." + try: + from services.smartschool_api import SmartschoolService + self.status.update(bezig=True, voortgang=0, totaal=0, fout=None) + self.ensure_tables() + ss = SmartschoolService(Config.SS_API_PLATFORM, Config.SS_API_PW) + leerlingen = self._leerlingen(ss) + # Leerlingen zonder co-accountvelden in de klaslijst: details apart opvragen + zonder = [i for i, (a, _) in enumerate(leerlingen) if not heeft_co_velden(a)] + self.status.update(totaal=self.status['totaal'] + len(zonder)) + for n, i in enumerate(zonder, 1): + a, klas = leerlingen[i] + try: + d = _json(ss.client.service.getUserDetailsByUsername(Config.SS_API_PW, a.get('gebruikersnaam'))) + if isinstance(d, dict): + leerlingen[i] = ({**a, **d}, klas) + except Exception as e: + sys.stderr.write(f"Co-accounts: {a.get('gebruikersnaam')}: {e}\n") + self.status['voortgang'] += 1 + nu = datetime.now() + rijen = [] + for a, klas in leerlingen: + intern = str(a.get('internnummer') or a.get('gebruikersnaam') or '').strip() + for c in co_accounts_uit(a): + rijen.append((intern, c['nr'], a.get('gebruikersnaam'), a.get('naam'), a.get('voornaam'), klas, + c['voornaam'], c['naam'], c['type'], c['email'], c['login'], nu)) + if not leerlingen: + raise RuntimeError("Smartschool gaf geen leerlingen terug. Heeft het webservice-wachtwoord de " + "rechten voor gebruikers en klassen?") + execute_query("DELETE FROM smartschool_coaccounts", commit=True) + for r in rijen: + execute_query("INSERT INTO smartschool_coaccounts (Internnummer, Nr, Gebruikersnaam, Leerling_naam, " + "Leerling_voornaam, Klas, Voornaam, Naam, Type, Email, Laatste_login, Opgehaald) " + "VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", r, commit=True) + nooit = sum(1 for r in rijen if not r[10]) + msg = (f"{len(leerlingen)} leerlingen en {len(rijen)} co-accounts opgehaald; " + f"{nooit} co-account(s) nog nooit aangemeld.") + self.status['resultaat'] = msg + return True, msg + except Exception as e: + self.status['fout'] = str(e) + return False, f"Ophalen mislukt: {e}" + finally: + self.status['bezig'] = False + self._lock.release() + + def sync_op_achtergrond(self): + if self.status['bezig']: + return False + self.status.update(bezig=True, voortgang=0, totaal=0) + threading.Thread(target=met_school(self.sync), daemon=True).start() + return True diff --git a/services/contacten_service.py b/services/contacten_service.py new file mode 100644 index 0000000..4ada095 --- /dev/null +++ b/services/contacten_service.py @@ -0,0 +1,391 @@ +""" +Gmail › Contacten: twee soorten contactbeheer in Google Workspace. + +1. Adresboek van de organisatie (Directory API, admin.directory.user) + Per gebruiker 'includeInGlobalAddressList': zichtbaar of verborgen in het adresboek en bij het aanvullen van adressen. + +2. Contactlijsten in de mailboxen (People API, https://www.googleapis.com/auth/contacts) + Een lijst (label) met contacten die PIVOT in de persoonlijke contacten van elke gebruiker in de gekozen OU's zet en + bijhoudt. PIVOT herkent zijn eigen contacten aan een eigen veld (userDefined 'PIVOT'), en past enkel die aan. +""" +import hashlib +import json +import sys +import threading +import time +from datetime import datetime + +from config import Config +from database import execute_query +from tenancy import school_singleton, met_school, google_credentials, huidige_school + +SCOPE_PEOPLE = 'https://www.googleapis.com/auth/contacts' +PIVOT_SLEUTEL = 'PIVOT' + + +class ContactFout(Exception): + pass + + +def vriendelijk(e, scope=None): + t = str(e) + laag = t.lower() + if 'unauthorized_client' in laag or 'access_denied' in laag or 'invalid_scope' in laag: + return ("Google weigert de toegang: voeg in de Admin-console › Beveiliging › API-beheer › Domeinbrede delegatie " + f"het bereik {scope or '(zie handleiding)'} toe bij het serviceaccount van PIVOT.") + if 'has not been used' in laag or 'is disabled' in laag or 'accessnotconfigured' in laag or 'service_disabled' in laag: + return ("De nodige API staat niet aan in het Google Cloud-project van het serviceaccount " + "(voor contactlijsten: People API).") + return t[:300] + + +def _directory(): + from googleapiclient.discovery import build + creds = google_credentials(Config.GOOGLE_API_SCOPES, subject=Config.GOOGLE_ADMIN_EMAIL) + return build('admin', 'directory_v1', credentials=creds, static_discovery=False, cache_discovery=False) + + +def ou_lijst(): + try: + resp = _directory().orgunits().list(customerId='my_customer', type='all').execute() + except Exception as e: + raise ContactFout(f"OU's ophalen mislukt: {vriendelijk(e)}") + return sorted([o['orgUnitPath'] for o in resp.get('organizationUnits', [])] + ['/'], key=str.lower) + + +def gebruikers_in(ous, met_sub=True, velden='primaryEmail,name,orgUnitPath,includeInGlobalAddressList,suspended'): + api, uit, gezien = _directory(), [], set() + for ou in ous: + token = None + while True: + params = dict(customer='my_customer', maxResults=500, pageToken=token, + fields=f'nextPageToken,users({velden})') + if ou != '/': + params['query'] = "orgUnitPath='" + ou.replace("\\", "\\\\").replace("'", "\\'") + "'" + try: + resp = api.users().list(**params).execute() + except Exception as e: + raise ContactFout(f"Gebruikers van {ou} ophalen mislukt: {vriendelijk(e)}") + for u in resp.get('users', []): + pad = u.get('orgUnitPath') or '/' + if (not met_sub and pad != ou) or u['primaryEmail'].lower() in gezien: + continue + gezien.add(u['primaryEmail'].lower()) + n = u.get('name') or {} + uit.append({'email': u['primaryEmail'].lower(), 'naam': n.get('fullName') or u['primaryEmail'], + 'achternaam': n.get('familyName', ''), 'ou': pad, 'geschorst': bool(u.get('suspended')), + 'zichtbaar': u.get('includeInGlobalAddressList', True) is not False}) + token = resp.get('nextPageToken') + if not token: + break + return sorted(uit, key=lambda x: (x['achternaam'].lower(), x['naam'].lower())) + + +# ===================================================================== +# 1. Adresboek: zichtbaar of verborgen +# ===================================================================== +def zet_zichtbaar(emails, zichtbaar): + api, fouten = _directory(), [] + for e in emails: + try: + api.users().patch(userKey=e, body={'includeInGlobalAddressList': bool(zichtbaar)}).execute() + except Exception as ex: + fouten.append(f"{e}: {vriendelijk(ex)}") + return fouten + + +# ===================================================================== +# 2. Contactlijsten in de mailboxen (People API) +# ===================================================================== +def ensure_tables(): + execute_query(""" + CREATE TABLE IF NOT EXISTS contact_lijsten ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Naam VARCHAR(100) NOT NULL, + OUs TEXT NULL, + Met_sub_ous TINYINT NOT NULL DEFAULT 1, + Bijgewerkt DATETIME NULL, + Door VARCHAR(255) NULL, + Laatste_sync DATETIME NULL, + Resultaat VARCHAR(500) NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", commit=True) + execute_query(""" + CREATE TABLE IF NOT EXISTS contact_lijst_items ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Lijst_ID INT NOT NULL, + Voornaam VARCHAR(100) NULL, + Achternaam VARCHAR(100) NULL, + Organisatie VARCHAR(150) NULL, + Functie VARCHAR(150) NULL, + Email VARCHAR(255) NULL, + Telefoon VARCHAR(60) NULL, + Notitie VARCHAR(500) NULL, + KEY idx_cli_lijst (Lijst_ID) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", commit=True) + + +def _schoon(c): + uit = {k: (str(c.get(k) or '').strip())[:500] for k in + ('voornaam', 'achternaam', 'organisatie', 'functie', 'email', 'telefoon', 'notitie')} + if not (uit['voornaam'] or uit['achternaam'] or uit['organisatie']): + raise ContactFout("Geef bij elk contact minstens een naam of een organisatie.") + if uit['email'] and '@' not in uit['email']: + raise ContactFout(f"Ongeldig e-mailadres: {uit['email']}") + return uit + + +def _ous(r): + try: + return [o for o in json.loads(r.get('OUs') or '[]') if isinstance(o, str)] + except ValueError: + return [] + + +def lijsten(): + ensure_tables() + rijen = execute_query("SELECT l.*, (SELECT COUNT(*) FROM contact_lijst_items i WHERE i.Lijst_ID = l.ID) AS aantal " + "FROM contact_lijsten l ORDER BY l.Naam") or [] + for r in rijen: + r['ous'] = _ous(r) + return rijen + + +def lijst(lijst_id): + ensure_tables() + r = execute_query("SELECT * FROM contact_lijsten WHERE ID = %s", (lijst_id,)) + if not r: + return None + r = r[0] + r['ous'] = _ous(r) + r['items'] = execute_query("SELECT * FROM contact_lijst_items WHERE Lijst_ID = %s ORDER BY Achternaam, Voornaam, " + "Organisatie", (lijst_id,)) or [] + return r + + +def lijst_bewaren(lijst_id, naam, ous, met_sub, items, door): + ensure_tables() + naam = (naam or '').strip()[:100] + if not naam: + raise ContactFout("Geef de lijst een naam (die wordt het label in Google Contacten).") + schoon = [] + for i in items: + if any(str(i.get(k) or '').strip() for k in i if k != 'id'): + c = _schoon(i) + c['id'] = int(i['id']) if str(i.get('id') or '').isdigit() else None + schoon.append(c) + if lijst_id: + execute_query("UPDATE contact_lijsten SET Naam = %s, OUs = %s, Met_sub_ous = %s, Bijgewerkt = NOW(), Door = %s " + "WHERE ID = %s", (naam, json.dumps(sorted(set(ous))), 1 if met_sub else 0, door, lijst_id), + commit=True) + else: + from database import execute_insert + lijst_id = execute_insert("INSERT INTO contact_lijsten (Naam, OUs, Met_sub_ous, Bijgewerkt, Door) " + "VALUES (%s, %s, %s, NOW(), %s)", + (naam, json.dumps(sorted(set(ous))), 1 if met_sub else 0, door)) + # Bestaande contacten behouden hun ID (zo herkent PIVOT ze in de mailboxen en past het ze aan i.p.v. opnieuw te maken) + bestaand = {r['ID'] for r in execute_query("SELECT ID FROM contact_lijst_items WHERE Lijst_ID = %s", (lijst_id,)) or []} + behouden = set() + velden = (lambda i: (i['voornaam'], i['achternaam'], i['organisatie'], i['functie'], i['email'], i['telefoon'], + i['notitie'])) + for i in schoon: + if i['id'] in bestaand: + execute_query("UPDATE contact_lijst_items SET Voornaam = %s, Achternaam = %s, Organisatie = %s, Functie = %s, " + "Email = %s, Telefoon = %s, Notitie = %s WHERE ID = %s AND Lijst_ID = %s", + velden(i) + (i['id'], lijst_id), commit=True) + behouden.add(i['id']) + else: + execute_query("INSERT INTO contact_lijst_items (Lijst_ID, Voornaam, Achternaam, Organisatie, Functie, Email, " + "Telefoon, Notitie) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)", (lijst_id,) + velden(i), commit=True) + for weg in bestaand - behouden: + execute_query("DELETE FROM contact_lijst_items WHERE ID = %s", (weg,), commit=True) + return lijst_id + + +def lijst_verwijderen_db(lijst_id): + execute_query("DELETE FROM contact_lijst_items WHERE Lijst_ID = %s", (lijst_id,), commit=True) + execute_query("DELETE FROM contact_lijsten WHERE ID = %s", (lijst_id,), commit=True) + + +def _people(mailbox): + from googleapiclient.discovery import build + creds = google_credentials([SCOPE_PEOPLE], subject=mailbox) + try: + return build('people', 'v1', credentials=creds, static_discovery=True, cache_discovery=False) + except Exception: + return build('people', 'v1', credentials=creds, static_discovery=False, cache_discovery=False) + + +def _persoon(item, merk, groep): + p = {'names': [{'givenName': item['Voornaam'] or '', 'familyName': item['Achternaam'] or ''}], + 'userDefined': [{'key': PIVOT_SLEUTEL, 'value': merk}], + 'memberships': [{'contactGroupMembership': {'contactGroupResourceName': groep}}]} + if not (item['Voornaam'] or item['Achternaam']): + p['names'] = [{'givenName': item['Organisatie'] or item['Email'] or ''}] + if item['Email']: + p['emailAddresses'] = [{'value': item['Email'], 'type': 'work'}] + if item['Telefoon']: + p['phoneNumbers'] = [{'value': item['Telefoon'], 'type': 'work'}] + if item['Organisatie'] or item['Functie']: + p['organizations'] = [{'name': item['Organisatie'] or '', 'title': item['Functie'] or ''}] + if item['Notitie']: + p['biographies'] = [{'value': item['Notitie'], 'contentType': 'TEXT_PLAIN'}] + return p + + +def _hash(item): + return hashlib.sha1(json.dumps([item[k] for k in ('Voornaam', 'Achternaam', 'Organisatie', 'Functie', 'Email', + 'Telefoon', 'Notitie')]).encode()).hexdigest()[:12] + + +PERSON_FIELDS = 'names,emailAddresses,phoneNumbers,organizations,biographies,userDefined,memberships' + + +def _herhaal(fn, pogingen=5): + for poging in range(pogingen): + try: + return fn() + except Exception as e: + status = getattr(getattr(e, 'resp', None), 'status', None) + if status in (429, 500, 503) and poging < pogingen - 1: + time.sleep(2 ** poging + 1) + continue + raise + + +def _pivot_contacten(svc, lijst_id): + """{item-sleutel: person} van de contacten die PIVOT voor deze lijst in deze mailbox zette.""" + uit, token = {}, None + prefix = f"lijst{lijst_id}:" + while True: + resp = _herhaal(lambda: svc.people().connections().list( + resourceName='people/me', pageSize=1000, pageToken=token, personFields=PERSON_FIELDS).execute()) + for p in resp.get('connections', []): + merk = next((u.get('value', '') for u in p.get('userDefined', []) if u.get('key') == PIVOT_SLEUTEL), '') + if merk.startswith(prefix): + uit[merk.split('#')[0]] = (merk, p) + token = resp.get('nextPageToken') + if not token: + return uit + + +def _groep(svc, naam, maak=True): + resp = _herhaal(lambda: svc.contactGroups().list(pageSize=1000).execute()) + for g in resp.get('contactGroups', []): + if g.get('groupType') == 'USER_CONTACT_GROUP' and g.get('name') == naam: + return g['resourceName'] + if not maak: + return None + return _herhaal(lambda: svc.contactGroups().create(body={'contactGroup': {'name': naam}}).execute())['resourceName'] + + +def sync_mailbox(email, l, verwijderen=False, oude_naam=None): + """Zet de contacten van lijst `l` in de mailbox (of haalt ze weg). Geeft (toegevoegd, gewijzigd, verwijderd).""" + svc = _people(email) + bestaand = _pivot_contacten(svc, l['ID']) + toegevoegd = gewijzigd = verwijderd = 0 + gewenst = {} if verwijderen else {f"lijst{l['ID']}:{i['ID']}": i for i in l['items']} + groep = None + if gewenst: + groep = _groep(svc, l['Naam']) + if oude_naam and oude_naam != l['Naam']: + oud = _groep(svc, oude_naam, maak=False) + if oud and oud != groep: + _herhaal(lambda: svc.contactGroups().delete(resourceName=oud, deleteContacts=False).execute()) + for sleutel, item in gewenst.items(): + merk = f"{sleutel}#{_hash(item)}" + if sleutel in bestaand: + oud_merk, p = bestaand[sleutel] + in_groep = any(m.get('contactGroupMembership', {}).get('contactGroupResourceName') == groep + for m in p.get('memberships', [])) + if oud_merk == merk and in_groep: + continue + body = _persoon(item, merk, groep) + body['etag'] = p.get('etag') + body['memberships'] = [m for m in p.get('memberships', []) + if m.get('contactGroupMembership', {}).get('contactGroupResourceName') != groep] \ + + body['memberships'] + _herhaal(lambda: svc.people().updateContact( + resourceName=p['resourceName'], updatePersonFields=PERSON_FIELDS, body=body).execute()) + gewijzigd += 1 + else: + _herhaal(lambda: svc.people().createContact(body=_persoon(item, merk, groep)).execute()) + toegevoegd += 1 + for sleutel, (merk, p) in bestaand.items(): + if sleutel not in gewenst: + _herhaal(lambda: svc.people().deleteContact(resourceName=p['resourceName']).execute()) + verwijderd += 1 + if verwijderen: + g = _groep(svc, l['Naam'], maak=False) + if g: + try: + _herhaal(lambda: svc.contactGroups().delete(resourceName=g, deleteContacts=False).execute()) + except Exception: + pass + return toegevoegd, gewijzigd, verwijderd + + +class LijstSync: + def __new__(cls): + def init(inst): + inst._lock = threading.Lock() + inst.status = {'bezig': False, 'lijst': None, 'voortgang': 0, 'totaal': 0, 'fouten': 0, 'fout': None, + 'resultaat': None, 'foutvoorbeelden': []} + return school_singleton(cls, init) + + def run(self, lijst_id, verwijderen=False, oude_naam=None, oude_ous=None): + if not self._lock.acquire(blocking=False): + return False, "Er loopt al een opdracht." + s = self.status + try: + l = lijst(lijst_id) + if not l: + raise ContactFout("Lijst niet gevonden.") + s.update(bezig=True, lijst=l['Naam'], voortgang=0, totaal=0, fouten=0, fout=None, resultaat=None, + foutvoorbeelden=[]) + ontvangers = gebruikers_in(l['ous'], bool(l['Met_sub_ous']), 'primaryEmail,name,orgUnitPath,suspended') + ontvangers = [u for u in ontvangers if not u['geschorst']] + # Wie niet meer in de gekozen OU's zit (OU's gewijzigd): de contacten van deze lijst weghalen + weg = [] + if oude_ous is not None: + nu = {u['email'] for u in ontvangers} + weg = [u for u in gebruikers_in(oude_ous, True, 'primaryEmail,name,orgUnitPath,suspended') + if u['email'] not in nu and not u['geschorst']] + s['totaal'] = len(ontvangers) + len(weg) + t = {'toegevoegd': 0, 'gewijzigd': 0, 'verwijderd': 0} + for u, enkel_weg in [(u, verwijderen) for u in ontvangers] + [(u, True) for u in weg]: + try: + a, b, c = sync_mailbox(u['email'], l, verwijderen=enkel_weg, oude_naam=oude_naam) + t['toegevoegd'] += a; t['gewijzigd'] += b; t['verwijderd'] += c + except Exception as e: + s['fouten'] += 1 + if len(s['foutvoorbeelden']) < 6: + s['foutvoorbeelden'].append(f"{u['email']}: {vriendelijk(e, SCOPE_PEOPLE)[:180]}") + sys.stderr.write(f"Contactlijst {l['Naam']} → {u['email']}: {e}\n") + s['voortgang'] += 1 + if verwijderen: + msg = f"Lijst '{l['Naam']}' uit {len(ontvangers)} mailbox(en) gehaald ({t['verwijderd']} contacten)" + else: + msg = (f"Lijst '{l['Naam']}' in {len(ontvangers)} mailbox(en): {t['toegevoegd']} toegevoegd, " + f"{t['gewijzigd']} bijgewerkt, {t['verwijderd']} verwijderd") + if s['fouten']: + msg += f", {s['fouten']} mailbox(en) mislukt" + s['resultaat'] = msg + '.' + if verwijderen and not s['fouten']: + lijst_verwijderen_db(lijst_id) + else: + execute_query("UPDATE contact_lijsten SET Laatste_sync = NOW(), Resultaat = %s WHERE ID = %s", + (s['resultaat'][:500], lijst_id), commit=True) + return True, s['resultaat'] + except Exception as e: + s['fout'] = vriendelijk(e, SCOPE_PEOPLE) + return False, s['fout'] + finally: + s['bezig'] = False + self._lock.release() + + def start(self, *args, **kw): + if self.status['bezig']: + return False + self.status.update(bezig=True, voortgang=0, totaal=0, fout=None, resultaat=None) + threading.Thread(target=met_school(lambda: self.run(*args, **kw)), daemon=True).start() + return True diff --git a/services/facturatie_service.py b/services/facturatie_service.py new file mode 100644 index 0000000..b81ded7 --- /dev/null +++ b/services/facturatie_service.py @@ -0,0 +1,405 @@ +""" +Leerlingfacturatie: de facturen en creditnota's van de leerlingen uit Informat (Rekeningen API / Invoice API). + +- Token: zelfde identityserver en client-ID/secret als de leerlingen-API, met scope + api_informat_invoices.invoices.read._ + Die scope krijgt de client zodra de school in Informat de app toegang geeft tot de rekeningen (toegangsgroep); + Informat stuurt dan een e-mail naar de eigenaar van de app. De accessGroupIdentifier in de bevragingen en + PDF-adressen is het deel na "read.": _. + Staat ze niet in de schoolinstellingen, dan vraagt PIVOT een token zonder scope en leest de toegekende scopes. +- API: GraphQL op /graphql (standaard https://api.informatsoftware.be/invoices/v1/graphql). Per schooljaar de factuurgroepen (enkel type STUDENT) en per groep de + geboekte facturen en creditnota's (totaal, betaald, open, OGM, leerling). +- PDF: /download///pdf (400 = nog niet aangemaakt: dan eerst .../create/...). +Het resultaat wordt 10 minuten per school en schooljaar bewaard. +""" +import re +import time +from datetime import date + +import requests + +from config import Config + +STANDAARD_API = 'https://api.informatsoftware.be/invoices/v1' # centraal APIM-adres uit de implementatiegids +SCOPE_RE = re.compile(r'api_informat_invoices\.invoices\.read\.([0-9a-fA-F-]{36})_(\w+)') +CACHE_SECONDEN = 600 +TIMEOUT = (15, 120) + +Q_GROEPEN = """ +query groepen($schoolYear: String!, $accessGroupIdentifier: String!) { + accessGroup(accessGroupIdentifier: $accessGroupIdentifier) { + invoiceGroups(schoolYear: $schoolYear, where: {invoiceGroupType: {eq: STUDENT}}, order: [{name: ASC}]) { + id name invoiceGroupType schoolYear fromDate toDate + } + } +}""" + +Q_FACTUREN = """ +query facturen($schoolYear: String!, $accessGroupIdentifier: String!, $invoiceGroupId: Int!) { + accessGroup(accessGroupIdentifier: $accessGroupIdentifier) { + invoiceGroups(schoolYear: $schoolYear, where: {id: {eq: $invoiceGroupId}}) { + id name + invoices(order: [{printDate: DESC}]) { + invoiceId invoiceType printDate dueDate total paid open paymentReference paymentReferenceInvoice + recipient { databaseId firstName lastName stamNumber class classNumber } + } + } + } +}""" + + +Q_NAAM = """ +query naam($accessGroupIdentifier: String!) { + accessGroup(accessGroupIdentifier: $accessGroupIdentifier) { guid name } +}""" + +MAX_PROBEER = 400 # meer kandidaat-scopes dan dit proberen we niet één voor één + + +class FacturatieFout(Exception): + pass + + +def schooljaren(aantal=3): + """['2026-27', '2025-26', ...] vanaf het huidige schooljaar.""" + vandaag = date.today() + start = vandaag.year if vandaag.month >= 9 else vandaag.year - 1 + return [f"{j}-{str(j + 1)[-2:]}" for j in range(start, start - aantal, -1)] + + +def _datum(w): + if not w: + return None + try: + return date.fromisoformat(str(w)[:10]) + except ValueError: + return None + + +def _bedrag(w): + try: + return round(float(w or 0), 2) + except (TypeError, ValueError): + return 0.0 + + +def status_van(f): + if f['type'] == 'CREDIT_NOTE': + return 'credit' + if abs(f['open']) < 0.005: + return 'betaald' + if abs(f['betaald']) >= 0.005: + return 'gedeeltelijk' + return 'open' + + +def _scopes_uit(js): + """Scopes uit een token-antwoord: het veld 'scope' of, als dat ontbreekt, de claim 'scope' in het JWT.""" + import base64, json + scope = js.get('scope') + if not scope: + try: + deel = js['access_token'].split('.')[1] + claims = json.loads(base64.urlsafe_b64decode(deel + '=' * (-len(deel) % 4))) + scope = claims.get('scope') + except Exception: + scope = None + if isinstance(scope, str): + scope = scope.split() + return [str(x) for x in (scope or [])] + + +class FacturatieService: + def __init__(self): + from tenancy import huidige_school + self.school = huidige_school() + self.base = (self.school.get('INFORMAT_FACTUUR_API') or STANDAARD_API).rstrip('/') + + # ---------------- authenticatie ---------------- + def _token_aanvraag(self, scope=None): + data = {'grant_type': 'client_credentials', 'client_id': Config.INFORMAT_ID, + 'client_secret': Config.INFORMAT_SECRET} + if scope: + data['scope'] = scope + try: + r = requests.post(Config.INFORMAT_AUTH_URL, data=data, timeout=15) + except Exception as e: + raise FacturatieFout(f"Informat (identityserver) is niet bereikbaar: {e}") + try: + js = r.json() + except Exception: + js = {} + if r.status_code != 200 or not js.get('access_token'): + fout = js.get('error') or f"HTTP {r.status_code}" + if fout == 'invalid_scope': + raise FacturatieFout(f"Informat weigert de scope {scope or '(geen)'} (invalid_scope). Heeft de school in " + "Informat de app toegang gegeven tot de rekeningen (toegangsgroep)?") + if fout == 'invalid_client': + raise FacturatieFout("Informat kent deze client-ID/secret niet (invalid_client). Kijk Koppelingen › Informat na.") + raise FacturatieFout(f"Aanmelden bij Informat mislukt: {fout}") + return js + + def scopes(self): + """[(scope, toegangsgroep-GUID)] uit de instellingen, of opgezocht bij Informat.""" + ingesteld = [x.strip() for x in re.split(r'[,\s]+', self.school.get('INFORMAT_FACTUUR_SCOPE') or '') if x.strip()] + if ingesteld: + uit = [] + for sc in ingesteld: + m = SCOPE_RE.search(sc) + if not m: + raise FacturatieFout(f"'{sc}' is geen geldige scope voor de Rekeningen API " + "(verwacht: api_informat_invoices.invoices.read._).") + uit.append((m.group(0), f"{m.group(1)}_{m.group(2)}")) # accessGroupIdentifier = _ + return uit + bewaard = self.school.cache.get('factuur_scopes') + if bewaard and time.time() - bewaard[0] < 3600: + return bewaard[1] + uit = self._bewaarde_scopes() + if not uit: + uit, info = self.zoek_scopes() + if not uit: + raise FacturatieFout("PIVOT kon de scope van de Rekeningen API niet zelf vinden. " + info + " Vul bij " + "Koppelingen › Informat de 'Scope Rekeningen API' in " + "(api_informat_invoices.invoices.read._). " + "Informat mailt die scope naar de eigenaar van de app zodra de school toegang geeft.") + self._bewaar_scopes(uit) + self.school.cache['factuur_scopes'] = (time.time(), uit) + return uit + + # ---------------- scope zelf zoeken ---------------- + def _groepnamen(self): + """De ingevulde naam/namen van de toegangsgroep(en) in Rekeningen (veld 'Toegangsgroep Rekeningen').""" + return [x.strip() for x in str(self.school.get('INFORMAT_FACTUUR_GROEP') or '').split(';') if x.strip()] + + def _instelling_sleutel(self): + # Hangt ook af van de ingevulde toegangsgroep: pas je die aan, dan zoekt PIVOT opnieuw + import zlib + groep = ';'.join(n.lower() for n in self._groepnamen()) + return f"factuur_scope_{self.school.code}"[:40] + f"_{zlib.crc32(groep.encode()):08x}" + + def _bewaarde_scopes(self): + """Eerder gevonden scopes van deze school (centrale tabel PIVOT_instellingen).""" + try: + from database import central_query + rij = central_query("SELECT Waarde FROM PIVOT_instellingen WHERE Sleutel = %s", (self._instelling_sleutel(),)) + except Exception: + return [] + waarde = (rij[0]['Waarde'] if rij else '') or '' + return [(f"api_informat_invoices.invoices.read.{g}_{i}", f"{g}_{i}") for g, i in SCOPE_RE.findall(waarde)] + + def _bewaar_scopes(self, uit): + try: + from database import central_query + from services import ipblokkade + ipblokkade.ensure_table() + central_query("INSERT INTO PIVOT_instellingen (Sleutel, Waarde, Bijgewerkt, Door) VALUES (%s, %s, NOW(), 'PIVOT') " + "ON DUPLICATE KEY UPDATE Waarde = VALUES(Waarde), Bijgewerkt = NOW()", + (self._instelling_sleutel(), ' '.join(sc for sc, _ in uit)[:255]), commit=True) + except Exception: + pass + + def vergeet_scopes(self): + self.school.cache.pop('factuur_scopes', None) + try: + from database import central_query + central_query("DELETE FROM PIVOT_instellingen WHERE Sleutel = %s", (self._instelling_sleutel(),), commit=True) + except Exception: + pass + + def _discovery_scopes(self): + """Alle rekeningen-scopes die de identityserver publiek bekendmaakt (.well-known/openid-configuration).""" + basis = Config.INFORMAT_AUTH_URL.split('/connect/')[0].rstrip('/') + r = requests.get(f"{basis}/.well-known/openid-configuration", timeout=30) + r.raise_for_status() + return [sc for sc in (r.json().get('scopes_supported') or []) if SCOPE_RE.fullmatch(str(sc))] + + def _mag(self, scope): + """True als deze client een token voor `scope` krijgt (loopt in een aparte thread: school meegeven).""" + from tenancy import in_school + try: + with in_school(self.school): + self._token(scope) + return True + except FacturatieFout: + return False + except Exception: + return False + + def _naam_toegangsgroep(self, scope, ag): + try: + data = self._gql(scope, Q_NAAM, {'accessGroupIdentifier': ag}) + return ((data.get('accessGroup') or {}).get('name') or '').strip() + except FacturatieFout: + return '' + + def zoek_scopes(self): + """Zoekt de rekeningen-scope(s) van deze school. Geeft ([(scope, accessGroupIdentifier)], uitleg). + 1) token zonder scope: soms staan de toegekende scopes in het antwoord of in het token; + 2) anders: de publieke lijst van scopes van de identityserver, en daarvan enkel die waarvoor deze client + een token krijgt (de toegangsgroepen die scholen aan deze app gaven); + 3) heeft de client toegang tot meer dan één school: de toegangsgroep waarvan de naam het instellingsnummer + (of de naam) van deze school bevat, bv. '000448 BS Irishof Kapellen'.""" + info = '' + kandidaten = [] + try: + kandidaten = [sc for sc in _scopes_uit(self._token_aanvraag(None)) if SCOPE_RE.fullmatch(sc)] + except FacturatieFout: + pass + if not kandidaten: + try: + alle = self._discovery_scopes() + except Exception as e: + return [], f"De lijst van scopes van Informat kon niet gelezen worden ({e})." + if not alle: + return [], "Informat maakt de rekeningen-scopes niet publiek bekend." + if len(alle) > MAX_PROBEER: + return [], f"Informat kent {len(alle)} rekeningen-scopes; te veel om ze allemaal te proberen." + from concurrent.futures import ThreadPoolExecutor + with ThreadPoolExecutor(max_workers=8) as pool: + kandidaten = [sc for sc, ok in zip(alle, pool.map(self._mag, alle)) if ok] + if not kandidaten: + return [], f"Deze Informat-client krijgt voor geen enkele van de {len(alle)} rekeningen-scopes toegang." + paren = [(sc, '_'.join(SCOPE_RE.fullmatch(sc).groups())) for sc in dict.fromkeys(kandidaten)] + gevraagd = [n.lower() for n in self._groepnamen()] + if gevraagd: + # Toegangsgroep ingevuld: enkel de groep(en) met precies die naam (of die de naam bevatten) + namen, juist = [], [] + for sc, ag in paren: + gnaam = self._naam_toegangsgroep(sc, ag) + namen.append(gnaam or ag) + laag = ' '.join(gnaam.lower().split()) + if any(laag == g or g in laag for g in (' '.join(x.split()) for x in gevraagd)): + juist.append((sc, ag)) + if juist: + return juist, '' + return [], ("Geen toegangsgroep gevonden met de naam '" + '; '.join(self._groepnamen()) + "'. Deze client heeft " + "toegang tot: " + ', '.join(namen) + ".") + if len(paren) == 1: + return paren, '' + # Meerdere toegangsgroepen: die van deze school kiezen op naam + from tenancy import informat_campussen + nummers = {n for n, _ in informat_campussen(self.school.waarden.get('INFORMAT_INST_NUMBER'))} + nummers |= {str(self.school.get('INSTELLINGSNUMMER') or '').strip()} - {''} + naam = (self.school.naam or '').lower() + eigen, namen = [], [] + for sc, ag in paren: + gnaam = self._naam_toegangsgroep(sc, ag) + namen.append(gnaam or ag) + laag = gnaam.lower() + if any(n and (n in laag or n.lstrip('0') and re.search(rf'\b0*{re.escape(n.lstrip("0"))}\b', laag)) for n in nummers) \ + or (naam and naam in laag): + eigen.append((sc, ag)) + if eigen: + return eigen, '' + return [], ("Deze client heeft toegang tot meerdere toegangsgroepen (" + ', '.join(namen) + "), maar geen " + "enkele naam bevat het instellingsnummer van deze school.") + + def _token(self, scope): + sleutel = ('factuur_token', scope) + bewaard = self.school.cache.get(sleutel) + if bewaard and time.time() < bewaard[0]: + return bewaard[1] + js = self._token_aanvraag(scope) + self.school.cache[sleutel] = (time.time() + int(js.get('expires_in') or 3600) - 60, js['access_token']) + return js['access_token'] + + # ---------------- GraphQL ---------------- + def _gql(self, scope, query, variabelen): + headers = {'Authorization': f"BEARER {self._token(scope)}", 'Content-Type': 'application/json', + 'Accept': 'application/json'} + try: + r = requests.post(f"{self.base}/graphql", json={'query': query, 'variables': variabelen}, + headers=headers, timeout=TIMEOUT) + except requests.exceptions.Timeout: + raise FacturatieFout("De Rekeningen API van Informat antwoordde niet op tijd. Probeer later opnieuw.") + except Exception as e: + raise FacturatieFout(f"De Rekeningen API van Informat is niet bereikbaar: {e}") + if r.status_code == 429: + raise FacturatieFout("Informat meldt te veel aanvragen (429). Probeer over een minuut opnieuw.") + if r.status_code in (401, 403): + raise FacturatieFout(f"Informat weigert de toegang tot de rekeningen ({r.status_code}).") + if not r.text.strip(): + return {} + try: + js = r.json() + except Exception: + raise FacturatieFout(f"Onverwacht antwoord van de Rekeningen API (HTTP {r.status_code}): {r.text[:200]}") + if js.get('errors'): + raise FacturatieFout("Rekeningen API: " + '; '.join(str(e.get('message', e)) for e in js['errors'])[:400]) + return js.get('data') or {} + + def groepen(self, schooljaar): + """Factuurgroepen van type STUDENT: [{scope, toegangsgroep, id, naam}].""" + uit = [] + for scope, ag in self.scopes(): + data = self._gql(scope, Q_GROEPEN, {'schoolYear': schooljaar, 'accessGroupIdentifier': ag}) + for g in ((data.get('accessGroup') or {}).get('invoiceGroups') or []): + if str(g.get('invoiceGroupType') or '').upper() == 'STUDENT': + uit.append({'scope': scope, 'toegangsgroep': ag, 'id': g.get('id'), 'naam': g.get('name') or f"Groep {g.get('id')}"}) + uit.sort(key=lambda g: str(g['naam']).lower()) + return uit + + def facturen(self, schooljaar, vernieuw=False): + """(facturen, groepen, opgehaald) voor alle leerlingen-factuurgroepen van het schooljaar.""" + sleutel = ('facturen', schooljaar) + bewaard = self.school.cache.get(sleutel) + if bewaard and not vernieuw and time.time() - bewaard[0] < CACHE_SECONDEN: + return bewaard[1], bewaard[2], bewaard[0] + groepen = self.groepen(schooljaar) + rijen = [] + for g in groepen: + data = self._gql(g['scope'], Q_FACTUREN, {'schoolYear': schooljaar, 'accessGroupIdentifier': g['toegangsgroep'], + 'invoiceGroupId': g['id']}) + for grp in ((data.get('accessGroup') or {}).get('invoiceGroups') or []): + for f in grp.get('invoices') or []: + ont = f.get('recipient') or {} + rij = { + 'id': f.get('invoiceId'), + 'toegangsgroep': g['toegangsgroep'], + 'groep_id': g['id'], 'groep': g['naam'], + 'type': str(f.get('invoiceType') or 'INVOICE').upper(), + 'datum': _datum(f.get('printDate')), 'vervaldag': _datum(f.get('dueDate')), + 'totaal': _bedrag(f.get('total')), 'betaald': _bedrag(f.get('paid')), 'open': _bedrag(f.get('open')), + 'ogm': f.get('paymentReference') or '', + 'ogm_factuur': f.get('paymentReferenceInvoice') or '', # bij een creditnota: die van de factuur + 'klas': ont.get('class') or '', 'klasnummer': ont.get('classNumber'), + 'voornaam': (ont.get('firstName') or '').strip(), 'naam': (ont.get('lastName') or '').strip(), + 'stamnummer': ont.get('stamNumber') or '', 'leerling_id': ont.get('databaseId'), + } + rij['status'] = status_van(rij) + rij['teken'] = -1 if rij['type'] == 'CREDIT_NOTE' else 1 # creditnota's: positief bedrag in Informat + rijen.append(rij) + rijen.sort(key=lambda r: (r['naam'].lower(), r['voornaam'].lower(), r['datum'] or date.min)) + nu = time.time() + self.school.cache[sleutel] = (nu, rijen, groepen) + return rijen, groepen, nu + + # ---------------- PDF ---------------- + def pdf(self, toegangsgroep, invoice_id, pogingen=8): + """De PDF van één factuur (bytes), via .../download/{accessGroupIdentifier}/{invoiceId}/pdf. + Bestaat die nog niet (Informat antwoordt dan 400), dan eerst .../create/... (202) en even wachten.""" + scope = next((sc for sc, ag in self.scopes() if ag == toegangsgroep), None) + if not scope: + raise FacturatieFout("Onbekende toegangsgroep voor deze factuur.") + auth = {'Authorization': f"BEARER {self._token(scope)}"} + download = f"{self.base}/download/{toegangsgroep}/{invoice_id}/pdf" + aanmaken = f"{self.base}/create/{toegangsgroep}/{invoice_id}/pdf" + aangevraagd = False + for poging in range(pogingen + 1): + r = requests.get(download, headers=auth, timeout=TIMEOUT) + if r.status_code == 200 and r.content: + return r.content + if r.status_code not in (400, 404): + raise FacturatieFout(f"De PDF kon niet opgehaald worden (HTTP {r.status_code}).") + if not aangevraagd: + c = requests.post(aanmaken, headers=auth, timeout=TIMEOUT) + if c.status_code == 405: + c = requests.get(aanmaken, headers=auth, timeout=TIMEOUT) + if c.status_code not in (200, 201, 202, 204): + raise FacturatieFout(f"Informat kon de PDF niet aanmaken (HTTP {c.status_code}). Controleer of het " + "factuuradres van deze factuur een titel en naam heeft.") + aangevraagd = True + if poging < pogingen: + time.sleep(3) + raise FacturatieFout("Informat is de PDF nog aan het aanmaken (dat kan tot 2 minuten duren). " + "Probeer zo dadelijk opnieuw.") diff --git a/services/gedeelde_drives_service.py b/services/gedeelde_drives_service.py new file mode 100644 index 0000000..27022ee --- /dev/null +++ b/services/gedeelde_drives_service.py @@ -0,0 +1,280 @@ +""" +Google › Gedeelde drives: alle gedeelde drives van het domein, wie er rechten op heeft, en leden beheren. + +Google Drive API v3 namens de beheerder (domeinbrede delegatie), met useDomainAdminAccess=True zodat ook drives +zichtbaar zijn waar de beheerder zelf geen lid van is: + drives.list / drives.create + permissions.list / create / update / delete (supportsAllDrives=True) +Vereist: https://www.googleapis.com/auth/drive (en de Google Drive API aan in het Cloud-project). +""" +import threading +import time +import uuid +from concurrent.futures import ThreadPoolExecutor +from datetime import datetime + +from config import Config +from tenancy import google_credentials, huidige_school, in_school + +SCOPE = 'https://www.googleapis.com/auth/drive' +CACHE_SECONDEN = 10 * 60 +ROLLEN = [('organizer', 'Beheerder'), ('fileOrganizer', 'Inhoudsbeheerder'), ('writer', 'Bijdrager'), + ('commenter', 'Reageerder'), ('reader', 'Lezer')] +ROL_NAAM = dict(ROLLEN) +PERM_VELDEN = 'nextPageToken,permissions(id,type,role,emailAddress,domain,displayName,deleted)' + + +class DriveFout(Exception): + pass + + +def vriendelijk(e): + t = str(e) + laag = t.lower() + if 'unauthorized_client' in laag or 'access_denied' in laag: + return ("Google weigert de toegang: voeg in de Admin-console › Beveiliging › API-beheer › Domeinbrede delegatie " + f"het bereik {SCOPE} toe bij het serviceaccount van PIVOT.") + if 'has not been used' in laag or 'is disabled' in laag or 'accessnotconfigured' in laag: + return "De Google Drive API staat niet aan in het Google Cloud-project van het serviceaccount." + if 'insufficientadministratorprivileges' in laag or 'domain administrator' in laag: + return "De beheerder (Koppelingen › Algemeen) heeft geen beheerdersrechten voor Drive in het Admin-console." + if 'cannotremovelastorganizer' in laag or 'last organizer' in laag: + return "Dit is de laatste beheerder van de drive; voeg eerst een andere beheerder toe." + if 'invalidsharingrequest' in laag or 'shareoutnotpermitted' in laag or 'sharingrateLimitExceeded'.lower() in laag: + return "Google laat dit delen niet toe (bv. delen buiten het domein staat uit voor deze drive of organisatie)." + if 'notfound' in laag.replace(' ', '') or ' 404' in t: + return "Niet gevonden (bestaat de drive, de gebruiker of de groep nog?)." + return t[:300] + + +def _drive(): + from googleapiclient.discovery import build + creds = google_credentials([SCOPE], subject=Config.GOOGLE_ADMIN_EMAIL) + try: + return build('drive', 'v3', credentials=creds, static_discovery=True, cache_discovery=False) + except Exception: + return build('drive', 'v3', credentials=creds, static_discovery=False, cache_discovery=False) + + +def _eigen_domeinen(): + s = huidige_school() + d = {x.lower() for x in (getattr(s, 'domeinen', None) or [s.domein]) if x} + if Config.GOOGLE_ADMIN_EMAIL: + d.add(Config.GOOGLE_ADMIN_EMAIL.lower().partition('@')[2]) + return d + + +def _is_extern(p, domeinen): + if p.get('type') == 'anyone': + return True + if p.get('type') == 'domain': + return (p.get('domain') or '').lower() not in domeinen + mail = (p.get('emailAddress') or '').lower() + return bool(mail) and mail.partition('@')[2] not in domeinen + + +def _leden(svc, drive_id): + uit, token = [], None + while True: + resp = svc.permissions().list(fileId=drive_id, supportsAllDrives=True, useDomainAdminAccess=True, + pageSize=100, pageToken=token, fields=PERM_VELDEN).execute() + uit += resp.get('permissions', []) + token = resp.get('nextPageToken') + if not token: + return uit + + +def _samenvatting(d, leden, domeinen): + return {'id': d['id'], 'naam': d.get('name', ''), 'aangemaakt': (d.get('createdTime') or '')[:10], + 'verborgen': bool(d.get('hidden')), 'leden': len(leden), + 'beheerders': sum(1 for p in leden if p.get('role') == 'organizer'), + 'extern': sum(1 for p in leden if _is_extern(p, domeinen)), + 'groepen': sum(1 for p in leden if p.get('type') == 'group'), + 'fout': None} + + +def overzicht(vernieuw=False): + """[{id, naam, aangemaakt, leden, beheerders, extern, groepen, verborgen, fout}] gesorteerd op naam.""" + school = huidige_school() + bewaard = school.cache.get('gedeelde_drives') + if bewaard and not vernieuw and time.time() - bewaard[0] < CACHE_SECONDEN: + return bewaard[1], bewaard[0] + try: + svc = _drive() + drives, token = [], None + while True: + resp = svc.drives().list(useDomainAdminAccess=True, pageSize=100, pageToken=token, + fields='nextPageToken,drives(id,name,createdTime,hidden)').execute() + drives += resp.get('drives', []) + token = resp.get('nextPageToken') + if not token: + break + except Exception as e: + raise DriveFout(vriendelijk(e)) + domeinen = _eigen_domeinen() + lokaal = threading.local() + alle_leden = {} + + def info(d): + with in_school(school): + if not hasattr(lokaal, 'svc'): + lokaal.svc = _drive() + try: + leden = _leden(lokaal.svc, d['id']) + alle_leden[d['id']] = leden + return _samenvatting(d, leden, domeinen) + except Exception as e: + r = _samenvatting(d, [], domeinen) + r['fout'] = vriendelijk(e) + return r + + with ThreadPoolExecutor(max_workers=6) as pool: + uit = list(pool.map(info, drives)) + uit.sort(key=lambda d: d['naam'].lower()) + nu = time.time() + school.cache['gedeelde_drives'] = (nu, uit) + school.cache['gedeelde_drives_leden'] = alle_leden + return uit, nu + + +def _vergeet(): + huidige_school().cache.pop('gedeelde_drives', None) + + +def drive(drive_id): + """(drive-info, leden) van één drive. Leden gesorteerd: beheerders eerst, dan op naam.""" + svc = _drive() + try: + d = svc.drives().get(driveId=drive_id, useDomainAdminAccess=True, fields='id,name,createdTime,hidden').execute() + leden = _leden(svc, drive_id) + except Exception as e: + raise DriveFout(vriendelijk(e)) + domeinen = _eigen_domeinen() + volgorde = {r: i for i, (r, _) in enumerate(ROLLEN)} + rijen = [{'id': p['id'], 'type': p.get('type'), 'rol': p.get('role'), 'rol_naam': ROL_NAAM.get(p.get('role'), p.get('role')), + 'email': p.get('emailAddress') or (p.get('domain') if p.get('type') == 'domain' else ''), + 'naam': p.get('displayName') or '', 'extern': _is_extern(p, domeinen), 'verwijderd': bool(p.get('deleted'))} + for p in leden] + rijen.sort(key=lambda r: (volgorde.get(r['rol'], 9), (r['naam'] or r['email']).lower())) + return _samenvatting(d, leden, domeinen), rijen + + +def _soort(email): + """'group' als het adres een Google-groep is, anders 'user'.""" + try: + from googleapiclient.discovery import build + creds = google_credentials(Config.GOOGLE_API_SCOPES, subject=Config.GOOGLE_ADMIN_EMAIL) + build('admin', 'directory_v1', credentials=creds, static_discovery=False, cache_discovery=False) \ + .groups().get(groupKey=email, fields='id').execute() + return 'group' + except Exception: + return 'user' + + +def lid_toevoegen(drive_id, email, rol, melding=False): + email = (email or '').strip().lower() + if '@' not in email: + raise DriveFout("Geef een geldig e-mailadres (persoon of groep).") + if rol not in ROL_NAAM: + raise DriveFout("Onbekende rol.") + try: + _drive().permissions().create(fileId=drive_id, supportsAllDrives=True, useDomainAdminAccess=True, + sendNotificationEmail=bool(melding), fields='id', + body={'type': _soort(email), 'role': rol, 'emailAddress': email}).execute() + except Exception as e: + raise DriveFout(vriendelijk(e)) + _vergeet() + + +def lid_wijzigen(drive_id, perm_id, rol): + if rol not in ROL_NAAM: + raise DriveFout("Onbekende rol.") + try: + _drive().permissions().update(fileId=drive_id, permissionId=perm_id, supportsAllDrives=True, + useDomainAdminAccess=True, body={'role': rol}, fields='id').execute() + except Exception as e: + raise DriveFout(vriendelijk(e)) + _vergeet() + + +def lid_verwijderen(drive_id, perm_id): + try: + _drive().permissions().delete(fileId=drive_id, permissionId=perm_id, supportsAllDrives=True, + useDomainAdminAccess=True).execute() + except Exception as e: + raise DriveFout(vriendelijk(e)) + _vergeet() + + +def drive_maken(naam, beheerder=None): + """Nieuwe gedeelde drive (de PIVOT-beheerder wordt eerst beheerder); optioneel meteen een andere beheerder.""" + naam = (naam or '').strip() + if not naam: + raise DriveFout("Geef de drive een naam.") + try: + d = _drive().drives().create(requestId=str(uuid.uuid4()), body={'name': naam[:100]}, fields='id,name').execute() + except Exception as e: + raise DriveFout(vriendelijk(e)) + _vergeet() + if beheerder: + lid_toevoegen(d['id'], beheerder, 'organizer') + return d['id'] + + +# --------------------------------------------------------------------- +# Een gebruiker op alle gedeelde drives vervangen door een andere +# --------------------------------------------------------------------- +def drives_van(email, vernieuw=True): + """Alle gedeelde drives waar `email` lid van is: [{drive, naam, perm, rol, rol_naam}] (vers opgehaald).""" + email = (email or '').strip().lower() + drives, _ = overzicht(vernieuw=vernieuw) + leden = huidige_school().cache.get('gedeelde_drives_leden') or {} + uit = [] + for d in drives: + for p in leden.get(d['id'], []): + adres = (p.get('emailAddress') or '').lower() + # Met een @: exact dat adres; zonder @: een deel van het adres of de naam (bv. 'peeters') + if adres == email or ('@' not in email and email and + (email in adres or email in (p.get('displayName') or '').lower())): + uit.append({'drive': d['id'], 'naam': d['naam'], 'perm': p['id'], 'rol': p.get('role'), + 'rol_naam': ROL_NAAM.get(p.get('role'), p.get('role')), 'email': adres, + 'wie': p.get('displayName') or adres}) + return uit + + +def vervang(oud, nieuw, drive_ids, oud_verwijderen=True, melding=False): + """Op elke gekozen drive: `nieuw` krijgt exact de rol van `oud` (ook als hij al lid was), daarna wordt `oud` + verwijderd (optioneel). Geeft [{naam, ok, melding}].""" + oud, nieuw = (oud or '').strip().lower(), (nieuw or '').strip().lower() + if '@' not in nieuw: + raise DriveFout("Geef een geldig e-mailadres voor de nieuwe gebruiker.") + if oud == nieuw: + raise DriveFout("De oude en de nieuwe gebruiker zijn dezelfde.") + svc, soort, uit = _drive(), _soort(nieuw), [] + kies = set(drive_ids) + for t in drives_van(oud, vernieuw=False): + if t['drive'] not in kies: + continue + try: + leden = _leden(svc, t['drive']) + bestaand = next((p for p in leden if (p.get('emailAddress') or '').lower() == nieuw), None) + if bestaand is None: + svc.permissions().create(fileId=t['drive'], supportsAllDrives=True, useDomainAdminAccess=True, + sendNotificationEmail=bool(melding), fields='id', + body={'type': soort, 'role': t['rol'], 'emailAddress': nieuw}).execute() + tekst = f"{nieuw} toegevoegd als {t['rol_naam']}" + elif bestaand.get('role') != t['rol']: # altijd exact dezelfde rechten als de oude gebruiker + svc.permissions().update(fileId=t['drive'], permissionId=bestaand['id'], supportsAllDrives=True, + useDomainAdminAccess=True, body={'role': t['rol']}, fields='id').execute() + tekst = f"{nieuw} was al lid, nu {t['rol_naam']}" + else: + tekst = f"{nieuw} was al lid ({ROL_NAAM.get(bestaand.get('role'))})" + if oud_verwijderen: + svc.permissions().delete(fileId=t['drive'], permissionId=t['perm'], supportsAllDrives=True, + useDomainAdminAccess=True).execute() + tekst += f", {oud} verwijderd" + uit.append({'naam': t['naam'], 'ok': True, 'melding': tekst}) + except Exception as e: + uit.append({'naam': t['naam'], 'ok': False, 'melding': vriendelijk(e)}) + _vergeet() + return uit diff --git a/services/gmail_delegatie_overzicht.py b/services/gmail_delegatie_overzicht.py new file mode 100644 index 0000000..1c732c3 --- /dev/null +++ b/services/gmail_delegatie_overzicht.py @@ -0,0 +1,169 @@ +""" +Overzicht van alle lopende e-mailmachtigingen (Gmail-delegaties) van de school. + +Google heeft geen lijst "alle delegaties van het domein": je kan ze enkel per mailbox opvragen +(users.settings.delegates.list, in naam van de eigenaar). Daarom loopt er een achtergrondtaak die +alle actieve (niet-geschorste) gebruikers afgaat, met een paar parallelle verzoeken. +Het resultaat komt in de tabel gmail_delegaties en wordt: + - volledig vernieuwd met de knop op de pagina, of vanzelf als het ouder is dan VERVERS_UREN; + - meteen bijgewerkt als in PIVOT een machtiging toegevoegd of ingetrokken wordt, of als je een mailbox opent. +""" +import sys +import threading +from concurrent.futures import ThreadPoolExecutor +from datetime import datetime + +from database import execute_query +from tenancy import school_singleton, met_school, huidige_school, in_school + +VERVERS_UREN = 24 +PARALLEL = 8 + + +class DelegatieOverzicht: + def __new__(cls): + def init(inst): + inst._lock = threading.Lock() + inst.status = {'bezig': False, 'voortgang': 0, 'totaal': 0, 'fout': None, 'resultaat': None} + return school_singleton(cls, init) + + @staticmethod + def ensure_table(): + execute_query(""" + CREATE TABLE IF NOT EXISTS gmail_delegaties ( + Mailbox VARCHAR(255) NOT NULL, + Mailbox_naam VARCHAR(255) NULL, + Gedelegeerde VARCHAR(255) NOT NULL, + Gedelegeerde_naam VARCHAR(255) NULL, + Status VARCHAR(20) NULL, + Opgehaald DATETIME NOT NULL, + PRIMARY KEY (Mailbox, Gedelegeerde), + KEY idx_gmail_deleg_gedelegeerde (Gedelegeerde) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", commit=True) + execute_query("CREATE TABLE IF NOT EXISTS gmail_delegaties_scan (ID TINYINT NOT NULL PRIMARY KEY, " + "Opgehaald DATETIME NULL, Mailboxen INT NULL, Fouten INT NULL) ENGINE=InnoDB", commit=True) + + # ---------------- opvragen ---------------- + def alle(self): + return execute_query("SELECT * FROM gmail_delegaties ORDER BY Mailbox, Gedelegeerde") or [] + + def laatst_opgehaald(self): + rij = execute_query("SELECT Opgehaald, Mailboxen, Fouten FROM gmail_delegaties_scan WHERE ID = 1") + return rij[0] if rij else None + + def verouderd(self): + laatst = self.laatst_opgehaald() + return not laatst or not laatst['Opgehaald'] or \ + (datetime.now() - laatst['Opgehaald']).total_seconds() > VERVERS_UREN * 3600 + + # ---------------- één mailbox bijwerken (na toevoegen/intrekken/openen in PIVOT) ---------------- + def bewaar_mailbox(self, mailbox, naam, delegates, namen=None): + """Vervangt de rijen van één mailbox door de opgegeven gedelegeerden [{'email','status'}].""" + try: + self.ensure_table() + # Namen die we al kennen (uit de volledige ophaling) behouden + bekend = {} + for r in execute_query("SELECT Mailbox, Mailbox_naam, Gedelegeerde, Gedelegeerde_naam FROM gmail_delegaties") or []: + if r['Mailbox_naam']: + bekend[r['Mailbox'].lower()] = r['Mailbox_naam'] + if r['Gedelegeerde_naam']: + bekend[r['Gedelegeerde'].lower()] = r['Gedelegeerde_naam'] + namen = {**bekend, **(namen or {})} + execute_query("DELETE FROM gmail_delegaties WHERE Mailbox = %s", (mailbox,), commit=True) + for d in delegates: + execute_query("INSERT INTO gmail_delegaties (Mailbox, Mailbox_naam, Gedelegeerde, Gedelegeerde_naam, " + "Status, Opgehaald) VALUES (%s, %s, %s, %s, %s, NOW())", + (mailbox, naam, d['email'], namen.get(d['email'].lower()) or d.get('naam'), + d.get('status')), commit=True) + except Exception as e: + sys.stderr.write(f"Delegaties: mailbox {mailbox} niet bewaard: {e}\n") + + # ---------------- alles ophalen uit Google ---------------- + def _gebruikers(self, directory): + uit, token = [], None + while True: + resp = directory.users().list(customer='my_customer', maxResults=500, pageToken=token, + fields='nextPageToken,users(primaryEmail,name/fullName,suspended)').execute() + for u in resp.get('users', []): + uit.append({'email': u['primaryEmail'].lower(), 'naam': (u.get('name') or {}).get('fullName', ''), + 'geschorst': bool(u.get('suspended'))}) + token = resp.get('nextPageToken') + if not token: + return uit + + def sync(self): + if not self._lock.acquire(blocking=False): + return False, "Er loopt al een ophaling." + try: + from services.gmail_delegation_service import GmailDelegationService, DelegationError + self.status.update(bezig=True, voortgang=0, totaal=0, fout=None, resultaat=None) + self.ensure_table() + svc = GmailDelegationService() + gebruikers = self._gebruikers(svc._directory_api()) + namen = {u['email']: u['naam'] for u in gebruikers} + actief = [u for u in gebruikers if not u['geschorst']] + self.status['totaal'] = len(actief) + school = huidige_school() + fouten, rechtenfout, gelukt = [], [], [] + + def een(u): + # Krijgt Google telkens dezelfde rechtenfout, dan niet alle gebruikers blijven proberen + if len(rechtenfout) >= 3 and not gelukt: + self.status['voortgang'] += 1 + return u, None + with in_school(school): + try: + delegates = svc.list_delegates(u['email']) + gelukt.append(1) + return u, delegates + except DelegationError as e: + tekst = str(e) + if 'serviceaccount mist een Gmail-recht' in tekst or 'Gmail API staat nog niet aan' in tekst: + rechtenfout.append(tekst) + fouten.append(u['email']) + return u, None + except Exception: + fouten.append(u['email']) + return u, None + finally: + self.status['voortgang'] += 1 + + resultaten = [] + with ThreadPoolExecutor(max_workers=PARALLEL) as pool: + for u, delegates in pool.map(een, actief): + if delegates: + resultaten.append((u, delegates)) + if rechtenfout and not gelukt: + raise RuntimeError(rechtenfout[0]) + + nu = datetime.now() + execute_query("DELETE FROM gmail_delegaties", commit=True) + aantal = 0 + for u, delegates in resultaten: + for d in delegates: + execute_query("INSERT INTO gmail_delegaties (Mailbox, Mailbox_naam, Gedelegeerde, Gedelegeerde_naam, " + "Status, Opgehaald) VALUES (%s, %s, %s, %s, %s, %s)", + (u['email'], u['naam'], d['email'], namen.get(d['email'].lower()), d['status'], nu), + commit=True) + aantal += 1 + execute_query("INSERT INTO gmail_delegaties_scan (ID, Opgehaald, Mailboxen, Fouten) VALUES (1, %s, %s, %s) " + "ON DUPLICATE KEY UPDATE Opgehaald = VALUES(Opgehaald), Mailboxen = VALUES(Mailboxen), " + "Fouten = VALUES(Fouten)", (nu, len(actief), len(fouten)), commit=True) + msg = f"{len(actief)} mailboxen nagekeken: {aantal} machtiging(en) bij {len(resultaten)} mailbox(en)." + if fouten: + msg += f" {len(fouten)} mailbox(en) konden niet bevraagd worden (bv. zonder Gmail-licentie)." + self.status['resultaat'] = msg + return True, msg + except Exception as e: + self.status['fout'] = str(e) + return False, f"Ophalen mislukt: {e}" + finally: + self.status['bezig'] = False + self._lock.release() + + def sync_op_achtergrond(self): + if self.status['bezig']: + return False + self.status.update(bezig=True, voortgang=0, totaal=0, fout=None) + threading.Thread(target=met_school(self.sync), daemon=True).start() + return True diff --git a/services/gmail_delegation_service.py b/services/gmail_delegation_service.py new file mode 100644 index 0000000..467f4d3 --- /dev/null +++ b/services/gmail_delegation_service.py @@ -0,0 +1,199 @@ +""" +Gmail-delegatie: andere gebruikers toegang geven tot een mailbox. + +Werkt via de Gmail API (users.settings.delegates). Het service-account handelt +in naam van de EIGENAAR van de mailbox (de delegator). + +Vereist (eenmalig): + 1. Admin-console › Beveiliging › API-beheer › Domeinbrede delegatie: + scope toevoegen aan het service-account: + https://www.googleapis.com/auth/gmail.settings.sharing + 2. Admin-console › Apps › Google Workspace › Gmail › Gebruikersinstellingen: + 'E-maildelegatie' inschakelen voor de betrokken organisatie-eenheden. + +Beperkingen van Google: + - de gedelegeerde moet in dezelfde Google Workspace-organisatie zitten + - max. 25 gedelegeerden per mailbox, max. 10 mailboxen per gedelegeerde + - het kan tot 1 minuut duren voor de toegang actief is +""" +import sys +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError +from config import Config +from database import execute_query +from tenancy import google_credentials + +# Toevoegen/verwijderen van gedelegeerden: gmail.settings.sharing. +# Opvragen (delegates.list/get): gmail.settings.basic (sharing volstaat daar NIET). +GMAIL_SCOPE = 'https://www.googleapis.com/auth/gmail.settings.sharing' +GMAIL_LEES_SCOPE = 'https://www.googleapis.com/auth/gmail.settings.basic' +MAX_DELEGATES = 25 + +STATUS_LABELS = { + 'accepted': 'Actief', + 'pending': 'In afwachting', + 'rejected': 'Geweigerd', + 'expired': 'Verlopen', +} + + +class DelegationError(Exception): + pass + + +class GmailDelegationService: + def __init__(self, directory_service=None): + # Bestaande Directory-client hergebruiken om adressen/aliassen op te zoeken + self._directory = directory_service + + # ---------- clients ---------- + def _gmail_for(self, mailbox, scope=GMAIL_SCOPE): + creds = google_credentials([scope], subject=mailbox) + try: # meegeleverde API-beschrijving: geen extra verzoek naar Google per mailbox + return build('gmail', 'v1', credentials=creds, static_discovery=True, cache_discovery=False) + except Exception: + return build('gmail', 'v1', credentials=creds, static_discovery=False, cache_discovery=False) + + def _directory_api(self): + if self._directory is None: + from services.google_service import GoogleAdminService + self._directory = GoogleAdminService().service + return self._directory + + # ---------- hulpfuncties ---------- + @staticmethod + def _friendly_error(e, mailbox=None, delegate=None): + msg = str(e) + status = getattr(getattr(e, 'resp', None), 'status', None) + if 'unauthorized_client' in msg or 'access_denied' in msg or 'insufficient authentication scopes' in msg.lower(): + return ("Google weigert de toegang: het serviceaccount mist een Gmail-recht. Voeg in admin.google.com › " + "Beveiliging › Toegangs- en gegevensbeheer › API-beheer › Domeinbrede delegatie bij het serviceaccount " + f"deze twee bereiken toe: {GMAIL_LEES_SCOPE} en {GMAIL_SCOPE}. Het kan enkele minuten duren voor dit werkt.") + if status == 409: + return f"{delegate} heeft al toegang tot {mailbox}." + laag = msg.lower() + reden = msg.split('returned', 1)[-1].strip(' ">')[:200] if 'returned' in msg else msg[:200] + if 'has not been used' in laag or 'is disabled' in laag or 'accessnotconfigured' in laag: + return ("De Gmail API staat nog niet aan in het Google Cloud-project van het serviceaccount " + "(console.cloud.google.com › API's en services › Bibliotheek › Gmail API › Inschakelen). " + f"Google: {reden}") + if 'mail service not enabled' in laag or 'failedprecondition' in laag or 'precondition' in laag: + return (f"{mailbox or 'Deze gebruiker'} heeft (nog) geen werkende Gmail-mailbox: controleer of Gmail aanstaat " + "en of de gebruiker een licentie heeft. Een net aangemaakt account kan tot 24 uur nodig hebben. " + f"Google: {reden}") + if 'delegation denied' in laag or 'not allowed' in laag or 'delegation is not allowed' in laag: + return ("Delegatie is niet toegestaan voor deze gebruiker. Controleer of 'E-maildelegatie' aanstaat " + "(Admin-console › Apps › Google Workspace › Gmail › Gebruikersinstellingen) voor de OU van de " + "mailbox én van de gedelegeerde. Een gewijzigde instelling kan tot 24 uur nodig hebben. " + f"Google: {reden}") + if status == 403: + return f"Google weigert deze actie (403). Google: {reden}" + if status == 400 and 'limit' in msg.lower(): + return "Limiet bereikt: max. 25 gedelegeerden per mailbox en max. 10 mailboxen per gedelegeerde." + if status == 400: + return f"Google weigert deze delegatie: {getattr(e, 'reason', '') or msg}" + if status == 404: + return "Gebruiker of delegatie niet gevonden." + return msg + + def resolve_user(self, email): + """Zoekt de gebruiker op in Google en geeft het PRIMAIRE adres terug (aliassen werken niet bij delegatie).""" + email = (email or '').strip().lower() + if not email or '@' not in email: + raise DelegationError("Geef een volledig e-mailadres op.") + try: + u = self._directory_api().users().get(userKey=email).execute() + except HttpError as e: + if getattr(e.resp, 'status', None) == 404: + raise DelegationError(f"{email} bestaat niet in jullie Google Workspace. " + "Delegeren naar externe (bv. @gmail.com) adressen kan niet.") + raise DelegationError(self._friendly_error(e)) + return { + 'email': u['primaryEmail'].lower(), + 'naam': (u.get('name') or {}).get('fullName', ''), + 'ou': u.get('orgUnitPath', ''), + 'geschorst': bool(u.get('suspended')), + 'is_alias': u['primaryEmail'].lower() != email, + } + + def search_users(self, query): + """Gebruikers zoeken op naam of adres (voor de zoekbox).""" + q = query.strip() + try: + resp = self._directory_api().users().list( + customer='my_customer', query=q, maxResults=15, orderBy='email').execute() + except Exception as e: + sys.stderr.write(f"Zoeken mislukt: {e}\n") + return [] + return [{'email': u['primaryEmail'], 'naam': (u.get('name') or {}).get('fullName', ''), + 'ou': u.get('orgUnitPath', '')} for u in resp.get('users', [])] + + # ---------- delegaties ---------- + def list_delegates(self, mailbox): + try: + resp = self._gmail_for(mailbox, GMAIL_LEES_SCOPE).users().settings().delegates().list(userId='me').execute() + except HttpError as e: + raise DelegationError(self._friendly_error(e, mailbox)) + except Exception as e: + raise DelegationError(self._friendly_error(e, mailbox)) + result = [] + for d in resp.get('delegates', []): + status = d.get('verificationStatus', '') + result.append({'email': d.get('delegateEmail', ''), + 'status': status, + 'status_label': STATUS_LABELS.get(status, status)}) + result.sort(key=lambda d: d['email']) + return result + + def add_delegate(self, mailbox, delegate): + if mailbox == delegate: + raise DelegationError("Een mailbox kan niet aan zichzelf gedelegeerd worden.") + try: + self._gmail_for(mailbox).users().settings().delegates().create( + userId='me', body={'delegateEmail': delegate}).execute() + except HttpError as e: + raise DelegationError(self._friendly_error(e, mailbox, delegate)) + except Exception as e: + raise DelegationError(self._friendly_error(e, mailbox, delegate)) + + def remove_delegate(self, mailbox, delegate): + try: + self._gmail_for(mailbox).users().settings().delegates().delete( + userId='me', delegateEmail=delegate).execute() + except HttpError as e: + raise DelegationError(self._friendly_error(e, mailbox, delegate)) + except Exception as e: + raise DelegationError(self._friendly_error(e, mailbox, delegate)) + + # ---------- logboek ---------- + @staticmethod + def ensure_table(): + execute_query(""" + CREATE TABLE IF NOT EXISTS gmail_delegatie_log ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Tijdstip DATETIME NOT NULL, + Gebruiker VARCHAR(100) NULL, + Actie VARCHAR(20) NOT NULL, + Mailbox VARCHAR(255) NOT NULL, + Gedelegeerde VARCHAR(255) NOT NULL, + INDEX idx_mailbox (Mailbox), + INDEX idx_tijdstip (Tijdstip) + )""", commit=True) + + @staticmethod + def log(gebruiker, actie, mailbox, gedelegeerde): + execute_query( + "INSERT INTO gmail_delegatie_log (Tijdstip, Gebruiker, Actie, Mailbox, Gedelegeerde) " + "VALUES (NOW(), %s, %s, %s, %s)", + (gebruiker, actie, mailbox, gedelegeerde), commit=True) + + @staticmethod + def history(mailbox=None, limit=25): + if mailbox: + return execute_query( + "SELECT Tijdstip, Gebruiker, Actie, Mailbox, Gedelegeerde FROM gmail_delegatie_log " + "WHERE Mailbox = %s OR Gedelegeerde = %s ORDER BY Tijdstip DESC LIMIT %s", + (mailbox, mailbox, int(limit))) + return execute_query( + "SELECT Tijdstip, Gebruiker, Actie, Mailbox, Gedelegeerde FROM gmail_delegatie_log " + "ORDER BY Tijdstip DESC LIMIT %s", (int(limit),)) diff --git a/services/gmail_label_service.py b/services/gmail_label_service.py new file mode 100644 index 0000000..046622e --- /dev/null +++ b/services/gmail_label_service.py @@ -0,0 +1,237 @@ +""" +Google › E-mails met een label verplaatsen: alle berichten met een bepaald label uit een mailbox kopiëren of +verplaatsen naar een andere mailbox van dezelfde Google Workspace. + +Werking (Gmail API, het serviceaccount werkt in naam van de mailbox via domeinbrede delegatie): +1. bron: users.messages.list(labelIds=[label]) → alle berichten met het label +2. bron: users.messages.get(format=raw) → het volledige bericht (met bijlagen, datum, afzender ...) +3. doel: users.messages.import(raw, labelIds=[...]) → in de doelmailbox, onder hetzelfde label + (de originele datum blijft, geen spamfilter; gelezen/ongelezen en ster gaan mee) +4. bij 'verplaatsen': bron: users.messages.trash → in de bronmailbox naar de prullenbak (30 dagen terug te halen) +Elk bericht dat al gekopieerd werd naar dezelfde doelmailbox, wordt overgeslagen (tabel gmail_label_items), +zodat je een onderbroken opdracht gewoon opnieuw kan starten. + +Vereist (eenmalig, Admin-console › Beveiliging › API-beheer › Domeinbrede delegatie, bij het serviceaccount): + https://www.googleapis.com/auth/gmail.modify +""" +import sys +import threading +import time +from datetime import datetime + +from database import execute_query +from tenancy import school_singleton, met_school, google_credentials + +SCOPE = 'https://www.googleapis.com/auth/gmail.modify' +MEEGAAN = ('UNREAD', 'STARRED', 'IMPORTANT') # systeemlabels die mee naar de doelmailbox gaan + + +class LabelFout(Exception): + pass + + +def _gmail(mailbox): + from googleapiclient.discovery import build + creds = google_credentials([SCOPE], subject=mailbox) + try: + return build('gmail', 'v1', credentials=creds, static_discovery=True, cache_discovery=False) + except Exception: + return build('gmail', 'v1', credentials=creds, static_discovery=False, cache_discovery=False) + + +def vriendelijk(e, mailbox=None): + tekst = str(e) + laag = tekst.lower() + if 'unauthorized_client' in laag or 'insufficient' in laag or 'access_denied' in laag: + return ("Google weigert de toegang: het serviceaccount mist het Gmail-recht om berichten te lezen en te " + "importeren. Voeg in admin.google.com › Beveiliging › Toegangs- en gegevensbeheer › API-beheer › " + f"Domeinbrede delegatie bij het serviceaccount dit bereik toe: {SCOPE} (het kan enkele minuten duren).") + if 'has not been used' in laag or 'is disabled' in laag or 'accessnotconfigured' in laag: + return ("De Gmail API staat nog niet aan in het Google Cloud-project van het serviceaccount " + "(console.cloud.google.com › API's en services › Bibliotheek › Gmail API › Inschakelen).") + if 'mail service not enabled' in laag or 'failedprecondition' in laag: + return f"{mailbox or 'Deze gebruiker'} heeft geen werkende Gmail-mailbox (geen licentie of Gmail uitgeschakeld)." + if 'notfound' in laag.replace(' ', '') or ' 404' in tekst: + return "Niet gevonden (bestaat de mailbox of het label nog?)." + return tekst[:300] + + +def ensure_tables(): + execute_query(""" + CREATE TABLE IF NOT EXISTS gmail_label_log ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Gestart DATETIME NOT NULL, + Klaar DATETIME NULL, + Door VARCHAR(255) NULL, + Bron VARCHAR(255) NOT NULL, + Label VARCHAR(255) NOT NULL, + Doel VARCHAR(255) NOT NULL, + Modus VARCHAR(12) NOT NULL, + Totaal INT NULL, + Gelukt INT NULL, + Overgeslagen INT NULL, + Fouten INT NULL, + Melding VARCHAR(500) NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", commit=True) + execute_query(""" + CREATE TABLE IF NOT EXISTS gmail_label_items ( + Bron VARCHAR(255) NOT NULL, + Bron_ID VARCHAR(64) NOT NULL, + Doel VARCHAR(255) NOT NULL, + Doel_ID VARCHAR(64) NULL, + Gekopieerd DATETIME NOT NULL, + PRIMARY KEY (Bron, Bron_ID, Doel) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", commit=True) + + +def labels(mailbox): + """Eigen labels van een mailbox, met het aantal berichten: [{'id', 'naam', 'aantal'}], alfabetisch.""" + try: + g = _gmail(mailbox) + lijst = g.users().labels().list(userId='me').execute().get('labels', []) + uit = [] + for l in lijst: + if l.get('type') != 'user': + continue + try: + info = g.users().labels().get(userId='me', id=l['id']).execute() + aantal = info.get('messagesTotal') + except Exception: + aantal = None + uit.append({'id': l['id'], 'naam': l.get('name', ''), 'aantal': aantal}) + except Exception as e: + raise LabelFout(vriendelijk(e, mailbox)) + return sorted(uit, key=lambda l: l['naam'].lower()) + + +def geschiedenis(limiet=20): + ensure_tables() + return execute_query("SELECT * FROM gmail_label_log ORDER BY Gestart DESC LIMIT %s", (int(limiet),)) or [] + + +class LabelVerplaatser: + def __new__(cls): + def init(inst): + inst._lock = threading.Lock() + inst.status = {'bezig': False, 'voortgang': 0, 'totaal': 0, 'gelukt': 0, 'overgeslagen': 0, 'fouten': 0, + 'fout': None, 'resultaat': None, 'opdracht': None, 'foutvoorbeelden': []} + return school_singleton(cls, init) + + # ---------------- hulpfuncties ---------------- + @staticmethod + def _alle_ids(g, label_id): + ids, token = [], None + while True: + resp = g.users().messages().list(userId='me', labelIds=[label_id], maxResults=500, pageToken=token, + includeSpamTrash=False).execute() + ids += [m['id'] for m in resp.get('messages', [])] + token = resp.get('nextPageToken') + if not token: + return ids + + @staticmethod + def _doel_label(g, naam): + """Id van het label `naam` in de doelmailbox (aangemaakt als het nog niet bestaat, ook sublabels).""" + bestaand = {l['name']: l['id'] for l in g.users().labels().list(userId='me').execute().get('labels', [])} + if naam in bestaand: + return bestaand[naam] + # Bovenliggende labels eerst aanmaken (A, A/B, A/B/C), zodat de nesting in Gmail klopt + delen = naam.split('/') + for i in range(1, len(delen) + 1): + pad = '/'.join(delen[:i]) + if pad not in bestaand: + nieuw = g.users().labels().create(userId='me', body={ + 'name': pad, 'labelListVisibility': 'labelShow', 'messageListVisibility': 'show'}).execute() + bestaand[pad] = nieuw['id'] + return bestaand[naam] + + @staticmethod + def _herhaal(fn, pogingen=4): + """Google-aanroep met een paar nieuwe pogingen bij 429/5xx (te snel / tijdelijk).""" + for poging in range(pogingen): + try: + return fn() + except Exception as e: + status = getattr(getattr(e, 'resp', None), 'status', None) + if status in (429, 500, 502, 503) and poging < pogingen - 1: + time.sleep(2 ** poging) + continue + raise + + # ---------------- opdracht ---------------- + def run(self, bron, label_id, label_naam, doel, modus, door): + if not self._lock.acquire(blocking=False): + return False, "Er loopt al een opdracht." + log_id = None + try: + ensure_tables() + self.status.update(bezig=True, voortgang=0, totaal=0, gelukt=0, overgeslagen=0, fouten=0, prullenbak=0, fout=None, + resultaat=None, foutvoorbeelden=[], + opdracht={'bron': bron, 'label': label_naam, 'doel': doel, 'modus': modus}) + execute_query("INSERT INTO gmail_label_log (Gestart, Door, Bron, Label, Doel, Modus) " + "VALUES (NOW(), %s, %s, %s, %s, %s)", (door, bron, label_naam, doel, modus), commit=True) + log_id = (execute_query("SELECT MAX(ID) AS id FROM gmail_label_log WHERE Bron = %s AND Doel = %s", + (bron, doel)) or [{}])[0].get('id') + try: + gb, gd = _gmail(bron), _gmail(doel) + ids = self._alle_ids(gb, label_id) + doel_label = self._doel_label(gd, label_naam) + except Exception as e: + raise LabelFout(vriendelijk(e)) + self.status['totaal'] = len(ids) + al = {r['Bron_ID'] for r in execute_query( + "SELECT Bron_ID FROM gmail_label_items WHERE Bron = %s AND Doel = %s", (bron, doel)) or []} + for mid in ids: + try: + if mid in al: + self.status['overgeslagen'] += 1 + else: + bericht = self._herhaal(lambda: gb.users().messages().get(userId='me', id=mid, format='raw').execute()) + extra = [l for l in bericht.get('labelIds', []) if l in MEEGAAN] + nieuw = self._herhaal(lambda: gd.users().messages().import_( + userId='me', body={'raw': bericht['raw'], 'labelIds': [doel_label] + extra}, + internalDateSource='dateHeader', neverMarkSpam=True, processForCalendar=False).execute()) + execute_query("INSERT IGNORE INTO gmail_label_items (Bron, Bron_ID, Doel, Doel_ID, Gekopieerd) " + "VALUES (%s, %s, %s, %s, NOW())", (bron, mid, doel, nieuw.get('id')), commit=True) + self.status['gelukt'] += 1 + if modus == 'verplaatsen': + self._herhaal(lambda: gb.users().messages().trash(userId='me', id=mid).execute()) + self.status['prullenbak'] = self.status.get('prullenbak', 0) + 1 + except Exception as e: + self.status['fouten'] += 1 + if len(self.status['foutvoorbeelden']) < 5: + self.status['foutvoorbeelden'].append(vriendelijk(e)[:200]) + sys.stderr.write(f"Label verplaatsen {bron} → {doel}, bericht {mid}: {e}\n") + self.status['voortgang'] += 1 + s = self.status + msg = f"Label '{label_naam}' van {bron} naar {doel}: {s['gelukt']} bericht(en) gekopieerd" + if s['overgeslagen']: + msg += f", {s['overgeslagen']} stonden er al" + if modus == 'verplaatsen': + msg += f", {s.get('prullenbak', 0)} in de bronmailbox naar de prullenbak" + if s['fouten']: + msg += f", {s['fouten']} mislukt" + s['resultaat'] = msg + '.' + return True, s['resultaat'] + except Exception as e: + self.status['fout'] = vriendelijk(e) + return False, self.status['fout'] + finally: + s = self.status + if log_id: + try: + execute_query("UPDATE gmail_label_log SET Klaar = NOW(), Totaal = %s, Gelukt = %s, Overgeslagen = %s, " + "Fouten = %s, Melding = %s WHERE ID = %s", + (s['totaal'], s['gelukt'], s['overgeslagen'], s['fouten'], + (s['fout'] or s['resultaat'] or '')[:500], log_id), commit=True) + except Exception: + pass + s['bezig'] = False + self._lock.release() + + def start(self, *args): + if self.status['bezig']: + return False + self.status.update(bezig=True, voortgang=0, totaal=0, fout=None, resultaat=None) + threading.Thread(target=met_school(lambda: self.run(*args)), daemon=True).start() + return True diff --git a/services/google_license_service.py b/services/google_license_service.py new file mode 100644 index 0000000..354dc1e --- /dev/null +++ b/services/google_license_service.py @@ -0,0 +1,276 @@ +""" +Google Workspace for Education – licentie-overzicht. + +Haalt via de Enterprise License Manager API op welke gebruikers een +licentie hebben. Google geeft het aantal AANGEKOCHTE licenties niet vrij +via de API; dat aantal wordt in PIVOT bijgehouden (tabel google_licenties) +en door een admin ingevuld. + +Vereist (eenmalig, Google Admin-console): + Beveiliging > Toegangs- en gegevensbeheer > API-beheer > + Domeinbrede delegatie > service-account bewerken en deze scope toevoegen: + https://www.googleapis.com/auth/apps.licensing +""" +import sys +import time +from googleapiclient.discovery import build +from config import Config +from database import execute_query +from tenancy import google_credentials + +LICENSING_SCOPE = 'https://www.googleapis.com/auth/apps.licensing' + +# Product- en SKU-ID's volgens Google: +# https://developers.google.com/workspace/admin/licensing/v1/how-tos/products +EDU_PRODUCT_ID = '101031' +SKU_NAMES = { + '1010310008': 'Education Plus', + '1010310009': 'Education Plus (Staff)', + '1010310010': 'Education Plus (Extra Student)', + '1010310005': 'Education Standard', + '1010310006': 'Education Standard (Staff)', + '1010310007': 'Education Standard (Extra Student)', +} +# Deze SKU's worden altijd getoond, ook als er (nog) niemand een licentie heeft +DEFAULT_SKUS = ['1010310008'] +# Licenties die de scholengroep niet gebruikt: niet tonen, tenzij iemand er toch (per vergissing) één heeft +VERBORGEN_SKUS = {'1010310009'} # Education Plus (Staff) + +CACHE_SECONDS = 10 * 60 + + +def _soort_fout(e): + """'scope' = delegatie/scope ontbreekt, 'api' = API niet ingeschakeld, anders None.""" + laag = str(e).lower() + if 'unauthorized_client' in laag or 'access_denied' in laag or 'invalid_scope' in laag: + return 'scope' + if 'accessnotconfigured' in laag or 'has not been used' in laag or 'is disabled' in laag \ + or 'service_disabled' in laag: + return 'api' + return None + + +def _google_reden(e): + """De foutboodschap van Google zelf (zonder de lange URL).""" + try: + import json + inhoud = json.loads(getattr(e, 'content', b'') or b'{}') + fout = inhoud.get('error') or {} + if isinstance(fout, dict) and fout.get('message'): + return f"{getattr(getattr(e, 'resp', None), 'status', '')} {fout['message']}".strip() + except Exception: + pass + return str(e)[:250] + + +class GoogleLicenseService: + def __init__(self, directory_service=None): + self._cache = None # (timestamp, data) + self._licensing = None + self._klant = None # customerId die werkt + # Bestaande Directory-client hergebruiken (scopes zijn daar al geautoriseerd) + self._directory = directory_service + + # ---------- API-clients (lui aangemaakt, zodat de app ook start zonder scope) ---------- + def _creds(self, scope): + return google_credentials([scope], subject=Config.GOOGLE_ADMIN_EMAIL) + + def _licensing_api(self): + if self._licensing is None: + self._licensing = build('licensing', 'v1', credentials=self._creds(LICENSING_SCOPE), + static_discovery=False, cache_discovery=False) + return self._licensing + + def _directory_api(self): + if self._directory is None: + from services.google_service import GoogleAdminService + self._directory = GoogleAdminService().service + return self._directory + + # ---------- Database: aangekochte aantallen ---------- + @staticmethod + def ensure_table(): + execute_query(""" + CREATE TABLE IF NOT EXISTS google_licenties ( + SKU_ID VARCHAR(32) NOT NULL PRIMARY KEY, + Naam VARCHAR(128) NOT NULL, + Aangekocht INT NOT NULL DEFAULT 0, + Bijgewerkt DATETIME NULL, + Bijgewerkt_door VARCHAR(100) NULL + )""", commit=True) + + def get_purchased(self): + rows = execute_query("SELECT SKU_ID, Naam, Aangekocht, Bijgewerkt, Bijgewerkt_door FROM google_licenties") + return {r['SKU_ID']: r for r in rows} + + def set_purchased(self, sku_id, aantal, gebruiker): + naam = SKU_NAMES.get(sku_id, sku_id) + execute_query(""" + INSERT INTO google_licenties (SKU_ID, Naam, Aangekocht, Bijgewerkt, Bijgewerkt_door) + VALUES (%s, %s, %s, NOW(), %s) + ON DUPLICATE KEY UPDATE Aangekocht = VALUES(Aangekocht), Naam = VALUES(Naam), + Bijgewerkt = NOW(), Bijgewerkt_door = VALUES(Bijgewerkt_door) + """, (sku_id, naam, int(aantal), gebruiker), commit=True) + + # ---------- Google: toegewezen licenties ---------- + def _klant_kandidaten(self): + """Waarden om als customerId te proberen. De Licensing API wil het PRIMAIRE domein van de Google-klant + (of de klant-ID, bv. C01abc23d). Het domein dat in PIVOT bij de school staat, is soms een secundair domein + of alias: dan antwoordt Google met 403/400. Daarom ook de klant-ID van de beheerder proberen.""" + kandidaten = [Config.SCHOOL_DOMAIN] + try: + u = self._directory_api().users().get(userKey=Config.GOOGLE_ADMIN_EMAIL, + fields='customerId,primaryEmail').execute() + kandidaten += [u.get('customerId'), (u.get('primaryEmail') or '').partition('@')[2]] + except Exception as e: + sys.stderr.write(f"Licenties: klant-ID van de beheerder niet op te halen: {e}\n") + kandidaten.append((Config.GOOGLE_ADMIN_EMAIL or '').partition('@')[2]) + return [k for k in dict.fromkeys(k.strip() for k in kandidaten if k and k.strip())] + + def _list_assignments(self): + api = self._licensing_api() + laatste = None + for klant in (self._klant_kandidaten() if not getattr(self, '_klant', None) else [self._klant]): + assignments, token = [], None + try: + while True: + resp = api.licenseAssignments().listForProduct( + productId=EDU_PRODUCT_ID, customerId=klant, maxResults=1000, pageToken=token).execute() + assignments.extend(resp.get('items', [])) + token = resp.get('nextPageToken') + if not token: + self._klant = klant # onthouden welke waarde werkt + return assignments + except Exception as e: + status = getattr(getattr(e, 'resp', None), 'status', None) + if status not in (400, 403, 404) or _soort_fout(e) in ('scope', 'api'): + raise + sys.stderr.write(f"Licenties met customerId={klant} mislukt: {e}\n") + laatste = e + raise laatste or RuntimeError("Geen Google-klant gevonden om licenties voor op te vragen.") + + def _uitleg(self, e): + """Begrijpelijke melding met de echte reden van Google en wat je kan nakijken.""" + from tenancy import huidige_school + sleutel = huidige_school().google_sleutel or {} + client_id = sleutel.get('client_id', '?') + project = sleutel.get('project_id', '?') + admin = Config.GOOGLE_ADMIN_EMAIL + soort = _soort_fout(e) + reden = _google_reden(e) + if soort == 'scope': + return (f"Google weigert de toegang (unauthorized_client): voor client-ID {client_id} staat de scope " + f"{LICENSING_SCOPE} niet in de domeinbrede delegatie. Kijk na in de Admin-console van het domein van " + f"{admin} (Beveiliging › API-beheer › Domeinbrede delegatie) dat de scope bij exact deze client-ID " + "staat — elke school met een eigen JSON-sleutel heeft een eigen client-ID. Een wijziging kan tot " + "een uur duren.") + if soort == 'api': + return (f"De Enterprise License Manager API staat niet aan in Google Cloud-project '{project}' " + "(console.cloud.google.com › API's en services › Bibliotheek › 'Enterprise License Manager API' " + f"› Inschakelen). Google: {reden}") + return (f"Google weigert de licenties ({reden}). De delegatie zelf werkt, dus de scope is in orde. " + f"Mogelijke oorzaken: {admin} is geen hoofdbeheerder (super admin) van het domein, of het domein " + f"'{Config.SCHOOL_DOMAIN}' is niet het primaire domein van de Google-klant (ook de klant-ID werd " + f"geprobeerd), of deze school heeft geen Education Standard/Plus-licenties. Service-account: " + f"client-ID {client_id}, project '{project}'.") + + def _user_details(self): + """Alle gebruikers met OU en status, zodat we per licentie context kunnen tonen.""" + api = self._directory_api() + users, token = {}, None + while True: + resp = api.users().list( + customer='my_customer', maxResults=500, pageToken=token, + projection='basic', + fields='nextPageToken,users(primaryEmail,name/fullName,orgUnitPath,suspended,archived,lastLoginTime)' + ).execute() + for u in resp.get('users', []): + users[u['primaryEmail'].lower()] = u + token = resp.get('nextPageToken') + if not token: + return users + + def get_overview(self, force=False): + """ + Geeft (data, fout) terug. data = { + 'skus': [ {sku_id, naam, in_gebruik, aangekocht, vrij, procent, geschorst, ...}, ... ], + 'users': [ {email, naam, ou, sku_id, sku_naam, geschorst, gearchiveerd, laatste_login}, ... ], + 'opgehaald': timestamp + } + """ + if not force and self._cache and time.time() - self._cache[0] < CACHE_SECONDS: + return self._cache[1], None + + try: + assignments = self._list_assignments() + except Exception as e: + sys.stderr.write(f"Licenties ophalen mislukt: {e}\n") + self._licensing = None # volgende keer opnieuw opbouwen (bv. na een nieuwe JSON-sleutel) + self._klant = None + try: + return None, self._uitleg(e) + except Exception: + return None, str(e)[:400] + + try: + directory = self._user_details() + except Exception as e: + sys.stderr.write(f"Gebruikersdetails ophalen mislukt (niet kritisch): {e}\n") + directory = {} + + try: + purchased = self.get_purchased() + except Exception as e: + sys.stderr.write(f"Tabel google_licenties niet leesbaar: {e}\n") + purchased = {} + + users, counts, suspended_counts = [], {}, {} + for a in assignments: + sku = a.get('skuId') + email = (a.get('userId') or '').lower() + d = directory.get(email, {}) + geschorst = bool(d.get('suspended')) + gearchiveerd = bool(d.get('archived')) + counts[sku] = counts.get(sku, 0) + 1 + if geschorst or gearchiveerd: + suspended_counts[sku] = suspended_counts.get(sku, 0) + 1 + users.append({ + 'email': email, + 'naam': (d.get('name') or {}).get('fullName', ''), + 'ou': d.get('orgUnitPath', ''), + 'sku_id': sku, + 'sku_naam': SKU_NAMES.get(sku, a.get('skuName', sku)), + 'geschorst': geschorst, + 'gearchiveerd': gearchiveerd, + 'onbekend': not d, + 'laatste_login': (d.get('lastLoginTime') or '')[:10].replace('1970-01-01', ''), + }) + users.sort(key=lambda u: (u['sku_naam'], u['ou'], u['email'])) + + sku_ids = list(dict.fromkeys(DEFAULT_SKUS + list(counts) + list(purchased))) + skus = [] + for sku in sku_ids: + in_gebruik = counts.get(sku, 0) + if sku in VERBORGEN_SKUS and not in_gebruik: + continue + aangekocht = int(purchased.get(sku, {}).get('Aangekocht') or 0) + vrij = aangekocht - in_gebruik + procent = round(in_gebruik / aangekocht * 100) if aangekocht else None + skus.append({ + 'sku_id': sku, + 'naam': SKU_NAMES.get(sku, purchased.get(sku, {}).get('Naam', sku)), + 'in_gebruik': in_gebruik, + 'aangekocht': aangekocht, + 'vrij': vrij, + 'procent': procent, + 'geschorst': suspended_counts.get(sku, 0), + 'bijgewerkt': purchased.get(sku, {}).get('Bijgewerkt'), + 'bijgewerkt_door': purchased.get(sku, {}).get('Bijgewerkt_door'), + }) + + data = {'skus': skus, 'users': users, 'opgehaald': time.time()} + self._cache = (time.time(), data) + return data, None + + def clear_cache(self): + self._cache = None diff --git a/services/google_service.py b/services/google_service.py new file mode 100644 index 0000000..a514105 --- /dev/null +++ b/services/google_service.py @@ -0,0 +1,391 @@ +from googleapiclient.discovery import build +from config import Config +from tenancy import google_credentials +import sys +from datetime import datetime, timedelta, timezone +import smtplib +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart + +class GoogleAdminService: + def __init__(self): + #lijst met scopes + self.conf = Config() + self.server = Config.GOOGLE_SMTP_SERVER + self.port = Config.GOOGLE_SMTP_PORT + self.sender = Config.GOOGLE_SMTP_SENDER_adres + # Serviceaccount van de huidige school, gedelegeerd naar de admin van die school + self.delegated_creds = google_credentials(self.conf.GOOGLE_API_SCOPES, subject=self.conf.GOOGLE_ADMIN_EMAIL) + self.service = build('admin', 'directory_v1', credentials=self.delegated_creds,static_discovery=False) + + #functie die passwoord aanpast + def change_password(self, email, new_password): + """Wijzigt het wachtwoord van een gebruiker in Google Workspace.""" + try: + self.service.users().update( + userKey=email, + body={'password': new_password, 'changePasswordAtNextLogin': True} + ).execute() + return True, "Wachtwoord succesvol gewijzigd." + except Exception as e: + return False, str(e) + + #Functie die info ophaalt + def get_user_info(self, email): + """Haalt info op over een specifieke gebruiker.""" + try: + user = self.service.users().get(userKey=email).execute() + return user + except: + return None + #Functie die nieuwe gebruiker aanmaakt + def create_user(self, first_name, last_name, password, org_unit_path): + try: + primary_email = f"{first_name.lower()}.{last_name.lower()}@{self.conf.SCHOOL_DOMAIN}" + user_body = { + 'primaryEmail': primary_email, + 'name': {'givenName': first_name.capitalize(), 'familyName': last_name.capitalize()}, + 'password': password, + 'orgUnitPath': org_unit_path, + 'changePasswordAtNextLogin': True + } + self.service.users().insert(body=user_body).execute() + return True, primary_email + except Exception as e: + return False, str(e) + #functie die opzoek of genruiger reeds aawezig is + def search_users(self, query_string): + """ + Zoekt gebruikers in Google Workspace op basis van een query. + Bijv: query_string="name:Jan*" of "email:jan@school.be" + """ + try: + results = self.service.users().list( + customer='my_customer', + query=query_string, + maxResults=10, + orderBy='email' + ).execute() + + return results.get('users', []) + except Exception as e: + print(f"Fout bij zoeken in Google: {e}") + return [] + + #functie die toestelstatus aanpast (disabled/enabled) + def toggle_device_status(self, device_id, lock=True): + print("My debug message", flush=True) + """Blokkeert (disable) of deblokkeert (reenable) een ChromeOS device.""" + try: + import sys + #print die gebruikt word als debug check + sys.stderr.write(f"DEBUG: Calling Google API for ID: {device_id}\n") + action_type = 'disable' if lock else 'reenable' + + + + self.service.chromeosdevices().action( + customerId='my_customer', + resourceId=device_id, + body={'action': action_type} + ).execute() + + return True, f"Toestel status succesvol gewijzigd naar {action_type}" + except Exception as e: + import sys + sys.stderr.write(f"\n--- GOOGLE API ERROR: {str(e)} ---\n") + return False, f"Google API Fout: {str(e)}" + + #Functie die na het ingeven van de serienummer het DeviceID ophaalt (dit is een andere string dan het serienummer en essentieel om het toestel te kunnen blokkeren) + def lijst_chromebooks(self, ous=None): + """Alle ingeschreven Chromebooks (niet uitgeschreven), eventueel beperkt tot OU's (incl. sub-OU's). + Geeft een lijst dicts met serialNumber, model, status, orgUnitPath, annotatedAssetId.""" + velden = 'nextPageToken,chromeosdevices(serialNumber,model,status,orgUnitPath,annotatedAssetId)' + toestellen, gezien = [], set() + for ou in (ous or [None]): + token = None + while True: + params = dict(customerId='my_customer', maxResults=200, projection='BASIC', fields=velden, + pageToken=token) + if ou: + params.update(orgUnitPath=ou, includeChildOrgunits=True) + resp = self.service.chromeosdevices().list(**params).execute() + for d in resp.get('chromeosdevices', []): + serie = (d.get('serialNumber') or '').strip() + if not serie or serie in gezien or d.get('status') == 'DEPROVISIONED': + continue + gezien.add(serie) + toestellen.append(d) + token = resp.get('nextPageToken') + if not token: + break + return toestellen + + def chromebook_info(self, serienummer): + """Gebruiksinfo van één Chromebook: recente gebruikers, laatste synchronisatie, actieve tijd per dag. + Geeft (dict, None) of (None, foutmelding).""" + serie = str(serienummer or '').strip() + if not serie: + return None, "Dit toestel heeft geen serienummer." + velden = ('chromeosdevices(serialNumber,model,status,orgUnitPath,lastSync,lastEnrollmentTime,osVersion,' + 'recentUsers,activeTimeRanges,annotatedUser,annotatedLocation)') + devices = [] + for query in (f"id:{serie}", serie): # id: = zoeken op serienummer + resp = self.service.chromeosdevices().list(customerId='my_customer', query=query, projection='FULL', + maxResults=5, fields=velden).execute() + devices = [d for d in resp.get('chromeosdevices', []) + if (d.get('serialNumber') or '').strip().upper() == serie.upper()] + if devices: + break + if not devices: + return None, f"Geen Chromebook met serienummer {serie} gevonden in Google Admin." + d = devices[0] + return { + 'serienummer': d.get('serialNumber'), + 'model': d.get('model'), + 'status': d.get('status'), + 'ou': d.get('orgUnitPath'), + 'os': d.get('osVersion'), + 'laatste_sync': d.get('lastSync'), + 'ingeschreven': d.get('lastEnrollmentTime'), + 'gebruikers': [{'email': u.get('email') or '', 'beheerd': u.get('type') == 'USER_TYPE_MANAGED'} + for u in d.get('recentUsers', [])], + 'actief': sorted(({'datum': r.get('date'), 'minuten': round(int(r.get('activeTime') or 0) / 60000)} + for r in d.get('activeTimeRanges', [])), key=lambda r: r['datum'] or '', + reverse=True)[:14], + }, None + + def zoek_chromebook(self, serienummer): + """(deviceId, status) van de Chromebook met exact dit serienummer, of (None, foutmelding). + Status: ACTIVE, DISABLED, DEPROVISIONED, ...""" + serie = str(serienummer or '').strip().replace('\t', '').replace('\n', '').replace('\r', '') + if not serie: + return None, "Dit toestel heeft geen serienummer." + gevonden = [] + for query in (f"id:{serie}", serie): # id: = zoeken op serienummer + resp = self.service.chromeosdevices().list(customerId='my_customer', query=query, maxResults=10, + projection='BASIC', + fields='chromeosdevices(deviceId,serialNumber,status)').execute() + gevonden = [d for d in resp.get('chromeosdevices', []) + if (d.get('serialNumber') or '').strip().upper() == serie.upper()] + if gevonden: + break + if not gevonden: + return None, f"Geen Chromebook met serienummer {serie} gevonden in Google Admin." + # Bij een opnieuw ingeschreven toestel: de niet-uitgeschreven versie + d = next((x for x in gevonden if x.get('status') != 'DEPROVISIONED'), gevonden[0]) + return {'id': d.get('deviceId'), 'status': d.get('status')}, None + + def get_device_id_by_serial(self, serienummer): + """Zoekt het deviceId op basis van het fysieke serienummer.""" + print(f"DEBUG: Zoeken naar serienummer: '{serienummer}'", flush=True) + try: + + # Verwijder spaties, tabs (\t) en newlines (\n) + clean_serial = str(serienummer).strip().replace('\t', '').replace('\n', '').replace('\r', '') + + # Voer de API call uit met het schone serienummer + results = self.service.chromeosdevices().list( + customerId='my_customer', + query=f"{clean_serial}" + ).execute() + + devices = results.get('chromeosdevices', []) + + if devices: + dev_id = devices[0].get('deviceId') + sys.stderr.write(f"DEBUG: Toestel gevonden! ID: {dev_id}\n") + return dev_id, None + + return None, f"Device met serienummer {clean_serial} niet gevonden." + + except Exception as e: + sys.stderr.write(f"DEBUG: Fout in get_device_id_by_serial: {str(e)}\n") + return None, str(e) + + def list_org_units(self): + """Haalt alle Organizational Units op en sorteert ze alfabetisch.""" + try: + results = self.service.orgunits().list(customerId='my_customer', type='all').execute() + org_units = results.get('organizationUnits', []) + + # Sorteren op het volledige pad (bijv. /Leerlingen komt na /Beheer) + org_units.sort(key=lambda x: x.get('orgUnitPath', '').lower()) + + return org_units + except Exception as e: + import sys + sys.stderr.write(f"Fout bij ophalen OUs: {e}\n") + return [] + + def move_users_ou(self, source_ou, target_ou, only_enrolled=True, enrolled_emails=None): + """ + Verplaatst gebruikers van source naar target. + enrolled_emails: een lijst met e-mailadressen die volgens Informat/database ingeschreven zijn. + """ + users_moved = 0 + try: + # We zoeken specifiek gebruikers in de bron-OU om API-quota te besparen + query = f"orgUnitPath='{source_ou}'" + results = self.service.users().list(customer='my_customer', query=query).execute() + users = results.get('users', []) + + for user in users: + user_email = user.get('primaryEmail') + + # Logica voor de radiobuttons uit je HTML + should_move = False + if not only_enrolled: + should_move = True # "Alle leerlingen" + elif enrolled_emails and user_email in enrolled_emails: + should_move = True # "Enkel ingeschreven leerlingen" + + if should_move: + self.service.users().update( + userKey=user_email, + body={'orgUnitPath': target_ou} + ).execute() + users_moved += 1 + + return True, f"{users_moved} gebruikers succesvol verplaatst." + except Exception as e: + return False, f"Fout bij verplaatsen: {str(e)}" + + def move_chromebooks_ou(self, source_ou, target_ou): + """Verplaatst alle Chromebooks van de bron-OU naar de doel-OU.""" + devices_moved = 0 + next_page_token = None + try: + while True: + # We halen alle toestellen op en filteren handmatig op de OU + results = self.service.chromeosdevices().list( + customerId='my_customer', + pageToken=next_page_token, + maxResults=100 + ).execute() + + devices = results.get('chromeosdevices', []) + for device in devices: + if device.get('orgUnitPath') == source_ou: + device_id = device['deviceId'] + self.service.chromeosdevices().update( + customerId='my_customer', + deviceId=device_id, + body={'orgUnitPath': target_ou} + ).execute() + devices_moved += 1 + + next_page_token = results.get('nextPageToken') + if not next_page_token: + break + return True, f"{devices_moved} Chromebooks succesvol verplaatst." + except Exception as e: + return False, f"Fout bij verplaatsen Chromebooks: {str(e)}" + + def toggle_ou_devices_status(self, org_unit_path, block=True): + """ + Blokkeert of deblokkeert alle ChromeOS toestellen in een specifieke OU. + Voorkomt 412 errors door de huidige status te controleren. + """ + devices_processed = 0 + action_type = 'disable' if block else 'reenable' + # De status die het toestel AL heeft als de actie overbodig is + forbidden_status = 'DISABLED' if block else 'ACTIVE' + + next_page_token = None + + try: + while True: + results = self.service.chromeosdevices().list( + customerId='my_customer', + pageToken=next_page_token, + maxResults=100 + ).execute() + + devices = results.get('chromeosdevices', []) + + for device in devices: + if device.get('orgUnitPath') == org_unit_path: + current_status = device.get('status') # bijv. 'ACTIVE' of 'DISABLED' + device_id = device['deviceId'] + serial = device.get('serialNumber', 'Onbekend') + + # Alleen actie ondernemen als de status nog niet is + if current_status != forbidden_status: + try: + self.service.chromeosdevices().action( + customerId='my_customer', + resourceId=device_id, + body={'action': action_type} + ).execute() + devices_processed += 1 + except Exception as e: + print(f"Kon {serial} niet wijzigen: {e}") + else: + print(f"Overgeslagen: {serial} is al {current_status}") + + next_page_token = results.get('nextPageToken') + if not next_page_token: + break + + status_tekst = "geblokkeerd" if block else "gedeblokkeerd" + return True, f"{devices_processed} toestellen succesvol {status_tekst}. Toestellen die al de juiste status hadden zijn overgeslagen." + except Exception as e: + return False, f"Algemene fout: {str(e)}" + + def send_custom_mail(self, receiver_email, subject, body): + msg = MIMEMultipart() + msg['From'] = self.sender + msg['To'] = receiver_email + msg['Subject'] = subject + + msg.attach(MIMEText(body, 'html')) # We sturen het als HTML voor mooie opmaak + + try: + with smtplib.SMTP(self.server, self.port) as server: + server.starttls() + # Geen login nodig voor de relay indien geconfigureerd op IP + wachtwoord = Config.GOOGLE_SMTP_EMAIL_PASSWORD + if wachtwoord and wachtwoord != 'None': + server.login(self.sender, wachtwoord) + server.sendmail(self.sender, receiver_email, msg.as_string()) + return True, "Email succesvol verzonden" + except Exception as e: + return False, str(e) + + def archive_inactive_users(self, source_ou, days_inactive): + """Archiveert gebruikers die X dagen niet zijn ingelogd, zonder van OU te wisselen.""" + users_archived = 0 + cutoff_date = datetime.now(timezone.utc) - timedelta(days=days_inactive) + + try: + # Zoek gebruikers in de bron-OU + query = f"orgUnitPath='{source_ou}'" + results = self.service.users().list(customer='my_customer', query=query).execute() + users = results.get('users', []) + + for user in users: + last_login_str = user.get('lastLoginTime') + user_email = user.get('primaryEmail') + + should_archive = False + if last_login_str: + last_login_dt = datetime.fromisoformat(last_login_str.replace('Z', '+00:00')) + if last_login_dt < cutoff_date: + should_archive = True + else: + # Nooit ingelogd = inactief + should_archive = True + + if should_archive: + # We sturen enkel 'archived': True en GEEN 'orgUnitPath' + self.service.users().update( + userKey=user_email, + body={'archived': True} + ).execute() + users_archived += 1 + + return True, f"{users_archived} gebruikers succesvol gearchiveerd (OU ongewijzigd)." + except Exception as e: + return False, f"Fout bij archiveren: {str(e)}" + \ No newline at end of file diff --git a/services/gopro_service.py b/services/gopro_service.py new file mode 100644 index 0000000..651f047 --- /dev/null +++ b/services/gopro_service.py @@ -0,0 +1,641 @@ +""" +GO! Pro: personeelsleden van de actieve school uit Informat (Personeel WEB API, versie 2). + +- GET /employees → naam, voornaam, isActive, comnrs (telefoonnummers), ... +- GET /employees/assignments → opdrachten met ambt (functie), begindatum en einddatum +Scope: api_informat_sas_personeel.personeel.{instellingsnummer} (zelfde client-ID/secret als de leerlingen-API, +maar de client moet ook deze scope hebben). + +Per personeelslid komt er één rij. Functie en rol kies je in PIVOT uit dezelfde lijst (standaard Leerkracht, +een directeur Directeur) en worden per personeelslid bewaard in de schooldatabase (tabel gopro_keuzes). +""" +import re +import unicodedata +from datetime import date, datetime, timezone + +import requests + +from config import Config +from database import execute_query +from services.sync_service import informat_get + +ROLLEN = [ + 'Algemeen Directeur', 'Coordinerend Directeur', 'Communicatie', 'Financiën', 'Infrastructuur', 'HR', 'ICT', + 'Preventie en veiligheid', 'MVD', 'Administratief', 'RVB-lid', 'RVB', 'Voorzitter RVB', 'Beleidsondersteuner', + 'Directeur Coordinator', 'Directeur', 'Internationalisering', 'Leerkracht', 'GO Studio Schoolbeheerder', + 'Medewerker SGR', 'Adjunct-directeur', 'Administratief school', 'Beleidsondersteuner school', +] +STANDAARD_ROL = 'Leerkracht' + + + +def standaard_rol(ambten): + """Functie en rol zolang er in PIVOT niets gekozen is: een directeur blijft Directeur (adjunct-directeur blijft + Adjunct-directeur), alle anderen Leerkracht. `ambten` = de ambten uit Informat (lopende opdrachten + hoofdambt).""" + tekst = ' '.join(a.lower() for a in ambten if a) + if 'adjunct' in tekst and 'directeur' in tekst: + return 'Adjunct-directeur' + if 'directeur' in tekst: + return 'Directeur' + return STANDAARD_ROL + + +# Kolommen van het GO! Pro-importbestand (zelfde namen en volgorde) +EXPORT_KOLOMMEN = ['Naam', 'Achternaam', 'AanmeldEmailadres', 'UPN', 'CommunicatiefEmailadres', + 'OnderwijsinstellingNr', 'Functie', 'rol', 'StartDatum', 'EindDatum', 'ProfessioneelTelefoonNr'] + + +# --------------------------------------------------------------------- +# Hulpfuncties +# --------------------------------------------------------------------- +def naamdeel(tekst): + """'Van den Broeck' → 'vandenbroeck', 'Zoë' → 'zoe': kleine letters, geen accenten, spaties of leestekens + (een koppelteken blijft staan).""" + t = unicodedata.normalize('NFKD', str(tekst or '')).encode('ascii', 'ignore').decode() + return re.sub(r'[^a-z0-9-]', '', t.lower()).strip('-') + + +def upn_van(voornaam, achternaam): + v, a = naamdeel(voornaam), naamdeel(achternaam) + return f"{v}.{a}" if v and a else (v or a) + + +def _datum(waarde): + """'2026-09-01T00:00:00' → date; leeg of ongeldig → None.""" + if not waarde: + return None + try: + return datetime.strptime(str(waarde)[:10], '%Y-%m-%d').date() + except ValueError: + return None + + +def _lijst(data, *sleutels): + if isinstance(data, list): + return data + for s in sleutels: + if isinstance(data, dict) and isinstance(data.get(s), list): + return data[s] + return [] + + +def _telefoon(personeelslid): + """Enkel een professioneel nummer (type 'Werk'): privénummers gaan niet naar GO! Pro.""" + for c in personeelslid.get('comnrs') or []: + if str(c.get('type') or '').strip().lower() == 'werk' and c.get('nr'): + return str(c['nr']).strip() + return '' + + +# --------------------------------------------------------------------- +# Keuzes voor functie en rol (schooldatabase) +# --------------------------------------------------------------------- +VELDEN = ('functie', 'rol', 'email', 'upn') +ADRES_RE = re.compile(r'^[^@\s]+@[^@\s]+\.[^@\s]+$') + + +def ensure_tables(): + execute_query(""" + CREATE TABLE IF NOT EXISTS gopro_keuzes ( + Person_ID VARCHAR(64) NOT NULL PRIMARY KEY, + Functie VARCHAR(100) NULL, + Rol VARCHAR(100) NULL, + Email VARCHAR(255) NULL, + UPN VARCHAR(255) NULL, + Bijgewerkt DATETIME NOT NULL, + Door VARCHAR(255) NULL + )""", commit=True) + # Bestaande tabel van vóór de bewerkbare e-mail/UPN + kolommen = {r['Field'].lower() for r in execute_query("SHOW COLUMNS FROM gopro_keuzes") or []} + for kolom in ('Email', 'UPN'): + if kolom.lower() not in kolommen: + execute_query(f"ALTER TABLE gopro_keuzes ADD COLUMN {kolom} VARCHAR(255) NULL AFTER Rol", commit=True) + + +def keuzes(): + """{person_id: {'functie': ..., 'rol': ...}} met wat in PIVOT gekozen is (None = niets gekozen). + Rollen uit de vroegere tabel gopro_rollen (indien die bestaat) tellen mee als er nog geen nieuwe keuze is.""" + ensure_tables() + uit = {r['Person_ID']: {'functie': r['Functie'], 'rol': r['Rol'], 'email': r['Email'], 'upn': r['UPN']} + for r in execute_query("SELECT Person_ID, Functie, Rol, Email, UPN FROM gopro_keuzes") or []} + if execute_query("SHOW TABLES LIKE 'gopro_rollen'"): + for r in execute_query("SELECT Person_ID, Rol FROM gopro_rollen ORDER BY Bijgewerkt DESC") or []: + k = uit.setdefault(r['Person_ID'], {'functie': None, 'rol': None, 'email': None, 'upn': None}) + k['rol'] = k['rol'] or r['Rol'] + return uit + + +def keuze_opslaan(person_id, veld, waarde, door=None): + """Bewaart één keuze. Voor e-mail en UPN: leeg = terug naar het standaardadres (voornaam.achternaam@domein).""" + if veld not in VELDEN: + raise ValueError(f"Onbekend veld '{veld}'") + if not person_id: + raise ValueError("Geen personeelslid opgegeven") + if veld in ('email', 'upn'): + waarde = (waarde or '').strip().lower() or None + if waarde and not ADRES_RE.match(waarde): + raise ValueError(f"'{waarde}' is geen geldig e-mailadres.") + elif waarde not in ROLLEN: + raise ValueError(f"Onbekende waarde '{waarde}'") + ensure_tables() + kolom = {'functie': 'Functie', 'rol': 'Rol', 'email': 'Email', 'upn': 'UPN'}[veld] + execute_query( + f"INSERT INTO gopro_keuzes (Person_ID, {kolom}, Bijgewerkt, Door) VALUES (%s, %s, NOW(), %s) " + f"ON DUPLICATE KEY UPDATE {kolom} = VALUES({kolom}), Bijgewerkt = NOW(), Door = VALUES(Door)", + (person_id, waarde, door), commit=True) + + +def pas_keuzes_toe(rij, gekozen): + """Zet functie en rol van een rij: wat in PIVOT gekozen is, anders de standaard uit Informat.""" + k = gekozen.get(rij['person_id']) or {} + rij['functie'] = k.get('functie') or rij['standaard'] + rij['rol'] = k.get('rol') or rij['standaard'] + rij['email'] = k.get('email') or rij['standaard_email'] + rij['upn'] = k.get('upn') or rij['standaard_upn'] + rij['email_aangepast'] = bool(k.get('email')) + rij['upn_aangepast'] = bool(k.get('upn')) + return rij + + +def markeer_dubbel(rijen): + """Rijen waarvan het e-mailadres ook bij een ander personeelslid staat (bv. zelfde naam) krijgen 'dubbel'.""" + per_mail = {} + for r in rijen: + per_mail.setdefault(r['email'], set()).add(r['person_id']) + for r in rijen: + r['dubbel'] = bool(r['email']) and len(per_mail[r['email']]) > 1 + return rijen + + +def google_kleur(rij, google): + """'account' als e-mail of UPN een account is in Google, 'alias' als één ervan een alias is, anders 'geen'. + Zelfde regel als de kleuren op de pagina.""" + soorten = [google.get((rij.get(v) or '').strip().lower()) for v in ('email', 'upn')] + return 'account' if 'primair' in soorten else 'alias' if 'alias' in soorten else 'geen' + + +def google_adressen(vernieuw=False): + """{adres: 'primair' | 'alias'} voor alle gebruikers in Google Workspace van de huidige school, 10 minuten + bewaard. Gebruikt de bestaande Directory-koppeling (scope admin.directory.user).""" + import time + from tenancy import huidige_school + school = huidige_school() + bewaard = school.cache.get('gopro_google') + if bewaard and not vernieuw and time.time() - bewaard[0] < 600: + return bewaard[1] + from services.google_service import GoogleAdminService + users = GoogleAdminService().service.users() + adressen, token = {}, None + while True: + res = users.list(customer='my_customer', maxResults=500, pageToken=token, + fields='nextPageToken,users(primaryEmail,aliases)').execute() + for u in res.get('users', []): + for a in u.get('aliases') or []: + adressen.setdefault(str(a).lower(), 'alias') + if u.get('primaryEmail'): + adressen[str(u['primaryEmail']).lower()] = 'primair' + token = res.get('nextPageToken') + if not token: + break + school.cache['gopro_google'] = (time.time(), adressen) + return adressen + + +# --------------------------------------------------------------------- +# Informat +# --------------------------------------------------------------------- +class GoProService: + def __init__(self): + self.api = str(Config.INFORMAT_PERSONEEL_API or '').rstrip('/') + self.scope_basis = re.sub(r'\.\d+$', '', str(Config.INFORMAT_PERSONEEL_SCOPE or '').strip()) + self.nummers = [n for n, _ in (Config.INFORMAT_CAMPUSSEN or [])] or [Config.INFORMAT_INST_NUMBER] + + def _token(self, nummer): + try: + r = requests.post(Config.INFORMAT_AUTH_URL, timeout=15, data={ + 'grant_type': 'client_credentials', 'client_id': Config.INFORMAT_ID, + 'client_secret': Config.INFORMAT_SECRET, 'scope': f"{self.scope_basis}.{nummer}"}) + except requests.RequestException as e: + raise RuntimeError(f"Informat niet bereikbaar: {e}") + try: + antwoord = r.json() + except ValueError: + antwoord = {} + if r.status_code == 200 and antwoord.get('access_token'): + return antwoord['access_token'] + # Het echte antwoord van de Informat-aanmeldserver tonen (bv. invalid_scope of invalid_client) + reden = ' – '.join(str(antwoord[k]) for k in ('error', 'error_description') if antwoord.get(k)) \ + or r.text[:200] or f"HTTP {r.status_code}" + uitleg = { + 'invalid_scope': f"de client heeft de scope {self.scope_basis}.{nummer} (nog) niet.", + 'invalid_client': "de client-ID of het client-secret van deze school klopt niet.", + 'unauthorized_client': "deze client mag zich niet op deze manier aanmelden.", + }.get(antwoord.get('error'), "") + raise RuntimeError( + f"Aanmelden bij de Informat Personeel-API mislukt voor instellingsnummer {nummer} " + f"(scope {self.scope_basis}.{nummer}). Informat antwoordt: {reden}" + (f". Dat betekent: {uitleg}" if uitleg else "")) + + def _get(self, pad, nummer, token, schooljaar): + headers = {'Authorization': f'BEARER {token}', 'InstituteNo': nummer, 'Api-Version': '2', + 'Accept': 'application/json', + 'Timestamp': datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.000Z')} + r = informat_get(f"{self.api}{pad}?schoolYear={schooljaar}", headers) + if r.status_code in (401, 403): + raise RuntimeError(f"Informat weigert de toegang tot {pad} (instellingsnummer {nummer}). Heeft de client " + f"de scope {self.scope_basis}.{nummer}?") + if r.status_code != 200: + raise RuntimeError(f"Informat Personeel-API fout {r.status_code} op {pad} " + f"(instellingsnummer {nummer}): {r.text[:300]}") + return r.json() + + def personeel(self, domein, instellingsnummer_officieel='', schooljaar=None, vandaag=None): + """Lijst van rijen (dicts) voor het scherm en de export, gesorteerd op achternaam en voornaam.""" + schooljaar = schooljaar or Config.SCHOOLYEAR + vandaag = vandaag or date.today() + domein = (domein or '').lstrip('@') + gekozen = keuzes() + rijen, gezien = [], set() + + for nummer in self.nummers: + token = self._token(nummer) + leden = _lijst(self._get('/employees', nummer, token, schooljaar), 'employees', 'items', 'data') + opdrachten = _lijst(self._get('/employees/assignments', nummer, token, schooljaar), + 'assignments', 'items', 'data') + + # Lopende opdrachten per personeelslid (alle ambten samen): vroegste begin, laatste einde + per = {} + for o in opdrachten: + begin, einde = _datum(o.get('begindatum')), _datum(o.get('einddatum')) + if begin and begin > vandaag or einde and einde < vandaag: + continue + f = per.setdefault(str(o.get('personId')), {'begin': begin, 'einde': einde, 'open': einde is None, + 'ambten': set()}) + f['ambten'].add((o.get('ambt') or '').strip()) + if begin and (not f['begin'] or begin < f['begin']): + f['begin'] = begin + if einde is None: + f['open'] = True + elif not f['open'] and (not f['einde'] or einde > f['einde']): + f['einde'] = einde + + for p in leden: + pid = str(p.get('personId') or p.get('pPersoon') or '') + if not pid or p.get('isActive') is False or p.get('isOverleden'): + continue + voornaam, achternaam = (p.get('voornaam') or '').strip(), (p.get('naam') or '').strip() + # Eén rij per persoon, ook als die in meer dan één instellingsnummer voorkomt + # (daar kan Informat een ander personId geven: dan herkennen we de persoon aan naam + geboortedatum) + geboren = str(p.get('geboortedatum') or '')[:10] + persoon = (naamdeel(voornaam), naamdeel(achternaam), geboren) if geboren else ('pid', pid) + f = per.get(pid) or {'begin': None, 'einde': None, 'open': True, 'ambten': set()} + ambten = f['ambten'] | {((p.get('hoofdAmbt') or {}).get('naam') or '').strip()} + if pid in gezien or persoon in gezien: + bestaand = next(r for r in rijen if r['person_id'] == pid or r['_persoon'] == persoon) + if f['begin'] and (not bestaand['start'] or f['begin'] < bestaand['start']): + bestaand['start'] = f['begin'] + if f['open']: + bestaand['einde'] = None + elif bestaand['einde'] and f['einde'] and f['einde'] > bestaand['einde']: + bestaand['einde'] = f['einde'] + bestaand['telefoon'] = bestaand['telefoon'] or _telefoon(p) + nieuw = standaard_rol(ambten) # bv. directeur in het tweede instellingsnummer + if nieuw != STANDAARD_ROL and bestaand['standaard'] == STANDAARD_ROL: + bestaand['standaard'] = nieuw + pas_keuzes_toe(bestaand, gekozen) + continue + gezien.update((pid, persoon)) + upn = upn_van(voornaam, achternaam) + rijen.append({ + 'id': pid, + 'person_id': pid, + '_persoon': persoon, + 'voornaam': voornaam, + 'achternaam': achternaam, + 'standaard_email': f"{upn}@{domein}" if upn and domein else '', + 'standaard_upn': f"{upn}@{domein}" if upn and domein else upn, # UPN = het volledige e-mailadres + 'instellingsnummer': instellingsnummer_officieel or nummer, + 'standaard': standaard_rol(ambten), + 'start': f['begin'], + 'einde': None if f['open'] else f['einde'], + 'telefoon': _telefoon(p), + }) + pas_keuzes_toe(rijen[-1], gekozen) + + markeer_dubbel(rijen) + rijen.sort(key=lambda r: (naamdeel(r['achternaam']), naamdeel(r['voornaam']))) + return rijen + + def tel(self, peildatum): + """Aantal personeelsleden met een lopende opdracht op `peildatum` (één keer per persoon, ook als die in + meerdere instellingsnummers werkt). Geeft (totaal, detail) met detail = [{'naam', 'nummer', 'aantal'}] + per instellingsnummer als de school er meer dan één heeft, anders None.""" + from tenancy import _automatisch_schooljaar + schooljaar = _automatisch_schooljaar(peildatum) + namen = dict(Config.INFORMAT_CAMPUSSEN or []) + alle, detail = set(), [] + for nummer in self.nummers: + token = self._token(nummer) + leden = _lijst(self._get('/employees', nummer, token, schooljaar), 'employees', 'items', 'data') + opdrachten = _lijst(self._get('/employees/assignments', nummer, token, schooljaar), + 'assignments', 'items', 'data') + # personId → persoon (naam + geboortedatum), om dezelfde persoon in een ander nummer te herkennen + persoon = {} + for p in leden: + pid = str(p.get('personId') or p.get('pPersoon') or '') + geboren = str(p.get('geboortedatum') or '')[:10] + persoon[pid] = ((naamdeel(p.get('voornaam')), naamdeel(p.get('naam')), geboren) if geboren + else (nummer, pid)) + hier = set() + for o in opdrachten: + begin, einde = _datum(o.get('begindatum')), _datum(o.get('einddatum')) + if (begin and begin > peildatum) or (einde and einde < peildatum): + continue + pid = str(o.get('personId') or '') + if pid: + hier.add(persoon.get(pid, (nummer, pid))) + alle |= hier + detail.append({'naam': namen.get(nummer) or nummer, 'nummer': nummer, 'aantal': len(hier)}) + return len(alle), (detail if len(detail) > 1 else None) + + +# --------------------------------------------------------------------- +# Verzameltabel (centrale database): personeel van alle scholen samen, voor één grote GO! Pro-import +# --------------------------------------------------------------------- +def schooljaar_periode(vandaag=None): + """(1 september, 31 augustus) van het lopende schooljaar: in de verzameltabel heeft iedereen deze periode.""" + vandaag = vandaag or date.today() + jaar = vandaag.year if vandaag.month >= 9 else vandaag.year - 1 + return date(jaar, 9, 1), date(jaar + 1, 8, 31) + + +_periode_gezet = {'dag': None} +_tabel_klaar = {'ok': False} # tabel/kolommen/index maar één keer per proces nakijken + + +def verzamel_ensure(): + from database import central_query + if _tabel_klaar['ok']: + _periode_bijwerken() + return + central_query(""" + CREATE TABLE IF NOT EXISTS GoPro_verzameltabel ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_code VARCHAR(32) NOT NULL, + School_naam VARCHAR(255) NULL, + Person_ID VARCHAR(64) NOT NULL, + Voornaam VARCHAR(100) NULL, + Achternaam VARCHAR(100) NULL, + Email VARCHAR(255) NULL, + UPN VARCHAR(255) NULL, + Instellingsnummer VARCHAR(20) NULL, + Functie VARCHAR(100) NULL, + Rol VARCHAR(100) NULL, + Startdatum DATE NULL, + Einddatum DATE NULL, + Telefoon VARCHAR(50) NULL, + Toegevoegd DATETIME NOT NULL, + Door VARCHAR(255) NULL, + Soort VARCHAR(10) NOT NULL DEFAULT 'groen', + Verzonden DATETIME NULL, + Verzonden_door VARCHAR(255) NULL, + UNIQUE KEY uq_gopro_verz (School_code, Person_ID), + KEY idx_gopro_verz_email (Email), + KEY idx_gopro_verz_soort (Soort, School_naam) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", commit=True) + # Soort: 'groen' = gaat mee in de GO! Pro-CSV, 'genegeerd' = rode lijst (nooit meer tonen, niet exporteren), + # 'verzonden' = al naar GO! Pro doorgestuurd (niet meer in de verzameltabel, nooit opnieuw toevoegen) + kolommen = {r['Field'].lower() for r in central_query("SHOW COLUMNS FROM GoPro_verzameltabel") or []} + if 'soort' not in kolommen: + central_query("ALTER TABLE GoPro_verzameltabel ADD COLUMN Soort VARCHAR(10) NOT NULL DEFAULT 'groen'", commit=True) + if 'verzonden' not in kolommen: + central_query("ALTER TABLE GoPro_verzameltabel ADD COLUMN Verzonden DATETIME NULL, " + "ADD COLUMN Verzonden_door VARCHAR(255) NULL", commit=True) + indexen = {r['Key_name'] for r in central_query("SHOW INDEX FROM GoPro_verzameltabel") or []} + if 'idx_gopro_verz_soort' not in indexen: + central_query("ALTER TABLE GoPro_verzameltabel ADD KEY idx_gopro_verz_soort (Soort, School_naam)", commit=True) + _tabel_klaar['ok'] = True + _periode_bijwerken() + + +def _periode_bijwerken(): + from database import central_query + # Iedereen in de verzameltabel: periode = het lopende schooljaar (1 keer per dag nagekeken) + if _periode_gezet['dag'] != date.today(): + start, einde = schooljaar_periode() + central_query("UPDATE GoPro_verzameltabel SET Startdatum = %s, Einddatum = %s WHERE Soort = 'groen' " + "AND (Startdatum IS NULL OR Einddatum IS NULL OR Startdatum <> %s OR Einddatum <> %s)", + (start, einde, start, einde), commit=True) + _periode_gezet['dag'] = date.today() + + +def verzameld_sleutels(): + """({(school_code, person_id): soort}, {e-mailadres: soort}) van alles in de verzameltabel (groen én genegeerd).""" + from database import central_query + verzamel_ensure() + rijen = central_query("SELECT School_code, Person_ID, Email, Soort FROM GoPro_verzameltabel") or [] + return ({(r['School_code'], str(r['Person_ID'])): r['Soort'] for r in rijen}, + {(r['Email'] or '').strip().lower(): r['Soort'] for r in rijen if r['Email']}) + + +def is_verzameld(rij, school_code, sleutels): + """In welke lijst staat dit personeelslid al ('groen' / 'genegeerd'), of None. + Herkend aan school + personeelslid, of aan het e-mailadres.""" + paren, mails = sleutels + return paren.get((school_code, str(rij['person_id']))) or mails.get((rij.get('email') or '').strip().lower()) + + +def verzamel_toevoegen(rijen, school, door=None, soort='groen'): + """Voegt de rijen toe aan de verzameltabel (soort 'groen') of aan de rode lijst ('genegeerd'). + Geeft (toegevoegd, overgeslagen).""" + from database import central_query + sleutels = verzameld_sleutels() + periode = schooljaar_periode() # iedereen: 1 september – 31 augustus van het lopende schooljaar + toegevoegd = overgeslagen = 0 + for r in rijen: + if is_verzameld(r, school.code, sleutels): + overgeslagen += 1 + continue + central_query( + "INSERT INTO GoPro_verzameltabel (School_code, School_naam, Person_ID, Voornaam, Achternaam, Email, UPN, " + "Instellingsnummer, Functie, Rol, Startdatum, Einddatum, Telefoon, Toegevoegd, Door, Soort) " + "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW(), %s, %s)", + (school.code, school.naam, str(r['person_id']), r['voornaam'], r['achternaam'], r['email'], r['upn'], + r['instellingsnummer'], r['functie'], r['rol'], periode[0], periode[1], r['telefoon'], door, soort), + commit=True) + sleutels[0][(school.code, str(r['person_id']))] = soort + if r.get('email'): + sleutels[1][r['email'].strip().lower()] = soort + toegevoegd += 1 + return toegevoegd, overgeslagen + + +def verzameld_alle(school_code=None, soort='groen'): + from database import central_query + verzamel_ensure() + if school_code: + return central_query("SELECT * FROM GoPro_verzameltabel WHERE School_code = %s AND Soort = %s " + "ORDER BY Achternaam, Voornaam", (school_code, soort)) or [] + return central_query("SELECT * FROM GoPro_verzameltabel WHERE Soort = %s " + "ORDER BY School_naam, Achternaam, Voornaam", (soort,)) or [] + + +def aantallen(): + """{'groen': n, 'genegeerd': n, 'verzonden': n} in één query (in plaats van alle rijen op te halen).""" + from database import central_query + verzamel_ensure() + return {r['Soort']: int(r['n']) for r in + central_query("SELECT Soort, COUNT(*) AS n FROM GoPro_verzameltabel GROUP BY Soort") or []} + + +def markeer_verzonden(door=None, school_code=None): + """Alle personeelsleden in de verzameltabel (of enkel die van één school) als verzonden markeren. + Ze verdwijnen uit de verzameltabel en worden nooit opnieuw toegevoegd. Geeft het aantal.""" + from database import central_query + verzamel_ensure() + n = len(verzameld_alle(school_code)) + if school_code: + central_query("UPDATE GoPro_verzameltabel SET Soort = 'verzonden', Verzonden = NOW(), Verzonden_door = %s " + "WHERE Soort = 'groen' AND School_code = %s", (door, school_code), commit=True) + else: + central_query("UPDATE GoPro_verzameltabel SET Soort = 'verzonden', Verzonden = NOW(), Verzonden_door = %s " + "WHERE Soort = 'groen'", (door,), commit=True) + return n + + +def aantal_verzonden(school_code): + from database import central_query + verzamel_ensure() + r = central_query("SELECT COUNT(*) AS n FROM GoPro_verzameltabel WHERE School_code = %s AND Soort = 'verzonden'", + (school_code,)) or [{}] + return int(r[0].get('n') or 0) + + +# --------------------------------------------------------------------- +# Nachtelijke verzameling: elke nacht van alle scholen de groene personeelsleden naar de verzameltabel +# --------------------------------------------------------------------- +NACHT_SLEUTEL = 'gopro_nachtelijk' # '1' = aan +NACHT_DAG_SLEUTEL = 'gopro_nachtelijk_dag' # laatste datum waarop het liep (zodat het één keer per nacht loopt) +NACHT_RESULTAAT_SLEUTEL = 'gopro_nachtelijk_resultaat' +NACHT_UUR_VAN, NACHT_UUR_TOT = 2, 6 # tussen 02:00 en 06:00 +NACHT_DOOR = 'Automatisch (nacht)' +_nacht = {'bezig': False} + + +def _instelling_ensure(): + from services import ipblokkade + ipblokkade.ensure_table() # maakt PIVOT_instellingen aan als die nog niet bestaat + + +def nacht_instelling(): + """{'aan': bool, 'door', 'bijgewerkt', 'resultaat', 'resultaat_op'}""" + from database import central_query + _instelling_ensure() + rijen = {r['Sleutel']: r for r in central_query( + "SELECT Sleutel, Waarde, Bijgewerkt, Door FROM PIVOT_instellingen WHERE Sleutel IN (%s, %s)", + (NACHT_SLEUTEL, NACHT_RESULTAAT_SLEUTEL)) or []} + aan, res = rijen.get(NACHT_SLEUTEL) or {}, rijen.get(NACHT_RESULTAAT_SLEUTEL) or {} + return {'aan': aan.get('Waarde') == '1', 'door': aan.get('Door'), 'bijgewerkt': aan.get('Bijgewerkt'), + 'resultaat': res.get('Waarde'), 'resultaat_op': res.get('Bijgewerkt'), 'bezig': _nacht['bezig']} + + +def zet_nacht(aan, door=None): + from database import central_query + _instelling_ensure() + central_query("INSERT INTO PIVOT_instellingen (Sleutel, Waarde, Bijgewerkt, Door) VALUES (%s, %s, NOW(), %s) " + "ON DUPLICATE KEY UPDATE Waarde = VALUES(Waarde), Bijgewerkt = NOW(), Door = VALUES(Door)", + (NACHT_SLEUTEL, '1' if aan else '0', door), commit=True) + + +def verzamel_groene_van_school(school, door=NACHT_DOOR): + """Haalt het personeel van `school` op (Informat), kijkt na wie een account heeft in Google en zet de groene + die nog niet in de verzameltabel of op de rode lijst staan in de verzameltabel. Geeft het aantal toegevoegd.""" + from tenancy import in_school + with in_school(school): + rijen = GoProService().personeel(school.domein, Config.INSTELLINGSNUMMER) + school.cache.pop('gopro', None) # de GO! Pro-pagina haalt daarna vers op + google = google_adressen(vernieuw=True) + sleutels = verzameld_sleutels() + groen = [r for r in rijen if not is_verzameld(r, school.code, sleutels) and google_kleur(r, google) == 'account'] + toegevoegd, _ = verzamel_toevoegen(groen, school, door) + return toegevoegd + + +def verzamel_alle_scholen(door=NACHT_DOOR): + """Voor elke actieve school met Informat en een e-maildomein. Geeft een korte samenvatting.""" + from database import central_query + from tenancy import alle_scholen + from rechten import log + _nacht['bezig'] = True + try: + totaal, scholen, fouten, details = 0, 0, [], [] + for school in alle_scholen(): + if not school.heeft('INFORMAT_INST_NUMBER', 'INFORMAT_ID', 'INFORMAT_SECRET') or not school.domein: + continue + try: + n = verzamel_groene_van_school(school, door) + totaal += n + scholen += 1 + details.append(f"{school.naam}: {n}") + except Exception as e: + fouten.append(f"{school.naam}: {str(e)[:120]}") + import sys + sys.stderr.write(f"[{school.code}] GO! Pro nachtelijk verzamelen: {e}\n") + samenvatting = f"{totaal} toegevoegd uit {scholen} school/scholen" + if fouten: + samenvatting += f"; {len(fouten)} mislukt ({' | '.join(fouten)})" + try: + log(f"GO! Pro automatisch verzamelen: {samenvatting}. " + '; '.join(details), url='(nachtelijke taak)') + except Exception: + pass + _instelling_ensure() + central_query("INSERT INTO PIVOT_instellingen (Sleutel, Waarde, Bijgewerkt, Door) VALUES (%s, %s, NOW(), %s) " + "ON DUPLICATE KEY UPDATE Waarde = VALUES(Waarde), Bijgewerkt = NOW(), Door = VALUES(Door)", + (NACHT_RESULTAAT_SLEUTEL, samenvatting[:255], door), commit=True) + return samenvatting + finally: + _nacht['bezig'] = False + + +def _nacht_claim(vandaag): + """True als dit proces de run van vandaag mag doen (ook als PIVOT in meerdere processen draait).""" + from database import central_query + central_query("INSERT IGNORE INTO PIVOT_instellingen (Sleutel, Waarde, Bijgewerkt) VALUES (%s, '', NOW())", + (NACHT_DAG_SLEUTEL,), commit=True) + return central_query("UPDATE PIVOT_instellingen SET Waarde = %s, Bijgewerkt = NOW() " + "WHERE Sleutel = %s AND (Waarde IS NULL OR Waarde <> %s)", + (vandaag, NACHT_DAG_SLEUTEL, vandaag), commit=True) == 1 + + +_nacht_thread = None + + +def start_scheduler(): + """Achtergrondtaak: elk kwartier kijken of het nacht is en de schakelaar aan staat.""" + import threading, time, sys + global _nacht_thread + if _nacht_thread: + return + + def loop(): + time.sleep(60) + while True: + try: + nu = datetime.now() + if NACHT_UUR_VAN <= nu.hour < NACHT_UUR_TOT and nacht_instelling()['aan'] \ + and _nacht_claim(nu.strftime('%Y-%m-%d')): + verzamel_alle_scholen() + except Exception as e: + sys.stderr.write(f"GO! Pro nachtelijke taak: {e}\n") + time.sleep(15 * 60) + + _nacht_thread = threading.Thread(target=loop, daemon=True) + _nacht_thread.start() + + +def verzamel_alle_scholen_op_achtergrond(door): + import threading + if _nacht['bezig']: + return False + _nacht['bezig'] = True + threading.Thread(target=lambda: verzamel_alle_scholen(door), daemon=True).start() + return True diff --git a/services/handleidingen_standaard.py b/services/handleidingen_standaard.py new file mode 100644 index 0000000..5671364 --- /dev/null +++ b/services/handleidingen_standaard.py @@ -0,0 +1,347 @@ +""" +Handleidingen die PIVOT meelevert. Bij het opstarten komt elke handleiding waarvan de slug nog niet bestaat in de +tabel Handleidingen. Daarna pas je ze aan in PIVOT zelf (📘 Handleidingen › Bewerken); wijzigingen hier overschrijven niets. +Een verwijderde handleiding blijft verborgen (Zichtbaar = 'weg') en komt dus niet terug. +""" + +TWEESTAPS_UITZONDERING = """ +

Met deze handleiding stel je in Google Admin alles in zodat PIVOT iemand tijdelijk zonder 2FA (tot 23:59 dezelfde dag) kan laten inloggen +(uitzondering) en 2FA kan resetten bij een nieuwe telefoon. Je doet dit één keer per domein; daarna enkel opnieuw +als er een organisatie-eenheid (OU) bijkomt.

+ +
Hoe werkt het? PIVOT zet een gebruiker in de groep 2fa-uitzondering. Voor die groep staat +"Afdwingen" op Uit. Zolang de gebruiker in de groep zit, mag hij zonder 2FA inloggen. Om 23:59 dezelfde dag haalt PIVOT +hem er automatisch weer uit.
+ +

Stap 1 – De groep aanmaken

+
    +
  1. Ga naar admin.google.com › Directory › Groepen › Groep maken.
  2. +
  3. Naam: 2fa-uitzondering, e-mailadres: 2fa-uitzondering@jouwdomein.be.
  4. +
  5. Bij de instellingen van de groep: +
      +
    • Wie kan lid worden: Alleen uitgenodigde gebruikers.
    • +
    • Wie kan berichten plaatsen: Groepseigenaren (de groep dient niet om te mailen).
    • +
    • Wie kan leden bekijken: Groepsbeheerders.
    • +
    +
  6. +
  7. Voeg zelf geen vaste leden toe. PIVOT voegt mensen toe en haalt ze er weer uit.
  8. +
+ +

Stap 2 – 2FA uitzetten voor de groep, in élke OU waar 2FA verplicht is

+
Let op: een 2FA-instelling op een onderliggende OU gaat altijd vóór een groepsinstelling +hoger in de boom. Stel de groep daarom in bij elke OU waar 2FA afgedwongen wordt, ook bij sub-OU's.
+
    +
  1. Ga naar Beveiliging › Authenticatie › Verificatie in 2 stappen (2-Step Verification).
  2. +
  3. Kies links onder Organisatie-eenheden de OU, bv. GO-Antwerpen. Klap met het pijltje open om sub-OU's te zien.
  4. +
  5. Klik links onderaan bij Groepen op de groep 2fa-uitzondering (of voeg ze toe via "Groepen zoeken"). + Bovenaan moet nu staan: "Instellingen tonen voor gebruikers in [jouw OU] (organisatie-eenheid) die zich ook in + 2fa-uitzondering (groep) bevinden".
  6. +
  7. Laat Gebruikers toestaan tweestapsverificatie aan te zetten aangevinkt.
  8. +
  9. Zet Afdwingen op Uit.
  10. +
  11. Klik op Overschrijven (of Opslaan). Onder "Verificatie" moet nu Overschreven staan, niet "Overgenomen".
  12. +
  13. Herhaal stap 2 tot 6 voor elke OU en sub-OU waar 2FA op Aan staat.
  14. +
+
Tip: per OU kan je maar één groep instellen. Gebruik daarom overal dezelfde groep 2fa-uitzondering.
+ +

Stap 3 – Rechten voor PIVOT (domeinbrede delegatie)

+
    +
  1. Ga naar Beveiliging › Toegangs- en gegevensbeheer › API-beheer › Domeinbrede delegatie beheren.
  2. +
  3. Klik bij het service-account van PIVOT op Bewerken.
  4. +
  5. Controleer dat minstens deze scopes erbij staan (in het veld gescheiden door komma's): +
      +
    • https://www.googleapis.com/auth/admin.directory.user
    • +
    • https://www.googleapis.com/auth/admin.directory.user.security (2FA resetten, back-upcodes)
    • +
    • https://www.googleapis.com/auth/admin.directory.group.member (in/uit de groep zetten)
    • +
    • https://www.googleapis.com/auth/admin.directory.orgunit
    • +
    +
  6. +
  7. Klik op Autoriseren. Het kan enkele minuten duren voor Google dit toepast.
  8. +
+ +

Stap 4 – De groep invullen in PIVOT

+
    +
  1. Open in PIVOT 🔌 Koppelingen van deze school › 🛡️ 2FA-hulp.
  2. +
  3. Vul bij Uitzonderingsgroep het e-mailadres van de groep in: 2fa-uitzondering@jouwdomein.be.
  4. +
  5. Opslaan en Testen.
  6. +
+ +

Stap 5 – Testen met een testaccount

+
    +
  1. Geef in PIVOT (🛡️ 2FA-hulp) een testgebruiker een tijdelijke uitzondering (loopt tot 23:59).
  2. +
  3. Kijk in Google Admin bij Gebruikers › [testgebruiker] › Groepen: 2fa-uitzondering moet in de lijst staan.
  4. +
  5. Kijk bij Gebruikers › [testgebruiker] › Beveiliging › Tweestapsverificatie. + Zolang daar "Afgedwongen in uw hele organisatie" staat, heeft Google de uitzondering nog niet toegepast.
  6. +
+
Geduld: Google past een nieuwe groepsinstelling meestal binnen enkele minuten toe, maar het kan +tot 24 uur duren, zeker bij een nieuwe groep of een nieuw account. PIVOT blijft een 2FA-reset elke minuut opnieuw proberen +zolang de uitzondering loopt.
+ +

Iemand heeft een nieuwe telefoon

+

Gebruik eerst een back-upcode: die werkt meteen, ook als 2FA afgedwongen wordt.

+
    +
  1. PIVOT: 🛡️ 2FA-hulp › zoek de gebruiker › Back-upcodes tonen / aanmaken + (of in Google Admin: Gebruikers › gebruiker › Beveiliging › Tweestapsverificatie › Back-upverificatiecodes ophalen).
  2. +
  3. Geef de gebruiker één code. Hij logt in met zijn wachtwoord en die code.
  4. +
  5. Daarna koppelt hij zijn nieuwe telefoon via myaccount.google.com › Beveiliging + › Verificatie in 2 stappen.
  6. +
+

Lukt dat niet, gebruik dan in PIVOT 📵 2FA resetten. PIVOT zet de gebruiker dan in de uitzonderingsgroep en zet 2FA uit +zodra Google de uitzondering toepast.

+ +

Problemen oplossen

+ + + + + + + + + + + + + + +
Wat zie je?OorzaakOplossing
Gebruiker zit in de groep, maar 2FA blijft "Afgedwongen"De gebruiker staat in een (sub-)OU waar de groep niet ingesteld is, of Google past de instelling nog toe.Controleer de OU van de gebruiker (Gebruikers › gebruiker, links onder "Organisatie-eenheid") en voer stap 2 uit voor + precies die OU. Wacht anders tot 24 uur.
"2-Step Verification cannot be turned off: … enforced"Google dwingt 2FA nog af voor deze gebruiker.Zie hierboven. PIVOT probeert automatisch opnieuw.
"Google weigert de toegang" / unauthorized_clientEen scope ontbreekt.Stap 3.
"Gebruiker of groep niet gevonden"Het e-mailadres van de groep in PIVOT klopt niet.Stap 4.
+""" + +MAIL_DELEGATIE = """ +

Met deze handleiding stel je Google Admin zo in dat PIVOT (✉️ Mailbox-delegatie) iemand toegang kan geven tot de +mailbox van iemand anders, bv. het secretariaat tot de mailbox van de directie. De gedelegeerde kan dan lezen, versturen en verwijderen +namens de eigenaar, maar kent het wachtwoord niet en kan de instellingen niet wijzigen.

+ +

Stap 1 – Maildelegatie toelaten

+
    +
  1. Ga naar admin.google.com › Apps › Google Workspace › Gmail › Gebruikersinstellingen.
  2. +
  3. Kies links de organisatie-eenheid van de mailboxen die gedeeld moeten worden (bv. GO-Antwerpen). + Kies de hoogste OU als het voor iedereen mag; sub-OU's nemen de instelling over, tenzij ze ze zelf overschrijven.
  4. +
  5. Open het onderdeel Maildelegatie (Mail delegation).
  6. +
  7. Vink aan: Gebruikers toestaan toegang tot hun mailbox te delegeren aan andere gebruikers in het domein.
  8. +
  9. Kies hoe verzonden mails getoond worden: +
      +
    • De accounteigenaar en de gedelegeerde die de e-mail heeft verzonden tonen (aangeraden: de ontvanger ziet wie echt schreef), of
    • +
    • Alleen de accounteigenaar tonen.
    • +
    +
  10. +
  11. Klik op Opslaan.
  12. +
+
Let op: staat maildelegatie in een sub-OU op "Overschreven" en uit, dan werkt delegatie daar niet, +ook al staat ze hoger in de boom aan. Controleer de OU van de mailbox-eigenaar.
+ +

Stap 2 – Gmail API aanzetten (eenmalig)

+
    +
  1. Ga naar console.cloud.google.com › API's › Gmail API.
  2. +
  3. Kies bovenaan het project van het PIVOT-service-account.
  4. +
  5. Klik op Inschakelen (staat er "Beheren", dan is het al aan).
  6. +
+ +

Stap 3 – Rechten voor PIVOT (domeinbrede delegatie)

+
    +
  1. Ga in Google Admin naar Beveiliging › Toegangs- en gegevensbeheer › API-beheer › Domeinbrede delegatie beheren.
  2. +
  3. Klik bij het service-account van PIVOT op Bewerken.
  4. +
  5. Voeg deze twee scopes toe aan de bestaande lijst (gescheiden door komma's; verwijder de andere niet): +
      +
    • https://www.googleapis.com/auth/gmail.settings.sharing (delegatie toevoegen en verwijderen)
    • +
    • https://www.googleapis.com/auth/gmail.settings.basic (bestaande delegaties tonen)
    • +
    +
  6. +
  7. Klik op Autoriseren.
  8. +
+
Tip: ontbreekt gmail.settings.basic, dan kan PIVOT wel delegaties toevoegen maar de lijst niet tonen +("insufficient authentication scopes").
+ +

Stap 4 – Rechten in PIVOT

+
    +
  1. Geef wie delegaties mag beheren het recht Mailbox-delegatie in de juiste school + (⚙️ Beheer › 🔐 Gebruikers & rechten › 🔐 Rechten).
  2. +
  3. Test in ✉️ Mailbox-delegatie met twee testaccounts: geef account B toegang tot de mailbox van account A.
  4. +
+ +

Goed om te weten

+
    +
  • Een delegatie via PIVOT werkt meestal na ongeveer een minuut. De gedelegeerde hoeft niets te bevestigen.
  • +
  • Een nieuwe instelling in Google Admin (stap 1) kan tot 24 uur duren voor ze overal geldt.
  • +
  • De gedelegeerde opent de mailbox in Gmail via zijn profielfoto rechtsboven › de gedeelde mailbox kiezen.
  • +
  • Eigenaar en gedelegeerde moeten in dezelfde Google Workspace-organisatie zitten. Gebruik het + primaire e-mailadres, geen alias.
  • +
  • Een mailbox kan maximaal 25 gedelegeerden hebben; iemand kan maximaal 10 mailboxen openen + (Google kan deze limieten per organisatie anders instellen).
  • +
+ +

Problemen oplossen

+ + + + + + + + + + + + +
Wat zie je?OorzaakOplossing
"insufficient authentication scopes" bij het tonengmail.settings.basic ontbreekt.Stap 3.
"unauthorized_client" / Google weigert de toeganggmail.settings.sharing ontbreekt of is nog niet toegepast.Stap 3, en enkele minuten wachten.
Gmail API has not been used / is disabledGmail API staat uit in het Cloud-project.Stap 2.
Toevoegen mislukt voor één persoon, voor anderen lukt hetMaildelegatie staat uit in de OU van die mailbox-eigenaar, of er zijn al 25 gedelegeerden.Stap 1 voor die OU.
Gedelegeerde ziet de mailbox nietNog niet toegepast, of hij kijkt niet via zijn profielfoto.Even wachten, opnieuw inloggen in Gmail.
+""" + +GOOGLE_KOPPELING = """ +

PIVOT praat met Google via een serviceaccount: een technisch account in Google Cloud dat namens een beheerder +(bv. ict@school.be) handelt. Daarvoor zijn er drie plaatsen: Google Cloud Console (project, API's, +serviceaccount, sleutel), Google Admin (domeinbrede delegatie) en PIVOT (sleutel uploaden). +Optioneel stel je ook Inloggen met Google in.

+ +
Wie? Je hebt een account nodig dat in Google Cloud projecten mag aanmaken en in Google Admin +superbeheerder is. Je doet dit één keer; meerdere scholen in hetzelfde Google-domein mogen dezelfde sleutel gebruiken.
+ +

Stap 1 – Project aanmaken

+
    +
  1. Ga naar console.cloud.google.com en log in met je beheerdersaccount.
  2. +
  3. Klik bovenaan op de projectkiezer › Nieuw project.
  4. +
  5. Naam: bv. PIVOT. Organisatie: jullie domein. Klik op Maken.
  6. +
  7. Controleer bovenaan dat het nieuwe project gekozen is voor je verder gaat.
  8. +
+ +

Stap 2 – API's inschakelen

+

Ga naar API's en services › Bibliotheek, zoek elke API en klik op Inschakelen:

+ + + + + + + + +
APINodig voor
Admin SDK APIGebruikers, wachtwoorden, OU's, Chromebooks, groepen, 2FA
Gmail APIMailbox-delegatie
Enterprise License Manager APIGoogle-licenties
Groups Settings APIVerzendlijsten: wie mag mailen naar de lijst
+ +

Stap 3 – Serviceaccount aanmaken

+
    +
  1. Ga naar IAM en beheer › Serviceaccounts › Serviceaccount maken.
  2. +
  3. Naam: bv. pivot. Klik op Maken en doorgaan.
  4. +
  5. De stappen "Rollen" en "Gebruikerstoegang" laat je leeg (PIVOT werkt via domeinbrede delegatie, niet via + Cloud-rollen). Klik op Klaar.
  6. +
  7. Open het serviceaccount en noteer de Unieke ID (een lang getal, ook "OAuth 2-client-ID" genoemd). + Die heb je nodig in stap 5.
  8. +
+ +

Stap 4 – JSON-sleutel maken

+
    +
  1. Open het serviceaccount › tabblad Sleutels › Sleutel toevoegen › Nieuwe sleutel maken.
  2. +
  3. Kies JSON › Maken. Het bestand wordt gedownload.
  4. +
  5. Bewaar het veilig: wie dit bestand heeft, kan alles wat PIVOT kan. Verwijder het van je pc na stap 6.
  6. +
+
"Het maken van serviceaccountsleutels is uitgeschakeld"? Nieuwe Google Cloud-organisaties blokkeren +sleutels standaard met de organisatiebeleidsregel iam.disableServiceAccountKeyCreation +(of iam.managed.disableServiceAccountKeyCreation). Zet ze uit voor enkel dit project: +
    +
  1. Geef jezelf op organisatieniveau de rol Beheerder van organisatiebeleid (Organization Policy Administrator) + via IAM en beheer › IAM (kies bovenaan de organisatie, niet het project).
  2. +
  3. Kies bovenaan opnieuw het project PIVOT › IAM en beheer › Organisatiebeleid.
  4. +
  5. Zoek disableServiceAccountKeyCreation › Beleid beheren › Beleid van bovenliggend item + overschrijven › regel toevoegen › Afdwingen: Uit › Beleid instellen.
  6. +
  7. Wacht enkele minuten (soms tot een uur) en probeer stap 4 opnieuw.
  8. +
+
+ +

Stap 5 – Domeinbrede delegatie in Google Admin

+
    +
  1. Ga naar admin.google.com › Beveiliging › Toegangs- en + gegevensbeheer › API-beheer › Domeinbrede delegatie beheren.
  2. +
  3. Klik op Nieuwe toevoegen.
  4. +
  5. Client-ID: de Unieke ID uit stap 3 (PIVOT toont ze ook na het uploaden van de sleutel).
  6. +
  7. OAuth-bereiken: plak deze regel in zijn geheel: +
    https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.user.security,https://www.googleapis.com/auth/admin.directory.group.member,https://www.googleapis.com/auth/admin.directory.orgunit,https://www.googleapis.com/auth/admin.directory.device.chromeos,https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly,https://www.googleapis.com/auth/admin.directory.device.mobile,https://www.googleapis.com/auth/admin.directory.device.mobile.readonly,https://www.googleapis.com/auth/apps.licensing,https://www.googleapis.com/auth/gmail.settings.sharing,https://www.googleapis.com/auth/gmail.settings.basic,https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/apps.groups.settings,https://www.googleapis.com/auth/gmail.modify,https://www.googleapis.com/auth/contacts,https://www.googleapis.com/auth/drive
    +
  8. +
  9. Klik op Autoriseren. Het kan enkele minuten duren voor Google dit toepast.
  10. +
+ + + + + + + + + + + + + + + + +
Scope (zonder https://www.googleapis.com/auth/)Waarvoor in PIVOT
admin.directory.userAccounts aanmaken, wachtwoord resetten, leerlingen
admin.directory.user.security2FA: back-upcodes, 2FA resetten
admin.directory.group.member2FA-uitzonderingsgroep
admin.directory.orgunitOrganisatie-eenheden
admin.directory.device.chromeos (+ .readonly)Chromebooks blokkeren/deblokkeren, opzoeken
admin.directory.device.mobile (+ .readonly)Mobiele toestellen
apps.licensingGoogle-licenties
gmail.settings.sharingMailbox-delegatie toevoegen/verwijderen
gmail.settings.basicMailbox-delegaties tonen, Gmail-handtekeningen instellen
gmail.modifyE-mails met een label kopiëren/verplaatsen naar een andere mailbox
driveGedeelde drives: overzicht, leden en rechten (Google Drive API moet aanstaan)
contactsContactlijsten in de mailboxen van gebruikers (People API moet aanstaan)
+
Tip: Bestaat er al een regel voor deze client-ID, klik dan op Bewerken en +vervang de lijst; anders heb je er twee.
+ +

Stap 6 – Sleutel en beheerder instellen in PIVOT

+
    +
  1. Open in PIVOT 🏫 Alle scholen beheren › de school › Bewerken + (of 🔌 Koppelingen van deze school).
  2. +
  3. Bij Algemeen › Beheerder (Google-admin): het account waarnamens PIVOT werkt, bv. ict@school.be. + Dit moet een superbeheerder zijn (of een beheerder met de nodige rechten) in Google Admin.
  4. +
  5. Bij 🔑 Google Workspace › Serviceaccount (JSON-sleutel): upload het JSON-bestand uit stap 4. + PIVOT bewaart het versleuteld en toont daarna het e-mailadres en de client-ID van het serviceaccount.
  6. +
  7. Opslaan, en daarna op 🩺 Testen klikken. Alles in orde? Verwijder het JSON-bestand van je pc.
  8. +
+ +

Stap 7 (optioneel) – Inloggen met Google

+

Hiermee loggen leerkrachten en PIVOT-gebruikers in met hun Google-account in plaats van een wachtwoord.

+
    +
  1. In de Cloud Console (zelfde project): API's en services › OAuth-toestemmingsscherm + (in de nieuwe versie: Google Auth Platform › Branding). Kies als doelgroep Intern, + app-naam PIVOT, ondersteunings-e-mail en je ontwikkelaarsadres. Opslaan.
  2. +
  3. Inloggegevens (of Google Auth Platform › Clients) › Inloggegevens maken › OAuth-client-ID.
  4. +
  5. Type: Webapplicatie, naam PIVOT login.
  6. +
  7. Bij Geautoriseerde omleidings-URI's: het adres van PIVOT + /callback, + bv. https://pivot.school.be/callback. Gebruik je meerdere adressen (per school een eigen hostnaam), voeg ze allemaal toe.
  8. +
  9. Klik op Maken en kopieer de client-ID en het clientgeheim.
  10. +
  11. In PIVOT: vul ze in bij de school onder 🔑 Google Workspace › Google-login client-ID / client-secret, + of één keer voor alle scholen in config.ini onder [google_sso].
  12. +
+ +

Problemen oplossen

+ + + + + + + + + + + + + + + + +
Wat zie je?OorzaakOplossing
unauthorized_client / "Client is unauthorized to retrieve access tokens"Client-ID of scope ontbreekt in de domeinbrede delegatie, of nog niet toegepast.Stap 5 nakijken (juiste Unieke ID, alle scopes), enkele minuten wachten.
"Invalid Input" / "Not Authorized to access this resource"Het beheerdersaccount klopt niet of is geen beheerder.Stap 6, Beheerder (Google-admin).
"<API> has not been used in project … or it is disabled"De API staat niet aan.Stap 2, in het juiste project.
"insufficient authentication scopes"Eén scope ontbreekt (vaak een Gmail-scope).Stap 5.
"redirect_uri_mismatch" bij inloggen met GoogleHet adres van PIVOT staat niet bij de omleidings-URI's.Stap 7.4: exact hetzelfde adres (https, hostnaam, /callback).
Sleutel maken lukt nietOrganisatiebeleid blokkeert sleutels.Kader bij stap 4.
+""" + +STANDAARD = [ + { + 'slug': 'google-koppeling-cloud-console', + 'titel': 'Google-koppeling instellen (Google Cloud Console)', + 'categorie': 'Google Workspace', + 'samenvatting': 'Project, API\'s, serviceaccount en JSON-sleutel, domeinbrede delegatie met alle scopes, ' + 'sleutel in PIVOT en inloggen met Google.', + 'inhoud': GOOGLE_KOPPELING, + }, + { + 'slug': '2fa-uitzondering-google-admin', + 'titel': '2FA-uitzondering instellen in Google Admin', + 'categorie': 'Google Workspace', + 'samenvatting': 'Groep 2fa-uitzondering aanmaken, 2FA uitzetten per OU, rechten voor PIVOT en testen.', + 'inhoud': TWEESTAPS_UITZONDERING, + }, + { + 'slug': 'mailbox-delegatie-google-admin', + 'titel': 'Mailbox-delegatie instellen in Google Admin', + 'categorie': 'Google Workspace', + 'samenvatting': 'Maildelegatie toelaten per OU, Gmail API, scopes voor PIVOT en testen.', + 'inhoud': MAIL_DELEGATIE, + }, +] diff --git a/services/handtekening_service.py b/services/handtekening_service.py new file mode 100644 index 0000000..8acf7cd --- /dev/null +++ b/services/handtekening_service.py @@ -0,0 +1,443 @@ +""" +Gmail › Handtekeningen: één HTML-sjabloon per school, ingevuld per gebruiker en ingesteld in Gmail. + +- Gebruikers: alle accounts in de gekozen OU's (Directory API, optioneel met de onderliggende OU's). +- Functie en telefoon komen uit Google (gebruikersprofiel: organizations[].title en phones[]) en worden daar ook + bewaard als je ze in PIVOT aanpast. Zo staan ze ook in het adresboek van de organisatie. +- Toepassen: Gmail API users.settings.sendAs.patch(signature) namens de gebruiker, voor het hoofdadres en de aliassen. +- Logo: geüpload in PIVOT (publiek op /handtekening-logo//) of een eigen publieke link. + Gmail toont geen ingesloten (base64) afbeeldingen in handtekeningen, enkel afbeeldingen via een link. +- Nachtelijk opnieuw toepassen (schakelaar): gebruikers kunnen hun handtekening in Gmail zelf wijzigen, + zo staat de juiste er de volgende ochtend terug. + +Vereist (domeinbrede delegatie): https://www.googleapis.com/auth/gmail.settings.basic +en voor functie/telefoon https://www.googleapis.com/auth/admin.directory.user (staat al in de standaardlijst). +""" +import hashlib +import html +import json +import re +import secrets +import sys +import threading +import time +from datetime import datetime + +from config import Config +from database import execute_query +from tenancy import school_singleton, met_school, google_credentials, huidige_school + +SCOPE = 'https://www.googleapis.com/auth/gmail.settings.basic' +MAX_TEKENS = 10000 # limiet van Gmail voor een handtekening +MAX_LOGO = 512 * 1024 +LOGO_TYPES = {'image/png': 'png', 'image/jpeg': 'jpg', 'image/gif': 'gif'} +NACHT_UUR_VAN, NACHT_UUR_TOT = 3, 6 + +VELDEN = [ # (sleutel, uitleg) + ('voornaam', 'Voornaam'), ('achternaam', 'Achternaam'), ('naam', 'Voornaam en achternaam'), + ('functie', 'Functie (uit Google)'), ('telefoon', 'Telefoon (uit Google)'), ('email', 'E-mailadres'), + ('schoolnaam', 'Naam van de school'), ('schooladres', 'Adres van de school'), ('logo', 'Logo (afbeelding)'), +] + +STANDAARD_SJABLOON = """ + + + + +
{logo} +
{voornaam} {achternaam}
+{#functie}
{functie}
{/functie} +
{schoolnaam}
+
{schooladres}
+{#telefoon}
Tel. {telefoon}
{/telefoon} + +
""" + + +class HandtekeningFout(Exception): + pass + + +# --------------------------------------------------------------------- +# Opslag (database van de school) +# --------------------------------------------------------------------- +def ensure_tables(): + execute_query(""" + CREATE TABLE IF NOT EXISTS gmail_handtekening ( + ID TINYINT NOT NULL PRIMARY KEY, + Sjabloon MEDIUMTEXT NULL, + OUs TEXT NULL, + Met_sub_ous TINYINT NOT NULL DEFAULT 1, + Logo MEDIUMBLOB NULL, + Logo_type VARCHAR(40) NULL, + Logo_sleutel VARCHAR(40) NULL, + Logo_url VARCHAR(500) NULL, + Logo_breedte INT NOT NULL DEFAULT 120, + Publiek_adres VARCHAR(255) NULL, + Nachtelijk TINYINT NOT NULL DEFAULT 0, + Laatste_nacht DATE NULL, + Nacht_resultaat VARCHAR(500) NULL, + Bijgewerkt DATETIME NULL, + Door VARCHAR(255) NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", commit=True) + execute_query(""" + CREATE TABLE IF NOT EXISTS gmail_handtekening_log ( + Email VARCHAR(255) NOT NULL PRIMARY KEY, + Toegepast DATETIME NOT NULL, + Ok TINYINT NOT NULL, + Melding VARCHAR(500) NULL, + Hash CHAR(40) NULL, + Door VARCHAR(255) NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", commit=True) + execute_query("INSERT IGNORE INTO gmail_handtekening (ID, Sjabloon) VALUES (1, %s)", (STANDAARD_SJABLOON,), commit=True) + + +def instellingen(): + ensure_tables() + r = (execute_query("SELECT ID, Sjabloon, OUs, Met_sub_ous, Logo_type, Logo_sleutel, Logo_url, Logo_breedte, " + "Publiek_adres, Nachtelijk, Laatste_nacht, Nacht_resultaat, Bijgewerkt, Door, " + "Logo IS NOT NULL AS heeft_logo FROM gmail_handtekening WHERE ID = 1") or [{}])[0] + try: + r['ous'] = [o for o in json.loads(r.get('OUs') or '[]') if isinstance(o, str)] + except ValueError: + r['ous'] = [] + r['logo_link'] = logo_link(r) + return r + + +def bewaar(sjabloon, ous, met_sub, logo_url, logo_breedte, publiek_adres, door): + sjabloon = (sjabloon or '').strip() + if len(sjabloon) > 50000: + raise HandtekeningFout("Het sjabloon is te lang.") + execute_query("UPDATE gmail_handtekening SET Sjabloon = %s, OUs = %s, Met_sub_ous = %s, Logo_url = %s, " + "Logo_breedte = %s, Publiek_adres = %s, Bijgewerkt = NOW(), Door = %s WHERE ID = 1", + (sjabloon, json.dumps(sorted(set(ous))), 1 if met_sub else 0, (logo_url or '').strip() or None, + max(20, min(600, int(logo_breedte or 120))), (publiek_adres or '').strip().rstrip('/') or None, door), + commit=True) + + +def bewaar_logo(data, mimetype): + if mimetype not in LOGO_TYPES: + raise HandtekeningFout("Enkel PNG, JPG of GIF als logo.") + if len(data) > MAX_LOGO: + raise HandtekeningFout(f"Het logo is te groot (max. {MAX_LOGO // 1024} kB).") + execute_query("UPDATE gmail_handtekening SET Logo = %s, Logo_type = %s, Logo_sleutel = %s WHERE ID = 1", + (data, mimetype, secrets.token_hex(12)), commit=True) + + +def verwijder_logo(): + execute_query("UPDATE gmail_handtekening SET Logo = NULL, Logo_type = NULL, Logo_sleutel = NULL WHERE ID = 1", + commit=True) + + +def logo_bestand(sleutel): + ensure_tables() + r = execute_query("SELECT Logo, Logo_type FROM gmail_handtekening WHERE ID = 1 AND Logo_sleutel = %s", (sleutel,)) + return (r[0]['Logo'], r[0]['Logo_type']) if r and r[0]['Logo'] else (None, None) + + +def logo_link(inst): + """Publieke link naar het logo: eigen link, of het geüploade logo via PIVOT.""" + if inst.get('Logo_url'): + return inst['Logo_url'] + if inst.get('heeft_logo') and inst.get('Logo_sleutel') and inst.get('Publiek_adres'): + ext = LOGO_TYPES.get(inst.get('Logo_type'), 'png') + return f"{inst['Publiek_adres']}/handtekening-logo/{huidige_school().code}/{inst['Logo_sleutel']}.{ext}" + return '' + + +def zet_nacht(aan, door): + execute_query("UPDATE gmail_handtekening SET Nachtelijk = %s, Door = %s WHERE ID = 1", (1 if aan else 0, door), + commit=True) + + +def logboek(): + ensure_tables() + return {r['Email'].lower(): r for r in execute_query("SELECT * FROM gmail_handtekening_log") or []} + + +# --------------------------------------------------------------------- +# Sjabloon invullen +# --------------------------------------------------------------------- +def gegevens(gebruiker): + s = huidige_school() + return {'voornaam': gebruiker.get('voornaam', ''), 'achternaam': gebruiker.get('achternaam', ''), + 'naam': f"{gebruiker.get('voornaam', '')} {gebruiker.get('achternaam', '')}".strip(), + 'functie': gebruiker.get('functie', ''), 'telefoon': gebruiker.get('telefoon', ''), + 'email': gebruiker.get('email', ''), 'schoolnaam': s.naam or '', 'schooladres': s.get('ADRES') or ''} + + +def vul_in(sjabloon, waarden, inst): + """{veld} → waarde (HTML-veilig); {#veld}...{/veld} valt weg als het veld leeg is; {logo} → .""" + def blok(m): + return m.group(2) if (waarden.get(m.group(1)) or '').strip() or (m.group(1) == 'logo' and inst['logo_link']) else '' + uit = re.sub(r'\{#(\w+)\}(.*?)\{/\1\}', blok, sjabloon or '', flags=re.S) + link = inst.get('logo_link') or '' + logo = (f'{html.escape(waarden.get(') if link else '' + + def veld(m): + k = m.group(1) + if k == 'logo': + return logo + if k in waarden: + w = html.escape(waarden[k] or '') + return w.replace('\n', '
') if k == 'schooladres' else w + return m.group(0) + return re.sub(r'\{(\w+)\}', veld, uit) + + +# --------------------------------------------------------------------- +# Google: gebruikers, functie en telefoon +# --------------------------------------------------------------------- +def _directory(): + from googleapiclient.discovery import build + creds = google_credentials(Config.GOOGLE_API_SCOPES, subject=Config.GOOGLE_ADMIN_EMAIL) + return build('admin', 'directory_v1', credentials=creds, static_discovery=False, cache_discovery=False) + + +def _gmail(mailbox): + from googleapiclient.discovery import build + creds = google_credentials([SCOPE], subject=mailbox) + try: + return build('gmail', 'v1', credentials=creds, static_discovery=True, cache_discovery=False) + except Exception: + return build('gmail', 'v1', credentials=creds, static_discovery=False, cache_discovery=False) + + +def vriendelijk(e): + t = str(e) + laag = t.lower() + if 'unauthorized_client' in laag or 'access_denied' in laag: + return (f"Google weigert de toegang: voeg in de Admin-console › Beveiliging › API-beheer › Domeinbrede delegatie " + f"het bereik {SCOPE} toe bij het serviceaccount van PIVOT.") + if 'has not been used' in laag or 'is disabled' in laag or 'accessnotconfigured' in laag: + return "De Gmail API staat niet aan in het Google Cloud-project van het serviceaccount." + if 'mail service not enabled' in laag or 'failedprecondition' in laag: + return "Deze gebruiker heeft geen Gmail (geen licentie of Gmail uitgeschakeld)." + if 'not authorized to access this resource' in laag or 'insufficient' in laag: + return "Google weigert het: de beheerder mag deze gebruiker niet aanpassen (scope admin.directory.user?)." + return t[:250] + + +def ou_lijst(): + try: + resp = _directory().orgunits().list(customerId='my_customer', type='all').execute() + except Exception as e: + raise HandtekeningFout(f"OU's ophalen mislukt: {vriendelijk(e)}") + return sorted([o['orgUnitPath'] for o in resp.get('organizationUnits', [])] + ['/'], key=str.lower) + + +def _functie(u): + orgs = u.get('organizations') or [] + org = next((o for o in orgs if o.get('primary')), orgs[0] if orgs else {}) + return (org.get('title') or '').strip() + + +def _telefoon(u): + tel = u.get('phones') or [] + t = next((p for p in tel if p.get('type') == 'work'), None) or next((p for p in tel if p.get('primary')), None) \ + or (tel[0] if tel else {}) + return (t.get('value') or '').strip() + + +def gebruikers(ous, met_sub=True): + """Alle (niet-geschorste) gebruikers in de OU's: [{'email','voornaam','achternaam','ou','functie','telefoon'}].""" + if not ous: + return [] + api, uit, gezien = _directory(), [], set() + for ou in ous: + token = None + while True: + try: + params = dict(customer='my_customer', maxResults=500, pageToken=token, projection='full', + fields='nextPageToken,users(primaryEmail,name,orgUnitPath,organizations,phones,suspended,archived)') + if ou != '/': + params['query'] = "orgUnitPath='" + ou.replace("\\", "\\\\").replace("'", "\\'") + "'" + resp = api.users().list(**params).execute() + except Exception as e: + raise HandtekeningFout(f"Gebruikers van {ou} ophalen mislukt: {vriendelijk(e)}") + for u in resp.get('users', []): + pad = u.get('orgUnitPath') or '/' + if not met_sub and pad != ou: + continue + if u.get('suspended') or u.get('archived'): + continue + email = u['primaryEmail'].lower() + if email in gezien: + continue + gezien.add(email) + n = u.get('name') or {} + uit.append({'email': email, 'voornaam': n.get('givenName', ''), 'achternaam': n.get('familyName', ''), + 'ou': pad, 'functie': _functie(u), 'telefoon': _telefoon(u)}) + token = resp.get('nextPageToken') + if not token: + break + return sorted(uit, key=lambda x: (x['achternaam'].lower(), x['voornaam'].lower())) + + +def bewaar_in_google(email, functie, telefoon): + """Functie (primaire organisatie) en werktelefoon van een gebruiker in Google aanpassen; de rest blijft.""" + api = _directory() + try: + u = api.users().get(userKey=email, projection='full', fields='organizations,phones').execute() + orgs = u.get('organizations') or [] + org = next((o for o in orgs if o.get('primary')), orgs[0] if orgs else None) + if org is None: + if functie: + orgs = [{'title': functie, 'primary': True, 'customType': ''}] + else: + org['title'] = functie + tel = [p for p in (u.get('phones') or []) if p.get('type') != 'work'] + if telefoon: + tel.insert(0, {'value': telefoon, 'type': 'work', 'primary': not any(p.get('primary') for p in tel)}) + api.users().patch(userKey=email, body={'organizations': orgs, 'phones': tel or []}).execute() + except Exception as e: + raise HandtekeningFout(f"{email}: {vriendelijk(e)}") + + +def pas_toe(gebruiker, inst, door=None, alleen_gewijzigd=False): + """Zet de handtekening voor het hoofdadres en de aliassen. Geeft 'ok' / 'ongewijzigd' of gooit HandtekeningFout.""" + tekst = vul_in(inst.get('Sjabloon') or '', gegevens(gebruiker), inst) + if len(tekst) > MAX_TEKENS: + raise HandtekeningFout(f"De handtekening is te lang voor Gmail ({len(tekst)} tekens, max. {MAX_TEKENS}).") + h = hashlib.sha1(tekst.encode('utf-8')).hexdigest() + email = gebruiker['email'] + if alleen_gewijzigd: + oud = execute_query("SELECT Hash, Ok FROM gmail_handtekening_log WHERE Email = %s", (email,)) + if oud and oud[0]['Ok'] and oud[0]['Hash'] == h and _huidige_in_gmail_gelijk(email, tekst): + return 'ongewijzigd' + try: + g = _gmail(email) + adressen = g.users().settings().sendAs().list(userId='me').execute().get('sendAs', []) + for a in adressen: + if a.get('isPrimary') or a.get('verificationStatus') == 'accepted' or a.get('treatAsAlias'): + g.users().settings().sendAs().patch(userId='me', sendAsEmail=a['sendAsEmail'], + body={'signature': tekst}).execute() + melding, ok = None, 1 + except Exception as e: + melding, ok = vriendelijk(e), 0 + execute_query("INSERT INTO gmail_handtekening_log (Email, Toegepast, Ok, Melding, Hash, Door) " + "VALUES (%s, NOW(), %s, %s, %s, %s) ON DUPLICATE KEY UPDATE Toegepast = NOW(), Ok = VALUES(Ok), " + "Melding = VALUES(Melding), Hash = VALUES(Hash), Door = VALUES(Door)", + (email, ok, melding, h if ok else None, door), commit=True) + if not ok: + raise HandtekeningFout(melding) + return 'ok' + + +def _huidige_in_gmail_gelijk(email, tekst): + """Staat de handtekening nog ongewijzigd in Gmail? (De gebruiker kan ze zelf aangepast hebben.)""" + try: + for a in _gmail(email).users().settings().sendAs().list(userId='me').execute().get('sendAs', []): + if a.get('isPrimary'): + gewoon = lambda x: re.sub(r'\s+', '', html.unescape(x or '')).lower() + return gewoon(a.get('signature')) == gewoon(tekst) + except Exception: + pass + return False + + +# --------------------------------------------------------------------- +# Toepassen op de achtergrond (met voortgang) +# --------------------------------------------------------------------- +class Toepasser: + def __new__(cls): + def init(inst): + inst._lock = threading.Lock() + inst.status = {'bezig': False, 'voortgang': 0, 'totaal': 0, 'gelukt': 0, 'ongewijzigd': 0, 'fouten': 0, + 'fout': None, 'resultaat': None, 'foutvoorbeelden': []} + return school_singleton(cls, init) + + def run(self, emails=None, door=None, alleen_gewijzigd=False): + if not self._lock.acquire(blocking=False): + return False, "Er loopt al een opdracht." + s = self.status + try: + s.update(bezig=True, voortgang=0, totaal=0, gelukt=0, ongewijzigd=0, fouten=0, fout=None, resultaat=None, + foutvoorbeelden=[]) + inst = instellingen() + lijst = gebruikers(inst['ous'], bool(inst.get('Met_sub_ous'))) + if emails is not None: + kies = {e.lower() for e in emails} + lijst = [u for u in lijst if u['email'] in kies] + s['totaal'] = len(lijst) + for u in lijst: + try: + if pas_toe(u, inst, door, alleen_gewijzigd) == 'ongewijzigd': + s['ongewijzigd'] += 1 + else: + s['gelukt'] += 1 + except Exception as e: + s['fouten'] += 1 + if len(s['foutvoorbeelden']) < 6: + s['foutvoorbeelden'].append(f"{u['email']}: {str(e)[:180]}") + s['voortgang'] += 1 + msg = f"Handtekening ingesteld voor {s['gelukt']} gebruiker(s)" + if s['ongewijzigd']: + msg += f", {s['ongewijzigd']} waren al in orde" + if s['fouten']: + msg += f", {s['fouten']} mislukt" + s['resultaat'] = msg + '.' + return True, s['resultaat'] + except Exception as e: + s['fout'] = str(e)[:400] + return False, s['fout'] + finally: + s['bezig'] = False + self._lock.release() + + def start(self, emails=None, door=None): + if self.status['bezig']: + return False + self.status.update(bezig=True, voortgang=0, totaal=0, fout=None, resultaat=None) + threading.Thread(target=met_school(lambda: self.run(emails, door)), daemon=True).start() + return True + + +# --------------------------------------------------------------------- +# Nachtelijk opnieuw toepassen (per school met de schakelaar aan) +# --------------------------------------------------------------------- +def _nacht_claim(vandaag): + return execute_query("UPDATE gmail_handtekening SET Laatste_nacht = %s WHERE ID = 1 AND Nachtelijk = 1 " + "AND (Laatste_nacht IS NULL OR Laatste_nacht < %s)", (vandaag, vandaag), commit=True) == 1 + + +def nacht_voor_alle_scholen(): + from tenancy import alle_scholen, in_school + vandaag = datetime.now().strftime('%Y-%m-%d') + for school in alle_scholen(): + if not school.google_sleutel: + continue + with in_school(school): + try: + ensure_tables() + if not _nacht_claim(vandaag): + continue + ok, msg = Toepasser().run(door='PIVOT (nachtelijk)', alleen_gewijzigd=True) + execute_query("UPDATE gmail_handtekening SET Nacht_resultaat = %s WHERE ID = 1", + (f"{datetime.now():%d-%m-%Y %H:%M}: {msg}"[:500],), commit=True) + except Exception as e: + sys.stderr.write(f"Handtekeningen nachtelijk ({school.code}): {e}\n") + + +_thread = None + + +def start_scheduler(): + global _thread + if _thread: + return + + def loop(): + time.sleep(90) + while True: + try: + if NACHT_UUR_VAN <= datetime.now().hour < NACHT_UUR_TOT: + nacht_voor_alle_scholen() + except Exception as e: + sys.stderr.write(f"Handtekeningen nachtelijke taak: {e}\n") + time.sleep(15 * 60) + + _thread = threading.Thread(target=loop, daemon=True) + _thread.start() diff --git a/services/html_schoon.py b/services/html_schoon.py new file mode 100644 index 0000000..4520acc --- /dev/null +++ b/services/html_schoon.py @@ -0,0 +1,115 @@ +""" +Maakt HTML uit de handleiding-editor veilig: enkel een vaste lijst tags en attributen blijft over. +Scripts, event-handlers (onclick, ...), stijlen en javascript:-links verdwijnen. +""" +from html import escape +from html.parser import HTMLParser + +TOEGELATEN = { + 'p': (), 'br': (), 'hr': (), 'div': (), 'span': (), + 'h2': ('id',), 'h3': ('id',), 'h4': ('id',), + 'strong': (), 'b': (), 'em': (), 'i': (), 'u': (), 's': (), 'mark': (), 'kbd': (), 'sub': (), 'sup': (), + 'ul': (), 'ol': ('start',), 'li': (), + 'blockquote': (), 'code': (), 'pre': (), + 'a': ('href', 'title', 'target'), + 'img': ('src', 'alt', 'title', 'width'), + 'table': (), 'thead': (), 'tbody': (), 'tr': (), 'th': ('colspan', 'rowspan'), 'td': ('colspan', 'rowspan'), + 'figure': (), 'figcaption': (), +} +LEEG = {'br', 'hr', 'img'} +KLASSEN = {'tip', 'let-op', 'info'} # kaders in de editor +WEGGOOIEN_MET_INHOUD = {'script', 'style', 'iframe', 'object', 'embed', 'noscript', 'template', 'svg', 'math'} +# Word/Docs plakt deze tags; de inhoud blijft, de tag niet +VERTALING = {'b': 'strong', 'i': 'em', 'h1': 'h2', 'h5': 'h4', 'h6': 'h4'} + + +def _veilige_url(url, afbeelding=False): + u = (url or '').strip() + laag = u.lower().replace('\x00', '') + if afbeelding and laag.startswith('data:image/') and ';base64,' in laag and not laag.startswith('data:image/svg'): + return u + if laag.startswith(('http://', 'https://', '/', '#')) or (not afbeelding and laag.startswith('mailto:')): + return u + return None + + +class _Schoonmaker(HTMLParser): + def __init__(self): + super().__init__(convert_charrefs=True) + self.uit = [] + self.open = [] + self.weg = 0 + + def handle_starttag(self, tag, attrs): + if tag in WEGGOOIEN_MET_INHOUD: + if tag not in LEEG: + self.weg += 1 + return + if self.weg: + return + tag = VERTALING.get(tag, tag) + if tag not in TOEGELATEN: + return + delen = [tag] + for naam, waarde in attrs: + naam = (naam or '').lower() + if naam == 'class': + klassen = [k for k in (waarde or '').split() if k in KLASSEN] + if klassen: + delen.append(f'class="{escape(" ".join(klassen))}"') + continue + if naam not in TOEGELATEN[tag]: + continue + if naam in ('href', 'src'): + waarde = _veilige_url(waarde, afbeelding=(naam == 'src')) + if waarde is None: + continue + if naam == 'target': + waarde = '_blank' + if naam in ('width', 'colspan', 'rowspan', 'start') and not str(waarde or '').isdigit(): + continue + delen.append(f'{naam}="{escape(waarde or "", quote=True)}"') + if tag == 'a' and any(d.startswith('target=') for d in delen): + delen.append('rel="noopener noreferrer"') + if tag == 'img' and not any(d.startswith('src=') for d in delen): + return + self.uit.append('<' + ' '.join(delen) + '>') + if tag not in LEEG: + self.open.append(tag) + + def handle_startendtag(self, tag, attrs): + self.handle_starttag(tag, attrs) + tag = VERTALING.get(tag, tag) + if tag not in LEEG and self.open and self.open[-1] == tag: + self.handle_endtag(tag) + + def handle_endtag(self, tag): + if tag in WEGGOOIEN_MET_INHOUD: + self.weg = max(0, self.weg - 1) + return + if self.weg: + return + tag = VERTALING.get(tag, tag) + if tag not in TOEGELATEN or tag in LEEG or tag not in self.open: + return + while self.open: + t = self.open.pop() + self.uit.append(f'') + if t == tag: + break + + def handle_data(self, data): + if not self.weg: + self.uit.append(escape(data, quote=False)) + + def resultaat(self): + while self.open: + self.uit.append(f'') + return ''.join(self.uit) + + +def schoon(html): + p = _Schoonmaker() + p.feed(html or '') + p.close() + return p.resultaat().strip() diff --git a/services/internaat_service.py b/services/internaat_service.py new file mode 100644 index 0000000..b0b6708 --- /dev/null +++ b/services/internaat_service.py @@ -0,0 +1,233 @@ +""" +Internaat: de internen uit Informat (Internaat WEB API, versie 1). + +- Token: zelfde identityserver en client-ID/secret als de andere Informat-API's, scope + api_informat_sas_internaat. + (meerdere instellingsnummers mogen in één token, gescheiden door een spatie). +- GET /pupils?schoolYear=2026-27&refdate=JJJJ-MM-DD → de internen met hun gegevens, relaties, ... +- GET /registrations?schoolYear=2026-27 → de inschrijvingen (internaat, vestiging, kamers, ...) + Headers: InstituteNo (instellingsnummer) en Api-Version: 1. 404 = geen gegevens. +Het resultaat wordt 10 minuten per school, schooljaar en peildatum bewaard. +""" +import time +from datetime import date + +import requests + +from config import Config + +CACHE_SECONDEN = 600 +TIMEOUT = (15, 180) +STANDAARD_API = 'https://internaatapi.informatsoftware.be' +STANDAARD_SCOPE = 'api_informat_sas_internaat' + + +class InternaatFout(Exception): + pass + + +def _datum(w): + if not w: + return None + try: + return date.fromisoformat(str(w)[:10]) + except ValueError: + return None + + +def _lopend(item, peildatum): + """Loopt dit (inschrijving of kamer) op de peildatum?""" + begin, einde = _datum(item.get('begindatum')), _datum(item.get('einddatum')) + return (not begin or begin <= peildatum) and (not einde or einde >= peildatum) + + +class InternaatService: + def __init__(self): + from tenancy import huidige_school, informat_campussen + self.school = huidige_school() + self.base = (self.school.get('INFORMAT_INTERNAAT_API') or STANDAARD_API).rstrip('/') + scope = (self.school.get('INFORMAT_INTERNAAT_SCOPE') or STANDAARD_SCOPE).strip() + self.scope_basis = scope.rsplit('.', 1)[0] if scope.rsplit('.', 1)[-1].isdigit() else scope + # Instellingsnummer(s) van het internaat; leeg = die van de Informat-koppeling van de school + eigen = informat_campussen(self.school.waarden.get('INFORMAT_INTERNAAT_NUMMER')) + self.nummers = eigen or informat_campussen(self.school.waarden.get('INFORMAT_INST_NUMBER')) + + # ---------------- authenticatie ---------------- + def _token(self, nummer): + sleutel = ('internaat_token', nummer) + bewaard = self.school.cache.get(sleutel) + if bewaard and time.time() < bewaard[0]: + return bewaard[1] + scope = f"{self.scope_basis}.{nummer}" + try: + r = requests.post(Config.INFORMAT_AUTH_URL, data={ + 'grant_type': 'client_credentials', 'client_id': Config.INFORMAT_ID, + 'client_secret': Config.INFORMAT_SECRET, 'scope': scope}, timeout=15) + except Exception as e: + raise InternaatFout(f"Informat (identityserver) is niet bereikbaar: {e}") + try: + js = r.json() + except Exception: + js = {} + if r.status_code != 200 or not js.get('access_token'): + fout = js.get('error') or f"HTTP {r.status_code}" + if fout == 'invalid_scope': + raise InternaatFout(f"Informat weigert de scope {scope} (invalid_scope). Heeft het internaat met " + f"instellingsnummer {nummer} in Informat de app toegang gegeven tot de Internaat-API? " + "Klopt het instellingsnummer van het internaat (Koppelingen › Informat)?") + if fout == 'invalid_client': + raise InternaatFout("Informat kent deze client-ID/secret niet (invalid_client). Kijk Koppelingen › Informat na.") + raise InternaatFout(f"Aanmelden bij de Internaat-API mislukt: {fout}") + self.school.cache[sleutel] = (time.time() + int(js.get('expires_in') or 3600) - 60, js['access_token']) + return js['access_token'] + + def _get(self, pad, nummer, params): + headers = {'Authorization': f"BEARER {self._token(nummer)}", 'InstituteNo': nummer, 'Api-Version': '1', + 'Accept': 'application/json'} + url = f"{self.base}{pad}" + try: + r = requests.get(url, params=params, headers=headers, timeout=TIMEOUT) + if r.status_code == 405: # de voorbeelden in de handleiding gebruiken POST + r = requests.post(url, params=params, headers=headers, timeout=TIMEOUT) + except requests.exceptions.Timeout: + raise InternaatFout("De Internaat-API van Informat antwoordde niet op tijd. Probeer later opnieuw.") + except Exception as e: + raise InternaatFout(f"De Internaat-API van Informat is niet bereikbaar: {e}") + if r.status_code == 404: + return [] # volgens Informat: geen gegevens + if r.status_code in (401, 403): + raise InternaatFout(f"Informat weigert de toegang tot de internen van {nummer} ({r.status_code}).") + if r.status_code != 200: + raise InternaatFout(f"Internaat-API ({nummer}): HTTP {r.status_code} {r.text[:200]}") + try: + data = r.json() + except Exception: + raise InternaatFout(f"Onverwacht antwoord van de Internaat-API: {r.text[:200]}") + return data if isinstance(data, list) else (data.get('items') or data.get('data') or []) + + # ---------------- internen ---------------- + def internen(self, schooljaar, peildatum=None, vernieuw=False): + """(rijen, opgehaald) met één rij per intern die op de peildatum ingeschreven is.""" + if not self.nummers: + raise InternaatFout("Er is nog geen instellingsnummer voor het internaat ingesteld (Koppelingen › Informat).") + peildatum = peildatum or date.today() + sleutel = ('internen', schooljaar, peildatum.isoformat()) + bewaard = self.school.cache.get(sleutel) + if bewaard and not vernieuw and time.time() - bewaard[0] < CACHE_SECONDEN: + return bewaard[1], bewaard[0] + rijen, gezien = [], set() + for nummer, campusnaam in self.nummers: + inschrijvingen = {} + for ins in self._get('/registrations', nummer, {'schoolYear': schooljaar}): + if _lopend(ins, peildatum) or str(ins.get('pPersoon')) not in inschrijvingen: + inschrijvingen[str(ins.get('pPersoon'))] = ins + for p in self._get('/pupils', nummer, {'schoolYear': schooljaar, 'refdate': peildatum.isoformat()}): + sleutel_p = str(p.get('persoonId') or p.get('pPersoon')) + if sleutel_p in gezien: # zelfde intern via een tweede instellingsnummer + continue + gezien.add(sleutel_p) + ins = inschrijvingen.get(str(p.get('pPersoon'))) or {} + kamer = next((k for k in ins.get('kamers') or [] if _lopend(k, peildatum)), None) + ouders = [] + for rel in sorted(p.get('relaties') or [], key=lambda x: (x.get('lpv') or 9)): + if rel.get('isOverleden'): + continue + gsm = next((c.get('nr') for c in rel.get('comnrs') or [] if (c.get('soort') or '').lower() == 'gsm'), None) \ + or next((c.get('nr') for c in rel.get('comnrs') or []), None) + mail = next((e.get('email') for e in rel.get('emails') or [] if e.get('schoolcom')), None) \ + or next((e.get('email') for e in rel.get('emails') or []), None) + ouders.append({'type': rel.get('type') or '', 'naam': f"{rel.get('voornaam') or ''} {rel.get('naam') or ''}".strip(), + 'gsm': gsm or '', 'email': mail or ''}) + adres = next((a for a in p.get('adressen') or [] if a.get('isVerblijf')), None) or \ + next(iter(p.get('adressen') or []), None) or {} + rijen.append({ + 'id': p.get('pPersoon'), + 'naam': (p.get('naam') or '').strip(), 'voornaam': (p.get('voornaam') or '').strip(), + 'geboortedatum': _datum(p.get('geboortedatum')), 'geslacht': p.get('geslacht') or '', + 'stamnummer': ins.get('stamnr') or '', + 'internaat': ins.get('internaat') or campusnaam or nummer, 'nummer': nummer, + 'vestiging': ins.get('vestiging') or '', + 'begin': _datum(ins.get('begindatum')), 'einde': _datum(ins.get('einddatum')), + 'financiering': ins.get('fin') or '', + 'kamer': ' '.join(x for x in ( + f"blok {kamer.get('blok')}" if kamer and kamer.get('blok') else '', + f"verd. {kamer.get('verdiep')}" if kamer and kamer.get('verdiep') not in (None, '') else '', + f"nr. {kamer.get('nr')}" if kamer and kamer.get('nr') not in (None, '') else '') if x), + 'kamer_sort': f"{(kamer or {}).get('blok') or ''}-{str((kamer or {}).get('verdiep') or '').zfill(3)}-{str((kamer or {}).get('nr') or '').zfill(5)}" if kamer else '', + 'ouders': ouders, + 'gemeente': ' '.join(x for x in (adres.get('postcode'), adres.get('gemeente')) if x), + 'huisdokter': ' – '.join(x for x in (p.get('huisdokter'), p.get('telefoonHuisdokter')) if x), + }) + rijen.sort(key=lambda r: (r['naam'].lower(), r['voornaam'].lower())) + nu = time.time() + self.school.cache[sleutel] = (nu, rijen) + return rijen, nu + + +# --------------------------------------------------------------------- +# Bestaat de intern in Smartschool? (gebruikersnaam = "voornaam achternaam") +# --------------------------------------------------------------------- +SS_CACHE_SECONDEN = 3600 + + +def _naamdeel(tekst): + """'Van den Broeck' → 'vandenbroeck', 'Zoë' → 'zoe'.""" + import unicodedata + t = unicodedata.normalize('NFKD', str(tekst or '')).encode('ascii', 'ignore').decode().lower() + return ''.join(c for c in t if c.isalnum() or c == '-') + + +def ss_kandidaten(voornaam, naam): + """Mogelijke Smartschool-gebruikersnamen: eerst "voornaam achternaam" (met spatie), dan varianten.""" + v, n = _naamdeel(voornaam), _naamdeel(naam) + vol = ' '.join(f"{str(voornaam).strip()} {str(naam).strip()}".split()) + # Op het internaat: "voornaam achternaam" met een spatie (eerst zoals in Informat, dan in kleine letters) + uit = [vol, vol.lower(), f"{v} {n}", + f"{v}.{n}", f"{v}.{n.replace('-', '')}", f"{v.replace('-', '')}.{n.replace('-', '')}", f"{v}{n}"] + return [x for x in dict.fromkeys(uit) if x.strip('. ')] + + +def smartschool_status(personen): + """personen: [{'pid', 'voornaam', 'naam'}] → {pid: gebruikersnaam of None}. 1 uur bewaard per school.""" + import threading + from concurrent.futures import ThreadPoolExecutor + from tenancy import huidige_school, in_school + school = huidige_school() + if not school.heeft('SS_API_PLATFORM', 'SS_API_PW'): + raise InternaatFout("Smartschool is nog niet ingesteld voor deze school (🔌 Koppelingen › Smartschool).") + cache = school.cache.setdefault('ss_internen', {}) + nu = time.time() + uit, te_doen = {}, [] + for p in personen: + sleutel = (str(p.get('pid')), p.get('voornaam') or '', p.get('naam') or '') + hit = cache.get(sleutel) + if hit and nu - hit[0] < SS_CACHE_SECONDEN: + uit[sleutel[0]] = hit[1] + else: + te_doen.append(sleutel) + if not te_doen: + return uit + lokaal = threading.local() + + def zoek(sleutel): + pid, voornaam, naam = sleutel + with in_school(school): + if not hasattr(lokaal, 'ss'): + from services.smartschool_api import SmartschoolService + lokaal.ss = SmartschoolService(Config.SS_API_PLATFORM, Config.SS_API_PW) + gevonden = None + for kandidaat in ss_kandidaten(voornaam, naam): + try: + raw = lokaal.ss.client.service.getUserDetailsByUsername(Config.SS_API_PW, kandidaat) + except Exception: + continue + if isinstance(raw, str) and raw.strip().startswith('{'): + gevonden = kandidaat + break + return sleutel, gevonden + + with ThreadPoolExecutor(max_workers=4) as pool: + for sleutel, gevonden in pool.map(zoek, te_doen): + cache[sleutel] = (time.time(), gevonden) + uit[sleutel[0]] = gevonden + return uit diff --git a/services/ipblokkade.py b/services/ipblokkade.py new file mode 100644 index 0000000..8eb3aca --- /dev/null +++ b/services/ipblokkade.py @@ -0,0 +1,196 @@ +""" +IP-blokkades: aanvragen van bepaalde IP-adressen of reeksen weigeren, voor alle scholen. + +Regels staan in de centrale tabel IP_blokkades: +- Soort 'blokkeren' → elke aanvraag van zo'n adres krijgt 403 (ook de loginpagina). +- Soort 'toestaan' → uitzondering: dit adres mag altijd, ook als het in een geblokkeerde reeks valt. + +Een reeks kan je schrijven als: + 85. → alles wat met 85. begint (85.0.0.0/8) + 85.12. → 85.12.0.0/16 + 85.12.3. → 85.12.3.0/24 + 85.12.3.4 → één adres + 85.0.0.0/8 → CIDR-notatie (ook IPv6, bv. 2a02:1810::/32) +De lijst wordt 30 seconden in het geheugen gehouden; een wijziging in PIVOT geldt meteen. +Lukt het lezen van de database niet, dan wordt niemand geweigerd (de site blijft bereikbaar). +""" +import ipaddress +import sys +import threading +import time + +CACHE_SECONDEN = 30 +_cache = {'t': 0, 'regels': []} +_lock = threading.Lock() + + +class OngeldigeReeks(ValueError): + pass + + +def normaliseer(reeks): + """Tekst van de gebruiker → ip_network. '85.' → 85.0.0.0/8, '85.12.3.4' → 85.12.3.4/32.""" + t = str(reeks or '').strip().replace(' ', '') + if not t: + raise OngeldigeReeks("Vul een IP-adres of reeks in.") + if '/' not in t and ':' not in t: + delen = t.rstrip('.').split('.') if t.endswith('.') or t.count('.') < 3 else None + if delen is not None: + if not 1 <= len(delen) <= 3 or not all(d.isdigit() and 0 <= int(d) <= 255 for d in delen): + raise OngeldigeReeks(f"'{reeks}' is geen geldige reeks. Voorbeelden: 85. 85.12. 85.12.3.4 85.0.0.0/8") + t = '.'.join(delen + ['0'] * (4 - len(delen))) + f"/{8 * len(delen)}" + try: + return ipaddress.ip_network(t, strict=False) + except ValueError: + raise OngeldigeReeks(f"'{reeks}' is geen geldig IP-adres of geldige reeks. " + "Voorbeelden: 85. 85.12. 85.12.3.4 85.0.0.0/8") + + +def ensure_table(): + from database import central_query + central_query(""" + CREATE TABLE IF NOT EXISTS PIVOT_instellingen ( + Sleutel VARCHAR(50) NOT NULL PRIMARY KEY, + Waarde VARCHAR(255) NULL, + Bijgewerkt DATETIME NULL, + Door VARCHAR(100) NULL + ) ENGINE=InnoDB""", commit=True) + central_query(""" + CREATE TABLE IF NOT EXISTS IP_blokkades ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Reeks VARCHAR(64) NOT NULL, + Soort VARCHAR(10) NOT NULL DEFAULT 'blokkeren', + Opmerking VARCHAR(255) NULL, + Scholen VARCHAR(1000) NULL, + Aangemaakt DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Gebruiker_ID INT NULL, + Aantal_geweigerd INT NOT NULL DEFAULT 0, + Laatst_geweigerd DATETIME NULL, + UNIQUE KEY uq_ip_reeks (Reeks, Soort) + ) ENGINE=InnoDB""", commit=True) + # Bestaande tabel van vóór de schoolkeuze bij "Altijd toestaan" (of met de eerdere kolom School_code: één school) + kolommen = {r['Field'].lower() for r in central_query("SHOW COLUMNS FROM IP_blokkades") or []} + if 'scholen' not in kolommen: + central_query("ALTER TABLE IP_blokkades ADD COLUMN Scholen VARCHAR(1000) NULL AFTER Opmerking", commit=True) + if 'school_code' in kolommen: + central_query("UPDATE IP_blokkades SET Scholen = School_code WHERE School_code IS NOT NULL", commit=True) + if 'school_code' in kolommen: + central_query("ALTER TABLE IP_blokkades DROP COLUMN School_code", commit=True) + if 'gebruiker_id' not in kolommen: # wie de regel toevoegde (gewone gebruikers mogen enkel hun eigen regels verwijderen) + central_query("ALTER TABLE IP_blokkades ADD COLUMN Gebruiker_ID INT NULL AFTER Door", commit=True) + + +def scholen_codes(waarde): + """'a,b' (kolom Scholen) → ['a', 'b'].""" + return [c for c in (x.strip() for x in str(waarde or '').split(',')) if c] + + +def scholen_waarde(codes): + """['a', 'b'] → 'a,b' (of None), zonder dubbels, in de gegeven volgorde.""" + uit = [] + for c in codes or []: + c = str(c).strip() + if c and c not in uit: + uit.append(c) + return ','.join(uit)[:1000] or None + + +MODUS_SLEUTEL = 'ip_enkel_toegestaan' # '1' = enkel adressen uit "Altijd toestaan" mogen binnen +TELLER_SLEUTEL = 'ip_whitelist_geweigerd' # aantal weigeringen door die modus + + +def _laad(): + from database import central_query + uit = [] + for r in central_query("SELECT ID, Reeks, Soort FROM IP_blokkades") or []: + try: + uit.append((r['ID'], r['Soort'], ipaddress.ip_network(r['Reeks'], strict=False))) + except ValueError: + continue + rij = central_query("SELECT Waarde FROM PIVOT_instellingen WHERE Sleutel = %s", (MODUS_SLEUTEL,)) + _cache.update(t=time.time(), regels=uit, enkel_toegestaan=bool(rij and rij[0]['Waarde'] == '1')) + + +def regels(vers=False): + """[(id, soort, ip_network)] uit de database (gecachet).""" + if vers or time.time() - _cache['t'] >= CACHE_SECONDEN: + with _lock: + if vers or time.time() - _cache['t'] >= CACHE_SECONDEN: + _laad() + return _cache['regels'] + + +def enkel_toegestaan(vers=False): + """True als de modus "enkel Altijd toestaan" aan staat.""" + regels(vers) + return _cache.get('enkel_toegestaan', False) + + +def zet_enkel_toegestaan(aan, door=None): + from database import central_query + central_query("INSERT INTO PIVOT_instellingen (Sleutel, Waarde, Bijgewerkt, Door) VALUES (%s, %s, NOW(), %s) " + "ON DUPLICATE KEY UPDATE Waarde = VALUES(Waarde), Bijgewerkt = NOW(), Door = VALUES(Door)", + (MODUS_SLEUTEL, '1' if aan else '0', door), commit=True) + vergeet_cache() + + +def instelling(sleutel): + from database import central_query + rij = central_query("SELECT Waarde, Bijgewerkt, Door FROM PIVOT_instellingen WHERE Sleutel = %s", (sleutel,)) + return rij[0] if rij else None + + +def is_lokaal(ip): + """127.0.0.1 of ::1: dan ziet PIVOT waarschijnlijk een reverse proxy i.p.v. de echte bezoeker.""" + try: + a = ipaddress.ip_address(str(ip or '').strip()) + except ValueError: + return False + return a.is_loopback + + +def vergeet_cache(): + _cache['t'] = 0 + + +def beoordeel(ip, lijst=None, enkel_toe=None): + """Geeft (geweigerd, regel_id). Een 'toestaan'-regel wint altijd van een 'blokkeren'-regel. + In de modus "enkel Altijd toestaan" wordt alles geweigerd wat niet op die lijst staat (regel_id = 'modus').""" + try: + adres = ipaddress.ip_address(str(ip or '').strip()) + except ValueError: + return False, None + if getattr(adres, 'ipv4_mapped', None): # ::ffff:85.1.2.3 → 85.1.2.3 + adres = adres.ipv4_mapped + lijst = regels() if lijst is None else lijst + if any(s == 'toestaan' and adres in net for _, s, net in lijst if net.version == adres.version): + return False, None + if enkel_toegestaan() if enkel_toe is None else enkel_toe: + return True, 'modus' + for rid, s, net in lijst: + if s == 'blokkeren' and net.version == adres.version and adres in net: + return True, rid + return False, None + + +def controleer(ip): + """Voor elke aanvraag: True = weigeren. Telt de weigering bij de regel. Faalt nooit (fout → doorlaten).""" + try: + geweigerd, rid = beoordeel(ip) + except Exception as e: + sys.stderr.write(f"PIVOT: IP-blokkades lezen mislukt: {e}\n") + return False + if geweigerd: + try: + from database import central_query + if rid == 'modus': + central_query("INSERT INTO PIVOT_instellingen (Sleutel, Waarde, Bijgewerkt) VALUES (%s, '1', NOW()) " + "ON DUPLICATE KEY UPDATE Waarde = CAST(Waarde AS UNSIGNED) + 1, Bijgewerkt = NOW()", + (TELLER_SLEUTEL,), commit=True) + else: + central_query("UPDATE IP_blokkades SET Aantal_geweigerd = Aantal_geweigerd + 1, " + "Laatst_geweigerd = NOW() WHERE ID = %s", (rid,), commit=True) + except Exception: + pass + return geweigerd diff --git a/services/personeel_service.py b/services/personeel_service.py new file mode 100644 index 0000000..04d7060 --- /dev/null +++ b/services/personeel_service.py @@ -0,0 +1,371 @@ +""" +Personeel: afwezigheden van leerkrachten, nascholingen en uitstappen. + +Rollen (config.ini › [personeel]): + - leerkracht : iedereen in personeel_ous die met Google inlogt (PIVOT-groep 5). + Ziet en beheert enkel zijn eigen meldingen/aanvragen. + - directie : e-mailadressen in 'directie' → keurt nascholingen en uitstappen goed. + - secretariaat : e-mailadressen in 'secretariaat' → dagoverzicht, vervangingen, + melden namens een leerkracht. + PIVOT-gebruikers met het recht 'personeel_secretariaat' / 'personeel_directie' in deze + school krijgen die rol ook. Administrators hebben de secretariaatsrechten, en ook de + directierechten zolang er nog geen directie is ingesteld. + +Soorten: + - afwezigheid : geen goedkeuring nodig, meteen zichtbaar voor het secretariaat + - nascholing : goedkeuring door de directie + - uitstap : goedkeuring door de directie (klassen + begeleiders zijn weg) +""" +import json +import sys +import threading +import time +from datetime import date, timedelta + +from config import Config +from database import execute_query, get_db_connection +from tenancy import huidige_school, met_school + +LEERKRACHT_GROEP = 5 + +SOORTEN = { + 'afwezigheid': {'label': 'Afwezigheid', 'icoon': '🤒', 'goedkeuring': False}, + 'nascholing': {'label': 'Nascholing', 'icoon': '🎓', 'goedkeuring': True}, + 'uitstap': {'label': 'Uitstap', 'icoon': '🚌', 'goedkeuring': True}, +} +STATUS = { + 'gemeld': ('Gemeld', 'info'), + 'ingediend': ('Wacht op directie', 'warning'), + 'vraag': ('Vraag van directie', 'warning'), + 'goedgekeurd': ('Goedgekeurd', 'success'), + 'geweigerd': ('Geweigerd', 'danger'), + 'geannuleerd': ('Geannuleerd', ''), +} +DAGDELEN = {'dag': 'Hele dag', 'vm': 'Voormiddag', 'nm': 'Namiddag', 'uren': 'Bepaalde lesuren'} +# Statussen die in het dagoverzicht meetellen als "is weg" +ACTIEF = ('gemeld', 'goedgekeurd') + + +def _lijst(waarde): + return [x.strip().lower() for x in (waarde or '').replace(';', ',').split(',') if x.strip()] + + +# ---------------- rollen ---------------- +def directie(): + return _lijst(Config.PERSONEEL_DIRECTIE) + + +def secretariaat(): + return _lijst(Config.PERSONEEL_SECRETARIAAT) + + +def rollen(sess): + """Rollen in de personeelsmodule: via de e-maillijsten van de school of via de PIVOT-rechten + 'personeel_directie' / 'personeel_secretariaat' (Gebruikers & rechten).""" + from rechten import heeft_recht, is_admin + email = (sess.get('user') or '').lower() + admin = is_admin() + r = {'leerkracht'} + if email in directie() or (heeft_recht('personeel_directie') and (not admin or not directie())): + r.add('directie') + if email in secretariaat() or heeft_recht('personeel_secretariaat'): + r.add('secretariaat') + return r + + +_ou_cache = {} + + +def is_personeelslid(email): + """True als het Google-account in een van de personeels-OU's zit (cache 10 min).""" + email = (email or '').lower() + school = huidige_school() + if email.rsplit('@', 1)[-1] not in school.domeinen: + return False + sleutel = (school.code, email) + hit = _ou_cache.get(sleutel) + if hit and time.time() - hit[0] < 600: + return hit[1] + ok = False + try: + from services.google_service import GoogleAdminService + u = GoogleAdminService().get_user_info(email) or {} + ou = u.get('orgUnitPath', '') + ok = (not u.get('suspended')) and any(ou == p or ou.startswith(p.rstrip('/') + '/') + for p in [x.strip() for x in Config.PERSONEEL_OUS.split(',') if x.strip()]) + except Exception as e: + sys.stderr.write(f"Personeel: OU-controle mislukt voor {email}: {e}\n") + _ou_cache[sleutel] = (time.time(), ok) + return ok + + +# ---------------- klassen uit Smartschool ---------------- +def klassen(): + """Officiële klassen uit Smartschool (cache 6 uur, per school). Lege lijst als het niet lukt.""" + _klassen_cache = huidige_school().object('klassen_cache', lambda: {'t': 0, 'lijst': []}) + if _klassen_cache['lijst'] and time.time() - _klassen_cache['t'] < 6 * 3600: + return _klassen_cache['lijst'] + try: + from services.smartschool_api import SmartschoolService + ss = SmartschoolService(platform=Config.SS_API_PLATFORM, webservice_pwd=Config.SS_API_PW) + raw = ss.client.service.getClassListJson(Config.SS_API_PW) + data = json.loads(raw) if isinstance(raw, str) else raw + if isinstance(data, dict): + data = list(data.values()) + namen = [] + for k in data or []: + if not isinstance(k, dict): + continue + officieel = k.get('isKlas', k.get('isOfficial', True)) + if str(officieel).lower() in ('false', '0', 'none'): + continue + naam = (k.get('name') or k.get('code') or '').strip() + if naam: + namen.append(naam) + lijst = sorted(set(namen), key=lambda n: (len(n) > 3, n)) + if lijst: + _klassen_cache.update(t=time.time(), lijst=lijst) + return lijst + except Exception as e: + sys.stderr.write(f"Personeel: klassenlijst uit Smartschool mislukt: {e}\n") + return _klassen_cache['lijst'] + + +# ---------------- database ---------------- +def ensure_tables(): + execute_query(""" + CREATE TABLE IF NOT EXISTS personeel_aanvragen ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Soort VARCHAR(20) NOT NULL, + Status VARCHAR(20) NOT NULL, + Email VARCHAR(255) NOT NULL, + Naam VARCHAR(255) NULL, + Ingediend_door VARCHAR(255) NULL, + Titel VARCHAR(255) NOT NULL, + Omschrijving TEXT NULL, + Locatie VARCHAR(255) NULL, + Van_datum DATE NOT NULL, + Tot_datum DATE NOT NULL, + Dagdeel VARCHAR(10) NOT NULL DEFAULT 'dag', + Lesuren VARCHAR(50) NULL, + Klassen TEXT NULL, + Begeleiders TEXT NULL, + Kost DECIMAL(10,2) NULL, + Vervanging_ok TINYINT(1) NOT NULL DEFAULT 0, + Vervanging_info VARCHAR(255) NULL, + Aangemaakt DATETIME NOT NULL, + Bijgewerkt DATETIME NOT NULL, + INDEX idx_status (Status), + INDEX idx_datum (Van_datum, Tot_datum), + INDEX idx_email (Email) + )""", commit=True) + execute_query(""" + CREATE TABLE IF NOT EXISTS personeel_reacties ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Aanvraag_ID INT NOT NULL, + Tijdstip DATETIME NOT NULL, + Email VARCHAR(255) NULL, + Naam VARCHAR(255) NULL, + Actie VARCHAR(30) NOT NULL, + Tekst TEXT NULL, + INDEX idx_aanvraag (Aanvraag_ID) + )""", commit=True) + + +def _reactie(aanvraag_id, email, naam, actie, tekst=None): + execute_query("INSERT INTO personeel_reacties (Aanvraag_ID, Tijdstip, Email, Naam, Actie, Tekst) " + "VALUES (%s, NOW(), %s, %s, %s, %s)", (aanvraag_id, email, naam, actie, tekst), commit=True) + + +def aanmaken(data, door_email, door_naam): + soort = data['soort'] + status = 'ingediend' if SOORTEN[soort]['goedkeuring'] else 'gemeld' + conn = get_db_connection() + cur = conn.cursor() + try: + cur.execute(""" + INSERT INTO personeel_aanvragen (Soort, Status, Email, Naam, Ingediend_door, Titel, Omschrijving, Locatie, + Van_datum, Tot_datum, Dagdeel, Lesuren, Klassen, Begeleiders, Kost, Aangemaakt, Bijgewerkt) + VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,NOW(),NOW())""", + (soort, status, data['email'], data['naam'], door_email if door_email != data['email'] else None, + data['titel'], data.get('omschrijving'), data.get('locatie'), data['van'], data['tot'], + data['dagdeel'], data.get('lesuren'), ', '.join(data.get('klassen') or []), + data.get('begeleiders'), data.get('kost'))) + conn.commit() + aid = cur.lastrowid + finally: + cur.close() + conn.close() + tekst = None if door_email == data['email'] else f"Gemeld door {door_naam or door_email}" + _reactie(aid, door_email, door_naam, 'gemeld' if status == 'gemeld' else 'ingediend', tekst) + return aid + + +def get(aid): + rows = execute_query("SELECT * FROM personeel_aanvragen WHERE ID = %s", (aid,)) + return rows[0] if rows else None + + +def reacties(aid): + return execute_query( + "SELECT Tijdstip, Email, Naam, Actie, Tekst FROM personeel_reacties WHERE Aanvraag_ID = %s ORDER BY Tijdstip, ID", + (aid,)) + + +def wijzig_status(aid, nieuwe_status, door_email, door_naam, actie, tekst=None): + execute_query("UPDATE personeel_aanvragen SET Status = %s, Bijgewerkt = NOW() WHERE ID = %s", + (nieuwe_status, aid), commit=True) + _reactie(aid, door_email, door_naam, actie, tekst) + + +def commentaar(aid, door_email, door_naam, tekst): + execute_query("UPDATE personeel_aanvragen SET Bijgewerkt = NOW() WHERE ID = %s", (aid,), commit=True) + _reactie(aid, door_email, door_naam, 'commentaar', tekst) + + +def vervanging(aid, ok, info, door_email, door_naam): + execute_query("UPDATE personeel_aanvragen SET Vervanging_ok = %s, Vervanging_info = %s, Bijgewerkt = NOW() " + "WHERE ID = %s", (1 if ok else 0, (info or '')[:255] or None, aid), commit=True) + _reactie(aid, door_email, door_naam, 'vervanging', + ('Vervanging geregeld' if ok else 'Vervanging nog niet geregeld') + (f": {info}" if info else '')) + + +def mijn(email): + return execute_query("SELECT * FROM personeel_aanvragen WHERE Email = %s ORDER BY Van_datum DESC, ID DESC LIMIT 200", + (email,)) + + +def te_beoordelen(): + return execute_query("SELECT * FROM personeel_aanvragen WHERE Status IN ('ingediend','vraag') " + "ORDER BY Status = 'vraag', Van_datum, ID") + + +def recent_beslist(limit=20): + return execute_query("SELECT * FROM personeel_aanvragen WHERE Status IN ('goedgekeurd','geweigerd') " + "AND Soort <> 'afwezigheid' ORDER BY Bijgewerkt DESC LIMIT %s", (int(limit),)) + + +def periode(van, tot, statussen=ACTIEF): + ph = ','.join(['%s'] * len(statussen)) + return execute_query( + f"SELECT * FROM personeel_aanvragen WHERE Status IN ({ph}) AND Van_datum <= %s AND Tot_datum >= %s " + "ORDER BY Van_datum, Naam", tuple(statussen) + (tot, van)) + + +def aantal_te_beoordelen(): + try: + return execute_query("SELECT COUNT(*) AS n FROM personeel_aanvragen WHERE Status = 'ingediend'")[0]['n'] + except Exception: + return 0 + + +# ---------------- dagoverzicht ---------------- +def dagoverzicht(van, tot): + """Per dag: wie is weg en welke klassen zijn weg (enkel gemeld/goedgekeurd), plus wat nog wacht.""" + items = periode(van, tot) + wachtend = periode(van, tot, ('ingediend', 'vraag')) + dagen = [] + d = van + while d <= tot: + if d.weekday() < 5: + vandaag = [i for i in items if i['Van_datum'] <= d <= i['Tot_datum']] + personen, klassen_weg = [], [] + for i in vandaag: + personen.append({'naam': i['Naam'] or i['Email'], 'email': i['Email'], 'item': i, 'rol': None}) + if i['Soort'] == 'uitstap': + for b in [x.strip() for x in (i['Begeleiders'] or '').split(',') if x.strip()]: + personen.append({'naam': b, 'email': None, 'item': i, 'rol': 'begeleider'}) + for k in [x.strip() for x in (i['Klassen'] or '').split(',') if x.strip()]: + klassen_weg.append({'klas': k, 'item': i}) + dagen.append({ + 'datum': d, 'personen': personen, + 'klassen': sorted(klassen_weg, key=lambda k: k['klas']), + 'wachtend': [w for w in wachtend if w['Van_datum'] <= d <= w['Tot_datum']], + 'open_vervanging': sum(1 for i in vandaag if i['Klassen'] and i['Soort'] != 'uitstap' and not i['Vervanging_ok']), + }) + d += timedelta(days=1) + return dagen + + +# ---------------- e-mail ---------------- +def _mail_async(ontvangers, onderwerp, html): + ontvangers = sorted({o for o in ontvangers if o and '@' in o}) + if not Config.PERSONEEL_MAILS or not ontvangers: + return + + def verstuur(): + try: + from services.google_service import GoogleAdminService + svc = GoogleAdminService() + for o in ontvangers: + ok, msg = svc.send_custom_mail(o, onderwerp, html) + if not ok: + sys.stderr.write(f"Personeel: mail naar {o} mislukt: {msg}\n") + except Exception as e: + sys.stderr.write(f"Personeel: mail mislukt: {e}\n") + + threading.Thread(target=met_school(verstuur), daemon=True).start() + + +def _mailtekst(item, intro, link, extra=None): + soort = SOORTEN[item['Soort']] + periode_txt = item['Van_datum'].strftime('%d/%m/%Y') + if item['Tot_datum'] != item['Van_datum']: + periode_txt += ' – ' + item['Tot_datum'].strftime('%d/%m/%Y') + dagdeel = DAGDELEN.get(item['Dagdeel'], '') + if item['Dagdeel'] == 'uren' and item['Lesuren']: + dagdeel += f" ({item['Lesuren']})" + rijen = [('Wie', item['Naam'] or item['Email']), ('Wat', f"{soort['icoon']} {soort['label']}: {item['Titel']}"), + ('Wanneer', f"{periode_txt}, {dagdeel}")] + if item['Klassen']: + rijen.append(('Klassen', item['Klassen'])) + if item['Begeleiders']: + rijen.append(('Begeleiders', item['Begeleiders'])) + if item['Kost']: + rijen.append(('Kost', f"€ {item['Kost']}")) + tabel = ''.join(f"{k}{v}" + for k, v in rijen) + extra_html = f"

{extra}

" if extra else '' + return (f"
" + f"

{intro}

{tabel}
{extra_html}" + f"

" + f"Openen in PIVOT

") + + +def secretariaat_adressen(): + return _lijst(Config.PERSONEEL_SECRETARIAAT_MAIL) or secretariaat() + + +def mail_nieuw(item, link): + soort = SOORTEN[item['Soort']] + if soort['goedkeuring']: + _mail_async(directie(), f"Nieuwe aanvraag {soort['label'].lower()}: {item['Naam']} – {item['Titel']}", + _mailtekst(item, f"Er is een nieuwe aanvraag voor een {soort['label'].lower()} die je goedkeuring vraagt.", link)) + else: + _mail_async(secretariaat_adressen(), f"Afwezig: {item['Naam']} ({item['Van_datum']:%d/%m})", + _mailtekst(item, "Er is een afwezigheid gemeld.", link, item['Omschrijving'])) + + +def mail_beslissing(item, beslissing, tekst, link): + soort = SOORTEN[item['Soort']] + woorden = {'goedgekeurd': 'is goedgekeurd ✅', 'geweigerd': 'is geweigerd ❌', 'vraag': 'heeft een vraag van de directie ❓'} + _mail_async([item['Email']], f"Je aanvraag {soort['label'].lower()} {woorden[beslissing]}", + _mailtekst(item, f"Je aanvraag {item['Titel']} {woorden[beslissing]}.", link, + f"Commentaar: {tekst}" if tekst else None)) + if beslissing == 'goedgekeurd': + _mail_async(secretariaat_adressen(), f"Goedgekeurd: {soort['label'].lower()} {item['Naam']} ({item['Van_datum']:%d/%m})", + _mailtekst(item, f"Een {soort['label'].lower()} is goedgekeurd en staat nu in het dagoverzicht.", link)) + + +def mail_antwoord(item, tekst, link): + _mail_async(directie(), f"Antwoord van {item['Naam']}: {item['Titel']}", + _mailtekst(item, "De leerkracht heeft geantwoord op je vraag; de aanvraag wacht opnieuw op je beslissing.", + link, tekst)) + + +def mail_geannuleerd(item, link): + ontvangers = secretariaat_adressen() if item['Status'] in ('gemeld', 'goedgekeurd') else [] + if SOORTEN[item['Soort']]['goedkeuring']: + ontvangers = ontvangers + directie() + _mail_async(ontvangers, f"Geannuleerd: {SOORTEN[item['Soort']]['label'].lower()} {item['Naam']} ({item['Van_datum']:%d/%m})", + _mailtekst(item, "Deze melding/aanvraag is geannuleerd.", link)) diff --git a/services/sgr_groepen_service.py b/services/sgr_groepen_service.py new file mode 100644 index 0000000..a40b5c8 --- /dev/null +++ b/services/sgr_groepen_service.py @@ -0,0 +1,193 @@ +""" +Smartschool › SGR groepen: de subgroepen van één hoofdgroep (standaard 'groepen GO-Antwerpen') met hun huidige leden. + +Werking (Smartschool-webservices V3): +1. getAllGroupsAndClasses → de volledige boom van groepen en klassen (XML, meestal base64-gecodeerd) +2. de hoofdgroep zoeken op naam of code, en alle groepen eronder verzamelen (ook dieper geneste) +3. getAllAccountsExtended(code, '0') → de rechtstreekse leden van elke (sub)groep +Het resultaat wordt 10 minuten per school bewaard (knop 'Opnieuw ophalen' om te vernieuwen). +""" +import base64 +import json +import threading +import time +import xml.etree.ElementTree as ET +from concurrent.futures import ThreadPoolExecutor + +from config import Config + +STANDAARD_GROEP = 'groepen GO-Antwerpen' +CACHE_SECONDEN = 10 * 60 +ROLLEN = {'1': 'Leerling', '2': 'Leerkracht', '3': 'Directie', '4': 'Andere', '5': 'Andere', '6': 'Andere'} + + +class SgrFout(Exception): + pass + + +def _foutcode(raw): + return isinstance(raw, (int, float)) or (isinstance(raw, str) and raw.strip().lstrip('-').isdigit()) + + +def _tekst(raw): + """Antwoord van Smartschool → tekst (base64 wordt gedecodeerd als dat XML/JSON oplevert).""" + if isinstance(raw, bytes): + raw = raw.decode('utf-8', 'replace') + t = str(raw or '').strip() + if t and t[0] not in '<{[': + try: + d = base64.b64decode(t, validate=False).decode('utf-8', 'replace').strip() + if d[:1] in ('<', '{', '['): + return d + except Exception: + pass + return t + + +def _kind(el, *namen): + for n in namen: + for c in el: + if c.tag.lower() == n: + return c + return None + + +def _veld(el, *namen): + c = _kind(el, *namen) + return (c.text or '').strip() if c is not None and c.text else '' + + +def _groepen_xml(root): + """XML-boom → [{'naam','code','omschrijving','type','kinderen':[...]}].""" + def groep(el): + details = _kind(el, 'details') + d = details if details is not None else el + kids_el = _kind(el, 'children') + kinderen = [groep(c) for c in (kids_el if kids_el is not None else el) if c.tag.lower() == 'group'] + return {'naam': _veld(d, 'name', 'naam'), 'code': _veld(d, 'code'), 'omschrijving': _veld(d, 'desc', 'description'), + 'type': _veld(d, 'type'), 'kinderen': kinderen} + if root.tag.lower() == 'group': + return [groep(root)] + return [groep(c) for c in root if c.tag.lower() == 'group'] + + +def _groepen_json(data): + def groep(g): + kids = g.get('children') or g.get('groups') or [] + if isinstance(kids, dict): + kids = kids.get('group') or list(kids.values()) + if isinstance(kids, dict): + kids = [kids] + d = g.get('details') or g + return {'naam': str(d.get('name') or ''), 'code': str(d.get('code') or ''), 'omschrijving': str(d.get('desc') or ''), + 'type': str(d.get('type') or ''), 'kinderen': [groep(k) for k in kids if isinstance(k, dict)]} + if isinstance(data, dict): + data = data.get('groups') or data.get('group') or [data] + if isinstance(data, dict): + data = [data] + return [groep(g) for g in data if isinstance(g, dict)] + + +def boom(ss): + raw = ss.client.service.getAllGroupsAndClasses(Config.SS_API_PW) + if _foutcode(raw): + raise SgrFout(f"Smartschool weigert de groepenlijst (foutcode {raw}). Heeft het webservice-wachtwoord het recht " + "'getAllGroupsAndClasses'?") + t = _tekst(raw) + try: + return _groepen_xml(ET.fromstring(t)) if t.startswith('<') else _groepen_json(json.loads(t)) + except Exception as e: + raise SgrFout(f"Kon de groepenlijst van Smartschool niet lezen: {e}") + + +def zoek(groepen, naam): + """Eerste groep (diepte-eerst) waarvan naam of code overeenkomt (hoofdletterongevoelig).""" + n = (naam or '').strip().lower() + for g in groepen: + if g['naam'].lower() == n or g['code'].lower() == n: + return g + hit = zoek(g['kinderen'], naam) + if hit: + return hit + return None + + +def plat(groep, pad=()): + """Alle groepen onder `groep` (niet de groep zelf), met hun pad en diepte, in boomvolgorde.""" + uit = [] + for k in sorted(groep['kinderen'], key=lambda g: g['naam'].lower()): + uit.append({**k, 'pad': list(pad), 'diepte': len(pad)}) + uit += plat(k, pad + (k['naam'],)) + return uit + + +def _leden(ss, code, recursief='0'): + raw = ss.client.service.getAllAccountsExtended(Config.SS_API_PW, code, recursief) + if _foutcode(raw): + raise SgrFout(f"foutcode {raw}") + t = _tekst(raw) + if not t: + return [] + data = json.loads(t) + if isinstance(data, dict): + data = next((data[k] for k in ('accounts', 'users', 'items') if isinstance(data.get(k), list)), list(data.values())) + uit = [] + for a in data or []: + if not isinstance(a, dict): + continue + rol = str(a.get('basisrol') or a.get('basisRol') or '').strip() + uit.append({'voornaam': str(a.get('voornaam') or '').strip(), 'naam': str(a.get('naam') or '').strip(), + 'gebruikersnaam': str(a.get('gebruikersnaam') or '').strip(), + 'rol': ROLLEN.get(rol, rol), 'email': str(a.get('emailadres') or a.get('email') or '').strip(), + 'status': str(a.get('status') or '').strip()}) + return sorted(uit, key=lambda x: (x['naam'].lower(), x['voornaam'].lower())) + + +def overzicht(hoofdgroep=None, vernieuw=False): + """(hoofdgroep-dict, [subgroepen met 'leden' of 'fout'], opgehaald-tijdstip).""" + from tenancy import huidige_school, in_school + from services.smartschool_api import SmartschoolService + school = huidige_school() + if not school.heeft('SS_API_PLATFORM', 'SS_API_PW'): + raise SgrFout("Smartschool is nog niet ingesteld voor deze school (🔌 Koppelingen › Smartschool).") + hoofdgroep = (hoofdgroep or school.get('SS_SGR_GROEP') or STANDAARD_GROEP).strip() + sleutel = ('sgr_groepen', hoofdgroep.lower()) + bewaard = school.cache.get(sleutel) + if bewaard and not vernieuw and time.time() - bewaard[0] < CACHE_SECONDEN: + return bewaard[1], bewaard[2], bewaard[0] + + try: + ss = SmartschoolService(Config.SS_API_PLATFORM, Config.SS_API_PW) + except Exception as e: + raise SgrFout(f"Smartschool is niet bereikbaar: {e}") + hoofd = zoek(boom(ss), hoofdgroep) + if not hoofd: + raise SgrFout(f"De groep '{hoofdgroep}' bestaat niet in Smartschool ({Config.SS_API_PLATFORM}).") + groepen = plat(hoofd) + + lokaal = threading.local() + + def haal(g): + with in_school(school): + if not hasattr(lokaal, 'ss'): + lokaal.ss = SmartschoolService(Config.SS_API_PLATFORM, Config.SS_API_PW) + try: + if not g['code']: + return {**g, 'leden': [], 'fout': 'geen code'} + leden = _leden(lokaal.ss, g['code']) + if not leden and not g['kinderen']: + # Groep zonder subgroepen: rechtstreeks = recursief; sommige platformen geven enkel zo de leden + leden = _leden(lokaal.ss, g['code'], '1') + return {**g, 'leden': leden, 'fout': None} + except Exception as e: + return {**g, 'leden': [], 'fout': str(e)[:200]} + + with ThreadPoolExecutor(max_workers=4) as pool: + resultaat = list(pool.map(haal, groepen)) + for g in resultaat: + g.pop('kinderen', None) + g['aantal_sub'] = sum(1 for x in resultaat if x['pad'][:len(g['pad']) + 1] == g['pad'] + [g['naam']]) + info = {'naam': hoofd['naam'], 'code': hoofd['code'], 'omschrijving': hoofd['omschrijving']} + nu = time.time() + school.cache[sleutel] = (nu, info, resultaat) + return info, resultaat, nu diff --git a/services/signpost_byod_service.py b/services/signpost_byod_service.py new file mode 100644 index 0000000..27adc61 --- /dev/null +++ b/services/signpost_byod_service.py @@ -0,0 +1,140 @@ +import requests +from config import Config + +BASE_DATA_URL = "https://byod-api.signpost.be/v1" + + +def get_signpost_token(): + """Token met de Signpost/M4S-gegevens van de huidige school (None bij een fout).""" + return signpost_token_met_reden()[0] + + +def signpost_token_met_reden(): + """Geeft (token, None) of (None, leesbare foutmelding).""" + if not (Config.M4S_CLIENT_ID and Config.M4S_CLIENT_SECRET): + return None, ("Signpost is nog niet ingesteld voor deze school: vul de client-ID en het client-secret in " + "via 🔌 Koppelingen van deze school › Signpost / M4S.") + auth_payload = { + "grant_type": "client_credentials", + "client_id": Config.M4S_CLIENT_ID, + "client_secret": Config.M4S_CLIENT_SECRET, + "scope": "openid", + "resource": "management_portal:api" + } + try: + response = requests.post(Config.M4S_AUTH_URL, data=auth_payload, timeout=15) + except requests.exceptions.RequestException as e: + return None, f"Signpost ({Config.M4S_AUTH_URL}) is niet bereikbaar: {e}" + if response.status_code in (400, 401, 403): + detail = '' + try: + j = response.json() + detail = j.get('error_description') or j.get('error') or '' + except ValueError: + pass + return None, (f"Signpost weigert de aanmelding (HTTP {response.status_code}{': ' + detail if detail else ''}). " + "Controleer de client-ID en het client-secret bij 🔌 Koppelingen van deze school.") + if not response.ok: + return None, f"Signpost gaf foutcode {response.status_code} bij het aanmelden." + token = response.json().get("access_token") + return (token, None) if token else (None, "Signpost gaf geen token terug.") + + +#------------------------------------------------------------------------------------------------- +#herstelling signpost doorgeven +#------------------------------------------------------------------------------------------------- + +def create_signpost_case(serial_number, description, damage_flags=None): + """ + Maakt een nieuw herstellingsdossier aan bij Signpost. + :param serial_number: Het serienummer van het toestel. + :param description: Omschrijving van het probleem. + :param damage_flags: Dict met booleans (bv. {'waterDamage': True}) + """ + token = get_signpost_token() + if not token: + return False, "Authenticatie mislukt." + + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + "Accept": "application/json" + } + + # Bouw het payload op basis van de Config klasse + payload = { + "languageCode": getattr(Config, "M4S_LANGUAGE_CODE", "nl-BE"), + "description": description, + "status": getattr(Config, "M4S_REPAIR_STATUS", "Nieuw"), + "repairLocationType": int(getattr(Config, "M4S_REPAIR_LOCATION_TYPE", 1)), + "serialNumber": serial_number, + "institutionGuid": Config.M4S_INSTITUTIONGUID, + "address": { + "street": Config.M4S_REPAIR_STREET, + "number": Config.M4S_REPAIR_STREETNUMBER, + "zipCode": Config.M4S_REPAIR_ZIPCODE, + "city": Config.M4S_REPAIIR_CITY, + "countryCode": Config.M4S_REPAIR_COUNTRYCODE, + "repairAtInstitution": True + }, + "contacts": [{ + "firstName": Config.M4S_CONTACT_FIRST_NAME, + "lastName": Config.M4S_CONTACT_LAST_NAME, + "email": Config.M4S_CONTACT_EMAIL, + "phone": Config.M4S_CONTACT_PHONE + }], + "billingContact": { + "firstName": Config.M4S_BILLING_FIRST_NAME, + "lastName": Config.M4S_BILLING_LAST_NAME, + "email": Config.M4S_BILLING_EMAIL, + "phone": Config.M4S_BILLING_PHONE, + "street": Config.M4S_REPAIR_STREET, + "number": Config.M4S_REPAIR_STREETNUMBER, + "zipCode": Config.M4S_REPAIR_ZIPCODE, + "city": Config.M4S_REPAIIR_CITY, + "countryCode": Config.M4S_REPAIR_COUNTRYCODE + } + } + + # Voeg schade-indicatoren toe indien meegegeven + if damage_flags: + payload.update(damage_flags) + + try: + res = requests.post(f"{BASE_DATA_URL}/field-service/cases", headers=headers, json=payload, timeout=15) + if res.status_code in [200, 201]: + return True, res.json().get("ourReference", "Succesvol aangemaakt") + else: + return False, f"API Fout {res.status_code}: {res.text}" + except Exception as e: + return False, f"Verbindingsfout: {str(e)}" + + + +#------------------------------------------------------------------------------------------------- +# +#------------------------------------------------------------------------------------------------- + + +def get_cases_by_serial(serial_number): + token = get_signpost_token() + if not token: + return [] + + headers = { + "Authorization": f"Bearer {token}", + "Accept": "application/json" + } + params = {"$search": serial_number} + + try: + res = requests.get(f"{BASE_DATA_URL}/field-service/cases", headers=headers, params=params, timeout=15) + if res.status_code == 200: + return res.json().get("items", []) + return [] + except Exception as e: + print(f"Signpost API Fout: {e}") + return [] + + + \ No newline at end of file diff --git a/services/skore_service.py b/services/skore_service.py new file mode 100644 index 0000000..b3e7c9e --- /dev/null +++ b/services/skore_service.py @@ -0,0 +1,326 @@ +""" +Skore-synchronisatie in Smartschool (klassen en leerlingen van Smartschool → Skore). + +Smartschool-webservices: + startSkoreSync(accesscode) → start de synchronisatie, geeft een taak-ID (serviceId) terug + checkStatus(accesscode, serviceId) → status van die taak + +Per school: + - skore_planning : één rij met de planning (uit / dagelijks / weekdagen / wekelijks / maandelijks + uur) + - skore_log : elke gestarte synchronisatie (manueel of gepland) met taak-ID en laatste status + +Eén achtergrondtaak overloopt elke minuut alle scholen en start de synchronisatie wanneer de planning dat vraagt. +""" +import json +import sys +import threading +import time +from datetime import datetime, timedelta + +from config import Config +from database import execute_query, execute_insert +from tenancy import alle_scholen, in_school + +FREQUENTIES = [ + ('uit', 'Niet automatisch (enkel manueel)'), + ('dagelijks', 'Elke dag'), + ('weekdagen', 'Elke weekdag (ma–vr)'), + ('wekelijks', 'Eén keer per week'), + ('maandelijks', 'Eén keer per maand'), +] +WEEKDAGEN = ['maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag', 'zondag'] +# Een geplande synchronisatie die gemist werd (PIVOT stond uit) wordt nog ingehaald tot zoveel uur later. +INHAAL_UREN = 6 +# Statuscodes van checkStatus die we kennen (vastgesteld: 2 = "SYNC IS COMPLETED") +STATUSCODES = {2: 'voltooid'} +# Automatische opvolging na een start: elke 30 s de status opvragen, maximaal 45 minuten +OPVOLG_INTERVAL = 30 +OPVOLG_MAX = 45 * 60 +EINDSTATUS = ('voltooid', 'mislukt') + +TABELLEN = [ + """CREATE TABLE IF NOT EXISTS skore_planning ( + ID TINYINT NOT NULL PRIMARY KEY, + Frequentie VARCHAR(20) NOT NULL DEFAULT 'uit', + Uur TINYINT NOT NULL DEFAULT 6, + Minuut TINYINT NOT NULL DEFAULT 0, + Weekdag TINYINT NOT NULL DEFAULT 0, + Dag_van_maand TINYINT NOT NULL DEFAULT 1, + Laatst_gepland DATETIME NULL, + Bijgewerkt DATETIME NULL, + Bijgewerkt_door VARCHAR(255) NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", + """CREATE TABLE IF NOT EXISTS skore_log ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Gestart DATETIME NOT NULL, + Door VARCHAR(255) NULL, + Manier VARCHAR(20) NOT NULL, + Service_ID VARCHAR(100) NULL, + Status VARCHAR(30) NOT NULL, + Melding TEXT NULL, + Bijgewerkt DATETIME NULL, + INDEX idx_skore_gestart (Gestart) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci""", +] + + +class SkoreFout(RuntimeError): + pass + + +def ensure_tables(): + for sql in TABELLEN: + execute_query(sql, commit=True) + execute_query("INSERT IGNORE INTO skore_planning (ID) VALUES (1)", commit=True) + + +# ===================================================================== +# Smartschool +# ===================================================================== +def _client(): + if not (Config.SS_API_PLATFORM and Config.SS_API_PW): + raise SkoreFout("Smartschool is nog niet ingesteld voor deze school (platform en webservice-wachtwoord " + "via 🔌 Koppelingen van deze school).") + from services.smartschool_api import SmartschoolService + return SmartschoolService(Config.SS_API_PLATFORM, Config.SS_API_PW).client + + +def _json(raw): + """Smartschool geeft JSON als tekst terug; geeft een dict (of None).""" + if isinstance(raw, dict): + return raw + try: + data = json.loads(raw) if isinstance(raw, str) and raw.strip().startswith('{') else None + except ValueError: + data = None + return data if isinstance(data, dict) else None + + +def service_id_uit(raw): + """Taak-ID uit het antwoord van startSkoreSync, bv. {"serviceId":"db18…","message":"SERVICE STARTED"}. + Werkt ook voor oude logregels waarin het volledige antwoord als ID bewaard werd.""" + data = _json(raw) + if data is not None: + return str(data.get('serviceId') or data.get('serviceID') or data.get('id') or '').strip() or None + if raw in (None, ''): + return None + return str(raw).strip() or None + + +def _is_foutcode(raw): + return isinstance(raw, (int, float)) or (isinstance(raw, str) and raw.strip().lstrip('-').isdigit()) + + +def _foutcode_tekst(client, code): + """Smartschool geeft bij fouten een getal; probeer de omschrijving op te halen.""" + try: + lijst = json.loads(client.service.returnJsonErrorCodes()) + tekst = lijst.get(str(code).strip()) if isinstance(lijst, dict) else None + if tekst: + return f"Smartschool-fout {code}: {tekst}" + except Exception: + pass + return (f"Smartschool-fout {code}. Controleer of het webservice-wachtwoord het recht heeft om de " + "Skore-synchronisatie te starten (Smartschool › Beheer › Webservices).") + + +def _status_uit(raw): + """Zet het antwoord van checkStatus om naar (status, melding). + + Smartschool antwoordt met {"status": , "message": }. Wat de getallen betekenen is niet + publiek gedocumenteerd; daarom leiden we 'voltooid' of 'mislukt' enkel af uit de tekst, en tonen we anders + de statuscode zelf (bv. 'code 0').""" + tekst = raw if isinstance(raw, str) else json.dumps(raw, default=str) if raw is not None else '' + data = _json(raw) + code = data.get('status') if data else None + bericht = str((data or {}).get('message') or (data or {}).get('state') or '') if data else tekst + laag = bericht.lower() + if any(w in laag for w in ('error', 'fout', 'failed', 'mislukt')): + status = 'mislukt' + elif any(w in laag for w in ('done', 'finished', 'completed', 'klaar', 'voltooid', 'success')): + status = 'voltooid' + elif any(w in laag for w in ('running', 'busy', 'bezig', 'started', 'queue', 'wacht')): + status = 'bezig' + elif code is not None and str(code).strip().isdigit() and int(code) in STATUSCODES: + status = STATUSCODES[int(code)] + elif code is not None: + status = f"code {code}" + else: + status = 'onbekend' + melding = f"Smartschool: status {code}" + (f", {bericht}" if bericht else " (geen bericht)") if data else tekst + return status[:30], melding[:2000] + + +def start(door, manier='manueel'): + """Start de Skore-synchronisatie. Geeft de rij uit skore_log terug.""" + ensure_tables() + nu = datetime.now() + try: + client = _client() + raw = client.service.startSkoreSync(Config.SS_API_PW) + if _is_foutcode(raw) and str(raw).strip() not in ('', '0'): + raise SkoreFout(_foutcode_tekst(client, raw)) + service_id = service_id_uit(raw) + bericht = (_json(raw) or {}).get('message') + if not service_id: + raise SkoreFout(f"Smartschool startte de synchronisatie niet: {bericht or raw}") + status = 'gestart' + melding = f"Synchronisatie gestart bij Smartschool ({bericht})." if bericht else "Synchronisatie gestart bij Smartschool." + except SkoreFout as e: + service_id, status, melding = None, 'mislukt', str(e) + except Exception as e: + service_id, status, melding = None, 'mislukt', f"Smartschool niet bereikbaar: {e}" + log_id = execute_insert( + "INSERT INTO skore_log (Gestart, Door, Manier, Service_ID, Status, Melding, Bijgewerkt) " + "VALUES (%s, %s, %s, %s, %s, %s, %s)", (nu, door, manier, service_id, status, melding, nu)) + rij = execute_query("SELECT * FROM skore_log WHERE ID = %s", (log_id,))[0] + if rij['Service_ID']: + volg_op(log_id) + return rij + + +def volg_op(log_id): + """Vraagt op de achtergrond de status op tot de synchronisatie klaar of mislukt is.""" + from tenancy import met_school + + def loop(): + begin = time.time() + while time.time() - begin < OPVOLG_MAX: + time.sleep(OPVOLG_INTERVAL) + try: + rij = controleer(log_id) + except Exception as e: + sys.stderr.write(f"[{Config.SCHOOLNAME_SHORT}] Skore-opvolging: {e}\n") + continue + if not rij or rij['Status'] in EINDSTATUS: + return + threading.Thread(target=met_school(loop), daemon=True).start() + + +def bezig(): + """True als er een synchronisatie loopt die nog geen eindstatus heeft (laatste 45 minuten).""" + rows = execute_query("SELECT Status, Gestart FROM skore_log WHERE Service_ID IS NOT NULL " + "ORDER BY Gestart DESC, ID DESC LIMIT 1") + return bool(rows) and rows[0]['Status'] not in EINDSTATUS and \ + datetime.now() - rows[0]['Gestart'] < timedelta(seconds=OPVOLG_MAX) + + +def controleer(log_id): + """Vraagt de status van een gestarte synchronisatie op bij Smartschool en bewaart die.""" + rows = execute_query("SELECT * FROM skore_log WHERE ID = %s", (log_id,)) + if not rows or not rows[0]['Service_ID']: + return rows[0] if rows else None + try: + client = _client() + sid = service_id_uit(rows[0]['Service_ID']) + if sid != rows[0]['Service_ID']: + execute_query("UPDATE skore_log SET Service_ID = %s WHERE ID = %s", (sid, log_id), commit=True) + raw = client.service.checkStatus(Config.SS_API_PW, sid) + if _is_foutcode(raw) and str(raw).strip() not in ('', '0'): + status, melding = 'onbekend', _foutcode_tekst(client, raw) + else: + status, melding = _status_uit(raw) + except Exception as e: + status, melding = rows[0]['Status'], f"Status opvragen mislukt: {e}" + execute_query("UPDATE skore_log SET Status = %s, Melding = %s, Bijgewerkt = %s WHERE ID = %s", + (status, melding, datetime.now(), log_id), commit=True) + return execute_query("SELECT * FROM skore_log WHERE ID = %s", (log_id,))[0] + + +def logboek(n=25): + ensure_tables() + return execute_query("SELECT * FROM skore_log ORDER BY Gestart DESC, ID DESC LIMIT %s", (n,)) + + +# ===================================================================== +# Planning +# ===================================================================== +def planning(): + ensure_tables() + return execute_query("SELECT * FROM skore_planning WHERE ID = 1")[0] + + +def bewaar_planning(frequentie, uur, minuut, weekdag, dag_van_maand, door): + if frequentie not in dict(FREQUENTIES): + raise ValueError("Onbekende frequentie.") + uur, minuut, weekdag, dag = int(uur), int(minuut), int(weekdag), int(dag_van_maand) + if not (0 <= uur <= 23 and 0 <= minuut <= 59 and 0 <= weekdag <= 6 and 1 <= dag <= 28): + raise ValueError("Ongeldig tijdstip of ongeldige dag.") + ensure_tables() + # Laatst_gepland op 'nu' zetten: een planning die je net aanpast, start niet meteen voor een moment in het verleden + execute_query( + "UPDATE skore_planning SET Frequentie = %s, Uur = %s, Minuut = %s, Weekdag = %s, Dag_van_maand = %s, " + "Laatst_gepland = %s, Bijgewerkt = %s, Bijgewerkt_door = %s WHERE ID = 1", + (frequentie, uur, minuut, weekdag, dag, datetime.now(), datetime.now(), door), commit=True) + + +def laatste_moment(p, nu): + """Het laatste geplande moment op of vóór `nu` volgens planning `p` (of None als 'uit').""" + f = p['Frequentie'] + if f == 'uit': + return None + for terug in range(0, 62): + dag = (nu - timedelta(days=terug)).date() + moment = datetime(dag.year, dag.month, dag.day, int(p['Uur']), int(p['Minuut'])) + if moment > nu: + continue + if f == 'dagelijks' \ + or (f == 'weekdagen' and dag.weekday() < 5) \ + or (f == 'wekelijks' and dag.weekday() == int(p['Weekdag'])) \ + or (f == 'maandelijks' and dag.day == int(p['Dag_van_maand'])): + return moment + return None + + +def volgende_moment(p, nu=None): + """Het eerstvolgende geplande moment na `nu` (voor op de pagina).""" + nu = nu or datetime.now() + if p['Frequentie'] == 'uit': + return None + for vooruit in range(0, 62): + dag = (nu + timedelta(days=vooruit)).date() + moment = datetime(dag.year, dag.month, dag.day, int(p['Uur']), int(p['Minuut'])) + if moment > nu and laatste_moment(p, moment) == moment: + return moment + return None + + +def geplande_controle(nu=None): + """Start de synchronisatie als er een gepland moment voorbij is dat nog niet uitgevoerd werd.""" + nu = nu or datetime.now() + p = planning() + moment = laatste_moment(p, nu) + if not moment or nu - moment > timedelta(hours=INHAAL_UREN): + return None + if p['Laatst_gepland'] and p['Laatst_gepland'] >= moment: + return None + execute_query("UPDATE skore_planning SET Laatst_gepland = %s WHERE ID = 1", (nu,), commit=True) + rij = start('automatisch', manier='gepland') + print(f"[{Config.SCHOOLNAME_SHORT}] Skore-synchronisatie (gepland): {rij['Status']} – {rij['Melding']}", flush=True) + return rij + + +_scheduler = None + + +def start_scheduler(): + """Eén achtergrondtaak die elke minuut alle scholen met een Smartschool-koppeling overloopt.""" + global _scheduler + if _scheduler: + return + + def loop(): + time.sleep(45) # app eerst laten opstarten + while True: + for school in alle_scholen(): + if not school.heeft('SS_API_PLATFORM', 'SS_API_PW'): + continue + try: + with in_school(school): + geplande_controle() + except Exception as e: + sys.stderr.write(f"[{school.code}] Skore-planning: {e}\n") + time.sleep(60) + + _scheduler = threading.Thread(target=loop, daemon=True) + _scheduler.start() diff --git a/services/smartschool_api.py b/services/smartschool_api.py new file mode 100644 index 0000000..b7b4a8e --- /dev/null +++ b/services/smartschool_api.py @@ -0,0 +1,122 @@ +import zeep +import json + +class SmartschoolService: + def __init__(self, platform, webservice_pwd): + #----------------------------------- + clean_platform = platform.replace("https://", "").replace("http://", "").split('/')[0] + + self.platform = clean_platform + + #------------------------------ + #self.platform = platform + self.webservice_pwd = webservice_pwd + self.wsdl_url = f"https://{self.platform}/Webservices/V3?wsdl" + self.client = zeep.Client(wsdl=self.wsdl_url) + + def get_student_details(self, search_term): + """Zoekt een student op basis van internnummer of gebruikersnaam.""" + try: + # Poging 1: Via internnummer + raw_result = self.client.service.getUserDetails(self.webservice_pwd, search_term) + if raw_result and isinstance(raw_result, str) and raw_result.startswith('{'): + return json.loads(raw_result) + + # Poging 2: Via gebruikersnaam + raw_result_alt = self.client.service.getUserDetailsByUsername(self.webservice_pwd, search_term) + if raw_result_alt and isinstance(raw_result_alt, str) and raw_result_alt.startswith('{'): + return json.loads(raw_result_alt) + + return None + except Exception as e: + print(f"Service Error (GetDetails): {e}") + return None + + def get_co_accounts_from_details(self, username): + """Haalt co-accounts op en onthoudt hun index (1-6) voor wachtwoordresets.""" + try: + raw_result = self.client.service.getUserDetailsByUsername(self.webservice_pwd, username) + if raw_result and isinstance(raw_result, str) and raw_result.startswith('{'): + data = json.loads(raw_result) + co_accounts = [] + for i in range(1, 7): + voornaam = data.get(f"voornaam_coaccount{i}") + if voornaam: + co_accounts.append({ + "voornaam": voornaam, + "naam": data.get(f"naam_coaccount{i}", ""), + "type": data.get(f"type_coaccount{i}", "Co-account"), + "index": i, # Belangrijk voor savePassword + "parent_internnummer": data.get("internnummer") # Nodig voor de reset actie + }) + return co_accounts + return [] + except Exception as e: + print(f"Service Error (Co-Accounts): {e}") + return [] + + def reset_password(self, identifier, new_password, account_type=0): + """ + account_type: 0 voor leerling, 1-6 voor co-accounts. + """ + try: + # Gebruik de parameters uit je werkende voorbeeld + result_code = self.client.service.savePassword( + self.webservice_pwd, + identifier, + new_password, + account_type, + 0 + ) + return str(result_code) + except Exception as e: + print(f"Service Error (ResetPassword): {e}") + return "ERROR" + + def get_co_accounts_with_login(self, username): + """Haalt co-accounts op met de exacte velden uit de Smartschool JSON.""" + try: + # Gebruik de bestaande methode om de JSON op te halen + raw_result = self.client.service.getUserDetailsByUsername(self.webservice_pwd, username) + + if raw_result and isinstance(raw_result, str) and raw_result.startswith('{'): + data = json.loads(raw_result) + co_accounts = [] + + # Smartschool ondersteunt tot 6 co-accounts + for i in range(1, 7): + voornaam = data.get(f"voornaam_coaccount{i}") + # Alleen toevoegen als er daadwerkelijk een voornaam is ingevuld (account bestaat) + if voornaam and voornaam.strip() != "": + # Gebruik het specifieke veld uit jouw JSON voorbeeld + last_login = data.get(f"last_successful_login_coaccount{i}") + + co_accounts.append({ + "voornaam": voornaam, + "naam": data.get(f"naam_coaccount{i}", ""), + "type": data.get(f"type_coaccount{i}", "Onbekend"), + "last_login": last_login if last_login else "Nooit ingelogd", + "email": data.get(f"email_coaccount{i}", ""), + "index": i + }) + return co_accounts + return [] + except Exception as e: + print(f"Fout bij ophalen co-account status: {e}") + return [] + + def get_coaccount_report(self, search_query): + """ + Bundelt alle logica: zoekt student, formatteert naam en haalt co-accounts op. + Geeft een tuple terug: (student_naam, resultaten_lijst) + """ + student_data = self.get_student_details(search_query) + + if not student_data: + return None, [] + + student_name = f"{student_data.get('voornaam')} {student_data.get('naam')}" + username = student_data.get('gebruikersnaam') + results = self.get_co_accounts_with_login(username) + + return student_name, results \ No newline at end of file diff --git a/services/sync_service.py b/services/sync_service.py new file mode 100644 index 0000000..5f84dad --- /dev/null +++ b/services/sync_service.py @@ -0,0 +1,549 @@ +import json +import requests +from datetime import datetime, timezone # Essentieel voor de timestamp +from dateutil.relativedelta import relativedelta +from config import Config +from database import execute_query + +# Informat geeft de volledige leerlingenlijst soms pas na een minuut of langer terug. +# (verbinden, lezen) in seconden +INFORMAT_TIMEOUT = (15, 300) +ONEROSTER_TIMEOUT = (15, 120) + + +def informat_get(url, headers, pogingen=2): + """GET naar Informat met ruime wachttijd; bij een time-out nog één keer opnieuw.""" + for poging in range(1, pogingen + 1): + try: + return requests.get(url, headers=headers, timeout=INFORMAT_TIMEOUT) + except requests.exceptions.Timeout: + if poging == pogingen: + raise RuntimeError( + f"Informat antwoordde niet binnen {INFORMAT_TIMEOUT[1] // 60} minuten " + f"({pogingen} pogingen). Probeer het later opnieuw; Informat is soms traag of in onderhoud.") + print(f"[Informat] time-out, nieuwe poging ({poging + 1}/{pogingen})...") + + +def zorg_vertrokken_kolom(): + """Kolom Leerlingen.Vertrokken_op toevoegen in een bestaande schooldatabase (één keer per school).""" + try: + from tenancy import huidige_school + school = huidige_school() + except Exception: + school = None + if school is not None and school.cache.get('lln_vertrokken_kolom'): + return + kolommen = {r['Field'].lower() for r in execute_query("SHOW COLUMNS FROM Leerlingen") or []} + if 'vertrokken_op' not in kolommen: + execute_query("ALTER TABLE Leerlingen ADD COLUMN Vertrokken_op DATE NULL AFTER Schooljaar_ID", commit=True) + if school is not None: + school.cache['lln_vertrokken_kolom'] = True + + +def veld_waarden(obj, pad): + """Alle waarden op een pad met punten, ook door lijsten heen: veld_waarden(st, 'inschrijvingen.vestiging').""" + huidig = [obj] + for deel in pad.split('.'): + volgende = [] + for o in huidig: + items = o if isinstance(o, list) else [o] + for it in items: + if isinstance(it, dict) and deel in it: + volgende.append(it[deel]) + huidig = volgende + uit = [] + for h in huidig: + uit.extend(h if isinstance(h, list) else [h]) + return uit + + +class SyncService: + def __init__(self): + self.conf = Config() + # Informat-gegevens van de huidige school (beheerd via /scholen). + # Een school kan meerdere Informat-instellingsnummers hebben (één per campus). + self.campussen = Config.INFORMAT_CAMPUSSEN or [] + self.institute_no = Config.INFORMAT_INST_NUMBER + self.auth_url = Config.INFORMAT_AUTH_URL + self.api_base = Config.INFORMAT_API_BASE + # De scope MOET het instellingsnummer bevatten + self.scope = Config.INFORMAT_FULL_SCOPE + + def get_informat_token(self, nummer=None): + """Haalt een token op met de scope van het (eerste of opgegeven) instellingsnummer.""" + from tenancy import informat_scope + scope = informat_scope(Config.INFORMAT_SCOPE, nummer) if nummer else self.scope + payload = { + 'grant_type': 'client_credentials', + 'client_id': self.conf.INFORMAT_ID, + 'client_secret': self.conf.INFORMAT_SECRET, + 'scope': scope + } + try: + response = requests.post(self.auth_url, data=payload, timeout=10) + if response.status_code == 200: + return response.json().get('access_token') + except Exception: + return None + return None + + def tel_leerlingen(self, refdate, schooljaar, nummer=None): + """Aantal leerlingen in Informat op `refdate` (YYYY-MM-DD) voor `schooljaar` (bv. 2026-27), voor één + instellingsnummer (standaard het eerste). Geeft (True, aantal) of (False, foutmelding).""" + nummer = nummer or self.institute_no + token = self.get_informat_token(nummer) + if not token: + return False, f"Authenticatie bij Informat mislukt (instellingsnummer {nummer})." + url = f"{self.api_base}/students/?schoolYear={schooljaar}&refdate={refdate}" + headers = { + 'Authorization': f'BEARER {token}', + 'InstituteNo': nummer, + 'Timestamp': datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.000Z'), # verplicht bij Informat + 'Api-Version': '1', + 'Accept': 'application/json' + } + try: + response = informat_get(url, headers) + except Exception as e: + return False, f"Fout tijdens tellen: {e}" + if response.status_code != 200: + return False, f"API fout {response.status_code} (instellingsnummer {nummer}): {response.text[:300]}" + data = response.json() + lijst = data if isinstance(data, list) else data.get('students', []) + self._laatste_lijst = lijst # voor tellen per campusveld en de veldentest + return True, len(lijst) + + def informat_lijst(self, refdate, schooljaar, nummer=None): + """De volledige leerlingenlijst van Informat (zelfde oproep als het tellen). (True, lijst) of (False, fout).""" + ok, res = self.tel_leerlingen(refdate, schooljaar, nummer) + return (True, self._laatste_lijst) if ok else (False, res) + + def tel_locatie(self, refdate, schooljaar, locatie_id): + """Aantal leerlingen op één schoollocatie (Discimus-nummer) via de Informat Student API + (GET /smartschool-users). Geeft (True, aantal) of (False, foutmelding). + Let op: deze API telt enkel leerlingen met een actieve inschrijving (gerealiseerd of parallel, niet GON) + op een locatie die aan het Smartschool-platform gekoppeld is.""" + platform = (Config.SS_API_PLATFORM or '').strip() + if not platform: + return False, ("Voor het tellen per campus moet het Smartschool-platform ingevuld zijn " + "(🔌 Koppelingen › Smartschool).") + token = self.get_informat_token(self.institute_no) + if not token: + return False, f"Authenticatie bij Informat mislukt (instellingsnummer {self.institute_no})." + url = f"{str(Config.INFORMAT_STUDENT_API).rstrip('/')}/smartschool-users" + headers = {'Authorization': f'Bearer {token}', 'instituteNo': self.institute_no, 'Accept': 'application/json'} + # Informat vergelijkt het platformadres letterlijk met wat er in Informat staat. Dat kan met of zonder + # https:// of een / op het einde opgeslagen zijn: probeer de varianten tot er één gekend is (en onthoud die). + varianten = list(dict.fromkeys([v for v in (getattr(self, '_ss_platform_url', None), f"https://{platform}", + platform, f"https://{platform}/", f"http://{platform}") if v])) + response, geprobeerd = None, [] + for platform_url in varianten: + params = {'smartschoolPlatformUrl': platform_url, 'schoolYear': schooljaar, + 'locationIdDiscimus': int(locatie_id) if str(locatie_id).isdigit() else locatie_id, + 'referenceDate': refdate} + try: + for poging in (1, 2): + try: + response = requests.get(url, params=params, headers=headers, timeout=INFORMAT_TIMEOUT) + break + except requests.exceptions.Timeout: + if poging == 2: + raise RuntimeError("Informat antwoordde niet op tijd.") + except Exception as e: + return False, f"Fout tijdens tellen: {e}" + geprobeerd.append(platform_url) + if response.status_code == 409 and 'smartschoolplatform' in response.text.lower(): + continue # platform onder dit adres niet gekend: volgende variant + self._ss_platform_url = platform_url + break + if response.status_code != 200: + detail = '' + try: + detail = response.json().get('detail') or '' + except ValueError: + detail = response.text[:200] + if response.status_code == 409 and 'smartschoolplatform' in response.text.lower(): + return False, (f"Informat kent het Smartschool-platform niet voor instellingsnummer {self.institute_no} " + f"en schooljaar {schooljaar} (geprobeerd: {', '.join(geprobeerd)}). Is in Informat " + "voor dit instellingsnummer en dit schooljaar een Smartschool-koppeling actief?") + return False, f"Student API fout {response.status_code} (campus {locatie_id}): {detail}" + data = response.json() + lijst = data if isinstance(data, list) else data.get('items', []) + # Eén leerling kan meer dan één inschrijving hebben: uniek op persoon + return True, len({u['ppersoon'] if u.get('ppersoon') is not None else (u.get('persoonId') or id(u)) + for u in lijst}) + + def tel_per_campus(self, refdate, schooljaar): + """Geeft (True, totaal, detail) of (False, fout, None). detail = [{'naam', 'nummer', 'aantal'}] als de + school meerdere campussen heeft, anders None. + - Campussen (Discimus-nummers) ingesteld → per locatie geteld via de Student API. + - Anders: per instellingsnummer (meestal één) via de leerlingen-API zoals voorheen.""" + locaties = Config.INFORMAT_LOCATIES or [] + veld = (Config.INFORMAT_CAMPUS_VELD or '').strip() + if veld: + return self._tel_op_veld(refdate, schooljaar, veld, dict(locaties)) + if locaties: + telling = [(loc, naam, lambda loc=loc: self.tel_locatie(refdate, schooljaar, loc)) for loc, naam in locaties] + else: + campussen = self.campussen or [(self.institute_no, '')] + telling = [(nr, naam, lambda nr=nr: self.tel_leerlingen(refdate, schooljaar, nr)) for nr, naam in campussen] + detail, totaal = [], 0 + for nummer, naam, tel in telling: + ok, res = tel() + if not ok: + return False, (f"{naam}: {res}" if len(telling) > 1 else res), None + detail.append({'naam': naam or nummer, 'nummer': nummer, 'aantal': res}) + totaal += res + return True, totaal, (detail if len(detail) > 1 else None) + + def _tel_op_veld(self, refdate, schooljaar, veld, namen): + """Haalt de leerlingenlijst één keer op en telt per waarde van `veld` (pad met punten, bv. + 'inschrijvingen.vestiging'). `namen` vertaalt een waarde naar een campusnaam (uit 'Campussen').""" + lijst, gezien = [], set() + for nummer, naam in (self.campussen or [(self.institute_no, '')]): # alle instellingsnummers van de school + ok, deel = self.informat_lijst(refdate, schooljaar, nummer) + if not ok: + return False, (f"{naam}: {deel}" if len(self.campussen) > 1 else deel), None + for st in deel: + sleutel = str(st.get('pPersoon') or st.get('id') or id(st)) + if sleutel not in gezien: + gezien.add(sleutel) + lijst.append(st) + per = {} + for st in lijst: + for w in set(str(v) for v in veld_waarden(st, veld) if v not in (None, '')) or {'?'}: + per[w] = per.get(w, 0) + 1 + volgorde = [w for w in namen if w in per] + sorted(w for w in per if w not in namen) + detail = [{'naam': namen.get(w) or (f"Onbekend ({veld} leeg)" if w == '?' else f"Campus {w}"), + 'nummer': '' if w == '?' else w, 'aantal': per[w]} for w in volgorde] + return True, len(lijst), (detail if len(detail) > 1 else None) + + def sync_student_count(self, school_naam=None): + """Huidig aantal (peildatum vandaag + 1 maand, zodat net ingeschreven leerlingen meetellen).""" + refdate = (datetime.now() + relativedelta(months=1)).strftime('%Y-%m-%d') + ok, res, detail = self.tel_per_campus(refdate, Config.SCHOOLYEAR) + if not ok: + return False, res + # Bewaren bij de school in de centrale database (overzicht scholengroep) + from database import central_query + central_query("UPDATE Scholen SET Leerlingenaantal = %s, Leerlingenaantal_detail = %s, " + "Leerlingenaantal_sync = NOW() WHERE Code = %s", + (res, json.dumps(detail) if detail else None, Config.SCHOOLNAME_SHORT), commit=True) + if detail: + return True, f"Synchronisatie voltooid: {res} leerlingen (" + ", ".join( + f"{d['naam']}: {d['aantal']}" for d in detail) + ")." + return True, f"Synchronisatie voltooid: {res} leerlingen." + + def tel_op_peildatum(self, peildatum, door=None): + """Telt de leerlingen op een gekozen datum en bewaart het resultaat in Leerlingenaantal_tellingen.""" + from database import central_query + from tenancy import huidige_school, _automatisch_schooljaar + schooljaar = _automatisch_schooljaar(peildatum) + ok, res, detail = self.tel_per_campus(peildatum.strftime('%Y-%m-%d'), schooljaar) + if not ok: + return False, res + central_query( + "INSERT INTO Leerlingenaantal_tellingen (School_ID, Peildatum, Schooljaar, Aantal, Detail, Opgevraagd_op, Door) " + "VALUES (%s, %s, %s, %s, %s, NOW(), %s) " + "ON DUPLICATE KEY UPDATE Schooljaar = VALUES(Schooljaar), Aantal = VALUES(Aantal), Detail = VALUES(Detail), " + "Opgevraagd_op = NOW(), Door = VALUES(Door)", + (huidige_school().id, peildatum, schooljaar, res, json.dumps(detail) if detail else None, door), + commit=True) + return True, res + + #Haal ss token op + def get_smartschool_token(self): + """Haalt een OAuth2 token op bij Smartschool.""" + resp_ss = requests.post( + self.conf.SS_TOKEN_URL, + data={"grant_type": "client_credentials"}, + auth=(self.conf.SS_CLIENT_ID, self.conf.SS_CLIENT_SECRET) + ) + return resp_ss.json().get("access_token") + + #Vergelijkt leerlingenlijst uit informat met namen uit DB en vult eventuele ontbrekende leerlingen aan met gegevens van Informat (Internnummer) en Smartschool (Gebruikersnaam) + def sync_leerlingen_informat(self): + """ + Synchroniseert leerlingen door Informat data te vergelijken met de DB + en ontbrekende data aan te vullen via Smartschool. + """ + try: + # 1. Haal Informat data op + inf_token = self.get_informat_token() + + #Ik zet als parameter voor het ophalen huidige datum +1 maand om leerlingen die net ingeschreven zijn en pas na een vakantie starten mee te kunnen rekenen + future_date = datetime.now() + relativedelta(months=1) + refdate = future_date.strftime('%Y-%m-%d') + + + inf_url = f"{self.api_base}/students/?schoolYear={self.conf.INFORMAT_SCHOOLYEAR}&refdate={refdate}" + inf_headers = { + 'Authorization': f'BEARER {inf_token}', + 'InstituteNo': self.institute_no, + 'Api-Version': '1', + 'Accept': 'application/json' + } + inf_data = requests.get(inf_url, headers=inf_headers).json() + + if not inf_data or 'students' not in inf_data: + return False, "Geen data van Informat ontvangen" + + # 2. Haal Bestaande Database data op + # We gebruiken execute_query om alle bestaande Internnummers op te halen + db_rows = execute_query("SELECT Internnummer FROM Leerlingen") + db_numbers = {str(row['Internnummer']) for row in db_rows} if db_rows else set() + + # 3. Zoek ontbrekende ID's (Informat - Database) + json_numbers = {str(s['pPersoon']) for s in inf_data['students'] if 'pPersoon' in s} + missing_ids = json_numbers - db_numbers + + if not missing_ids: + return True, "Iedereen is al gesynchroniseerd." + + # 4. Haal Smartschool data op voor de match + ss_token = self.get_smartschool_token() + ss_res = requests.get( + f"{self.conf.SS_BASE_URL}/students", + headers={"Authorization": f"Bearer {ss_token}"} + ) + ss_students = ss_res.json().get("users", []) + + added_count = 0 + for m_id in missing_ids: + found_username = None + for ss_student in ss_students: + ss_internal = str(ss_student.get("metadata", {}).get("smsc.internalNumber", "")) + + if ss_internal.strip() == m_id.strip(): + found_username = ss_student.get("username") + break + + if found_username: + # 5. DATABASE INVOER + execute_query( + "INSERT INTO Leerlingen (Internnummer, Gebruikersnaam, ss_nummer) VALUES (%s, %s, %s)", + (m_id, found_username, "Niet ingesteld"), + commit=True + ) + added_count += 1 + + return True, f"Succes! {added_count} leerlingen toegevoegd." + + except Exception as e: + return False, f"Fout tijdens synchronisatie: {str(e)}" + + + + + +#---------------------Nieuwe aanpak------------------------ +import requests +from datetime import datetime, timezone +from config import Config +from database import execute_query + +class InformatSmartschoolSync: + + + def __init__(self): + self.conf = Config() + # Informat-gegevens van de huidige school (beheerd via /scholen) + self.institute_no = Config.INFORMAT_INST_NUMBER + self.auth_url = Config.INFORMAT_AUTH_URL + self.api_base = Config.INFORMAT_API_BASE + # De scope MOET het instellingsnummer bevatten + self.scope = Config.INFORMAT_FULL_SCOPE + self.campussen = Config.INFORMAT_CAMPUSSEN or [(self.institute_no, '')] + + def get_informat_token(self, nummer=None): + """Haalt token op met de scope van het (eerste of opgegeven) instellingsnummer.""" + from tenancy import informat_scope + payload = { + 'grant_type': 'client_credentials', + 'client_id': self.conf.INFORMAT_ID, + 'client_secret': self.conf.INFORMAT_SECRET, + 'scope': informat_scope(Config.INFORMAT_SCOPE, nummer) if nummer else self.scope + } + try: + response = requests.post(self.auth_url, data=payload, timeout=10) + if response.status_code == 200: + return response.json().get('access_token') + except Exception as e: + print(f"Fout bij ophalen Informat token: {e}") + return None + + def get_smartschool_oneroster_students(self): + """Haalt actieve leerlingen op uit de Smartschool OneRoster API (v1p1). Bij een fout: {}.""" + mapping, fout = self.smartschool_koppeling() + if fout: + print(f"Fout bij ophalen Smartschool OneRoster data: {fout}") + return mapping + + def smartschool_koppeling(self): + """{internnummer: {'username', 'ss_nummer'}} uit Smartschool OneRoster. Geeft (mapping, None) of ({}, fout).""" + if not (self.conf.SS_CLIENT_ID and self.conf.SS_CLIENT_SECRET): + return {}, "de OneRoster-koppeling van Smartschool is niet ingesteld" + try: + token_url = self.conf.SS_TOKEN_URL.strip() + if not token_url.startswith(("http://", "https://")): + token_url = f"https://{token_url}" + + resp_ss = requests.post( + token_url, + data={"grant_type": "client_credentials"}, + auth=(self.conf.SS_CLIENT_ID, self.conf.SS_CLIENT_SECRET), + timeout=10 + ) + resp_ss.raise_for_status() + ss_token = resp_ss.json().get("access_token") + + if not ss_token: + return {}, "geen access_token ontvangen van Smartschool" + + headers = { + "Authorization": f"Bearer {ss_token}", + "Accept": "application/json" + } + + base_url = self.conf.SS_BASE_URL.strip() + if not base_url.startswith(("http://", "https://")): + base_url = f"https://{base_url}" + + base_url = base_url.rstrip('/') + endpoint_url = f"{base_url}/students" + + response = requests.get(endpoint_url, headers=headers, timeout=ONEROSTER_TIMEOUT) + response.raise_for_status() + + json_data = response.json() + all_students = json_data.get("users", []) + + ss_mapping = {} + for student in all_students: + metadata = student.get("metadata", {}) + internal_number = metadata.get("smsc.internalNumber") + username = student.get("username") + sourced_id = student.get("sourcedId") + + if internal_number: + ss_mapping[str(internal_number).strip()] = { + "username": username, + "ss_nummer": sourced_id if sourced_id else "Niet ingesteld" + } + if not ss_mapping: + return {}, "Smartschool gaf geen enkele leerling met een internnummer terug" + return ss_mapping, None + + except Exception as e: + return {}, str(e) + + def _informat_leerlingen(self, nummer, school_year, refdate): + """Leerlingenlijst van één instellingsnummer. Geeft (lijst, None) of (None, fout).""" + inf_token = self.get_informat_token(nummer) + if not inf_token: + return None, f"Informat authenticatie mislukt (instellingsnummer {nummer})." + base_url_inf = self.api_base.strip().rstrip('/') + url = f"{base_url_inf}/students/?schoolYear={school_year}&refdate={refdate}" + headers = { + 'Authorization': f'BEARER {inf_token}', + 'InstituteNo': nummer, + 'Timestamp': datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.000Z'), + 'Api-Version': '1', + 'Accept': 'application/json' + } + response = informat_get(url, headers) + if response.status_code != 200: + return None, f"Informat API fout {response.status_code} (instellingsnummer {nummer}): {response.text}" + json_data = response.json() + return (json_data if isinstance(json_data, list) else json_data.get('students', json_data.get('items', []))), None + + def sync_actieve_leerlingen(self): + """ + Haalt actieve leerlingen op bij Informat (alle campussen / instellingsnummers van de school), + koppelt Smartschool OneRoster info en update de database 'Leerlingen'. + """ + school_year = Config.SCHOOLYEAR + # +1 maand: ook leerlingen die net ingeschreven zijn en pas na een vakantie starten + refdate = (datetime.now() + relativedelta(months=1)).strftime('%Y-%m-%d') + + students_list, gezien = [], set() + try: + for nummer, naam in self.campussen: + lijst, fout = self._informat_leerlingen(nummer, school_year, refdate) + if fout: + return False, (f"{naam}: {fout}" if len(self.campussen) > 1 else fout) + for st in lijst: + sleutel = str(st.get('pPersoon') or st.get('internNummer') or st.get('id', '')).strip() + if sleutel and sleutel not in gezien: + gezien.add(sleutel) + students_list.append(st) + except Exception as e: + return False, f"Fout opgetreden tijdens de synchronisatie: {str(e)}" + + if not students_list: + # Nooit iedereen als vertrokken markeren omdat Informat (tijdelijk) een lege lijst gaf + return False, "Informat gaf geen enkele actieve leerling terug; er is niets aangepast." + + # Smartschool (gebruikersnaam en Smartschool-nummer). Lukt dat niet, dan blijven die velden zoals ze waren. + ss_leerlingen, ss_fout = self.smartschool_koppeling() + + try: + print(f"[DEBUG] Aantal actieve leerlingen gevonden in Informat: {len(students_list)}") + zorg_vertrokken_kolom() + + db_rows = execute_query("SELECT Internnummer FROM Leerlingen") + bestaande_internnummers = {str(row['Internnummer']).strip() for row in db_rows} if db_rows else set() + + toegevoegd_teller = bijgewerkt_teller = 0 + schooljaar_id = Config.SCHOOLYEAR[:4] + actief = set() + + for student in students_list: + internnummer = str(student.get('pPersoon') or student.get('internNummer') or student.get('id', '')).strip() + voornaam = (student.get('voornaam' if 'voornaam' in student else 'firstName') or '').strip() + naam = (student.get('naam' if 'naam' in student else 'lastName') or '').strip() + if not internnummer or internnummer == "None": + continue + actief.add(internnummer) + ss_info = ss_leerlingen.get(internnummer) + standaard_gebruikersnaam = f"{voornaam}.{naam}".replace(" ", "").lower() + + if internnummer in bestaande_internnummers: + if ss_info: + execute_query(""" + UPDATE Leerlingen SET Gebruikersnaam = %s, Voornaam = %s, Naam = %s, SS_nummer = %s, + Schooljaar_ID = %s, Vertrokken_op = NULL + WHERE Internnummer = %s""", + (ss_info.get("username") or standaard_gebruikersnaam, voornaam, naam, + ss_info.get("ss_nummer") or "Niet ingesteld", schooljaar_id, internnummer), commit=True) + else: + # Niet (of niet bereikbaar) in Smartschool: gebruikersnaam en Smartschool-nummer niet overschrijven + execute_query(""" + UPDATE Leerlingen SET Voornaam = %s, Naam = %s, Schooljaar_ID = %s, Vertrokken_op = NULL + WHERE Internnummer = %s""", (voornaam, naam, schooljaar_id, internnummer), commit=True) + bijgewerkt_teller += 1 + else: + ss_info = ss_info or {} + execute_query(""" + INSERT INTO Leerlingen (Internnummer, Gebruikersnaam, Voornaam, Naam, SS_nummer, Schooljaar_ID) + VALUES (%s, %s, %s, %s, %s, %s)""", + (internnummer, ss_info.get("username") or standaard_gebruikersnaam, voornaam, naam, + ss_info.get("ss_nummer") or "Niet ingesteld", schooljaar_id), commit=True) + bestaande_internnummers.add(internnummer) + toegevoegd_teller += 1 + + # Leerlingen die niet meer actief zijn in Informat: als vertrokken markeren (niet verwijderen) + nog_actief = execute_query("SELECT Internnummer FROM Leerlingen WHERE Vertrokken_op IS NULL") or [] + weg = [r['Internnummer'] for r in nog_actief if str(r['Internnummer']).strip() not in actief] + for k in range(0, len(weg), 500): + deel = weg[k:k + 500] + execute_query(f"UPDATE Leerlingen SET Vertrokken_op = CURDATE() WHERE Internnummer IN " + f"({', '.join(['%s'] * len(deel))})", tuple(deel), commit=True) + + melding = f"{toegevoegd_teller} nieuw, {bijgewerkt_teller} bijgewerkt" + if weg: + melding += f", {len(weg)} als vertrokken gemarkeerd" + return True, {'melding': melding + '.', 'smartschool_fout': ss_fout} + + except Exception as e: + return False, f"Fout opgetreden tijdens de synchronisatie: {str(e)}" diff --git a/services/tabelnamen.py b/services/tabelnamen.py new file mode 100644 index 0000000..52cfef4 --- /dev/null +++ b/services/tabelnamen.py @@ -0,0 +1,148 @@ +""" +Tabelnamen met hoofdletters herstellen (Windows → Linux). + +MySQL op Windows bewaart tabelnamen standaard in kleine letters (lower_case_table_names = 1) en maakt hoofdletters +niet uit. Op Linux (lower_case_table_names = 0) zijn 'toestellen' en 'Toestellen' twee verschillende tabellen. +Een database die van Windows komt, heeft dan enkel kleine letters, terwijl PIVOT 'Toestellen' zoekt (en een lege +nieuwe aanmaakt). + +Bij het opstarten loopt PIVOT daarom de centrale database en de database van elke school na. Enkel op een server +waar hoofdletters tellen (lower_case_table_names = 0), en enkel voor de tabellen die PIVOT kent: + - alleen 'toestellen' bestaat → hernoemd naar 'Toestellen' + - beide bestaan, 'Toestellen' is leeg → de lege 'Toestellen' weg, 'toestellen' hernoemd naar 'Toestellen' + - beide bestaan, 'toestellen' is leeg → niets nodig ('Toestellen' wordt gebruikt), enkel gemeld + - beide bevatten gegevens → niets aangeraakt, gemeld in het logboek (handmatig samenvoegen) +Op Windows (of met lower_case_table_names = 1 of 2) doet dit niets. +""" +import glob +import os +import re +import sys + +_RE = re.compile(r"CREATE\s+TABLE\s+IF\s+NOT\s+EXISTS\s+`?([A-Za-z_][A-Za-z0-9_]*)`?", re.I) +_namen = None + + +def verwachte_namen(): + """Alle tabelnamen met minstens één hoofdletter, zoals PIVOT ze aanmaakt (uit de SQL-bestanden en de code).""" + global _namen + if _namen is None: + basis = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + bestanden = glob.glob(os.path.join(basis, 'sql', '*.sql')) + glob.glob(os.path.join(basis, '*.py')) \ + + glob.glob(os.path.join(basis, 'services', '*.py')) + glob.glob(os.path.join(basis, 'blueprints', '*.py')) + namen = set() + for pad in bestanden: + try: + with open(pad, encoding='utf-8', errors='ignore') as f: + namen.update(n for n in _RE.findall(f.read()) if n != n.lower()) + except OSError: + continue + _namen = sorted(namen) + return _namen + + +def _q(cur, sql, params=()): + cur.execute(sql, params) + return cur.fetchall() if cur.with_rows else [] + + +def herstel(conn, label): + """Herstelt de tabelnamen in de database van `conn`. Geeft een lijst meldingen (leeg = niets gedaan).""" + meldingen = [] + cur = conn.cursor() + try: + lctn = _q(cur, "SELECT @@lower_case_table_names") + if not lctn or int(lctn[0][0]) != 0: + return meldingen # Windows/macOS-gedrag: hoofdletters maken niet uit + bestaand = [r[0] for r in _q(cur, "SELECT TABLE_NAME FROM information_schema.TABLES " + "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_TYPE = 'BASE TABLE'")] + if not bestaand: + return meldingen + per_klein = {} + for t in bestaand: + per_klein.setdefault(t.lower(), []).append(t) + te_doen = [] + for naam in verwachte_namen(): + varianten = [t for t in per_klein.get(naam.lower(), []) if t != naam] + if not varianten: + continue + if len(varianten) > 1: + meldingen.append(f"{label}: meerdere varianten van {naam} ({', '.join(varianten)}), niets gewijzigd") + continue + te_doen.append((naam, varianten[0], naam in per_klein.get(naam.lower(), []))) + if not te_doen: + return meldingen + + aantal = lambda t: int(_q(cur, f"SELECT COUNT(*) FROM `{t}`")[0][0]) + _q(cur, "SET FOREIGN_KEY_CHECKS = 0") + try: + for naam, oud, juiste_bestaat in te_doen: + try: + if juiste_bestaat: + n_juist, n_oud = aantal(naam), aantal(oud) + if n_oud == 0: + meldingen.append(f"{label}: {oud} is leeg en wordt niet gebruikt ({naam} wel); " + f"je mag {oud} verwijderen") + continue + if n_juist > 0: + meldingen.append(f"{label}: zowel {oud} ({n_oud} rijen) als {naam} ({n_juist} rijen) " + f"bevatten gegevens; niets gewijzigd, voeg ze zelf samen") + continue + _q(cur, f"DROP TABLE `{naam}`") + _q(cur, f"RENAME TABLE `{oud}` TO `{naam}`") + meldingen.append(f"{label}: lege {naam} vervangen door {oud} ({n_oud} rijen)") + else: + _q(cur, f"RENAME TABLE `{oud}` TO `{naam}`") + meldingen.append(f"{label}: {oud} hernoemd naar {naam}") + except Exception as e: + meldingen.append(f"{label}: {oud} → {naam} mislukt: {e}") + finally: + _q(cur, "SET FOREIGN_KEY_CHECKS = 1") + conn.commit() + finally: + cur.close() + return meldingen + + +def _verbinding(host, user, password, database): + """Eén losse verbinding (geen pool): bij het opstarten zou een pool per school anders meteen + 5 verbindingen per school openen en blijven vasthouden ("Too many connections").""" + import mysql.connector + from config import Config + return mysql.connector.connect(host=host, port=Config.DB_PORT, user=user, password=password, database=database, + connection_timeout=10, charset='utf8mb4', collation='utf8mb4_unicode_ci') + + +def herstel_centraal(): + from config import Config + conn = _verbinding(Config.DB_HOST, Config.DB_USER, Config.DB_PASSWORD, Config.DB_CENTRAAL) + try: + return _log(herstel(conn, 'centrale database')) + finally: + conn.close() + + +def herstel_school(school): + cfg = school.db_config() + conn = _verbinding(cfg['host'], cfg['user'], cfg['password'], cfg['database']) + try: + return _log(herstel(conn, f"school {school.code}")) + finally: + conn.close() + + +def herstel_alle_scholen(): + from tenancy import alle_scholen + uit = [] + for school in alle_scholen(ook_inactief=True): + try: + uit += herstel_school(school) + except Exception as e: + uit += _log([f"school {school.code}: tabelnamen nakijken mislukt: {e}"]) + return uit + + +def _log(meldingen): + for m in meldingen: + print(f"PIVOT tabelnamen: {m}", file=sys.stderr, flush=True) + return meldingen diff --git a/services/toestellen.py b/services/toestellen.py new file mode 100644 index 0000000..6ef786e --- /dev/null +++ b/services/toestellen.py @@ -0,0 +1,121 @@ +""" +Hulpfuncties rond toestellen (tabellen Toestellen, Signpost_DB, Opmerkingen, Eigendom). + +Het toestelnummer dat gebruikers intypen (vroeger 'KAMXM_nummer') is Toestellen.Schooleigen_ID. +""" +from datetime import datetime, date + +from database import execute_query, execute_insert + +# Laatste opmerking van een toestel (subquery, t = alias van Toestellen) +LAATSTE_OPMERKING = ("(SELECT o.Opmerking FROM Opmerkingen o WHERE o.Toestel_ID = t.Toestel_ID " + "ORDER BY o.Timestamp DESC, o.Opmerking_ID DESC LIMIT 1)") + + +def zoek_toestel(nummer): + """Toestel op toestelnummer (Schooleigen_ID) of, als dat niet bestaat, op serienummer.""" + nummer = str(nummer or '').strip() + if not nummer: + return None + rows = execute_query("SELECT * FROM Toestellen WHERE Schooleigen_ID = %s", (nummer,)) + if not rows: + rows = execute_query("SELECT * FROM Toestellen WHERE Serienummer = %s", (nummer,)) + return rows[0] if rows else None + + +def zoek_leerling(nummer): + """Leerling op internnummer of Smartschool-nummer.""" + rows = execute_query("SELECT * FROM Leerlingen WHERE Internnummer = %s OR SS_nummer = %s LIMIT 1", + (str(nummer).strip(), str(nummer).strip())) + return rows[0] if rows else None + + +def laatste_opmerking(toestel_id): + rows = execute_query("SELECT Opmerking FROM Opmerkingen WHERE Toestel_ID = %s " + "ORDER BY Timestamp DESC, Opmerking_ID DESC LIMIT 1", (toestel_id,)) + return rows[0]['Opmerking'] if rows else None + + +def voeg_opmerking_toe(toestel_id, tekst, gebruiker=None): + """Bewaart een opmerking als die verschilt van de laatste (zo blijft de geschiedenis bewaard).""" + tekst = (tekst or '').strip() + if tekst and tekst != (laatste_opmerking(toestel_id) or ''): + execute_query("INSERT INTO Opmerkingen (Toestel_ID, Opmerking, Timestamp, Gebruiker) VALUES (%s, %s, NOW(), %s)", + (toestel_id, tekst, gebruiker), commit=True) + + +def lees_datum(waarde): + """'2027-08-31', '31-08-2027' of '31/08/2027' → date. Leeg → None. Ongeldig → ValueError.""" + if isinstance(waarde, date): + return waarde + w = (waarde or '').strip() + if not w: + return None + for fmt in ('%Y-%m-%d', '%d-%m-%Y', '%d/%m/%Y', '%d.%m.%Y'): + try: + return datetime.strptime(w, fmt).date() + except ValueError: + pass + raise ValueError(f"'{w}' is geen geldige datum (gebruik dd-mm-jjjj).") + + +def bewaar_signpost(toestel_id, signpostnummer=None, garantie=None): + """Maakt/werkt de Signpost-gegevens van een toestel bij (enkel ingevulde velden).""" + signpostnummer = (signpostnummer or '').strip() or None + garantie = lees_datum(garantie) + if not signpostnummer and not garantie: + return + execute_query( + "INSERT INTO Signpost_DB (Toestel_ID, Signpostnummer, Garantie) VALUES (%s, %s, %s) " + "ON DUPLICATE KEY UPDATE Signpostnummer = COALESCE(VALUES(Signpostnummer), Signpostnummer), " + "Garantie = COALESCE(VALUES(Garantie), Garantie)", + (toestel_id, signpostnummer, garantie), commit=True) + + +def nieuw_toestel(schooleigen_id=None, serienummer=None, type_toestel=None, status='Beschikbaar'): + return execute_insert( + "INSERT INTO Toestellen (Schooleigen_ID, Serienummer, Type, Status) VALUES (%s, %s, %s, %s)", + ((schooleigen_id or None), (serienummer or None), (type_toestel or None), status)) + + +def actieve_eigendom(toestel_id): + """Huidige toekenning van een toestel (Datum_inlevering leeg) of None.""" + rows = execute_query("SELECT * FROM Eigendom WHERE Toestel_ID = %s AND Datum_inlevering IS NULL " + "ORDER BY Datum_toekenning DESC LIMIT 1", (toestel_id,)) + return rows[0] if rows else None + + +# --------------------------------------------------------------------------- +# Geblokkeerd in Google (kolom Toestellen.Geblokkeerd) +# --------------------------------------------------------------------------- +def ensure_geblokkeerd(): + """Voegt de kolom Toestellen.Geblokkeerd toe als die nog niet bestaat. Bij het toevoegen krijgen toestellen die + bij een leerling geblokkeerd staan (Eigendom.Status = 1) meteen de waarde 1. Eén keer per school en proces.""" + from tenancy import huidige_school + school = huidige_school() + if school.cache.get('kol_geblokkeerd'): + return + if not execute_query("SHOW COLUMNS FROM Toestellen LIKE 'Geblokkeerd'"): + execute_query("ALTER TABLE Toestellen ADD COLUMN Geblokkeerd TINYINT(1) NOT NULL DEFAULT 0 AFTER Status", + commit=True) + execute_query("UPDATE Toestellen t JOIN Eigendom e ON e.Toestel_ID = t.Toestel_ID " + "AND e.Datum_inlevering IS NULL AND e.Status = 1 SET t.Geblokkeerd = 1", commit=True) + school.cache['kol_geblokkeerd'] = True + + +def zet_geblokkeerd(toestel_id, geblokkeerd): + """Bewaart de blokkeerstatus van een toestel, ook bij de huidige eigenaar (Eigendom.Status).""" + ensure_geblokkeerd() + w = 1 if geblokkeerd else 0 + execute_query("UPDATE Toestellen SET Geblokkeerd = %s WHERE Toestel_ID = %s", (w, toestel_id), commit=True) + execute_query("UPDATE Eigendom SET Status = %s WHERE Toestel_ID = %s AND Datum_inlevering IS NULL", + (w, toestel_id), commit=True) + + +def is_geblokkeerd(toestel_id): + try: + ensure_geblokkeerd() + rows = execute_query("SELECT Geblokkeerd FROM Toestellen WHERE Toestel_ID = %s", (toestel_id,)) + return bool(rows and int(rows[0]['Geblokkeerd'] or 0)) + except Exception: + return False diff --git a/services/toestellen_import.py b/services/toestellen_import.py new file mode 100644 index 0000000..ba8bfe8 --- /dev/null +++ b/services/toestellen_import.py @@ -0,0 +1,419 @@ +""" +Beheer › Database › Toestellen: de tabel Toestellen aanvullen vanuit een Excel-bestand. + +Werkwijze (twee stappen, zodat er niets in de database komt zonder dat je het gezien hebt): + 1. lees_excel() : het geüploade bestand → ruwe rijen (enkel tekst / ISO-datums) + 2. maak_plan() : ruwe rijen → per rij 'nieuw', 'bijwerken', 'ongewijzigd' of 'fout' (niets wordt bewaard) + 3. voer_uit() : het plan in één transactie uitvoeren (het plan wordt opnieuw gemaakt, nooit blind vertrouwd) + +Een toestel wordt herkend aan het toestelnummer (Schooleigen_ID) en anders aan het serienummer. +Er wordt nooit iets verwijderd. Lege cellen wissen nooit een bestaande waarde. +""" +import io +from datetime import date, datetime + +from database import execute_query, get_db_connection +from services import toestellen as tst + +STATUSSEN = ('Beschikbaar', 'Uitgeleend', 'Defect') +MAX_RIJEN = 5000 + +# (sleutel, kolomkop in het sjabloon, max. lengte, uitleg, andere namen die ook herkend worden) +KOLOMMEN = [ + ('schooleigen_id', 'Toestelnummer', 50, + "Het eigen toestelnummer van de school (Schooleigen_ID). Uniek. Toestelnummer of serienummer is verplicht.", + ('schooleigen_id', 'schooleigen id', 'kamxm_nummer', 'kamxm nummer', 'kamxm', 'nummer', 'toestel')), + ('serienummer', 'Serienummer', 100, + "Serienummer van de fabrikant (nodig om het toestel in Google te blokkeren). " + "Toestelnummer of serienummer is verplicht.", + ('serial', 'serial number', 'serienr', 'serie')), + ('type', 'Type', 100, "Model van het toestel, bv. Lenovo 300e Gen 4.", ('model', 'toesteltype')), + ('status', 'Status', None, + "Beschikbaar, Uitgeleend of Defect. Leeg bij een nieuw toestel = Beschikbaar.", ()), + ('afschrijfdatum', 'Afschrijfdatum', None, + "Datum (dd-mm-jjjj) of een Excel-datum. Mag leeg.", ('afschrijving', 'afschrijf datum')), + ('lokaal', 'Lokaal', None, + "Naam van een lokaal dat al in PIVOT bestaat (zie het tabblad Lokalen). Mag leeg.", ('lokaalnaam', 'lokaal_id')), +] +SLEUTELS = [k[0] for k in KOLOMMEN] +KOPPEN = {k[0]: k[1] for k in KOLOMMEN} + +# Databasekolom per sleutel (lokaal → Lokaal_ID wordt apart opgezocht) +DB_KOLOM = {'schooleigen_id': 'Schooleigen_ID', 'serienummer': 'Serienummer', 'type': 'Type', + 'status': 'Status', 'afschrijfdatum': 'Afschrijfdatum', 'lokaal': 'Lokaal_ID'} + + +class ImportFout(Exception): + """Het bestand zelf kan niet gelezen worden (geen rijfout).""" + + +def _norm(tekst): + return ' '.join(str(tekst or '').strip().lower().replace('_', ' ').replace('-', ' ').split()) + + +_HERKEN = {} +for _k, _kop, _m, _u, _alias in KOLOMMEN: + for _naam in (_k, _kop) + tuple(_alias): + _HERKEN[_norm(_naam)] = _k + + +# --------------------------------------------------------------------------- +# Sjabloon +# --------------------------------------------------------------------------- +def lokalen(): + """Alle lokalen van de huidige school: [{'Lokaal_ID', 'Naam', 'Campus'}].""" + return execute_query( + "SELECT l.Lokaal_ID, l.Naam, c.Campus_naam AS Campus FROM Lokalen l " + "LEFT JOIN Campus c ON c.Campus_ID = l.Campus_ID ORDER BY l.Naam") or [] + + +def maak_sjabloon(schoolnaam=''): + """Excel-sjabloon (bytes): tabblad Toestellen (in te vullen), Uitleg en Lokalen.""" + from openpyxl import Workbook + from openpyxl.styles import Font, PatternFill, Alignment + from openpyxl.worksheet.datavalidation import DataValidation + + wb = Workbook() + ws = wb.active + ws.title = 'Toestellen' + ws.append([k[1] for k in KOLOMMEN]) + kop_vulling = PatternFill('solid', fgColor='1E6FA5') + for c in ws[1]: + c.font = Font(bold=True, color='FFFFFF') + c.fill = kop_vulling + c.alignment = Alignment(vertical='center') + breedtes = {'Toestelnummer': 16, 'Serienummer': 20, 'Type': 26, 'Status': 14, 'Afschrijfdatum': 16, 'Lokaal': 18} + for i, k in enumerate(KOLOMMEN): + letter = ws.cell(row=1, column=i + 1).column_letter + ws.column_dimensions[letter].width = breedtes.get(k[1], 16) + ws.freeze_panes = 'A2' + ws.row_dimensions[1].height = 22 + + kol = {k[0]: ws.cell(row=1, column=i + 1).column_letter for i, k in enumerate(KOLOMMEN)} + # Nummers als tekst (anders maakt Excel van 00123 → 123) + for sleutel in ('schooleigen_id', 'serienummer'): + for r in range(2, MAX_RIJEN + 2): + ws[f"{kol[sleutel]}{r}"].number_format = '@' + for r in range(2, MAX_RIJEN + 2): + ws[f"{kol['afschrijfdatum']}{r}"].number_format = 'DD-MM-YYYY' + + dv_status = DataValidation(type='list', formula1='"' + ','.join(STATUSSEN) + '"', allow_blank=True, + showErrorMessage=True, errorTitle='Status', + error='Kies Beschikbaar, Uitgeleend of Defect (of laat leeg).') + dv_status.add(f"{kol['status']}2:{kol['status']}{MAX_RIJEN + 1}") + ws.add_data_validation(dv_status) + dv_datum = DataValidation(type='date', operator='greaterThan', formula1='1', allow_blank=True, + showErrorMessage=True, errorTitle='Afschrijfdatum', + error='Vul een datum in, bv. 31-08-2030.') + dv_datum.add(f"{kol['afschrijfdatum']}2:{kol['afschrijfdatum']}{MAX_RIJEN + 1}") + ws.add_data_validation(dv_datum) + + # Lokalen van deze school (keuzelijst in de kolom Lokaal) + wl = wb.create_sheet('Lokalen') + wl.append(['Lokaal', 'Campus']) + for c in wl[1]: + c.font = Font(bold=True) + lijst = [] + try: + lijst = lokalen() + except Exception: + pass + for l in lijst: + wl.append([l['Naam'], l.get('Campus') or '']) + wl.column_dimensions['A'].width = 24 + wl.column_dimensions['B'].width = 28 + if lijst: + dv_lokaal = DataValidation(type='list', formula1=f"=Lokalen!$A$2:$A${len(lijst) + 1}", allow_blank=True, + showErrorMessage=True, errorTitle='Lokaal', + error='Kies een lokaal uit de lijst (tabblad Lokalen) of laat leeg.') + dv_lokaal.add(f"{kol['lokaal']}2:{kol['lokaal']}{MAX_RIJEN + 1}") + ws.add_data_validation(dv_lokaal) + + # Uitleg + wu = wb.create_sheet('Uitleg') + wu.column_dimensions['A'].width = 18 + wu.column_dimensions['B'].width = 95 + wu.append([f"Toestellen importeren in PIVOT{' – ' + schoolnaam if schoolnaam else ''}"]) + wu['A1'].font = Font(bold=True, size=14) + regels = [ + "Vul het tabblad 'Toestellen' in: één toestel per rij, vanaf rij 2. Laat de kolomkoppen in rij 1 staan.", + "Een toestel wordt herkend aan het toestelnummer, en anders aan het serienummer.", + "Bestaat het toestel nog niet, dan wordt het toegevoegd.", + "Bestaat het al, dan worden (afhankelijk van je keuze bij het uploaden) enkel lege velden aangevuld " + "of de ingevulde velden overschreven. Een lege cel wist nooit iets.", + "Er wordt nooit een toestel verwijderd. Je krijgt eerst een voorbeeld te zien voordat er iets bewaard wordt.", + f"Maximaal {MAX_RIJEN} rijen per bestand.", + ] + for t in regels: + wu.append(['', t]) + wu.append([]) + wu.append(['Kolom', 'Uitleg']) + for c in wu[wu.max_row]: + c.font = Font(bold=True) + for _k, kop, maxlen, uitleg, _a in KOLOMMEN: + wu.append([kop, uitleg + (f" Max. {maxlen} tekens." if maxlen else '')]) + for rij in wu.iter_rows(min_row=2): + for c in rij: + c.alignment = Alignment(wrap_text=True, vertical='top') + wu.append([]) + wu.append(['Voorbeeld', 'Toestelnummer CB-0123 · Serienummer PF3ABC12 · Type Lenovo 300e Gen 4 · ' + 'Status Beschikbaar · Afschrijfdatum 31-08-2030 · Lokaal A101']) + + wb.active = 0 + buf = io.BytesIO() + wb.save(buf) + return buf.getvalue() + + +# --------------------------------------------------------------------------- +# Excel lezen +# --------------------------------------------------------------------------- +def _cel(waarde): + """Celwaarde → tekst (datums als ISO 'jjjj-mm-dd', 123.0 → '123').""" + if waarde is None: + return '' + if isinstance(waarde, datetime): + return waarde.date().isoformat() + if isinstance(waarde, date): + return waarde.isoformat() + if isinstance(waarde, float) and waarde.is_integer(): + return str(int(waarde)) + return str(waarde).strip() + + +def lees_excel(bestand): + """Leest een .xlsx (bestandsobject of bytes). Geeft (rijen, onbekende_kolommen). + rijen = [{'rij': , 'schooleigen_id': '...', ...}] (enkel niet-lege rijen).""" + from openpyxl import load_workbook + data = bestand if isinstance(bestand, (bytes, bytearray)) else bestand.read() + if not data: + raise ImportFout("Het bestand is leeg.") + try: + wb = load_workbook(io.BytesIO(data), read_only=True, data_only=True) + except Exception: + raise ImportFout("Dit bestand kan niet gelezen worden. Gebruik een Excel-bestand (.xlsx), " + "bv. het sjabloon van deze pagina.") + try: + ws = wb['Toestellen'] if 'Toestellen' in wb.sheetnames else wb.worksheets[0] + rijen_iter = ws.iter_rows(values_only=True) + # Kopregel zoeken in de eerste 10 rijen: de eerste rij met een herkende kolom + kop_index, onbekend, rijnr = None, [], 0 + for rij in rijen_iter: + rijnr += 1 + gevonden = {i: _HERKEN[_norm(v)] for i, v in enumerate(rij or ()) if _norm(v) in _HERKEN} + if gevonden: + kop_index = {} + for i, sleutel in gevonden.items(): + kop_index.setdefault(sleutel, i) # dubbele kolom: de eerste telt + onbekend = [_cel(v) for i, v in enumerate(rij) if _cel(v) and i not in gevonden] + break + if rijnr >= 10: + break + if not kop_index: + raise ImportFout("Geen kolomkoppen gevonden. Rij 1 moet de kolomnamen van het sjabloon bevatten " + f"({', '.join(KOPPEN.values())}).") + if 'schooleigen_id' not in kop_index and 'serienummer' not in kop_index: + raise ImportFout("De kolom Toestelnummer of Serienummer ontbreekt.") + + uit = [] + for rij in rijen_iter: + rijnr += 1 + waarden = {s: _cel(rij[i]) if rij and i < len(rij) else '' for s, i in kop_index.items()} + if not any(waarden.values()): + continue + if len(uit) >= MAX_RIJEN: + raise ImportFout(f"Het bestand bevat meer dan {MAX_RIJEN} rijen. Splits het op in kleinere bestanden.") + uit.append({'rij': rijnr, **{s: waarden.get(s, '') for s in SLEUTELS}}) + return uit, onbekend + finally: + wb.close() + + +# --------------------------------------------------------------------------- +# Plan maken (niets bewaren) +# --------------------------------------------------------------------------- +def _datum_tekst(w): + """'2030-08-31' / '31-08-2030' / '31/08/2030' → date, of ValueError.""" + w = (w or '').strip() + if not w: + return None + try: + return date.fromisoformat(w[:10]) if len(w) >= 10 and w[4] == '-' else tst.lees_datum(w) + except ValueError: + return tst.lees_datum(w) + + +def _toon(w): + if isinstance(w, date): + return w.strftime('%d-%m-%Y') + return '' if w is None else str(w) + + +def maak_plan(rijen, modus='aanvullen'): + """Bepaalt per rij wat er zou gebeuren. modus: 'aanvullen' (enkel lege velden) of 'overschrijven'. + Geeft {'rijen': [...], 'tellers': {...}}; elke rij heeft 'actie', 'meldingen' en 'waarden' (voor de database).""" + overschrijven = modus == 'overschrijven' + bestaand = execute_query("SELECT Toestel_ID, Schooleigen_ID, Serienummer, Type, Status, Afschrijfdatum, Lokaal_ID " + "FROM Toestellen") or [] + op_nummer = {(r['Schooleigen_ID'] or '').strip().upper(): r for r in bestaand if (r['Schooleigen_ID'] or '').strip()} + op_serie = {} + for r in bestaand: + s = (r['Serienummer'] or '').strip().upper() + if s: + op_serie.setdefault(s, r) + lok = {} + for l in lokalen(): + lok.setdefault((l['Naam'] or '').strip().upper(), l) + lok_naam = {l['Lokaal_ID']: l['Naam'] for l in lok.values()} + + gezien_nummer, gezien_serie = {}, {} + uit = [] + tellers = {'nieuw': 0, 'bijwerken': 0, 'ongewijzigd': 0, 'fout': 0} + + for invoer in rijen: + r = {'rij': invoer.get('rij'), 'invoer': {s: str(invoer.get(s) or '').strip() for s in SLEUTELS}, + 'meldingen': [], 'wijzigingen': [], 'actie': None, 'toestel_id': None, 'waarden': {}} + v = r['invoer'] + fouten = [] + + # --- waarden controleren --- + nummer, serie = v['schooleigen_id'], v['serienummer'] + if not nummer and not serie: + fouten.append("Toestelnummer of serienummer is verplicht.") + for s in ('schooleigen_id', 'serienummer', 'type'): + maxlen = next(k[2] for k in KOLOMMEN if k[0] == s) + if len(v[s]) > maxlen: + fouten.append(f"{KOPPEN[s]} is te lang (max. {maxlen} tekens).") + status = None + if v['status']: + status = next((x for x in STATUSSEN if x.lower() == v['status'].lower()), None) + if not status: + fouten.append(f"Status '{v['status']}' is ongeldig (kies {', '.join(STATUSSEN)}).") + afschrijf = None + if v['afschrijfdatum']: + try: + afschrijf = _datum_tekst(v['afschrijfdatum']) + except ValueError: + fouten.append(f"Afschrijfdatum '{v['afschrijfdatum']}' is geen geldige datum (gebruik dd-mm-jjjj).") + lokaal_id = None + if v['lokaal']: + l = lok.get(v['lokaal'].upper()) + if l: + lokaal_id = l['Lokaal_ID'] + else: + fouten.append(f"Lokaal '{v['lokaal']}' bestaat niet in PIVOT.") + + # --- dubbels in het bestand (enkel t.o.v. eerdere rijen zonder fout) --- + if nummer and gezien_nummer.get(nummer.upper()): + fouten.append(f"Toestelnummer {nummer} staat al op rij {gezien_nummer[nummer.upper()]}.") + if serie and gezien_serie.get(serie.upper()): + fouten.append(f"Serienummer {serie} staat al op rij {gezien_serie[serie.upper()]}.") + + # --- bestaand toestel? --- + t_nummer = op_nummer.get(nummer.upper()) if nummer else None + t_serie = op_serie.get(serie.upper()) if serie else None + toestel = t_nummer or t_serie + if t_nummer and t_serie and t_nummer['Toestel_ID'] != t_serie['Toestel_ID']: + fouten.append(f"Toestelnummer {nummer} en serienummer {serie} horen in PIVOT bij twee verschillende " + f"toestellen. Pas dit eerst aan in 💻 Alle toestellen.") + elif toestel: + db_nummer = (toestel['Schooleigen_ID'] or '').strip() + db_serie = (toestel['Serienummer'] or '').strip() + if t_nummer and serie and db_serie and db_serie.upper() != serie.upper(): + fouten.append(f"Toestel {nummer} heeft in PIVOT serienummer {db_serie}, niet {serie}.") + if not t_nummer and nummer and db_nummer and db_nummer.upper() != nummer.upper(): + fouten.append(f"Serienummer {serie} hoort in PIVOT bij toestel {db_nummer}, niet bij {nummer}.") + + if fouten: + r['actie'] = 'fout' + r['meldingen'] = fouten + tellers['fout'] += 1 + uit.append(r) + continue + + if nummer: + gezien_nummer[nummer.upper()] = r['rij'] + if serie: + gezien_serie[serie.upper()] = r['rij'] + + nieuw = {'schooleigen_id': nummer or None, 'serienummer': serie or None, 'type': v['type'] or None, + 'status': status, 'afschrijfdatum': afschrijf, 'lokaal': lokaal_id} + + if not toestel: + nieuw['status'] = status or 'Beschikbaar' + r['actie'] = 'nieuw' + r['waarden'] = {DB_KOLOM[s]: w for s, w in nieuw.items() if w is not None} + tellers['nieuw'] += 1 + uit.append(r) + continue + + # --- bijwerken --- + r['toestel_id'] = toestel['Toestel_ID'] + r['label'] = toestel['Schooleigen_ID'] or toestel['Serienummer'] or str(toestel['Toestel_ID']) + overgeslagen = [] + for s, w in nieuw.items(): + if w is None: + continue + kolom = DB_KOLOM[s] + huidig = toestel[kolom] + if isinstance(huidig, datetime): + huidig = huidig.date() + gelijk = (str(huidig).strip().upper() == str(w).strip().upper()) if huidig not in (None, '') else False + if gelijk: + continue + leeg = huidig is None or (isinstance(huidig, str) and not huidig.strip()) + if s == 'status' and not overschrijven: + leeg = False # status heeft altijd een waarde: enkel wijzigen bij overschrijven + if leeg or overschrijven: + r['waarden'][kolom] = w + oud = lok_naam.get(huidig, huidig) if s == 'lokaal' else huidig + nw = lok_naam.get(w, w) if s == 'lokaal' else w + r['wijzigingen'].append(f"{KOPPEN[s]}: {_toon(oud) or '–'} → {_toon(nw)}") + else: + oud = lok_naam.get(huidig, huidig) if s == 'lokaal' else huidig + overgeslagen.append(f"{KOPPEN[s]} ({_toon(oud)})") + if overgeslagen: + r['meldingen'].append("Niet overschreven: " + ', '.join(overgeslagen) + '.') + if r['waarden']: + r['actie'] = 'bijwerken' + tellers['bijwerken'] += 1 + else: + r['actie'] = 'ongewijzigd' + tellers['ongewijzigd'] += 1 + uit.append(r) + + return {'rijen': uit, 'tellers': tellers, 'modus': 'overschrijven' if overschrijven else 'aanvullen'} + + +# --------------------------------------------------------------------------- +# Uitvoeren +# --------------------------------------------------------------------------- +def voer_uit(rijen, modus, gebruiker=None): + """Maakt het plan opnieuw en voert 'nieuw' en 'bijwerken' uit in één transactie. + Geeft (plan, aantal_nieuw, aantal_bijgewerkt). Bij een databasefout wordt niets bewaard.""" + plan = maak_plan(rijen, modus) + conn = get_db_connection() + cur = conn.cursor() + nieuw = bijgewerkt = 0 + try: + conn.start_transaction() + for r in plan['rijen']: + w = r['waarden'] + if r['actie'] == 'nieuw': + kolommen = list(w.keys()) + cur.execute(f"INSERT INTO Toestellen ({', '.join(kolommen)}) " + f"VALUES ({', '.join(['%s'] * len(kolommen))})", tuple(w[k] for k in kolommen)) + nieuw += 1 + elif r['actie'] == 'bijwerken': + kolommen = list(w.keys()) + cur.execute(f"UPDATE Toestellen SET {', '.join(k + ' = %s' for k in kolommen)} WHERE Toestel_ID = %s", + tuple(w[k] for k in kolommen) + (r['toestel_id'],)) + bijgewerkt += 1 + conn.commit() + except Exception: + conn.rollback() + raise + finally: + cur.close() + conn.close() + return plan, nieuw, bijgewerkt diff --git a/services/tweestaps_service.py b/services/tweestaps_service.py new file mode 100644 index 0000000..e976ea6 --- /dev/null +++ b/services/tweestaps_service.py @@ -0,0 +1,515 @@ +""" +2FA-hulp: back-upcodes, tijdelijke uitzonderingen en overzicht van wie 2FA nog niet heeft ingesteld. + +Vereist (eenmalig, Google Admin-console): + 1. Beveiliging › API-beheer › Domeinbrede delegatie: aan het service-account toevoegen + https://www.googleapis.com/auth/admin.directory.user.security (back-upcodes) + https://www.googleapis.com/auth/admin.directory.group.member (uitzonderingsgroep) + 2. Een groep aanmaken, bv. 2fa-uitzondering@school.be, en bij + Beveiliging › Authenticatie › Verificatie in 2 stappen voor DIE GROEP + 'Afdwingen' op UIT zetten (groepsinstellingen gaan boven de OU-instelling). + 3. Het adres van die groep invullen in PIVOT › 🔌 Koppelingen van deze school › 🛡️ 2FA-hulp › Uitzonderingsgroep +""" +import sys +import threading +import time +from datetime import datetime, timedelta + +from googleapiclient.discovery import build +from googleapiclient.errors import HttpError +from config import Config +from database import execute_query +from tenancy import google_credentials, school_singleton, alle_scholen, in_school + +SECURITY_SCOPE = 'https://www.googleapis.com/auth/admin.directory.user.security' +GROUP_MEMBER_SCOPE = 'https://www.googleapis.com/auth/admin.directory.group.member' +RESET_INTERVAL = 60 # wachtende 2FA-reset elke minuut opnieuw proberen +CHECK_INTERVAL = 5 * 60 # elke 5 minuten verlopen uitzonderingen opruimen +LIJST_CACHE = 10 * 60 + + + +def _is_afgedwongen_fout(e): + """Google weigert turnOff zolang 2FA nog afgedwongen wordt (uitzonderingsgroep nog niet toegepast).""" + msg = str(e).lower() + return 'cannot be turned off' in msg or ('enforced' in msg and 'admin policy' in msg) + +def _is_netwerkfout(e): + """Tijdelijke verbindingsfout (SSL, time-out, Google 5xx): later opnieuw proberen.""" + import socket, ssl + if isinstance(e, (ssl.SSLError, socket.timeout, ConnectionError, TimeoutError, OSError)): + return True + status = getattr(getattr(e, 'resp', None), 'status', None) + try: + return int(status) >= 500 + except (TypeError, ValueError): + return False + + +class TweestapsError(Exception): + pass + + +class TweestapsService: + _scheduler = None # één achtergrondtaak voor alle scholen + + def __new__(cls): + # één instantie per school + def init(inst): + inst._clients = threading.local() # Google-clients (httplib2) zijn niet thread-safe: één per thread + inst._directory = None + inst._lock = threading.Lock() + inst._lijst_cache = None + return school_singleton(cls, init) + + # ---------------- clients ---------------- + def _build(self, scope): + creds = google_credentials([scope], subject=Config.GOOGLE_ADMIN_EMAIL) + return build('admin', 'directory_v1', credentials=creds, static_discovery=False, cache_discovery=False) + + def _client(self, naam, scope): + client = getattr(self._clients, naam, None) + if client is None: + client = self._build(scope) + setattr(self._clients, naam, client) + return client + + def _security_api(self): + return self._client('security', SECURITY_SCOPE) + + def _group_api(self): + return self._client('groups', GROUP_MEMBER_SCOPE) + + def _directory_api(self): + if self._directory is None: + from services.google_service import GoogleAdminService + self._directory = GoogleAdminService().service + return self._directory + + @staticmethod + def _friendly(e, scope=None): + msg = str(e) + status = getattr(getattr(e, 'resp', None), 'status', None) + if 'unauthorized_client' in msg or 'access_denied' in msg: + return (f"Google weigert de toegang. Voeg de scope {scope} toe aan de domeinbrede delegatie " + "van het service-account." if scope else "Google weigert de toegang (scope ontbreekt).") + if _is_afgedwongen_fout(e): + return ("Google dwingt 2FA nog af voor deze gebruiker. De uitzonderingsgroep is nog niet " + "toegepast (dat kan enkele minuten duren).") + if 'INVALID_OU_ID' in msg: + return ("Een organisatie-eenheid bestaat niet in Google. Controleer de OU's bij 🔌 Koppelingen van " + "deze school › 🛡️ 2FA-hulp.") + if status == 404: + return "Gebruiker of groep niet gevonden." + if status == 403: + return "Geen toestemming voor deze actie bij Google." + return msg + + ontbrekende_ous = [] + + def ou_melding(self): + if not self.ontbrekende_ous: + return None + return (f"Deze organisatie-eenheid bestaat niet in Google: {', '.join(self.ontbrekende_ous)}. " + "Pas ze aan bij 🔌 Koppelingen van deze school › 🛡️ 2FA-hulp › \"OU's voor 'nog geen 2FA'\" " + "(het volledige pad zoals in admin.google.com, bv. /Personeel/Leerkrachten; meerdere met komma's).") + + @property + def exception_group(self): + return (Config.TWEESTAPS_UITZONDERING_GROEP or '').strip() + + # ---------------- gebruiker opzoeken ---------------- + def get_user(self, email): + email = (email or '').strip().lower() + if '@' not in email: + raise TweestapsError("Geef een volledig e-mailadres op.") + try: + u = self._directory_api().users().get(userKey=email).execute() + except HttpError as e: + if getattr(e.resp, 'status', None) == 404: + raise TweestapsError(f"{email} bestaat niet in jullie Google Workspace.") + raise TweestapsError(self._friendly(e)) + return { + 'email': u['primaryEmail'].lower(), + 'naam': (u.get('name') or {}).get('fullName', ''), + 'ou': u.get('orgUnitPath', ''), + 'ingesteld': bool(u.get('isEnrolledIn2Sv')), + 'afgedwongen': bool(u.get('isEnforcedIn2Sv')), + 'geschorst': bool(u.get('suspended')), + 'laatste_login': (u.get('lastLoginTime') or '')[:16].replace('T', ' ').replace('1970-01-01 00:00', ''), + } + + def search_users(self, query): + try: + resp = self._directory_api().users().list( + customer='my_customer', query=query.strip(), maxResults=15, orderBy='email').execute() + except Exception as e: + sys.stderr.write(f"2FA zoeken: {e}\n") + return [] + return [{'email': u['primaryEmail'], 'naam': (u.get('name') or {}).get('fullName', ''), + 'ou': u.get('orgUnitPath', '')} for u in resp.get('users', [])] + + # ---------------- back-upcodes ---------------- + def list_codes(self, email): + try: + resp = self._security_api().verificationCodes().list(userKey=email).execute() + except Exception as e: + raise TweestapsError(self._friendly(e, SECURITY_SCOPE)) + return [i['verificationCode'] for i in resp.get('items', []) if i.get('verificationCode')] + + def generate_codes(self, email): + """Maakt een nieuwe set (de oude set wordt daardoor ongeldig) en geeft de codes terug.""" + try: + self._security_api().verificationCodes().generate(userKey=email).execute() + except Exception as e: + raise TweestapsError(self._friendly(e, SECURITY_SCOPE)) + return self.list_codes(email) + + def invalidate_codes(self, email): + try: + self._security_api().verificationCodes().invalidate(userKey=email).execute() + except Exception as e: + raise TweestapsError(self._friendly(e, SECURITY_SCOPE)) + + # ---------------- uitzonderingsgroep ---------------- + def _add_to_group(self, email): + if not self.exception_group: + raise TweestapsError("Er is nog geen uitzonderingsgroep ingesteld " + "(🔌 Koppelingen van deze school › 🛡️ 2FA-hulp › Uitzonderingsgroep).") + try: + self._group_api().members().insert( + groupKey=self.exception_group, body={'email': email, 'role': 'MEMBER'}).execute() + except HttpError as e: + if getattr(e.resp, 'status', None) == 409: # zit er al in → prima + return + raise TweestapsError(self._friendly(e, GROUP_MEMBER_SCOPE)) + except Exception as e: + raise TweestapsError(self._friendly(e, GROUP_MEMBER_SCOPE)) + + def _remove_from_group(self, email): + try: + self._group_api().members().delete(groupKey=self.exception_group, memberKey=email).execute() + except HttpError as e: + if getattr(e.resp, 'status', None) == 404: # zit er al niet meer in → prima + return + raise TweestapsError(self._friendly(e, GROUP_MEMBER_SCOPE)) + except Exception as e: + raise TweestapsError(self._friendly(e, GROUP_MEMBER_SCOPE)) + + # ---------------- database ---------------- + @staticmethod + def ensure_tables(): + execute_query(""" + CREATE TABLE IF NOT EXISTS tweestaps_uitzonderingen ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Email VARCHAR(255) NOT NULL, + Naam VARCHAR(255) NULL, + Reden VARCHAR(255) NULL, + Van DATETIME NOT NULL, + Tot DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Actief TINYINT(1) NOT NULL DEFAULT 1, + Beeindigd_op DATETIME NULL, + Beeindigd_door VARCHAR(100) NULL, + INDEX idx_actief (Actief, Tot), + INDEX idx_email (Email) + )""", commit=True) + execute_query(""" + CREATE TABLE IF NOT EXISTS tweestaps_log ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Tijdstip DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Actie VARCHAR(40) NOT NULL, + Email VARCHAR(255) NOT NULL, + Details VARCHAR(255) NULL, + INDEX idx_tijdstip (Tijdstip) + )""", commit=True) + execute_query(""" + CREATE TABLE IF NOT EXISTS tweestaps_resets ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Email VARCHAR(255) NOT NULL, + Gevraagd_op DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Reden VARCHAR(255) NULL, + Tot DATETIME NOT NULL, + Status VARCHAR(10) NOT NULL DEFAULT 'bezig', + Pogingen INT NOT NULL DEFAULT 0, + Laatste_fout VARCHAR(255) NULL, + Klaar_op DATETIME NULL, + INDEX idx_status (Status), + INDEX idx_email (Email) + )""", commit=True) + + @staticmethod + def log(door, actie, email, details=None): + try: + execute_query("INSERT INTO tweestaps_log (Tijdstip, Door, Actie, Email, Details) VALUES (NOW(), %s, %s, %s, %s)", + (door, actie, email, details), commit=True) + except Exception as e: + sys.stderr.write(f"2FA log: {e}\n") + + @staticmethod + def recent_log(pagina=1, per_pagina=10): + """Eén pagina van het logboek (nieuwste eerst). Geeft (rijen, totaal aantal).""" + totaal = execute_query("SELECT COUNT(*) AS n FROM tweestaps_log")[0]['n'] + pagina = max(1, int(pagina or 1)) + rijen = execute_query("SELECT Tijdstip, Door, Actie, Email, Details FROM tweestaps_log " + "ORDER BY Tijdstip DESC, ID DESC LIMIT %s OFFSET %s", + (int(per_pagina), (pagina - 1) * int(per_pagina))) + return rijen, totaal + + @staticmethod + def active_exceptions(): + return execute_query("SELECT ID, Email, Naam, Reden, Van, Tot, Door FROM tweestaps_uitzonderingen " + "WHERE Actief = 1 ORDER BY Tot") + + @staticmethod + def active_for(email): + rows = execute_query("SELECT ID, Tot FROM tweestaps_uitzonderingen WHERE Actief = 1 AND Email = %s " + "ORDER BY Tot DESC LIMIT 1", (email,)) + return rows[0] if rows else None + + # ---------------- uitzonderingen ---------------- + @staticmethod + def einde_vandaag(nu=None): + """Een uitzondering (of 2FA-reset) loopt altijd tot 23:59 dezelfde dag.""" + return (nu or datetime.now()).replace(hour=23, minute=59, second=0, microsecond=0) + + def grant_exception(self, email, eindtijd, door, reden=None): + user = self.get_user(email) + if user['geschorst']: + raise TweestapsError(f"{user['email']} is geschorst.") + bestaand = self.active_for(user['email']) + self._add_to_group(user['email']) + if bestaand: + execute_query("UPDATE tweestaps_uitzonderingen SET Tot = %s WHERE ID = %s", + (eindtijd, bestaand['ID']), commit=True) + else: + execute_query( + "INSERT INTO tweestaps_uitzonderingen (Email, Naam, Reden, Van, Tot, Door, Actief) " + "VALUES (%s, %s, %s, NOW(), %s, %s, 1)", + (user['email'], user['naam'], (reden or '')[:255], eindtijd, door), commit=True) + self.log(door, 'uitzondering', user['email'], f"tot {eindtijd:%d-%m %H:%M}" + (f" – {reden}" if reden else '')) + self._lijst_cache = None + return user + + def reset_2fa(self, email, eindtijd, door, reden=None): + """ + 2FA resetten (nieuwe telefoon, toestel kwijt): 2FA uitzetten voor de gebruiker zodat hij het opnieuw + kan instellen. Wordt 2FA afgedwongen, dan krijgt hij eerst een tijdelijke uitzondering; anders zou hij + na het uitzetten niet meer kunnen inloggen om 2FA opnieuw in te stellen. + Google: users.twoStepVerification.turnOff (scope admin.directory.user.security). + """ + user = self.get_user(email) + if user['geschorst']: + raise TweestapsError(f"{user['email']} is geschorst.") + if not user['ingesteld']: + raise TweestapsError(f"{user['email']} heeft nog geen 2FA ingesteld; er valt niets te resetten. " + "Moet hij 2FA nog instellen maar kan hij niet inloggen, geef dan een tijdelijke uitzondering.") + uitzondering = False + if user['afgedwongen']: + if not self.exception_group: + raise TweestapsError("2FA wordt afgedwongen voor deze gebruiker. Stel eerst een uitzonderingsgroep in " + "(🔌 Koppelingen van deze school › 🛡️ 2FA-hulp), anders kan hij na de reset niet " + "meer inloggen om 2FA opnieuw in te stellen.") + self.grant_exception(user['email'], eindtijd, door, reden or '2FA-reset') + uitzondering = True + try: + self._turn_off(user['email']) + except Exception as e: + if uitzondering and _is_afgedwongen_fout(e): + # Google past de uitzonderingsgroep pas na enkele minuten toe → op de achtergrond opnieuw proberen. + self._plan_reset(user['email'], eindtijd, door, reden) + user['uitzondering'] = True + user['wacht'] = True + return user + raise TweestapsError(f"2FA uitzetten mislukt: {self._friendly(e, SECURITY_SCOPE)}" + + (" De tijdelijke uitzondering blijft lopen tot ze afloopt." if uitzondering else "")) + self._lijst_cache = None + self.log(door, '2FA gereset', user['email'], reden or None) + user['uitzondering'] = uitzondering + user['wacht'] = False + return user + + def _turn_off(self, email): + self._security_api().twoStepVerification().turnOff(userKey=email).execute() + + # ---------------- 2FA-reset die op Google wacht ---------------- + def _plan_reset(self, email, tot, door, reden): + bestaand = self.reset_bezig(email) + if bestaand: + execute_query("UPDATE tweestaps_resets SET Tot = %s WHERE ID = %s", (tot, bestaand['ID']), commit=True) + rid = bestaand['ID'] + else: + execute_query( + "INSERT INTO tweestaps_resets (Email, Gevraagd_op, Door, Reden, Tot, Status, Pogingen) " + "VALUES (%s, NOW(), %s, %s, %s, 'bezig', 1)", (email, door, (reden or '')[:255], tot), commit=True) + rid = execute_query("SELECT ID FROM tweestaps_resets WHERE Email = %s AND Status = 'bezig' " + "ORDER BY ID DESC LIMIT 1", (email,))[0]['ID'] + self.log(door, '2FA reset wacht', email, 'Google past de uitzondering nog toe; PIVOT probeert opnieuw') + self._volg_reset_op(rid) + + @staticmethod + def reset_bezig(email=None): + if email: + rows = execute_query("SELECT * FROM tweestaps_resets WHERE Status = 'bezig' AND Email = %s " + "ORDER BY ID DESC LIMIT 1", ((email or '').strip().lower(),)) + return rows[0] if rows else None + return execute_query("SELECT * FROM tweestaps_resets WHERE Status = 'bezig' ORDER BY Gevraagd_op") + + def probeer_reset(self, rij): + """Eén poging voor een wachtende reset. Geeft 'klaar', 'mislukt' of 'bezig' terug.""" + email = rij['Email'] + try: + self._turn_off(email) + except Exception as e: + nog_tijd = rij['Tot'] > datetime.now() + tijdelijk = _is_afgedwongen_fout(e) or _is_netwerkfout(e) + if _is_netwerkfout(e): + self._clients.security = None # verbinding kapot → volgende poging met een nieuwe client + if tijdelijk and nog_tijd: + execute_query("UPDATE tweestaps_resets SET Pogingen = Pogingen + 1, Laatste_fout = %s WHERE ID = %s", + (self._friendly(e)[:255], rij['ID']), commit=True) + return 'bezig' + fout = (self._friendly(e, SECURITY_SCOPE) if nog_tijd else + "Google heeft de uitzondering niet toegepast voor ze afliep. Controleer of 'Afdwingen' op 'Uit' " + "staat voor de uitzonderingsgroep in admin.google.com en probeer opnieuw.") + execute_query("UPDATE tweestaps_resets SET Status = 'mislukt', Pogingen = Pogingen + 1, Laatste_fout = %s, " + "Klaar_op = NOW() WHERE ID = %s", (fout[:255], rij['ID']), commit=True) + self.log('automatisch', '2FA reset mislukt', email, fout[:255]) + return 'mislukt' + execute_query("UPDATE tweestaps_resets SET Status = 'klaar', Pogingen = Pogingen + 1, Laatste_fout = NULL, " + "Klaar_op = NOW() WHERE ID = %s", (rij['ID'],), commit=True) + self.log(rij['Door'] or 'automatisch', '2FA gereset', email, + (rij['Reden'] or '') + f" (na {rij['Pogingen'] + 1} pogingen)") + self._lijst_cache = None + return 'klaar' + + def verwerk_resets(self): + """Alle wachtende resets van deze school één keer proberen (vangnet van de 5-minutenplanner).""" + n = 0 + for rij in self.reset_bezig(): + if self.probeer_reset(rij) == 'klaar': + n += 1 + return n + + def _volg_reset_op(self, rid): + from tenancy import met_school + svc = self + + def loop(): + while True: + time.sleep(RESET_INTERVAL) + try: + rows = execute_query("SELECT * FROM tweestaps_resets WHERE ID = %s", (rid,)) + if not rows or rows[0]['Status'] != 'bezig': + return + if svc.probeer_reset(rows[0]) != 'bezig': + return + except Exception as e: + sys.stderr.write(f"2FA-reset {rid}: {e}\n") + threading.Thread(target=met_school(loop), daemon=True).start() + + def end_exception(self, uitz_id, door): + rows = execute_query("SELECT Email FROM tweestaps_uitzonderingen WHERE ID = %s AND Actief = 1", (uitz_id,)) + if not rows: + raise TweestapsError("Deze uitzondering is al beëindigd.") + email = rows[0]['Email'] + self._remove_from_group(email) + execute_query("UPDATE tweestaps_uitzonderingen SET Actief = 0, Beeindigd_op = NOW(), Beeindigd_door = %s " + "WHERE ID = %s", (door, uitz_id), commit=True) + self.log(door, 'uitzondering beëindigd', email) + self._lijst_cache = None + return email + + def expire_due(self): + """Haalt iedereen met een verlopen uitzondering terug uit de groep. Geeft het aantal terug.""" + if not self._lock.acquire(blocking=False): + return 0 + try: + rows = execute_query("SELECT ID, Email FROM tweestaps_uitzonderingen WHERE Actief = 1 AND Tot <= NOW()") + klaar = 0 + for r in rows: + try: + self._remove_from_group(r['Email']) + execute_query("UPDATE tweestaps_uitzonderingen SET Actief = 0, Beeindigd_op = NOW(), " + "Beeindigd_door = 'automatisch' WHERE ID = %s", (r['ID'],), commit=True) + self.log('automatisch', 'uitzondering verlopen', r['Email']) + klaar += 1 + except Exception as e: + # blijft actief → volgende ronde opnieuw proberen + sys.stderr.write(f"2FA: kon {r['Email']} niet uit de groep halen: {e}\n") + if klaar: + self._lijst_cache = None + return klaar + finally: + self._lock.release() + + @classmethod + def start_scheduler(cls): + """Ruimt elke 5 minuten verlopen uitzonderingen op, voor elke school met een Google-sleutel.""" + if TweestapsService._scheduler: + return + + def loop(): + time.sleep(20) + while True: + for school in alle_scholen(): + if not school.google_sleutel: + continue + try: + with in_school(school): + svc = cls() + svc.ensure_tables() + svc.verwerk_resets() + n = svc.expire_due() + if n: + print(f"[{school.code}] 2FA: {n} verlopen uitzondering(en) opgeruimd.", flush=True) + except Exception as e: + sys.stderr.write(f"[{school.code}] 2FA scheduler: {e}\n") + time.sleep(CHECK_INTERVAL) + + TweestapsService._scheduler = threading.Thread(target=loop, daemon=True) + TweestapsService._scheduler.start() + + # ---------------- wie heeft 2FA nog niet ingesteld ---------------- + def niet_ingesteld(self, force=False): + if not force and self._lijst_cache and time.time() - self._lijst_cache[0] < LIJST_CACHE: + return self._lijst_cache[1] + result = [] + ous = [o.strip() for o in Config.TWEESTAPS_OUS.split(',') if o.strip()] + self.ontbrekende_ous = [] + for ou in ous: + token = None + while True: + try: + resp = self._directory_api().users().list( + customer='my_customer', query=f"orgUnitPath='{ou}' isSuspended=false", + maxResults=500, pageToken=token, projection='basic', + fields='nextPageToken,users(primaryEmail,name/fullName,orgUnitPath,isEnrolledIn2Sv,' + 'isEnforcedIn2Sv,archived,lastLoginTime,creationTime)').execute() + except Exception as e: + if 'INVALID_OU_ID' in str(e): + self.ontbrekende_ous.append(ou) # deze OU bestaat niet in Google: overslaan + break + raise + for u in resp.get('users', []): + if u.get('archived') or u.get('isEnrolledIn2Sv'): + continue + result.append({ + 'email': u['primaryEmail'].lower(), + 'naam': (u.get('name') or {}).get('fullName', ''), + 'ou': u.get('orgUnitPath', ''), + 'afgedwongen': bool(u.get('isEnforcedIn2Sv')), + 'laatste_login': (u.get('lastLoginTime') or '')[:10].replace('1970-01-01', ''), + 'aangemaakt': (u.get('creationTime') or '')[:10], + }) + token = resp.get('nextPageToken') + if not token: + break + if ous and len(self.ontbrekende_ous) == len(ous): + raise TweestapsError(self.ou_melding()) + uniek = {r['email']: r for r in result} + lijst = sorted(uniek.values(), key=lambda r: (r['ou'], r['naam'])) + self._lijst_cache = (time.time(), lijst) + return lijst diff --git a/services/verzendlijsten_service.py b/services/verzendlijsten_service.py new file mode 100644 index 0000000..670fc31 --- /dev/null +++ b/services/verzendlijsten_service.py @@ -0,0 +1,173 @@ +""" +Verzendlijsten (Google Groepen) van de huidige school beheren via de Admin SDK. + +Directory API (scope admin.directory.group) → groepen en leden: bekijken, aanmaken, aanpassen +Groups Settings API (scope apps.groups.settings) → "wie mag e-mails sturen naar de lijst" (optioneel: ontbreekt de + scope, dan werkt de rest gewoon en wordt dit veld verborgen) +Beide scopes moeten in Google Admin › Beveiliging › API-beheer › Domeinbrede delegatie bij het serviceaccount staan. +""" +import re +import threading + +from googleapiclient.discovery import build + +from config import Config +from tenancy import google_credentials, school_singleton + +GROUP_SCOPE = 'https://www.googleapis.com/auth/admin.directory.group' +SETTINGS_SCOPE = 'https://www.googleapis.com/auth/apps.groups.settings' + +ROLLEN = [('MEMBER', 'Lid'), ('MANAGER', 'Beheerder'), ('OWNER', 'Eigenaar')] +WIE_MAILT = [ + ('ANYONE_CAN_POST', 'Iedereen, ook van buiten de school'), + ('ALL_IN_DOMAIN_CAN_POST', 'Iedereen van de school'), + ('ALL_MEMBERS_CAN_POST', 'Enkel leden van de lijst'), + ('ALL_MANAGERS_CAN_POST', 'Enkel beheerders en eigenaars'), +] +EMAIL_RE = re.compile(r'^[^@\s]+@[^@\s]+\.[^@\s]+$') + + +class VerzendlijstFout(Exception): + pass + + +def _uitleg(e): + """Google-fout → begrijpelijke melding.""" + t = str(e) + laag = t.lower() + if 'unauthorized_client' in laag or 'insufficient authentication scopes' in laag or 'access_denied' in laag: + return ("Google weigert de toegang tot de groepen. Voeg in Google Admin › Beveiliging › API-beheer › " + f"Domeinbrede delegatie bij het serviceaccount de scope {GROUP_SCOPE} toe " + f"(en voor 'wie mag mailen' ook {SETTINGS_SCOPE}). Een wijziging kan enkele minuten duren.") + if 'entity already exists' in laag or 'duplicate' in laag or 'member already exists' in laag: + return "Dat adres bestaat al (als groep, gebruiker of lid)." + if 'resource not found' in laag or 'notfound' in laag.replace(' ', ''): + return "Niet gevonden in Google (bestaat het adres of de groep wel?)." + if 'domain' in laag and ('not found' in laag or 'invalid' in laag): + return "Dat domein hoort niet bij jullie Google Workspace." + m = re.search(r'"message":\s*"([^"]+)"', t) or re.search(r'returned "([^"]+)"', t) + return f"Google: {m.group(1) if m else t[:300]}" + + +def adressen(tekst): + """Komma-, puntkomma-, spatie- of regelgescheiden lijst → [geldige adressen], [ongeldige stukken].""" + goed, fout = [], [] + for d in re.split(r'[\s,;]+', str(tekst or '')): + d = d.strip().strip('<>').lower() + if not d: + continue + (goed if EMAIL_RE.match(d) else fout).append(d) + return list(dict.fromkeys(goed)), fout + + +class VerzendlijstenService: + def __new__(cls): + def init(inst): + inst._clients = threading.local() # Google-clients zijn niet thread-safe: één per thread + return school_singleton(cls, init) + + def _api(self, naam, scope, api, versie): + client = getattr(self._clients, naam, None) + if client is None: + creds = google_credentials([scope], subject=Config.GOOGLE_ADMIN_EMAIL) + client = build(api, versie, credentials=creds, static_discovery=False, cache_discovery=False) + setattr(self._clients, naam, client) + return client + + def _dir(self): + return self._api('directory', GROUP_SCOPE, 'admin', 'directory_v1') + + def _settings(self): + return self._api('settings', SETTINGS_SCOPE, 'groupssettings', 'v1') + + def _uitvoeren(self, verzoek): + try: + return verzoek.execute() + except Exception as e: + raise VerzendlijstFout(_uitleg(e)) + + # ---------------- groepen ---------------- + def alle(self): + uit, token = [], None + while True: + res = self._uitvoeren(self._dir().groups().list(customer='my_customer', maxResults=200, pageToken=token, + orderBy='email')) + for g in res.get('groups', []): + uit.append({'email': g.get('email', ''), 'naam': g.get('name', ''), + 'beschrijving': g.get('description', ''), + 'leden': int(g.get('directMembersCount') or 0), 'aliassen': g.get('aliases', [])}) + token = res.get('nextPageToken') + if not token: + return uit + + def groep(self, email): + g = self._uitvoeren(self._dir().groups().get(groupKey=email)) + return {'email': g.get('email', ''), 'naam': g.get('name', ''), 'beschrijving': g.get('description', ''), + 'leden': int(g.get('directMembersCount') or 0), 'aliassen': g.get('aliases', [])} + + def aanmaken(self, email, naam, beschrijving=''): + email = (email or '').strip().lower() + if not EMAIL_RE.match(email): + raise VerzendlijstFout("Geef een geldig e-mailadres voor de verzendlijst.") + if not (naam or '').strip(): + raise VerzendlijstFout("Geef de verzendlijst een naam.") + self._uitvoeren(self._dir().groups().insert(body={'email': email, 'name': naam.strip(), + 'description': (beschrijving or '').strip()})) + return email + + def bijwerken(self, email, naam, beschrijving): + if not (naam or '').strip(): + raise VerzendlijstFout("De naam mag niet leeg zijn.") + self._uitvoeren(self._dir().groups().patch(groupKey=email, body={ + 'name': naam.strip(), 'description': (beschrijving or '').strip()})) + + # ---------------- wie mag mailen (Groups Settings API) ---------------- + def wie_mailt(self, email): + """Huidige instelling, of None als de Groups Settings-scope (nog) ontbreekt.""" + try: + s = self._settings().groups().get(groupUniqueId=email, alt='json').execute() + return s.get('whoCanPostMessage') + except Exception: + return None + + def zet_wie_mailt(self, email, waarde): + if waarde not in dict(WIE_MAILT): + raise VerzendlijstFout("Onbekende keuze voor 'wie mag mailen'.") + body = {'whoCanPostMessage': waarde} + if waarde == 'ANYONE_CAN_POST': + body['allowExternalMembers'] = 'false' # extern mailen mag, extern lid worden niet automatisch + self._uitvoeren(self._settings().groups().patch(groupUniqueId=email, body=body)) + + # ---------------- leden ---------------- + def leden(self, email): + uit, token = [], None + while True: + res = self._uitvoeren(self._dir().members().list(groupKey=email, maxResults=200, pageToken=token)) + for m in res.get('members', []): + uit.append({'email': m.get('email', ''), 'rol': m.get('role', 'MEMBER'), + 'soort': m.get('type', 'USER'), 'status': m.get('status', '')}) + token = res.get('nextPageToken') + if not token: + volgorde = {'OWNER': 0, 'MANAGER': 1, 'MEMBER': 2} + return sorted(uit, key=lambda m: (volgorde.get(m['rol'], 3), m['email'])) + + def leden_toevoegen(self, email, lijst, rol='MEMBER'): + """Geeft (toegevoegd, [(adres, fout)]).""" + if rol not in dict(ROLLEN): + rol = 'MEMBER' + gelukt, fouten = 0, [] + for adres in lijst: + try: + self._uitvoeren(self._dir().members().insert(groupKey=email, body={'email': adres, 'role': rol})) + gelukt += 1 + except VerzendlijstFout as e: + fouten.append((adres, str(e))) + return gelukt, fouten + + def lid_rol(self, email, lid, rol): + if rol not in dict(ROLLEN): + raise VerzendlijstFout("Onbekende rol.") + self._uitvoeren(self._dir().members().patch(groupKey=email, memberKey=lid, body={'role': rol})) + + def lid_verwijderen(self, email, lid): + self._uitvoeren(self._dir().members().delete(groupKey=email, memberKey=lid)) diff --git a/sql/centraal.sql b/sql/centraal.sql new file mode 100644 index 0000000..a2efb6c --- /dev/null +++ b/sql/centraal.sql @@ -0,0 +1,315 @@ +-- ===================================================================== +-- PIVOT 1.1.0 – CENTRALE database (structuur schooljaar 2026-27) +-- +-- Bevat wat voor ALLE scholen geldt: +-- Scholen de scholen (+ hun koppelingen, versleuteld) +-- Gebruikers één account per persoon, voor alle scholen +-- Veiligheidsgroepen 1 = Administrator, 2 = Gebruiker +-- Onderdelen de onderdelen van PIVOT waarop je rechten kan geven +-- Gebruiker_rechten wie mag welk onderdeel, in welke school +-- Logs bezochte pagina's en acties +-- Bugs, Status gemelde bugs +-- +-- De naam van deze database staat in config.ini › [database] › centrale_database. +-- Dit bestand is gegenereerd uit tenancy.py en rechten.py; PIVOT maakt +-- dezelfde tabellen ook zelf aan bij het opstarten (python beheer.py init). +-- ===================================================================== + +-- USE `pivot`; + +-- Veiligheidscontrole: stop als deze database nog OUDE tabellen met dezelfde naam bevat +-- (bv. 'scholen' van PIVOT 1.1.0). MySQL op Windows maakt geen onderscheid tussen +-- hoofdletters en kleine letters, dus 'Scholen' en 'scholen' zijn dezelfde tabel. +DROP PROCEDURE IF EXISTS pivot_controle_oude_tabellen; +DELIMITER // +CREATE PROCEDURE pivot_controle_oude_tabellen() +BEGIN + DECLARE oud TEXT; + SELECT GROUP_CONCAT(n.tabel SEPARATOR ', ') INTO oud + FROM (SELECT 'scholen' AS tabel, 'school_id' AS kolom UNION ALL + SELECT 'gebruikers', 'gebruiker_id' UNION ALL SELECT 'logs', 'log_id' UNION ALL + SELECT 'status', 'bugstatus_id' UNION ALL SELECT 'bugs', 'bug_id') n + WHERE EXISTS (SELECT 1 FROM information_schema.TABLES t + WHERE t.TABLE_SCHEMA = DATABASE() AND LOWER(t.TABLE_NAME) = n.tabel) + AND NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS c + WHERE c.TABLE_SCHEMA = DATABASE() AND LOWER(c.TABLE_NAME) = n.tabel + AND LOWER(c.COLUMN_NAME) = n.kolom); + IF oud IS NOT NULL THEN + SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = + 'STOP: deze database bevat nog oude PIVOT-tabellen (scholen/gebruikers/logs/status/bugs). Kies een nieuwe, lege database.'; + END IF; +END // +DELIMITER ; +CALL pivot_controle_oude_tabellen(); +DROP PROCEDURE pivot_controle_oude_tabellen; + +CREATE TABLE IF NOT EXISTS Scholen ( + School_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Code VARCHAR(32) NOT NULL, + School_naam VARCHAR(255) NOT NULL, + Smartschool_platform_url VARCHAR(255) NULL, + Adres VARCHAR(255) NULL, + Instellingsnummer VARCHAR(20) NULL, + Informat_instellingsnummer VARCHAR(500) NULL, + Onderwijsniveau VARCHAR(20) NULL, + Domein VARCHAR(500) NOT NULL DEFAULT '', + Hostnamen VARCHAR(500) NOT NULL DEFAULT '', + Actief TINYINT NOT NULL DEFAULT 1, + Db_naam VARCHAR(128) NOT NULL, + Instellingen MEDIUMTEXT NULL, + Google_sleutel MEDIUMTEXT NULL, + Leerlingenaantal INT NULL, + Leerlingenaantal_sync DATETIME NULL, + Leerlingenaantal_detail TEXT NULL, + Bijgewerkt DATETIME(6) NULL, + Bijgewerkt_door VARCHAR(255) NULL, + UNIQUE KEY uq_scholen_code (Code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Veiligheidsgroepen ( + Veiligheidsgroep TINYINT NOT NULL PRIMARY KEY, + Naam VARCHAR(50) NOT NULL, + Omschrijving VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Gebruikers ( + Gebruiker_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Gebruikersnaam VARCHAR(100) NOT NULL, + Veiligheidsgroep TINYINT NOT NULL DEFAULT 2, + Passwoordhash VARCHAR(255) NULL, + Emailadres VARCHAR(255) NULL, + Last_login DATETIME NULL, + IP_laatste_login VARCHAR(45) NULL, + Laatste_school VARCHAR(32) NULL, + Actief TINYINT NOT NULL DEFAULT 1, + UNIQUE KEY uq_gebruikersnaam (Gebruikersnaam), + UNIQUE KEY uq_emailadres (Emailadres), + CONSTRAINT fk_gebruikers_groep FOREIGN KEY (Veiligheidsgroep) + REFERENCES Veiligheidsgroepen (Veiligheidsgroep) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Onderdelen ( + Onderdeel_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Code VARCHAR(50) NOT NULL, + Naam VARCHAR(255) NOT NULL, + Categorie VARCHAR(50) NOT NULL, + Volgorde INT NOT NULL DEFAULT 0, + UNIQUE KEY uq_onderdeel_code (Code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Gebruiker_rechten ( + Gebruiker_ID INT NOT NULL, + School_ID INT NOT NULL, + Onderdeel_ID INT NOT NULL, + Toegekend_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Toegekend_door VARCHAR(100) NULL, + PRIMARY KEY (Gebruiker_ID, School_ID, Onderdeel_ID), + KEY idx_rechten_school (School_ID), + KEY idx_rechten_onderdeel (Onderdeel_ID), + CONSTRAINT fk_rechten_gebruiker FOREIGN KEY (Gebruiker_ID) + REFERENCES Gebruikers (Gebruiker_ID) ON DELETE CASCADE, + CONSTRAINT fk_rechten_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE, + CONSTRAINT fk_rechten_onderdeel FOREIGN KEY (Onderdeel_ID) + REFERENCES Onderdelen (Onderdeel_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Handleidingen ( + Handleiding_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Slug VARCHAR(100) NOT NULL, + Titel VARCHAR(200) NOT NULL, + Categorie VARCHAR(100) NULL, + Samenvatting VARCHAR(300) NULL, + Inhoud MEDIUMTEXT NULL, + Zichtbaar VARCHAR(10) NOT NULL DEFAULT 'iedereen', + Volgorde INT NOT NULL DEFAULT 0, + Gewijzigd_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Gewijzigd_door VARCHAR(100) NULL, + UNIQUE KEY uq_handleiding_slug (Slug) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Handleidingen_versies ( + Versie_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Handleiding_ID INT NOT NULL, + Titel VARCHAR(200) NOT NULL, + Inhoud MEDIUMTEXT NULL, + Opgeslagen_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Door VARCHAR(100) NULL, + KEY idx_versie_handleiding (Handleiding_ID, Opgeslagen_op), + CONSTRAINT fk_versie_handleiding FOREIGN KEY (Handleiding_ID) + REFERENCES Handleidingen (Handleiding_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Leerlingenaantal_tellingen ( + Telling_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_ID INT NOT NULL, + Peildatum DATE NOT NULL, + Schooljaar VARCHAR(10) NOT NULL, + Aantal INT NOT NULL, + Detail TEXT NULL, + Opgevraagd_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Door VARCHAR(100) NULL, + UNIQUE KEY uq_telling (School_ID, Peildatum), + KEY idx_telling_datum (Peildatum), + CONSTRAINT fk_telling_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Personeelsaantal_tellingen ( + Telling_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_ID INT NOT NULL, + Peildatum DATE NOT NULL, + Schooljaar VARCHAR(10) NOT NULL, + Aantal INT NOT NULL, + Detail TEXT NULL, + Opgevraagd_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Door VARCHAR(100) NULL, + UNIQUE KEY uq_ptelling (School_ID, Peildatum), + KEY idx_ptelling_datum (Peildatum), + CONSTRAINT fk_ptelling_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Personeelsaantal_huidig ( + School_ID INT NOT NULL PRIMARY KEY, + Aantal INT NOT NULL, + Detail TEXT NULL, + Gesynchroniseerd DATETIME NOT NULL, + CONSTRAINT fk_phuidig_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS PIVOT_instellingen ( + Sleutel VARCHAR(50) NOT NULL PRIMARY KEY, + Waarde VARCHAR(255) NULL, + Bijgewerkt DATETIME NULL, + Door VARCHAR(100) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS IP_blokkades ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Reeks VARCHAR(64) NOT NULL, + Soort VARCHAR(10) NOT NULL DEFAULT 'blokkeren', + Opmerking VARCHAR(255) NULL, + Scholen VARCHAR(1000) NULL, + Aangemaakt DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Gebruiker_ID INT NULL, + Aantal_geweigerd INT NOT NULL DEFAULT 0, + Laatst_geweigerd DATETIME NULL, + UNIQUE KEY uq_ip_reeks (Reeks, Soort) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS GoPro_verzameltabel ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_code VARCHAR(32) NOT NULL, + School_naam VARCHAR(255) NULL, + Person_ID VARCHAR(64) NOT NULL, + Voornaam VARCHAR(100) NULL, + Achternaam VARCHAR(100) NULL, + Email VARCHAR(255) NULL, + UPN VARCHAR(255) NULL, + Instellingsnummer VARCHAR(20) NULL, + Functie VARCHAR(100) NULL, + Rol VARCHAR(100) NULL, + Startdatum DATE NULL, + Einddatum DATE NULL, + Telefoon VARCHAR(50) NULL, + Toegevoegd DATETIME NOT NULL, + Door VARCHAR(255) NULL, + Soort VARCHAR(10) NOT NULL DEFAULT 'groen', -- groen = in de CSV, genegeerd = rode lijst, verzonden = al naar GO! Pro + Verzonden DATETIME NULL, + Verzonden_door VARCHAR(255) NULL, + UNIQUE KEY uq_gopro_verz (School_code, Person_ID), + KEY idx_gopro_verz_email (Email), + KEY idx_gopro_verz_soort (Soort, School_naam) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Koppeling_tests ( + School_ID INT NOT NULL, + Onderdeel VARCHAR(50) NOT NULL, + Ok TINYINT NULL, + Detail VARCHAR(500) NULL, + Getest_op DATETIME NOT NULL, + PRIMARY KEY (School_ID, Onderdeel), + CONSTRAINT fk_ktest_school FOREIGN KEY (School_ID) REFERENCES Scholen (School_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Logs ( + Log_ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Bezochte_url VARCHAR(2048) NOT NULL, + Gebruiker_ID INT NULL, + School_ID INT NULL, + Actie VARCHAR(255) NULL, + IP VARCHAR(45) NULL, + KEY idx_logs_tijd (Timestamp), + KEY idx_logs_gebruiker (Gebruiker_ID), + CONSTRAINT fk_logs_gebruiker FOREIGN KEY (Gebruiker_ID) + REFERENCES Gebruikers (Gebruiker_ID) ON DELETE SET NULL, + CONSTRAINT fk_logs_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Status ( + Bugstatus_ID TINYINT NOT NULL PRIMARY KEY, + Omschrijving VARCHAR(50) NOT NULL, + UNIQUE KEY uq_status_omschrijving (Omschrijving) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Bugs ( + Bug_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Timestamp DATETIME NOT NULL, + Omschrijving TEXT NOT NULL, + Foutcode VARCHAR(100) NULL, + Bugstatus_ID TINYINT NOT NULL DEFAULT 1, + Gebruiker_ID INT NULL, + Gebruikersnaam VARCHAR(255) NULL, + School_ID INT NULL, + Gemeld_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + KEY idx_bugs_status (Bugstatus_ID), + CONSTRAINT fk_bugs_status FOREIGN KEY (Bugstatus_ID) REFERENCES Status (Bugstatus_ID), + CONSTRAINT fk_bugs_gebruiker FOREIGN KEY (Gebruiker_ID) + REFERENCES Gebruikers (Gebruiker_ID) ON DELETE SET NULL, + CONSTRAINT fk_bugs_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT IGNORE INTO Veiligheidsgroepen (Veiligheidsgroep, Naam, Omschrijving) VALUES + (1, 'Administrator', 'Alle rechten in alle scholen; beheert gebruikers, rechten en scholen'), + (2, 'Gebruiker', 'Enkel de rechten die per school zijn aangevinkt'); + +INSERT IGNORE INTO Onderdelen (Code, Naam, Categorie, Volgorde) VALUES + ('eigendom_bekijken', 'Eigendom bekijken', 'Chromebooks', 10), + ('toestellen_uitdelen', 'Toestellen uitdelen en inleveren', 'Chromebooks', 20), + ('toestellen_beheren', 'Toestelleninventaris beheren', 'Chromebooks', 30), + ('toestel_blokkeren', 'Chromebook blokkeren / deblokkeren', 'Chromebooks', 40), + ('herstellingen', 'Herstellingen', 'Chromebooks', 50), + ('signpost', 'Signpost-toestellen', 'Chromebooks', 60), + ('leerlingen_bekijken', 'Leerlingen bekijken en bewerken', 'Leerlingen', 70), + ('leerlingen_synchroniseren', 'Leerlingen toevoegen en synchroniseren', 'Leerlingen', 80), + ('google_wachtwoord', 'Google-wachtwoord resetten', 'Google', 90), + ('google_accounts', 'Google-accounts aanmaken', 'Google', 100), + ('tweestaps_codes', '2FA: back-upcodes tonen / aanmaken', 'Google', 110), + ('tweestaps_uitzetten', '2FA tijdelijk uitzetten (uitzondering)', 'Google', 120), + ('google_licenties', 'Google-licenties', 'Google', 130), + ('gmail_delegatie', 'Mailbox-delegatie', 'Google', 140), + ('smartschool', 'Smartschool-wachtwoorden & info', 'Smartschool', 150), + ('smartschool_activiteit', 'Activiteit co-accounts & berichten', 'Smartschool', 160), + ('afwezigheden', 'Afwezigheden leerlingen (B-codes)', 'Smartschool', 170), + ('skore', 'Skore-synchronisatie (starten en plannen)', 'Smartschool', 180), + ('personeel_directie', 'Personeel: aanvragen goedkeuren (directie)', 'Personeel', 190), + ('personeel_secretariaat', 'Personeel: dagoverzicht (secretariaat)', 'Personeel', 200), + ('qr_codes', 'QR-code generator', 'Tools', 210), + ('co2', 'CO2-sensoren', 'IoT', 220), + ('leerlingenaantal', 'Leerlingenaantallen (alle scholen)', 'Scholengroep', 230), + ('bugs_bekijken', 'Bugs bekijken', 'Beheer', 240), + ('bugs_beheren', 'Status van bugs wijzigen', 'Beheer', 250), + ('nieuw_schooljaar', 'Nieuw schooljaar (accounts & toestellen)', 'Beheer', 260), + ('gebruikersbeheer', 'Gebruikers & rechten van deze school', 'PIVOT', 270), + ('koppelingen', 'Koppelingen van deze school', 'PIVOT', 280); + +INSERT IGNORE INTO Status (Bugstatus_ID, Omschrijving) VALUES + (1, 'Nieuw'), + (2, 'In behandeling'), + (3, 'Fixed'); diff --git a/sql/installatie_pivot_26-27.sql b/sql/installatie_pivot_26-27.sql new file mode 100644 index 0000000..5895cd5 --- /dev/null +++ b/sql/installatie_pivot_26-27.sql @@ -0,0 +1,806 @@ +-- ===================================================================== +-- PIVOT 1.1.0 – VOLLEDIGE INSTALLATIE (schooljaar 2026-27) +-- +-- Maakt in één keer aan: +-- 1. de centrale database `pivot` (Scholen, Gebruikers, rechten, Logs, Bugs) +-- 2. de school 'Scholengroep Antwerpen' (code: sg-antwerpen) +-- 3. de gebruiker Marijn (Administrator) wachtwoord: Binnenin10 +-- 4. de database van die school `pivot_sg_antwerpen` (Toestellen, Leerlingen, ...) +-- +-- Uitvoeren met: mysql -u -p < installatie_pivot_26-27.sql +-- (of in MySQL Workbench / phpMyAdmin: dit bestand importeren) +-- +-- ANDERE NAAM VOOR DE CENTRALE DATABASE (bv. pivot_test)? +-- Vervang `pivot` op BEIDE regels onder "1. Centrale database" +-- (CREATE DATABASE én USE) en zet dezelfde naam in config.ini +-- › [database] › centrale_database. +-- Het script stopt met een duidelijke melding als de gekozen database nog +-- oude tabellen bevat (bv. 'scholen' van de vorige versie). +-- ===================================================================== + +SET NAMES utf8mb4; + +-- --------------------------------------------------------------------- +-- 1. Centrale database +-- --------------------------------------------------------------------- +CREATE DATABASE IF NOT EXISTS `pivot` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +USE `pivot`; + +-- Veiligheidscontrole: stop als deze database nog OUDE tabellen met dezelfde naam bevat +-- (bv. 'scholen' van PIVOT 1.1.0). MySQL op Windows maakt geen onderscheid tussen +-- hoofdletters en kleine letters, dus 'Scholen' en 'scholen' zijn dezelfde tabel. +DROP PROCEDURE IF EXISTS pivot_controle_oude_tabellen; +DELIMITER // +CREATE PROCEDURE pivot_controle_oude_tabellen() +BEGIN + DECLARE oud TEXT; + SELECT GROUP_CONCAT(n.tabel SEPARATOR ', ') INTO oud + FROM (SELECT 'scholen' AS tabel, 'school_id' AS kolom UNION ALL + SELECT 'gebruikers', 'gebruiker_id' UNION ALL SELECT 'logs', 'log_id' UNION ALL + SELECT 'status', 'bugstatus_id' UNION ALL SELECT 'bugs', 'bug_id') n + WHERE EXISTS (SELECT 1 FROM information_schema.TABLES t + WHERE t.TABLE_SCHEMA = DATABASE() AND LOWER(t.TABLE_NAME) = n.tabel) + AND NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS c + WHERE c.TABLE_SCHEMA = DATABASE() AND LOWER(c.TABLE_NAME) = n.tabel + AND LOWER(c.COLUMN_NAME) = n.kolom); + IF oud IS NOT NULL THEN + SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = + 'STOP: deze database bevat nog oude PIVOT-tabellen (scholen/gebruikers/logs/status/bugs). Kies een nieuwe, lege database.'; + END IF; +END // +DELIMITER ; +CALL pivot_controle_oude_tabellen(); +DROP PROCEDURE pivot_controle_oude_tabellen; + +CREATE TABLE IF NOT EXISTS Scholen ( + School_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Code VARCHAR(32) NOT NULL, + School_naam VARCHAR(255) NOT NULL, + Smartschool_platform_url VARCHAR(255) NULL, + Adres VARCHAR(255) NULL, + Instellingsnummer VARCHAR(20) NULL, + Informat_instellingsnummer VARCHAR(500) NULL, + Onderwijsniveau VARCHAR(20) NULL, + Domein VARCHAR(500) NOT NULL DEFAULT '', + Hostnamen VARCHAR(500) NOT NULL DEFAULT '', + Actief TINYINT NOT NULL DEFAULT 1, + Db_naam VARCHAR(128) NOT NULL, + Instellingen MEDIUMTEXT NULL, + Google_sleutel MEDIUMTEXT NULL, + Leerlingenaantal INT NULL, + Leerlingenaantal_sync DATETIME NULL, + Leerlingenaantal_detail TEXT NULL, + Bijgewerkt DATETIME(6) NULL, + Bijgewerkt_door VARCHAR(255) NULL, + UNIQUE KEY uq_scholen_code (Code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Veiligheidsgroepen ( + Veiligheidsgroep TINYINT NOT NULL PRIMARY KEY, + Naam VARCHAR(50) NOT NULL, + Omschrijving VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Gebruikers ( + Gebruiker_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Gebruikersnaam VARCHAR(100) NOT NULL, + Veiligheidsgroep TINYINT NOT NULL DEFAULT 2, + Passwoordhash VARCHAR(255) NULL, + Emailadres VARCHAR(255) NULL, + Last_login DATETIME NULL, + IP_laatste_login VARCHAR(45) NULL, + Laatste_school VARCHAR(32) NULL, + Actief TINYINT NOT NULL DEFAULT 1, + UNIQUE KEY uq_gebruikersnaam (Gebruikersnaam), + UNIQUE KEY uq_emailadres (Emailadres), + CONSTRAINT fk_gebruikers_groep FOREIGN KEY (Veiligheidsgroep) + REFERENCES Veiligheidsgroepen (Veiligheidsgroep) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Onderdelen ( + Onderdeel_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Code VARCHAR(50) NOT NULL, + Naam VARCHAR(255) NOT NULL, + Categorie VARCHAR(50) NOT NULL, + Volgorde INT NOT NULL DEFAULT 0, + UNIQUE KEY uq_onderdeel_code (Code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Gebruiker_rechten ( + Gebruiker_ID INT NOT NULL, + School_ID INT NOT NULL, + Onderdeel_ID INT NOT NULL, + Toegekend_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Toegekend_door VARCHAR(100) NULL, + PRIMARY KEY (Gebruiker_ID, School_ID, Onderdeel_ID), + KEY idx_rechten_school (School_ID), + KEY idx_rechten_onderdeel (Onderdeel_ID), + CONSTRAINT fk_rechten_gebruiker FOREIGN KEY (Gebruiker_ID) + REFERENCES Gebruikers (Gebruiker_ID) ON DELETE CASCADE, + CONSTRAINT fk_rechten_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE, + CONSTRAINT fk_rechten_onderdeel FOREIGN KEY (Onderdeel_ID) + REFERENCES Onderdelen (Onderdeel_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Handleidingen ( + Handleiding_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Slug VARCHAR(100) NOT NULL, + Titel VARCHAR(200) NOT NULL, + Categorie VARCHAR(100) NULL, + Samenvatting VARCHAR(300) NULL, + Inhoud MEDIUMTEXT NULL, + Zichtbaar VARCHAR(10) NOT NULL DEFAULT 'iedereen', + Volgorde INT NOT NULL DEFAULT 0, + Gewijzigd_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Gewijzigd_door VARCHAR(100) NULL, + UNIQUE KEY uq_handleiding_slug (Slug) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Handleidingen_versies ( + Versie_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Handleiding_ID INT NOT NULL, + Titel VARCHAR(200) NOT NULL, + Inhoud MEDIUMTEXT NULL, + Opgeslagen_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Door VARCHAR(100) NULL, + KEY idx_versie_handleiding (Handleiding_ID, Opgeslagen_op), + CONSTRAINT fk_versie_handleiding FOREIGN KEY (Handleiding_ID) + REFERENCES Handleidingen (Handleiding_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Leerlingenaantal_tellingen ( + Telling_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_ID INT NOT NULL, + Peildatum DATE NOT NULL, + Schooljaar VARCHAR(10) NOT NULL, + Aantal INT NOT NULL, + Detail TEXT NULL, + Opgevraagd_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Door VARCHAR(100) NULL, + UNIQUE KEY uq_telling (School_ID, Peildatum), + KEY idx_telling_datum (Peildatum), + CONSTRAINT fk_telling_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Personeelsaantal_tellingen ( + Telling_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_ID INT NOT NULL, + Peildatum DATE NOT NULL, + Schooljaar VARCHAR(10) NOT NULL, + Aantal INT NOT NULL, + Detail TEXT NULL, + Opgevraagd_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Door VARCHAR(100) NULL, + UNIQUE KEY uq_ptelling (School_ID, Peildatum), + KEY idx_ptelling_datum (Peildatum), + CONSTRAINT fk_ptelling_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Personeelsaantal_huidig ( + School_ID INT NOT NULL PRIMARY KEY, + Aantal INT NOT NULL, + Detail TEXT NULL, + Gesynchroniseerd DATETIME NOT NULL, + CONSTRAINT fk_phuidig_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS PIVOT_instellingen ( + Sleutel VARCHAR(50) NOT NULL PRIMARY KEY, + Waarde VARCHAR(255) NULL, + Bijgewerkt DATETIME NULL, + Door VARCHAR(100) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS IP_blokkades ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Reeks VARCHAR(64) NOT NULL, + Soort VARCHAR(10) NOT NULL DEFAULT 'blokkeren', + Opmerking VARCHAR(255) NULL, + Scholen VARCHAR(1000) NULL, + Aangemaakt DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Gebruiker_ID INT NULL, + Aantal_geweigerd INT NOT NULL DEFAULT 0, + Laatst_geweigerd DATETIME NULL, + UNIQUE KEY uq_ip_reeks (Reeks, Soort) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS GoPro_verzameltabel ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_code VARCHAR(32) NOT NULL, + School_naam VARCHAR(255) NULL, + Person_ID VARCHAR(64) NOT NULL, + Voornaam VARCHAR(100) NULL, + Achternaam VARCHAR(100) NULL, + Email VARCHAR(255) NULL, + UPN VARCHAR(255) NULL, + Instellingsnummer VARCHAR(20) NULL, + Functie VARCHAR(100) NULL, + Rol VARCHAR(100) NULL, + Startdatum DATE NULL, + Einddatum DATE NULL, + Telefoon VARCHAR(50) NULL, + Toegevoegd DATETIME NOT NULL, + Door VARCHAR(255) NULL, + Soort VARCHAR(10) NOT NULL DEFAULT 'groen', -- groen = in de CSV, genegeerd = rode lijst, verzonden = al naar GO! Pro + Verzonden DATETIME NULL, + Verzonden_door VARCHAR(255) NULL, + UNIQUE KEY uq_gopro_verz (School_code, Person_ID), + KEY idx_gopro_verz_email (Email), + KEY idx_gopro_verz_soort (Soort, School_naam) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Koppeling_tests ( + School_ID INT NOT NULL, + Onderdeel VARCHAR(50) NOT NULL, + Ok TINYINT NULL, + Detail VARCHAR(500) NULL, + Getest_op DATETIME NOT NULL, + PRIMARY KEY (School_ID, Onderdeel), + CONSTRAINT fk_ktest_school FOREIGN KEY (School_ID) REFERENCES Scholen (School_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Logs ( + Log_ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Bezochte_url VARCHAR(2048) NOT NULL, + Gebruiker_ID INT NULL, + School_ID INT NULL, + Actie VARCHAR(255) NULL, + IP VARCHAR(45) NULL, + KEY idx_logs_tijd (Timestamp), + KEY idx_logs_gebruiker (Gebruiker_ID), + CONSTRAINT fk_logs_gebruiker FOREIGN KEY (Gebruiker_ID) + REFERENCES Gebruikers (Gebruiker_ID) ON DELETE SET NULL, + CONSTRAINT fk_logs_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Status ( + Bugstatus_ID TINYINT NOT NULL PRIMARY KEY, + Omschrijving VARCHAR(50) NOT NULL, + UNIQUE KEY uq_status_omschrijving (Omschrijving) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Bugs ( + Bug_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Timestamp DATETIME NOT NULL, + Omschrijving TEXT NOT NULL, + Foutcode VARCHAR(100) NULL, + Bugstatus_ID TINYINT NOT NULL DEFAULT 1, + Gebruiker_ID INT NULL, + Gebruikersnaam VARCHAR(255) NULL, + School_ID INT NULL, + Gemeld_op DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + KEY idx_bugs_status (Bugstatus_ID), + CONSTRAINT fk_bugs_status FOREIGN KEY (Bugstatus_ID) REFERENCES Status (Bugstatus_ID), + CONSTRAINT fk_bugs_gebruiker FOREIGN KEY (Gebruiker_ID) + REFERENCES Gebruikers (Gebruiker_ID) ON DELETE SET NULL, + CONSTRAINT fk_bugs_school FOREIGN KEY (School_ID) + REFERENCES Scholen (School_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT IGNORE INTO Veiligheidsgroepen (Veiligheidsgroep, Naam, Omschrijving) VALUES + (1, 'Administrator', 'Alle rechten in alle scholen; beheert gebruikers, rechten en scholen'), + (2, 'Gebruiker', 'Enkel de rechten die per school zijn aangevinkt'); + +INSERT IGNORE INTO Onderdelen (Code, Naam, Categorie, Volgorde) VALUES + ('eigendom_bekijken', 'Eigendom bekijken', 'Chromebooks', 10), + ('toestellen_uitdelen', 'Toestellen uitdelen en inleveren', 'Chromebooks', 20), + ('toestellen_beheren', 'Toestelleninventaris beheren', 'Chromebooks', 30), + ('toestel_blokkeren', 'Chromebook blokkeren / deblokkeren', 'Chromebooks', 40), + ('herstellingen', 'Herstellingen', 'Chromebooks', 50), + ('signpost', 'Signpost-toestellen', 'Chromebooks', 60), + ('leerlingen_bekijken', 'Leerlingen bekijken en bewerken', 'Leerlingen', 70), + ('leerlingen_synchroniseren', 'Leerlingen toevoegen en synchroniseren', 'Leerlingen', 80), + ('google_wachtwoord', 'Google-wachtwoord resetten', 'Google', 90), + ('google_accounts', 'Google-accounts aanmaken', 'Google', 100), + ('tweestaps_codes', '2FA: back-upcodes tonen / aanmaken', 'Google', 110), + ('tweestaps_uitzetten', '2FA tijdelijk uitzetten (uitzondering)', 'Google', 120), + ('google_licenties', 'Google-licenties', 'Google', 130), + ('gmail_delegatie', 'Mailbox-delegatie', 'Google', 140), + ('smartschool', 'Smartschool-wachtwoorden & info', 'Smartschool', 150), + ('smartschool_activiteit', 'Activiteit co-accounts & berichten', 'Smartschool', 160), + ('afwezigheden', 'Afwezigheden leerlingen (B-codes)', 'Smartschool', 170), + ('skore', 'Skore-synchronisatie (starten en plannen)', 'Smartschool', 180), + ('personeel_directie', 'Personeel: aanvragen goedkeuren (directie)', 'Personeel', 190), + ('personeel_secretariaat', 'Personeel: dagoverzicht (secretariaat)', 'Personeel', 200), + ('qr_codes', 'QR-code generator', 'Tools', 210), + ('co2', 'CO2-sensoren', 'IoT', 220), + ('leerlingenaantal', 'Leerlingenaantallen (alle scholen)', 'Scholengroep', 230), + ('bugs_bekijken', 'Bugs bekijken', 'Beheer', 240), + ('bugs_beheren', 'Status van bugs wijzigen', 'Beheer', 250), + ('nieuw_schooljaar', 'Nieuw schooljaar (accounts & toestellen)', 'Beheer', 260), + ('gebruikersbeheer', 'Gebruikers & rechten van deze school', 'PIVOT', 270), + ('koppelingen', 'Koppelingen van deze school', 'PIVOT', 280); + +INSERT IGNORE INTO Status (Bugstatus_ID, Omschrijving) VALUES + (1, 'Nieuw'), + (2, 'In behandeling'), + (3, 'Fixed'); + +-- --------------------------------------------------------------------- +-- 2. School: Scholengroep Antwerpen +-- Domein, Smartschool, Informat, Google, ... vul je daarna in via +-- PIVOT › 🏫 Alle scholen beheren › Bewerken. +-- --------------------------------------------------------------------- +INSERT INTO Scholen (Code, School_naam, Domein, Hostnamen, Actief, Db_naam, Instellingen, Bijgewerkt, Bijgewerkt_door) +VALUES ('sg-antwerpen', 'Scholengroep Antwerpen', '', '', 1, 'pivot_sg_antwerpen', '{}', NOW(6), 'installatie') +ON DUPLICATE KEY UPDATE School_naam = 'Scholengroep Antwerpen'; + +-- --------------------------------------------------------------------- +-- 3. Gebruiker Marijn – Administrator (alle rechten in alle scholen) +-- Wachtwoord 'Binnenin10' (enkel als hash bewaard; wijzigen kan in PIVOT +-- › Gebruikers & rechten). +-- --------------------------------------------------------------------- +INSERT INTO Gebruikers (Gebruikersnaam, Veiligheidsgroep, Passwoordhash, Emailadres, Actief) +VALUES ('Marijn', 1, 'scrypt:32768:8:1$FuAWb0nan2iFSInz$18994a1f3faf96e071b0cf1bded9a32daaf481c3cd92583e08d87c6e88b018be41d4aca7369108ae01ddb2f6523ab00817f60a12b41b2d255f91ad64857e4856', NULL, 1) +ON DUPLICATE KEY UPDATE Veiligheidsgroep = 1, Passwoordhash = 'scrypt:32768:8:1$FuAWb0nan2iFSInz$18994a1f3faf96e071b0cf1bded9a32daaf481c3cd92583e08d87c6e88b018be41d4aca7369108ae01ddb2f6523ab00817f60a12b41b2d255f91ad64857e4856', Actief = 1; + +-- Een administrator heeft automatisch alle rechten in elke school; deze rijen +-- maken dat ook zichtbaar in het overzicht (en blijven gelden als hij ooit +-- gewone gebruiker wordt). +INSERT IGNORE INTO Gebruiker_rechten (Gebruiker_ID, School_ID, Onderdeel_ID, Toegekend_door) +SELECT g.Gebruiker_ID, s.School_ID, o.Onderdeel_ID, 'installatie' +FROM Gebruikers g CROSS JOIN Scholen s CROSS JOIN Onderdelen o +WHERE g.Gebruikersnaam = 'Marijn' AND s.Code = 'sg-antwerpen'; + +-- --------------------------------------------------------------------- +-- 4. Database van Scholengroep Antwerpen +-- --------------------------------------------------------------------- +CREATE DATABASE IF NOT EXISTS `pivot_sg_antwerpen` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +USE `pivot_sg_antwerpen`; + +-- ===================================================================== +-- PIVOT 1.1.0 – database van ÉÉN school (structuur schooljaar 2026-27) +-- +-- Elke school in PIVOT heeft een eigen database met deze tabellen. +-- Gebruik: USE ; SOURCE school.sql; +-- of: python beheer.py nieuwe-schooldatabase +-- +-- Tabellen uit de PDF: Campus, Lokalen, Wifi, Toestellen, Signpost_DB, +-- Opmerkingen, Signpost_herstellingen_DB, Leerlingen, Eigendom, +-- Co_accounts, CO2_Metingen. +-- Aanvullingen die PIVOT nodig heeft staan gemarkeerd met -- [+] +-- (Scholen, Gebruikers, Logs, Bugs en Status staan in de centrale database.) +-- ===================================================================== + +-- --------------------------------------------------------------------- +-- Schooljaren [+] (Leerlingen.Schooljaar_ID = beginjaar, bv. 2026 → '2026-27') +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Schooljaar ( + Schooljaar_ID SMALLINT NOT NULL PRIMARY KEY, + Schooljaar VARCHAR(9) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT IGNORE INTO Schooljaar (Schooljaar_ID, Schooljaar) VALUES + (2022, '2022-23'), (2023, '2023-24'), (2024, '2024-25'), (2025, '2025-26'), + (2026, '2026-27'), (2027, '2027-28'), (2028, '2028-29'), (2029, '2029-30'), + (2030, '2030-31'), (2031, '2031-32'), (2032, '2032-33'), (2033, '2033-34'), + (2034, '2034-35'), (2035, '2035-36'); + +-- --------------------------------------------------------------------- +-- Campus → Lokalen +-- School_ID verwijst naar Scholen.School_ID in de CENTRALE database. +-- (Geen harde foreign key: een schooldatabase kan op een andere server staan.) +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Campus ( + Campus_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_ID INT NOT NULL, + Campus_naam VARCHAR(255) NOT NULL, + Adres VARCHAR(255) NULL, + KEY idx_campus_school (School_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Lokalen ( + Lokaal_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Naam VARCHAR(100) NOT NULL, + Campus_ID INT NULL, -- leeg = nog niet aan een campus gekoppeld (bv. nieuw CO2-lokaal) + Verdieping VARCHAR(20) NULL, + KEY idx_lokalen_naam (Naam), + CONSTRAINT fk_lokalen_campus FOREIGN KEY (Campus_ID) + REFERENCES Campus (Campus_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Wifi ( + Wifi_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Campus_ID INT NULL, -- [+] op welke campus dit netwerk hoort + Naam_Netwerk VARCHAR(100) NOT NULL, + Wifi_ww VARCHAR(255) NULL, + CONSTRAINT fk_wifi_campus FOREIGN KEY (Campus_ID) + REFERENCES Campus (Campus_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- Toestellen +-- Schooleigen_ID = het eigen toestelnummer van de school (vroeger KAMXM_nummer). +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Toestellen ( + Toestel_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Schooleigen_ID VARCHAR(50) NULL, + Serienummer VARCHAR(100) NULL, -- [+] nodig om het toestel in Google te (de)blokkeren + Type VARCHAR(100) NULL, -- [+] model + Status VARCHAR(20) NOT NULL DEFAULT 'Beschikbaar', -- [+] Beschikbaar / Uitgeleend / Defect + Geblokkeerd TINYINT(1) NOT NULL DEFAULT 0, -- [+] 1 = geblokkeerd in Google Admin + Afschrijfdatum DATE NULL, + Lokaal_ID INT NULL, + UNIQUE KEY uq_toestellen_schooleigen (Schooleigen_ID), + KEY idx_toestellen_serienummer (Serienummer), + KEY idx_toestellen_status (Status), + CONSTRAINT fk_toestellen_lokaal FOREIGN KEY (Lokaal_ID) + REFERENCES Lokalen (Lokaal_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Gegevens van Signpost (1 rij per toestel dat via Signpost aangekocht is) +CREATE TABLE IF NOT EXISTS Signpost_DB ( + Toestel_ID INT NOT NULL PRIMARY KEY, + Signpostnummer VARCHAR(50) NULL, + Aankoopbedrag DECIMAL(10,2) NULL, + Aankoopdatum DATE NULL, + Garantie DATE NULL, + UNIQUE KEY uq_signpost_nummer (Signpostnummer), + CONSTRAINT fk_signpost_toestel FOREIGN KEY (Toestel_ID) + REFERENCES Toestellen (Toestel_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Opmerkingen ( + Opmerking_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Toestel_ID INT NOT NULL, + Opmerking TEXT NOT NULL, + Timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Gebruiker VARCHAR(255) NULL, -- [+] wie de opmerking schreef + KEY idx_opmerkingen_toestel (Toestel_ID, Timestamp), + CONSTRAINT fk_opmerkingen_toestel FOREIGN KEY (Toestel_ID) + REFERENCES Toestellen (Toestel_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- Leerlingen +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Leerlingen ( + Leerling_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Internnummer VARCHAR(32) NOT NULL, + Gebruikersnaam VARCHAR(100) NULL, + Naam VARCHAR(100) NULL, + Voornaam VARCHAR(100) NULL, + SS_nummer VARCHAR(255) NULL, + Google_adres VARCHAR(255) NULL, + Schooljaar_ID SMALLINT NULL, -- [+] zie tabel Schooljaar + Vertrokken_op DATE NULL, -- niet meer actief in Informat sinds (NULL = actief) + UNIQUE KEY uq_leerlingen_internnummer (Internnummer), + KEY idx_leerlingen_gebruikersnaam (Gebruikersnaam) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Co_accounts ( + Co_account_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Internnummer VARCHAR(32) NOT NULL, + Naam VARCHAR(100) NULL, + Voornaam VARCHAR(100) NULL, + Laatste_aanmelding DATETIME NULL, + Emailadres_co_accounts VARCHAR(255) NULL, + KEY idx_coaccounts_intern (Internnummer), + CONSTRAINT fk_coaccounts_leerling FOREIGN KEY (Internnummer) + REFERENCES Leerlingen (Internnummer) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- Eigendom: welk toestel heeft welke leerling (ook de geschiedenis). +-- Datum_inlevering leeg = de leerling heeft het toestel nu. +-- (Vervangt de vroegere tabel Eigendom_archief.) +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Eigendom ( + Eigendom_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Internnummer VARCHAR(32) NOT NULL, + Toestel_ID INT NOT NULL, + Status TINYINT NOT NULL DEFAULT 0, -- 0 = actief, 1 = geblokkeerd in Google + Datum_toekenning DATE NOT NULL, + Datum_inlevering DATE NULL, + KEY idx_eigendom_leerling (Internnummer, Datum_inlevering), + KEY idx_eigendom_toestel (Toestel_ID, Datum_inlevering), + CONSTRAINT fk_eigendom_leerling FOREIGN KEY (Internnummer) + REFERENCES Leerlingen (Internnummer) ON UPDATE CASCADE, + CONSTRAINT fk_eigendom_toestel FOREIGN KEY (Toestel_ID) + REFERENCES Toestellen (Toestel_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- Herstellingen (via Signpost of intern) +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Signpost_herstellingen_DB ( + Incident_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Toestel_ID INT NOT NULL, + Omschrijving TEXT NULL, + Kostprijs DECIMAL(10,2) NULL, + Status_herstelling VARCHAR(30) NOT NULL DEFAULT 'geregistreerd', + Datum DATE NULL, -- [+] datum van de melding + Leerling_ID INT NULL, -- [+] leerling die het toestel binnenbracht + KEY idx_herstellingen_toestel (Toestel_ID), + CONSTRAINT fk_herstellingen_toestel FOREIGN KEY (Toestel_ID) + REFERENCES Toestellen (Toestel_ID) ON DELETE CASCADE, + CONSTRAINT fk_herstellingen_leerling FOREIGN KEY (Leerling_ID) + REFERENCES Leerlingen (Leerling_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- CO2-metingen per lokaal +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS CO2_Metingen ( + Meting_ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Lokaal_ID INT NOT NULL, + ppm INT NOT NULL, + Timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + KEY idx_co2_lokaal_tijd (Lokaal_ID, Timestamp), + KEY idx_co2_tijd (Timestamp), + CONSTRAINT fk_co2_lokaal FOREIGN KEY (Lokaal_ID) + REFERENCES Lokalen (Lokaal_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- ===================================================================== +-- [+] Tabellen van PIVOT-modules die niet in de PDF staan +-- (PIVOT maakt ze ook zelf aan bij het eerste gebruik) +-- ===================================================================== +CREATE TABLE IF NOT EXISTS smartschool_afwezigheden ( + Datum DATE NOT NULL, + Internnummer VARCHAR(32) NOT NULL, + Dagdeel CHAR(2) NOT NULL, + Code VARCHAR(8) NOT NULL, + PRIMARY KEY (Datum, Internnummer, Dagdeel), + INDEX idx_intern (Internnummer), + INDEX idx_code (Code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS smartschool_afwezigheden_sync ( + Datum DATE NOT NULL PRIMARY KEY, + Opgehaald DATETIME NOT NULL, + Aantal INT NOT NULL DEFAULT 0 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS tweestaps_uitzonderingen ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Email VARCHAR(255) NOT NULL, + Naam VARCHAR(255) NULL, + Reden VARCHAR(255) NULL, + Van DATETIME NOT NULL, + Tot DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Actief TINYINT NOT NULL DEFAULT 1, + Beeindigd_op DATETIME NULL, + Beeindigd_door VARCHAR(100) NULL, + INDEX idx_actief (Actief, Tot), + INDEX idx_email (Email) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS tweestaps_log ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Tijdstip DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Actie VARCHAR(40) NOT NULL, + Email VARCHAR(255) NOT NULL, + Details VARCHAR(255) NULL, + INDEX idx_tijdstip (Tijdstip) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_delegatie_log ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Tijdstip DATETIME NOT NULL, + Gebruiker VARCHAR(100) NULL, + Actie VARCHAR(20) NOT NULL, + Mailbox VARCHAR(255) NOT NULL, + Gedelegeerde VARCHAR(255) NOT NULL, + INDEX idx_mailbox (Mailbox), + INDEX idx_tijdstip (Tijdstip) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_delegaties ( + Mailbox VARCHAR(255) NOT NULL, + Mailbox_naam VARCHAR(255) NULL, + Gedelegeerde VARCHAR(255) NOT NULL, + Gedelegeerde_naam VARCHAR(255) NULL, + Status VARCHAR(20) NULL, + Opgehaald DATETIME NOT NULL, + PRIMARY KEY (Mailbox, Gedelegeerde), + KEY idx_gmail_deleg_gedelegeerde (Gedelegeerde) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_delegaties_scan ( + ID TINYINT NOT NULL PRIMARY KEY, + Opgehaald DATETIME NULL, + Mailboxen INT NULL, + Fouten INT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS internaat_aanwezigheid ( + Datum DATE NOT NULL, + Persoon_ID VARCHAR(64) NOT NULL, -- pPersoon/persoonId uit de Internaat-API van Informat + Moment VARCHAR(10) NOT NULL, -- ochtend | avond + Status VARCHAR(10) NOT NULL, -- aanwezig | afwezig (geen rij = nog niet gecontroleerd) + Naam VARCHAR(200) NULL, + Bijgewerkt DATETIME NOT NULL, + Door VARCHAR(255) NULL, + PRIMARY KEY (Datum, Persoon_ID, Moment), + KEY idx_aanw_persoon (Persoon_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_label_log ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Gestart DATETIME NOT NULL, + Klaar DATETIME NULL, + Door VARCHAR(255) NULL, + Bron VARCHAR(255) NOT NULL, + Label VARCHAR(255) NOT NULL, + Doel VARCHAR(255) NOT NULL, + Modus VARCHAR(12) NOT NULL, -- kopieren | verplaatsen + Totaal INT NULL, + Gelukt INT NULL, + Overgeslagen INT NULL, + Fouten INT NULL, + Melding VARCHAR(500) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_label_items ( + Bron VARCHAR(255) NOT NULL, + Bron_ID VARCHAR(64) NOT NULL, -- Gmail-id in de bronmailbox + Doel VARCHAR(255) NOT NULL, + Doel_ID VARCHAR(64) NULL, -- Gmail-id van de kopie in de doelmailbox + Gekopieerd DATETIME NOT NULL, + PRIMARY KEY (Bron, Bron_ID, Doel) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Gmail-handtekeningen: sjabloon, logo en gekozen OU's (één rij) en wanneer de handtekening per gebruiker gezet werd +CREATE TABLE IF NOT EXISTS gmail_handtekening ( + ID TINYINT NOT NULL PRIMARY KEY, + Sjabloon MEDIUMTEXT NULL, + OUs TEXT NULL, + Met_sub_ous TINYINT NOT NULL DEFAULT 1, + Logo MEDIUMBLOB NULL, + Logo_type VARCHAR(40) NULL, + Logo_sleutel VARCHAR(40) NULL, + Logo_url VARCHAR(500) NULL, + Logo_breedte INT NOT NULL DEFAULT 120, + Publiek_adres VARCHAR(255) NULL, + Nachtelijk TINYINT NOT NULL DEFAULT 0, + Laatste_nacht DATE NULL, + Nacht_resultaat VARCHAR(500) NULL, + Bijgewerkt DATETIME NULL, + Door VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_handtekening_log ( + Email VARCHAR(255) NOT NULL PRIMARY KEY, + Toegepast DATETIME NOT NULL, + Ok TINYINT NOT NULL, + Melding VARCHAR(500) NULL, + Hash CHAR(40) NULL, + Door VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Gmail › Contacten: contactlijsten die PIVOT in de mailboxen van de gekozen OU's zet +CREATE TABLE IF NOT EXISTS contact_lijsten ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Naam VARCHAR(100) NOT NULL, -- label in Google Contacten + OUs TEXT NULL, -- JSON-lijst van OU-paden + Met_sub_ous TINYINT NOT NULL DEFAULT 1, + Bijgewerkt DATETIME NULL, + Door VARCHAR(255) NULL, + Laatste_sync DATETIME NULL, + Resultaat VARCHAR(500) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS contact_lijst_items ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Lijst_ID INT NOT NULL, + Voornaam VARCHAR(100) NULL, + Achternaam VARCHAR(100) NULL, + Organisatie VARCHAR(150) NULL, + Functie VARCHAR(150) NULL, + Email VARCHAR(255) NULL, + Telefoon VARCHAR(60) NULL, + Notitie VARCHAR(500) NULL, + KEY idx_cli_lijst (Lijst_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + + +CREATE TABLE IF NOT EXISTS google_licenties ( + SKU_ID VARCHAR(32) NOT NULL PRIMARY KEY, + Naam VARCHAR(128) NOT NULL, + Aangekocht INT NOT NULL DEFAULT 0, + Bijgewerkt DATETIME NULL, + Bijgewerkt_door VARCHAR(100) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS personeel_aanvragen ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Soort VARCHAR(20) NOT NULL, + Status VARCHAR(20) NOT NULL, + Email VARCHAR(255) NOT NULL, + Naam VARCHAR(255) NULL, + Ingediend_door VARCHAR(255) NULL, + Titel VARCHAR(255) NOT NULL, + Omschrijving TEXT NULL, + Locatie VARCHAR(255) NULL, + Van_datum DATE NOT NULL, + Tot_datum DATE NOT NULL, + Dagdeel VARCHAR(10) NOT NULL DEFAULT 'dag', + Lesuren VARCHAR(50) NULL, + Klassen TEXT NULL, + Begeleiders TEXT NULL, + Kost DECIMAL(10,2) NULL, + Vervanging_ok TINYINT NOT NULL DEFAULT 0, + Vervanging_info VARCHAR(255) NULL, + Aangemaakt DATETIME NOT NULL, + Bijgewerkt DATETIME NOT NULL, + INDEX idx_status (Status), + INDEX idx_datum (Van_datum, Tot_datum), + INDEX idx_email (Email) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS personeel_reacties ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Aanvraag_ID INT NOT NULL, + Tijdstip DATETIME NOT NULL, + Email VARCHAR(255) NULL, + Naam VARCHAR(255) NULL, + Actie VARCHAR(30) NOT NULL, + Tekst TEXT NULL, + INDEX idx_aanvraag (Aanvraag_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Skore-synchronisatie (planning + logboek) +CREATE TABLE IF NOT EXISTS skore_planning ( + ID TINYINT NOT NULL PRIMARY KEY, + Frequentie VARCHAR(20) NOT NULL DEFAULT 'uit', + Uur TINYINT NOT NULL DEFAULT 6, + Minuut TINYINT NOT NULL DEFAULT 0, + Weekdag TINYINT NOT NULL DEFAULT 0, + Dag_van_maand TINYINT NOT NULL DEFAULT 1, + Laatst_gepland DATETIME NULL, + Bijgewerkt DATETIME NULL, + Bijgewerkt_door VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS skore_log ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Gestart DATETIME NOT NULL, + Door VARCHAR(255) NULL, + Manier VARCHAR(20) NOT NULL, + Service_ID VARCHAR(100) NULL, + Status VARCHAR(30) NOT NULL, + Melding TEXT NULL, + Bijgewerkt DATETIME NULL, + INDEX idx_skore_gestart (Gestart) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT IGNORE INTO skore_planning (ID) VALUES (1); + +CREATE TABLE IF NOT EXISTS smartschool_coaccounts ( + Internnummer VARCHAR(32) NOT NULL, + Nr TINYINT NOT NULL, + Gebruikersnaam VARCHAR(100) NULL, + Leerling_naam VARCHAR(100) NULL, + Leerling_voornaam VARCHAR(100) NULL, + Klas VARCHAR(50) NULL, + Voornaam VARCHAR(100) NULL, + Naam VARCHAR(100) NULL, + Type VARCHAR(50) NULL, + Email VARCHAR(255) NULL, + Laatste_login DATETIME NULL, + Opgehaald DATETIME NOT NULL, + PRIMARY KEY (Internnummer, Nr), + KEY idx_coacc_klas (Klas) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +CREATE TABLE IF NOT EXISTS gopro_keuzes ( + Person_ID VARCHAR(64) NOT NULL PRIMARY KEY, + Functie VARCHAR(100) NULL, + Rol VARCHAR(100) NULL, + Bijgewerkt DATETIME NOT NULL, + Door VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + diff --git a/sql/school.sql b/sql/school.sql new file mode 100644 index 0000000..cf4b6d0 --- /dev/null +++ b/sql/school.sql @@ -0,0 +1,448 @@ +-- ===================================================================== +-- PIVOT 1.1.0 – database van ÉÉN school (structuur schooljaar 2026-27) +-- +-- Elke school in PIVOT heeft een eigen database met deze tabellen. +-- Gebruik: USE ; SOURCE school.sql; +-- of: python beheer.py nieuwe-schooldatabase +-- +-- Tabellen uit de PDF: Campus, Lokalen, Wifi, Toestellen, Signpost_DB, +-- Opmerkingen, Signpost_herstellingen_DB, Leerlingen, Eigendom, +-- Co_accounts, CO2_Metingen. +-- Aanvullingen die PIVOT nodig heeft staan gemarkeerd met -- [+] +-- (Scholen, Gebruikers, Logs, Bugs en Status staan in de centrale database.) +-- ===================================================================== + +-- --------------------------------------------------------------------- +-- Schooljaren [+] (Leerlingen.Schooljaar_ID = beginjaar, bv. 2026 → '2026-27') +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Schooljaar ( + Schooljaar_ID SMALLINT NOT NULL PRIMARY KEY, + Schooljaar VARCHAR(9) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT IGNORE INTO Schooljaar (Schooljaar_ID, Schooljaar) VALUES + (2022, '2022-23'), (2023, '2023-24'), (2024, '2024-25'), (2025, '2025-26'), + (2026, '2026-27'), (2027, '2027-28'), (2028, '2028-29'), (2029, '2029-30'), + (2030, '2030-31'), (2031, '2031-32'), (2032, '2032-33'), (2033, '2033-34'), + (2034, '2034-35'), (2035, '2035-36'); + +-- --------------------------------------------------------------------- +-- Campus → Lokalen +-- School_ID verwijst naar Scholen.School_ID in de CENTRALE database. +-- (Geen harde foreign key: een schooldatabase kan op een andere server staan.) +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Campus ( + Campus_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + School_ID INT NOT NULL, + Campus_naam VARCHAR(255) NOT NULL, + Adres VARCHAR(255) NULL, + KEY idx_campus_school (School_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Lokalen ( + Lokaal_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Naam VARCHAR(100) NOT NULL, + Campus_ID INT NULL, -- leeg = nog niet aan een campus gekoppeld (bv. nieuw CO2-lokaal) + Verdieping VARCHAR(20) NULL, + KEY idx_lokalen_naam (Naam), + CONSTRAINT fk_lokalen_campus FOREIGN KEY (Campus_ID) + REFERENCES Campus (Campus_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Wifi ( + Wifi_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Campus_ID INT NULL, -- [+] op welke campus dit netwerk hoort + Naam_Netwerk VARCHAR(100) NOT NULL, + Wifi_ww VARCHAR(255) NULL, + CONSTRAINT fk_wifi_campus FOREIGN KEY (Campus_ID) + REFERENCES Campus (Campus_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- Toestellen +-- Schooleigen_ID = het eigen toestelnummer van de school (vroeger KAMXM_nummer). +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Toestellen ( + Toestel_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Schooleigen_ID VARCHAR(50) NULL, + Serienummer VARCHAR(100) NULL, -- [+] nodig om het toestel in Google te (de)blokkeren + Type VARCHAR(100) NULL, -- [+] model + Status VARCHAR(20) NOT NULL DEFAULT 'Beschikbaar', -- [+] Beschikbaar / Uitgeleend / Defect + Geblokkeerd TINYINT(1) NOT NULL DEFAULT 0, -- [+] 1 = geblokkeerd in Google Admin + Afschrijfdatum DATE NULL, + Lokaal_ID INT NULL, + UNIQUE KEY uq_toestellen_schooleigen (Schooleigen_ID), + KEY idx_toestellen_serienummer (Serienummer), + KEY idx_toestellen_status (Status), + CONSTRAINT fk_toestellen_lokaal FOREIGN KEY (Lokaal_ID) + REFERENCES Lokalen (Lokaal_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Gegevens van Signpost (1 rij per toestel dat via Signpost aangekocht is) +CREATE TABLE IF NOT EXISTS Signpost_DB ( + Toestel_ID INT NOT NULL PRIMARY KEY, + Signpostnummer VARCHAR(50) NULL, + Aankoopbedrag DECIMAL(10,2) NULL, + Aankoopdatum DATE NULL, + Garantie DATE NULL, + UNIQUE KEY uq_signpost_nummer (Signpostnummer), + CONSTRAINT fk_signpost_toestel FOREIGN KEY (Toestel_ID) + REFERENCES Toestellen (Toestel_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Opmerkingen ( + Opmerking_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Toestel_ID INT NOT NULL, + Opmerking TEXT NOT NULL, + Timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + Gebruiker VARCHAR(255) NULL, -- [+] wie de opmerking schreef + KEY idx_opmerkingen_toestel (Toestel_ID, Timestamp), + CONSTRAINT fk_opmerkingen_toestel FOREIGN KEY (Toestel_ID) + REFERENCES Toestellen (Toestel_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- Leerlingen +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Leerlingen ( + Leerling_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Internnummer VARCHAR(32) NOT NULL, + Gebruikersnaam VARCHAR(100) NULL, + Naam VARCHAR(100) NULL, + Voornaam VARCHAR(100) NULL, + SS_nummer VARCHAR(255) NULL, + Google_adres VARCHAR(255) NULL, + Schooljaar_ID SMALLINT NULL, -- [+] zie tabel Schooljaar + Vertrokken_op DATE NULL, -- niet meer actief in Informat sinds (NULL = actief) + UNIQUE KEY uq_leerlingen_internnummer (Internnummer), + KEY idx_leerlingen_gebruikersnaam (Gebruikersnaam) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS Co_accounts ( + Co_account_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Internnummer VARCHAR(32) NOT NULL, + Naam VARCHAR(100) NULL, + Voornaam VARCHAR(100) NULL, + Laatste_aanmelding DATETIME NULL, + Emailadres_co_accounts VARCHAR(255) NULL, + KEY idx_coaccounts_intern (Internnummer), + CONSTRAINT fk_coaccounts_leerling FOREIGN KEY (Internnummer) + REFERENCES Leerlingen (Internnummer) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- Eigendom: welk toestel heeft welke leerling (ook de geschiedenis). +-- Datum_inlevering leeg = de leerling heeft het toestel nu. +-- (Vervangt de vroegere tabel Eigendom_archief.) +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Eigendom ( + Eigendom_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Internnummer VARCHAR(32) NOT NULL, + Toestel_ID INT NOT NULL, + Status TINYINT NOT NULL DEFAULT 0, -- 0 = actief, 1 = geblokkeerd in Google + Datum_toekenning DATE NOT NULL, + Datum_inlevering DATE NULL, + KEY idx_eigendom_leerling (Internnummer, Datum_inlevering), + KEY idx_eigendom_toestel (Toestel_ID, Datum_inlevering), + CONSTRAINT fk_eigendom_leerling FOREIGN KEY (Internnummer) + REFERENCES Leerlingen (Internnummer) ON UPDATE CASCADE, + CONSTRAINT fk_eigendom_toestel FOREIGN KEY (Toestel_ID) + REFERENCES Toestellen (Toestel_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- Herstellingen (via Signpost of intern) +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS Signpost_herstellingen_DB ( + Incident_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Toestel_ID INT NOT NULL, + Omschrijving TEXT NULL, + Kostprijs DECIMAL(10,2) NULL, + Status_herstelling VARCHAR(30) NOT NULL DEFAULT 'geregistreerd', + Datum DATE NULL, -- [+] datum van de melding + Leerling_ID INT NULL, -- [+] leerling die het toestel binnenbracht + KEY idx_herstellingen_toestel (Toestel_ID), + CONSTRAINT fk_herstellingen_toestel FOREIGN KEY (Toestel_ID) + REFERENCES Toestellen (Toestel_ID) ON DELETE CASCADE, + CONSTRAINT fk_herstellingen_leerling FOREIGN KEY (Leerling_ID) + REFERENCES Leerlingen (Leerling_ID) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- --------------------------------------------------------------------- +-- CO2-metingen per lokaal +-- --------------------------------------------------------------------- +CREATE TABLE IF NOT EXISTS CO2_Metingen ( + Meting_ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Lokaal_ID INT NOT NULL, + ppm INT NOT NULL, + Timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + KEY idx_co2_lokaal_tijd (Lokaal_ID, Timestamp), + KEY idx_co2_tijd (Timestamp), + CONSTRAINT fk_co2_lokaal FOREIGN KEY (Lokaal_ID) + REFERENCES Lokalen (Lokaal_ID) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- ===================================================================== +-- [+] Tabellen van PIVOT-modules die niet in de PDF staan +-- (PIVOT maakt ze ook zelf aan bij het eerste gebruik) +-- ===================================================================== +CREATE TABLE IF NOT EXISTS smartschool_afwezigheden ( + Datum DATE NOT NULL, + Internnummer VARCHAR(32) NOT NULL, + Dagdeel CHAR(2) NOT NULL, + Code VARCHAR(8) NOT NULL, + PRIMARY KEY (Datum, Internnummer, Dagdeel), + INDEX idx_intern (Internnummer), + INDEX idx_code (Code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS smartschool_afwezigheden_sync ( + Datum DATE NOT NULL PRIMARY KEY, + Opgehaald DATETIME NOT NULL, + Aantal INT NOT NULL DEFAULT 0 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS tweestaps_uitzonderingen ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Email VARCHAR(255) NOT NULL, + Naam VARCHAR(255) NULL, + Reden VARCHAR(255) NULL, + Van DATETIME NOT NULL, + Tot DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Actief TINYINT NOT NULL DEFAULT 1, + Beeindigd_op DATETIME NULL, + Beeindigd_door VARCHAR(100) NULL, + INDEX idx_actief (Actief, Tot), + INDEX idx_email (Email) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS tweestaps_log ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Tijdstip DATETIME NOT NULL, + Door VARCHAR(100) NULL, + Actie VARCHAR(40) NOT NULL, + Email VARCHAR(255) NOT NULL, + Details VARCHAR(255) NULL, + INDEX idx_tijdstip (Tijdstip) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_delegatie_log ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Tijdstip DATETIME NOT NULL, + Gebruiker VARCHAR(100) NULL, + Actie VARCHAR(20) NOT NULL, + Mailbox VARCHAR(255) NOT NULL, + Gedelegeerde VARCHAR(255) NOT NULL, + INDEX idx_mailbox (Mailbox), + INDEX idx_tijdstip (Tijdstip) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_delegaties ( + Mailbox VARCHAR(255) NOT NULL, + Mailbox_naam VARCHAR(255) NULL, + Gedelegeerde VARCHAR(255) NOT NULL, + Gedelegeerde_naam VARCHAR(255) NULL, + Status VARCHAR(20) NULL, + Opgehaald DATETIME NOT NULL, + PRIMARY KEY (Mailbox, Gedelegeerde), + KEY idx_gmail_deleg_gedelegeerde (Gedelegeerde) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_delegaties_scan ( + ID TINYINT NOT NULL PRIMARY KEY, + Opgehaald DATETIME NULL, + Mailboxen INT NULL, + Fouten INT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS internaat_aanwezigheid ( + Datum DATE NOT NULL, + Persoon_ID VARCHAR(64) NOT NULL, -- pPersoon/persoonId uit de Internaat-API van Informat + Moment VARCHAR(10) NOT NULL, -- ochtend | avond + Status VARCHAR(10) NOT NULL, -- aanwezig | afwezig (geen rij = nog niet gecontroleerd) + Naam VARCHAR(200) NULL, + Bijgewerkt DATETIME NOT NULL, + Door VARCHAR(255) NULL, + PRIMARY KEY (Datum, Persoon_ID, Moment), + KEY idx_aanw_persoon (Persoon_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_label_log ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Gestart DATETIME NOT NULL, + Klaar DATETIME NULL, + Door VARCHAR(255) NULL, + Bron VARCHAR(255) NOT NULL, + Label VARCHAR(255) NOT NULL, + Doel VARCHAR(255) NOT NULL, + Modus VARCHAR(12) NOT NULL, -- kopieren | verplaatsen + Totaal INT NULL, + Gelukt INT NULL, + Overgeslagen INT NULL, + Fouten INT NULL, + Melding VARCHAR(500) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_label_items ( + Bron VARCHAR(255) NOT NULL, + Bron_ID VARCHAR(64) NOT NULL, -- Gmail-id in de bronmailbox + Doel VARCHAR(255) NOT NULL, + Doel_ID VARCHAR(64) NULL, -- Gmail-id van de kopie in de doelmailbox + Gekopieerd DATETIME NOT NULL, + PRIMARY KEY (Bron, Bron_ID, Doel) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Gmail-handtekeningen: sjabloon, logo en gekozen OU's (één rij) en wanneer de handtekening per gebruiker gezet werd +CREATE TABLE IF NOT EXISTS gmail_handtekening ( + ID TINYINT NOT NULL PRIMARY KEY, + Sjabloon MEDIUMTEXT NULL, + OUs TEXT NULL, + Met_sub_ous TINYINT NOT NULL DEFAULT 1, + Logo MEDIUMBLOB NULL, + Logo_type VARCHAR(40) NULL, + Logo_sleutel VARCHAR(40) NULL, + Logo_url VARCHAR(500) NULL, + Logo_breedte INT NOT NULL DEFAULT 120, + Publiek_adres VARCHAR(255) NULL, + Nachtelijk TINYINT NOT NULL DEFAULT 0, + Laatste_nacht DATE NULL, + Nacht_resultaat VARCHAR(500) NULL, + Bijgewerkt DATETIME NULL, + Door VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS gmail_handtekening_log ( + Email VARCHAR(255) NOT NULL PRIMARY KEY, + Toegepast DATETIME NOT NULL, + Ok TINYINT NOT NULL, + Melding VARCHAR(500) NULL, + Hash CHAR(40) NULL, + Door VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Gmail › Contacten: contactlijsten die PIVOT in de mailboxen van de gekozen OU's zet +CREATE TABLE IF NOT EXISTS contact_lijsten ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Naam VARCHAR(100) NOT NULL, -- label in Google Contacten + OUs TEXT NULL, -- JSON-lijst van OU-paden + Met_sub_ous TINYINT NOT NULL DEFAULT 1, + Bijgewerkt DATETIME NULL, + Door VARCHAR(255) NULL, + Laatste_sync DATETIME NULL, + Resultaat VARCHAR(500) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS contact_lijst_items ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Lijst_ID INT NOT NULL, + Voornaam VARCHAR(100) NULL, + Achternaam VARCHAR(100) NULL, + Organisatie VARCHAR(150) NULL, + Functie VARCHAR(150) NULL, + Email VARCHAR(255) NULL, + Telefoon VARCHAR(60) NULL, + Notitie VARCHAR(500) NULL, + KEY idx_cli_lijst (Lijst_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + + +CREATE TABLE IF NOT EXISTS google_licenties ( + SKU_ID VARCHAR(32) NOT NULL PRIMARY KEY, + Naam VARCHAR(128) NOT NULL, + Aangekocht INT NOT NULL DEFAULT 0, + Bijgewerkt DATETIME NULL, + Bijgewerkt_door VARCHAR(100) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS personeel_aanvragen ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Soort VARCHAR(20) NOT NULL, + Status VARCHAR(20) NOT NULL, + Email VARCHAR(255) NOT NULL, + Naam VARCHAR(255) NULL, + Ingediend_door VARCHAR(255) NULL, + Titel VARCHAR(255) NOT NULL, + Omschrijving TEXT NULL, + Locatie VARCHAR(255) NULL, + Van_datum DATE NOT NULL, + Tot_datum DATE NOT NULL, + Dagdeel VARCHAR(10) NOT NULL DEFAULT 'dag', + Lesuren VARCHAR(50) NULL, + Klassen TEXT NULL, + Begeleiders TEXT NULL, + Kost DECIMAL(10,2) NULL, + Vervanging_ok TINYINT NOT NULL DEFAULT 0, + Vervanging_info VARCHAR(255) NULL, + Aangemaakt DATETIME NOT NULL, + Bijgewerkt DATETIME NOT NULL, + INDEX idx_status (Status), + INDEX idx_datum (Van_datum, Tot_datum), + INDEX idx_email (Email) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS personeel_reacties ( + ID INT AUTO_INCREMENT PRIMARY KEY, + Aanvraag_ID INT NOT NULL, + Tijdstip DATETIME NOT NULL, + Email VARCHAR(255) NULL, + Naam VARCHAR(255) NULL, + Actie VARCHAR(30) NOT NULL, + Tekst TEXT NULL, + INDEX idx_aanvraag (Aanvraag_ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- Skore-synchronisatie (planning + logboek) +CREATE TABLE IF NOT EXISTS skore_planning ( + ID TINYINT NOT NULL PRIMARY KEY, + Frequentie VARCHAR(20) NOT NULL DEFAULT 'uit', + Uur TINYINT NOT NULL DEFAULT 6, + Minuut TINYINT NOT NULL DEFAULT 0, + Weekdag TINYINT NOT NULL DEFAULT 0, + Dag_van_maand TINYINT NOT NULL DEFAULT 1, + Laatst_gepland DATETIME NULL, + Bijgewerkt DATETIME NULL, + Bijgewerkt_door VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE IF NOT EXISTS skore_log ( + ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Gestart DATETIME NOT NULL, + Door VARCHAR(255) NULL, + Manier VARCHAR(20) NOT NULL, + Service_ID VARCHAR(100) NULL, + Status VARCHAR(30) NOT NULL, + Melding TEXT NULL, + Bijgewerkt DATETIME NULL, + INDEX idx_skore_gestart (Gestart) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT IGNORE INTO skore_planning (ID) VALUES (1); + +CREATE TABLE IF NOT EXISTS smartschool_coaccounts ( + Internnummer VARCHAR(32) NOT NULL, + Nr TINYINT NOT NULL, + Gebruikersnaam VARCHAR(100) NULL, + Leerling_naam VARCHAR(100) NULL, + Leerling_voornaam VARCHAR(100) NULL, + Klas VARCHAR(50) NULL, + Voornaam VARCHAR(100) NULL, + Naam VARCHAR(100) NULL, + Type VARCHAR(50) NULL, + Email VARCHAR(255) NULL, + Laatste_login DATETIME NULL, + Opgehaald DATETIME NOT NULL, + PRIMARY KEY (Internnummer, Nr), + KEY idx_coacc_klas (Klas) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +CREATE TABLE IF NOT EXISTS gopro_keuzes ( + Person_ID VARCHAR(64) NOT NULL PRIMARY KEY, + Functie VARCHAR(100) NULL, + Rol VARCHAR(100) NULL, + Bijgewerkt DATETIME NOT NULL, + Door VARCHAR(255) NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + diff --git a/static/PIVOT_transparant_logo.png b/static/PIVOT_transparant_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e6b17e1a08d6e647f5a38ee94b6f8851856de44f GIT binary patch literal 1231200 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 z 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­=QuDCD-jt#me~6o+6cY@LusNP6)lP% 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 z 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

RT4iHYkbNh!naW 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

ve~<|D-4K;st0(v$Vaq2B9D>mML>3; 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≠i(* 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 EU$_g7sQ>@~ literal 0 HcmV?d00001 diff --git a/static/global.css b/static/global.css new file mode 100644 index 0000000..dfcbdb7 --- /dev/null +++ b/static/global.css @@ -0,0 +1,593 @@ +/* ========================================================================== + PIVOT – GLOBALE HUISSTIJL + Eén stylesheet voor alle pagina's. Pagina's erven van templates/base.html + en gebruiken de klassen hieronder; paginaspecifieke CSS blijft beperkt + tot {% block extra_css %}. + ========================================================================== */ + +/* ---------- 1. Design tokens ---------- */ +:root { + /* Merkkleuren */ + --primary-color: #1e6fa5; + --primary-dark: #17577f; + --primary-light: #e8f1f8; + --background-color: #F4F7FA; + + /* Neutralen */ + --surface: #ffffff; + --surface-muted: #f8fafc; + --border: #e2e8f0; + --border-strong: #cbd5e1; + --text: #1e293b; + --text-muted: #64748b; + + /* Statuskleuren */ + --success: #16a34a; --success-bg: #dcfce7; --success-text: #166534; + --warning: #eab308; --warning-bg: #fef9c3; --warning-text: #854d0e; + --danger: #dc2626; --danger-bg: #fee2e2; --danger-text: #991b1b; + --info: #2563eb; --info-bg: #dbeafe; --info-text: #1e40af; + --accent: #f1c709; /* geel accent (toevoegen / bewerken) */ + --bug: #16a34a; /* groen accent voor bug-pagina's */ + + /* Vorm */ + --radius-sm: 6px; + --radius: 10px; + --radius-lg: 14px; + --shadow-sm: 0 1px 2px rgba(15, 23, 42, .06); + --shadow: 0 1px 3px rgba(15, 23, 42, .08), 0 4px 12px rgba(15, 23, 42, .05); + --shadow-lg: 0 10px 30px rgba(15, 23, 42, .18); + + --header-height: 64px; + --page-width: 1200px; + --font: "Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif; +} + +/* ---------- 2. Basis ---------- */ +*, *::before, *::after { box-sizing: border-box; } + +html { overflow-y: scroll; } + +body { + margin: 0; + min-height: 100vh; + display: flex; + flex-direction: column; + font-family: var(--font); + font-size: 15px; + line-height: 1.5; + color: var(--text); + background-color: var(--background-color); +} + +h1, h2, h3, h4 { margin: 0 0 .6em; line-height: 1.25; color: var(--text); } +h2 { font-size: 1.35rem; } +h3 { font-size: 1.1rem; } +p { margin: 0 0 1em; } +a { color: var(--primary-color); } + +.muted { color: var(--text-muted); } +.small { font-size: .85rem; } +.text-center { text-align: center; } +.text-right { text-align: right; } +.nowrap { white-space: nowrap; } +.mono { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: .85em; } +.hidden { display: none !important; } + +/* ---------- 3. Header ---------- */ +.app-header { + position: sticky; + top: 0; + z-index: 1000; + height: var(--header-height); + display: grid; + grid-template-columns: 1fr auto 1fr; + align-items: center; + gap: 16px; + padding: 0 24px; + background: var(--primary-color); + color: #fff; + box-shadow: 0 2px 8px rgba(0, 0, 0, .15); +} +.app-header.header--bug { background: var(--bug); } + +.header-left, .header-right { display: flex; align-items: center; gap: 12px; min-width: 0; } +.header-right { justify-content: flex-end; } + +.brand { + display: flex; align-items: center; gap: 10px; + color: #fff; text-decoration: none; font-weight: 700; letter-spacing: 1px; + white-space: nowrap; +} +.brand-mark { + width: 38px; height: 38px; border-radius: 50%; + background: #fff; padding: 4px; + display: grid; place-items: center; +} +.brand-mark img { width: 100%; height: 100%; object-fit: contain; } +.brand-name { font-size: 18px; } +.brand-school { font-weight: 400; opacity: .8; letter-spacing: 0; font-size: 14px; } + +.page-title { + margin: 0; + font-size: 22px; + font-weight: 700; + color: #fff; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: center; +} + +.header-user { font-size: 14px; opacity: .9; white-space: nowrap; } + +.home-btn, .logout-btn, .header-btn { + display: inline-flex; align-items: center; gap: 6px; + height: 36px; padding: 0 14px; + border: 0; border-radius: var(--radius-sm); + font: inherit; font-size: 14px; font-weight: 600; + text-decoration: none; cursor: pointer; white-space: nowrap; + transition: background-color .15s; +} +.home-btn, .header-btn { background: rgba(255, 255, 255, .16); color: #fff; } +.home-btn:hover, .header-btn:hover { background: rgba(255, 255, 255, .28); } +.logout-btn { background: #fff; color: var(--danger); } +.logout-btn:hover { background: var(--danger-bg); } +.app-header form { margin: 0; } + +/* ---------- 4. Pagina-layout ---------- */ +.app-main { + flex: 1; + width: 100%; + max-width: var(--page-width); + margin: 0 auto; + padding: 28px 24px 40px; +} +.app-main.narrow { max-width: 760px; } +.app-main.medium { max-width: 980px; } +.app-main.wide { max-width: 1400px; } + +.page-head { + display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; + gap: 12px; margin-bottom: 18px; +} +.page-head h2 { margin: 0; } +.page-head .actions { display: flex; flex-wrap: wrap; gap: 8px; } + +.card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow); + padding: 24px; +} +.card + .card { margin-top: 20px; } +.card-title { font-size: 1.1rem; margin: 0 0 14px; } +.card.subtle { background: var(--surface-muted); box-shadow: none; } + +/* Twee-koloms layout (formulier + scanner/info) */ +.split { + display: grid; + grid-template-columns: 3fr 2fr; + gap: 20px; + align-items: start; +} +.split > .card + .card { margin-top: 0; } +@media (max-width: 860px) { + .split { grid-template-columns: 1fr; } + .split .order-first-mobile { order: -1; } +} + +/* ---------- 5. Formulieren ---------- */ +label { font-weight: 600; font-size: 14px; } + +input:not([type=checkbox]):not([type=radio]):not([type=hidden]):not([type=file]), +select, textarea { + width: 100%; + padding: 10px 12px; + font: inherit; + font-size: 15px; + color: var(--text); + background: #fff; + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + transition: border-color .15s, box-shadow .15s; +} +input:focus, select:focus, textarea:focus { + outline: none; + border-color: var(--primary-color); + box-shadow: 0 0 0 3px rgba(30, 111, 165, .18); +} +input[readonly], input:disabled, textarea:disabled, select:disabled { + background: var(--surface-muted); color: var(--text-muted); cursor: not-allowed; +} +textarea { min-height: 100px; resize: vertical; } +input[type=checkbox], input[type=radio] { width: 18px; height: 18px; accent-color: var(--primary-color); cursor: pointer; } +input[type=file] { + width: 100%; padding: 12px; font: inherit; + background: var(--surface-muted); + border: 1px dashed var(--primary-color); border-radius: var(--radius-sm); +} + +.field { margin-bottom: 16px; } +.field > label { display: block; margin-bottom: 6px; } +.field-hint { font-size: 13px; color: var(--text-muted); margin-top: 4px; } + +.check { + display: flex; align-items: center; gap: 10px; + font-weight: 500; cursor: pointer; +} +.check-box { + display: flex; align-items: center; gap: 10px; + padding: 12px 14px; margin: 4px 0 16px; + background: var(--surface-muted); border: 1px solid var(--border); + border-radius: var(--radius-sm); font-weight: 500; cursor: pointer; +} + +/* Zoekbalk: invoerveld + knop op één lijn */ +.search-bar { + display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 16px; +} +.search-bar input:not([type=hidden]) { flex: 1 1 260px; width: auto; } + +.input-group { display: flex; gap: 6px; } +.input-group input { flex: 1; } + +.password-wrap { position: relative; } +.password-wrap input { padding-right: 44px !important; } +.password-toggle { + position: absolute; right: 6px; top: 50%; transform: translateY(-50%); + background: none !important; border: 0; padding: 4px 8px; font-size: 16px; + color: var(--text-muted); cursor: pointer; box-shadow: none; +} + +/* ---------- 6. Knoppen ---------- */ +button, .btn { + display: inline-flex; align-items: center; justify-content: center; gap: 6px; + padding: 9px 16px; + font: inherit; font-size: 14px; font-weight: 600; line-height: 1.3; + color: #fff; + background-color: var(--primary-color); + border: 1px solid transparent; + border-radius: var(--radius-sm); + text-decoration: none; + cursor: pointer; + white-space: nowrap; + transition: background-color .15s, border-color .15s, transform .05s; +} +button:hover, .btn:hover { background-color: var(--primary-dark); } +button:active, .btn:active { transform: translateY(1px); } +button:disabled, .btn:disabled { opacity: .5; cursor: not-allowed; } + +.btn-secondary { background: #475569; } +.btn-secondary:hover { background: #334155; } +.btn-light { background: #fff; color: var(--text); border-color: var(--border-strong); } +.btn-light:hover { background: var(--surface-muted); } +.btn-success { background: var(--success); } +.btn-success:hover { background: #15803d; } +.btn-warning { background: var(--accent); color: #3f3200; } +.btn-warning:hover { background: #d9b308; } +.btn-danger { background: var(--danger); } +.btn-danger:hover { background: #b91c1c; } +.btn-ghost { background: transparent; color: var(--text-muted); } +.btn-ghost:hover { background: var(--surface-muted); color: var(--text); } +.btn-link { background: none; color: var(--danger); padding: 6px; text-decoration: underline; } +.btn-link:hover { background: none; color: #991b1b; } +.btn-sm { padding: 6px 10px; font-size: 13px; } +.btn-lg { padding: 13px 22px; font-size: 16px; } +.btn-block { display: flex; width: 100%; } +.btn-block + .btn-block { margin-top: 10px; } + +/* Oude klassen die nog gebruikt worden */ +.add-btn { background: var(--accent); color: #3f3200; } +.add-btn:hover { background: #d9b308; } +.btn-bewerk { background: var(--accent); color: #3f3200; } +.btn-bewerk:hover { background: #d9b308; } + +/* ---------- 7. Tabellen ---------- */ +.table-wrap { + width: 100%; + overflow-x: auto; + border: 1px solid var(--border); + border-radius: var(--radius); + margin-top: 12px; +} +table { width: 100%; border-collapse: collapse; background: #fff; text-align: left; } +th, td { padding: 11px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; } +th { + background: var(--surface-muted); + font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; + color: var(--text-muted); white-space: nowrap; +} +tbody tr:last-child td { border-bottom: 0; } +tbody tr:hover { background: #f8fbfe; } +td.actions, th.actions { text-align: right; white-space: nowrap; } +td.actions form { display: inline; margin: 0; } +td.actions > * + * { margin-left: 6px; } +td.center, th.center { text-align: center; } +.empty-row td { text-align: center; color: var(--text-muted); padding: 32px; } + +/* Kolommen tonen/verbergen */ +.column-toggles { + display: flex; flex-wrap: wrap; gap: 8px; + margin: 4px 0 8px; +} +.column-toggles label { + display: inline-flex; align-items: center; gap: 6px; + padding: 5px 12px; font-size: 13px; font-weight: 500; + background: var(--surface-muted); border: 1px solid var(--border); + border-radius: 999px; cursor: pointer; user-select: none; +} +.column-toggles input { width: 15px; height: 15px; } + +/* ---------- 8. Badges ---------- */ +.badge { + display: inline-flex; align-items: center; gap: 4px; + padding: 3px 10px; border-radius: 999px; + font-size: 12.5px; font-weight: 600; white-space: nowrap; + background: #e2e8f0; color: #334155; +} +.badge-success { background: var(--success-bg); color: var(--success-text); } +.badge-warning { background: var(--warning-bg); color: var(--warning-text); } +.badge-danger { background: var(--danger-bg); color: var(--danger-text); } +.badge-info { background: var(--info-bg); color: var(--info-text); } + +/* ---------- 9. Flash-berichten ---------- */ +.flash-container { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; } +.flash-message { + display: flex; align-items: flex-start; gap: 10px; + padding: 12px 16px; + border-radius: var(--radius); + border: 1px solid transparent; + font-weight: 500; + background: var(--info-bg); color: var(--info-text); border-color: #bfdbfe; + animation: flashIn .3s ease; +} +.flash-message.success { background: var(--success-bg); color: var(--success-text); border-color: #bbf7d0; } +.flash-message.error, .flash-message.danger { background: var(--danger-bg); color: var(--danger-text); border-color: #fecaca; } +.flash-message.warning { background: var(--warning-bg); color: var(--warning-text); border-color: #fde68a; } +.flash-message .flash-close { + margin-left: auto; padding: 0 4px; background: none; color: inherit; + font-size: 18px; line-height: 1; opacity: .6; +} +.flash-message .flash-close:hover { opacity: 1; background: none; } +@keyframes flashIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } } + +/* Inline meldingen (bv. in een modal of loginformulier) */ +.alert { padding: 10px 14px; border-radius: var(--radius-sm); margin-bottom: 14px; font-size: 14px; text-align: left; + background: var(--info-bg); color: var(--info-text); } +.alert-success { background: var(--success-bg); color: var(--success-text); } +.alert-danger, .alert-error { background: var(--danger-bg); color: var(--danger-text); } +.alert-warning { background: var(--warning-bg); color: var(--warning-text); } + +/* ---------- 10. Tabs ---------- */ +.tabs { + display: flex; gap: 4px; flex-wrap: wrap; + border-bottom: 1px solid var(--border); + margin-bottom: 0; +} +.tab-link { + background: transparent; color: var(--text-muted); + border: 0; border-bottom: 3px solid transparent; border-radius: 0; + padding: 12px 18px; font-weight: 600; +} +.tab-link:hover { background: transparent; color: var(--text); } +.tab-link.active { color: var(--primary-color); border-bottom-color: var(--primary-color); } +.tab-content { + display: none; + background: var(--surface); + border: 1px solid var(--border); border-top: 0; + border-radius: 0 0 var(--radius-lg) var(--radius-lg); + box-shadow: var(--shadow); + padding: 24px; +} +.tab-content.active { display: block; } +/* Losstaande tabs (tabs staan in de page-head i.p.v. vast aan de kaart) */ +.tab-content.card { border-top: 1px solid var(--border); border-radius: var(--radius-lg); } +.tab-content + .tab-content { margin-top: 0; } +.page-head .tabs { border-bottom: 0; } + +/* ---------- 11. Modals ---------- */ +/* .modal wordt via JS op display:block gezet, .modal-overlay op display:flex */ +.modal, .modal-overlay { + display: none; + position: fixed; inset: 0; + z-index: 2000; + overflow-y: auto; + padding: 6vh 16px; + background: rgba(15, 23, 42, .5); +} +.modal-overlay { align-items: flex-start; justify-content: center; } +.modal-content { + position: relative; + width: 100%; + max-width: 480px; + margin: 0 auto; + background: var(--surface); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + padding: 26px; + text-align: left; + animation: modalIn .18s ease; +} +.modal-content.wide { max-width: 680px; } +.modal-content h2, .modal-content h3 { margin: 0 0 18px; padding-right: 30px; color: var(--primary-color); } +.modal-footer { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; } +.close, .close-btn { + position: absolute; top: 14px; right: 16px; + width: 32px; height: 32px; display: grid; place-items: center; + font-size: 24px; line-height: 1; color: var(--text-muted); + border-radius: 50%; cursor: pointer; +} +.close:hover, .close-btn:hover { background: var(--surface-muted); color: var(--text); } +@keyframes modalIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } } + +/* Grote statusknoppen in modals */ +.status-button { display: flex; width: 100%; padding: 14px; margin: 10px 0 0; font-size: 16px; border-radius: var(--radius); } +.status-success { background: var(--success); } +.status-success:hover { background: #15803d; } +.status-info { background: var(--info); } +.status-info:hover { background: #1d4ed8; } +.status-warning { background: #f59e0b; color: #fff; } +.status-warning:hover { background: #d97706; } +.status-danger { background: var(--danger); } +.status-danger:hover { background: #b91c1c; } + +/* ---------- 12. Schakelaar (toggle) ---------- */ +.switch { position: relative; display: inline-block; width: 46px; height: 26px; flex-shrink: 0; } +.switch input { opacity: 0; width: 0; height: 0; } +.slider { position: absolute; inset: 0; cursor: pointer; background: var(--border-strong); border-radius: 26px; transition: .25s; } +.slider::before { content: ""; position: absolute; width: 20px; height: 20px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: .25s; box-shadow: 0 1px 2px rgba(0,0,0,.2); } +.switch input:checked + .slider { background: var(--success); } +.switch input:checked + .slider::before { transform: translateX(20px); } +.switch-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); } +.switch-row:last-of-type { border-bottom: 0; } + +/* ---------- 13. Laadscherm ---------- */ +#loader-overlay { + display: none; + position: fixed; inset: 0; + z-index: 9999; + flex-direction: column; justify-content: center; align-items: center; gap: 16px; + background: rgba(255, 255, 255, .85); + backdrop-filter: blur(2px); +} +.spinner { + width: 52px; height: 52px; + border: 5px solid var(--primary-light); + border-top-color: var(--primary-color); + border-radius: 50%; + animation: spin .9s linear infinite; +} +.loader-text { font-weight: 600; color: var(--primary-color); font-size: 17px; text-align: center; } +.loader-sub { color: var(--text-muted); font-size: 14px; margin-top: -8px; } +@keyframes spin { to { transform: rotate(360deg); } } + +/* ---------- 14. Footer ---------- */ +.app-footer { + padding: 16px 24px; + font-size: 12.5px; + color: var(--text-muted); + text-align: right; +} + +/* ---------- 15. Dashboard ---------- */ +.dash-greeting { margin-bottom: 24px; } +.dash-greeting h2 { margin: 0 0 2px; font-size: 1.5rem; } +.dash-section-title { + display: flex; align-items: center; gap: 10px; + margin: 32px 0 14px; font-size: 13px; font-weight: 700; + letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); +} +.dash-section-title::after { content: ""; flex: 1; height: 1px; background: var(--border); } +.dash-section-title.admin { color: var(--danger); } +.dash-section-title.admin::after { background: #fecaca; } + +.tile-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 18px; +} +.tile { + display: flex; flex-direction: column; + background: var(--surface); + border: 1px solid var(--border); + border-top: 4px solid var(--primary-color); + border-radius: var(--radius-lg); + box-shadow: var(--shadow); + overflow: hidden; +} +.tile-head { display: flex; align-items: center; gap: 12px; padding: 18px 18px 10px; } +.tile-icon { + width: 42px; height: 42px; flex-shrink: 0; + display: grid; place-items: center; font-size: 22px; + background: var(--primary-light); border-radius: 10px; +} +.tile-head h3 { margin: 0; font-size: 1.05rem; color: var(--primary-color); } +.tile-links { list-style: none; margin: 0; padding: 4px 8px 10px; } +.tile-links a { + display: flex; align-items: center; gap: 10px; + padding: 9px 10px; border-radius: var(--radius-sm); + color: var(--text); text-decoration: none; font-weight: 500; + transition: background-color .12s, color .12s; +} +.tile-links a::after { content: "›"; margin-left: auto; color: var(--border-strong); font-size: 18px; transition: transform .12s; } +.tile-links a:hover { background: var(--primary-light); color: var(--primary-color); } +.tile-links a:hover::after { color: var(--primary-color); transform: translateX(2px); } +/* Links-blok: icoontjes even breed (favicon of emoji), lange adressen afgekort met … */ +.links-lijst .link-ico { flex: 0 0 18px; width: 18px; text-align: center; line-height: 1; font-size: 15px; } +.links-lijst .link-ico img { display: block; width: 16px; height: 16px; margin: 0 auto; border-radius: 3px; } +.links-lijst .link-tekst { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } + +.tile.tile-bug { border-top-color: var(--bug); } +.tile.tile-bug .tile-icon { background: var(--success-bg); } +.tile.tile-bug h3 { color: var(--success-text); } +.tile.tile-bug .tile-links a:hover { background: var(--success-bg); color: var(--success-text); } +.tile.tile-tools { border-top-color: #0d9488; } +.tile.tile-tools .tile-icon { background: #ccfbf1; } +.tile.tile-tools h3 { color: #0f766e; } +.tile.tile-tools .tile-links a:hover { background: #ccfbf1; color: #0f766e; } +.tile.tile-scholengroep { border-top-color: #7c3aed; } +.tile.tile-scholengroep .tile-icon { background: #ede9fe; } +.tile.tile-scholengroep h3 { color: #5b21b6; } +.tile.tile-scholengroep .tile-links a:hover { background: #ede9fe; color: #5b21b6; } +.tile.tile-handleiding { border-top-color: var(--info); } +.tile.tile-handleiding .tile-icon { background: var(--info-bg); } +.tile.tile-handleiding h3 { color: var(--info-text); } +.tile.tile-handleiding .tile-links a:hover { background: var(--info-bg); color: var(--info-text); } + +.tile.tile-admin { border-top-color: var(--danger); } +.tile.tile-admin .tile-icon { background: var(--danger-bg); } +.tile.tile-admin h3 { color: var(--danger-text); } +.tile.tile-admin .tile-links a:hover { background: var(--danger-bg); color: var(--danger-text); } + +/* ---------- 16. Loginpagina ---------- */ +body.auth-page { background: linear-gradient(160deg, #eaf2f9 0%, var(--background-color) 55%); } +.auth-wrap { + flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; + padding: 32px 16px; +} +.auth-logo { width: 100%; max-width: 380px; margin-bottom: 28px; } +.auth-card { width: 100%; max-width: 380px; } +.auth-card h2 { text-align: center; margin-bottom: 20px; } +.separator { display: flex; align-items: center; gap: 10px; margin: 18px 0; color: var(--text-muted); font-size: 13px; } +.separator::before, .separator::after { content: ""; flex: 1; border-bottom: 1px solid var(--border); } +.google-btn { + display: flex; align-items: center; justify-content: center; gap: 10px; + padding: 10px; border: 1px solid #dadce0; border-radius: var(--radius-sm); + background: #fff; color: #3c4043; font-weight: 600; text-decoration: none; + transition: background-color .15s, box-shadow .15s; +} +.google-btn:hover { background: #f8f9fa; box-shadow: 0 1px 3px rgba(60,64,67,.3); } +.google-btn img { width: 18px; height: 18px; } + +/* ---------- 17. Responsief ---------- */ +@media (max-width: 900px) { + .brand-school, .header-user { display: none; } +} +@media (max-width: 720px) { + .app-header { + height: auto; + grid-template-columns: 1fr auto; + grid-template-areas: "left right" "title title"; + padding: 10px 16px; + row-gap: 8px; + } + .header-left { grid-area: left; } + .header-right { grid-area: right; } + .page-title { grid-area: title; font-size: 18px; text-align: left; } + .brand-name { display: none; } + .app-main { padding: 20px 16px 32px; } + .card, .tab-content { padding: 18px; } + .modal-content { padding: 20px; } +} + +/* ---------- 18. Print ---------- */ +@media print { + .app-header, .app-footer, .page-head .actions, .search-bar, .column-toggles { display: none !important; } + body { background: #fff; } + .card { box-shadow: none; border: 0; padding: 0; } +} + +/* Keuze aantal rijen per pagina (perPaginaKiezer) */ +.per-pagina { display: inline-flex; align-items: center; gap: 6px; font-size: .85rem; color: var(--text-muted); margin: 0; font-weight: 400; white-space: nowrap; } +.per-pagina select { width: auto; padding: 4px 8px; font-size: .85rem; } diff --git a/static/img/go-logo.png b/static/img/go-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e3c66145f02c81f5f840f20686b9af142b0801ba GIT binary patch literal 6483 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ⅈ${#a(++UN8L8b&-q@N>R-8Fb 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 z

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

@^bT^4uD--ua3nzCX$rT>hSLNy$e6norb5 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 yb`=cydS;FN#(`B2_A% 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⪻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 O0000Dit kan tot 60 seconden duren. Even geduld a.u.b.{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +

+ + +
+
+ + Continu scannen + Uit +
+
+ + Resultaten ouder dan 7 dagen automatisch verwijderen + Uit +
+
+ +
+ + + + + + + + + + + {% for row in sensors %} + + + + + + + {% else %} + + {% endfor %} + +
LokaalCO2StatusActie
{{ row.lokaal }}{{ row.ppm }} ppm + {% if row.ppm < 800 %}Goed + {% elif row.ppm < 1200 %}Ventileren + {% else %}Kritiek + {% endif %} + + 📊 Grafiek +
Nog geen metingen. Start een handmatige scan.
+
+
+{% endblock %} + +{% block footer %} +
{{ school_name_short }} – PIVOT – Versie {{ version }} – CO2-monitor
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/Inventaris_Leerlingen.html b/templates/Inventaris_Leerlingen.html new file mode 100644 index 0000000..5b5a27d --- /dev/null +++ b/templates/Inventaris_Leerlingen.html @@ -0,0 +1,153 @@ +{% extends "base.html" %} + +{% block title %}Leerlingenbeheer{% endblock %} +{% block page_title %}Leerlingenbeheer{% endblock %} +{% block main_class %}wide{% endblock %} +{% block extra_css %} + +{% endblock %} +{% block loader_text %}Synchroniseren met Informat & Smartschool... Even geduld.{% endblock %} + +{% block content %} +
+
+

👥 Leerlingen

+
+ +
+ +
+
+
+ + + {% if aantal_vertrokken %} +

+ {% if toon_vertrokken %}Vertrokken leerlingen worden getoond ({{ aantal_vertrokken }}). + Verbergen + {% else %}{{ aantal_vertrokken }} leerling{{ 'en' if aantal_vertrokken != 1 }} niet meer actief in Informat (vertrokken) verborgen. + Toon ook vertrokken leerlingen{% endif %} +

+ {% endif %} + +
+ + + + + + + + + + + + + + + {% if results %} + {% for row in results %} + + + + + + + + + + + {% endfor %} + {% else %} + + {% endif %} + +
InternnummerGebruikersnaamVoornaamNaamSmartschool nr.Google e-mailadresSchooljaarActies
{{ row['Internnummer'] }}{% if row['Vertrokken_op'] %} + vertrokken{% endif %}{{ row['Gebruikersnaam'] or '' }}{{ row['Voornaam'] or '' }}{{ row['Naam'] or '' }}{{ row['SS_nummer'] or '' }}{{ row['Google_adres'] or '' }}{{ row['Schooljaar'] or '' }} + +
Geen leerlingen gevonden in de database.
+
+
+{% endblock %} + +{% block modals %} + + + +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/_handleiding_stijl.html b/templates/_handleiding_stijl.html new file mode 100644 index 0000000..cd75c8c --- /dev/null +++ b/templates/_handleiding_stijl.html @@ -0,0 +1,30 @@ + diff --git a/templates/_personeel.html b/templates/_personeel.html new file mode 100644 index 0000000..1d3acc0 --- /dev/null +++ b/templates/_personeel.html @@ -0,0 +1,32 @@ +{# Gedeelde stukjes voor de personeelsmodule #} + +{% macro status_badge(status) -%} + {%- set s = STATUS.get(status, (status, '')) -%} + {{ s[0] }} +{%- endmacro %} + +{% macro soort_label(soort) -%} + {%- set s = SOORTEN.get(soort) -%}{{ s.icoon }} {{ s.label }} +{%- endmacro %} + +{% macro periode(i) -%} + {%- if i.Van_datum == i.Tot_datum -%} + {{ ['ma','di','wo','do','vr','za','zo'][i.Van_datum.weekday()] }} {{ i.Van_datum.strftime('%d/%m/%Y') }} + {%- else -%} + {{ i.Van_datum.strftime('%d/%m') }} – {{ i.Tot_datum.strftime('%d/%m/%Y') }} + {%- endif -%} + · {{ DAGDELEN.get(i.Dagdeel, '') }}{% if i.Dagdeel == 'uren' and i.Lesuren %} ({{ i.Lesuren }}){% endif %} +{%- endmacro %} + +{% macro subnav(actief) %} +
+ 📋 Mijn aanvragen + {% if 'directie' in p_rollen %} + + ✅ Te beoordelen{% if p_te_beoordelen %} {{ p_te_beoordelen }}{% endif %} + {% endif %} + {% if 'secretariaat' in p_rollen %} + 🗓️ Dagoverzicht + {% endif %} +
+{% endmacro %} diff --git a/templates/_toestel_zoekveld.html b/templates/_toestel_zoekveld.html new file mode 100644 index 0000000..49cb33c --- /dev/null +++ b/templates/_toestel_zoekveld.html @@ -0,0 +1,90 @@ +{# Zoekvelden met suggesties voor uitdelen / inleveren: + - Internnummer ( +
    ): zoeken op internnummer of naam + - Toestelnummer ( +
      ): zoeken op toestel- of serienummer + Opties: toestel_voorkeur = 'beschikbaar' | 'uitgeleend' (die eerst tonen), + toestel_vul_intern = bij inleveren het andere veld automatisch invullen. #} + + diff --git a/templates/aanwezigheden.html b/templates/aanwezigheden.html new file mode 100644 index 0000000..ba6a599 --- /dev/null +++ b/templates/aanwezigheden.html @@ -0,0 +1,247 @@ +{% extends "base.html" %} + +{% block title %}Aanwezigheden internaat{% endblock %} +{% block page_title %}Aanwezigheden internaat{% endblock %} +{% block main_class %}wide{% endblock %} +{% block loader_text %}Register laden...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +
      +

      ✅ Aanwezigheden · {{ school_naam }}

      +
      + ← +
      + {{ dagen[0].day }} {{ ['jan','feb','mrt','apr','mei','jun','jul','aug','sep','okt','nov','dec'][dagen[0].month - 1] }} – + {{ dagen[6].day }} {{ ['jan','feb','mrt','apr','mei','jun','jul','aug','sep','okt','nov','dec'][dagen[6].month - 1] }} + {{ 'Deze week' if dagen[0] <= vandaag <= dagen[6] else 'Week ' ~ weeknr }} +
      + → + {% if not (dagen[0] <= vandaag <= dagen[6]) %} + Vandaag + {% endif %} +
      +
      + + {% if fout %} +
      {{ fout }}
      + {% elif not groepen %} +

      Er zijn deze week geen internen ingeschreven in Informat.

      + {% else %} +
      + +
      + Aanwezig + Afwezig + Nog niet gecontroleerd +
      +
      + +
      + + + + + {% for d in dagen %} + + {% endfor %} + + + {% for d in dagen %} + + + {% endfor %} + + + {% for groep, leden in groepen.items() %} + + + {% for r in leden %} + + + {% for d in dagen %}{% set i = loop.index0 %} + {% for m in ('ochtend', 'avond') %} + {% set st = data.get(r.pid ~ ':' ~ i ~ ':' ~ m, 'leeg') %} + + {% endfor %}{% endfor %} + + {% endfor %} + + {% endfor %} +
      Intern{{ dagnamen[loop.index0] }}{{ d.strftime('%d/%m') }}
      OA
      + +
      {{ r.naam }} {{ r.voornaam }}{{ r.kamer or r.vestiging }} + +
      +
      + +
      + 0 aanwezig + 0 afwezig + 0 nog te controleren + +
      +

      Klik op een vakje om te wisselen: nog niet gecontroleerd → aanwezig → afwezig. + Alles wordt meteen bewaard en is zichtbaar voor alle collega's met dit recht. De internen komen uit Informat.

      + {% endif %} +
      +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/admin_accounts.html b/templates/admin_accounts.html new file mode 100644 index 0000000..7b19cef --- /dev/null +++ b/templates/admin_accounts.html @@ -0,0 +1,143 @@ +{% extends "base.html" %} + +{% block title %}Gebruikers & rechten{% endblock %} +{% block page_title %}Gebruikers & rechten{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +
      +

      🔧 PIVOT-gebruikers

      +
      + +
      +
      +

      Eén account per persoon, voor alle scholen. Per school vink je aan op welke onderdelen iemand rechten heeft. + {% if is_admin %}Een administrator heeft altijd alle rechten in alle scholen.{% endif %}

      + +
      + + + + + + + + + + + + {% for u in users %} + + + + + + + + {% else %} + + {% endfor %} + +
      GebruikerRolRechten per schoolLaatste loginBeheren
      + {{ u.Gebruikersnaam }} + {% if not u.Actief %}uitgeschakeld{% endif %} + {% if u.Emailadres %}
      {{ u.Emailadres }}
      {% endif %} +
      {{ u.Rol }} + {% if u.Veiligheidsgroep == ADMIN %} + Alle rechten in alle scholen + {% else %} + {% for naam, n in u.scholen[:3] %} + 🏫 {{ naam }} · {{ n }} + {% else %} + Nog geen rechten + {% endfor %} + {% if u.scholen|length > 3 %} + +{{ u.scholen|length - 3 }} scholen + {% endif %} + {% endif %} + {{ u.Last_login.strftime('%d-%m-%Y %H:%M') if u.Last_login else '–' }} +
      + {% if u.Veiligheidsgroep != ADMIN %} + 🔐 Rechten + {% endif %} + 👤 Account +
      +
      Nog geen gebruikers.
      +
      +
      +{% endblock %} + +{% block modals %} + +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/admin_gebruiker.html b/templates/admin_gebruiker.html new file mode 100644 index 0000000..abf94e7 --- /dev/null +++ b/templates/admin_gebruiker.html @@ -0,0 +1,75 @@ +{% extends "base.html" %} + +{% block title %}{{ u.Gebruikersnaam }} – account{% endblock %} +{% block page_title %}Gebruiker: {{ u.Gebruikersnaam }}{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +← Alle gebruikers + +{# ---------------- Account ---------------- #} +
      +
      +

      👤 Account van {{ u.Gebruikersnaam }}

      + {% if u.Veiligheidsgroep != ADMIN %} + 🔐 Rechten + {% endif %} +
      +
      + + +
      + Laatste login: {{ u.Last_login.strftime('%d-%m-%Y %H:%M') if u.Last_login else 'nog nooit' }}{% if u.IP_laatste_login %} vanaf {{ u.IP_laatste_login }}{% endif %} +
      + +
      + + {% if is_admin and not zelf %} +
      + +
      + {% endif %} +
      +{% endblock %} diff --git a/templates/admin_rechten.html b/templates/admin_rechten.html new file mode 100644 index 0000000..06422d4 --- /dev/null +++ b/templates/admin_rechten.html @@ -0,0 +1,201 @@ +{% extends "base.html" %} + +{% block title %}{{ u.Gebruikersnaam }} – rechten{% endblock %} +{% block page_title %}Gebruiker: {{ u.Gebruikersnaam }}{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +← Alle gebruikers + +
      +
      +

      🔐 Rechten van {{ u.Gebruikersnaam }}

      + 👤 Account +
      + + {% if u.Veiligheidsgroep == ADMIN %} +
      {{ u.Gebruikersnaam }} is administrator en heeft daardoor altijd alle rechten in alle scholen. + De vinkjes hieronder gelden pas als de rol ooit "Gebruiker" wordt.
      + {% endif %} + + {% if not scholen %} +

      Je mag in geen enkele school rechten instellen.

      + {% else %} +
      + {# ---------- Scholen ---------- #} +
      +
      + + +
      + +
      + + {# ---------- Rechten van de gekozen school ---------- #} +
      + + + {% if gekozen %} +
      + +
      +

      🏫 {{ gekozen.naam }}

      +
      + + + +
      +
      +

      Zonder vinkje in deze school kan {{ u.Gebruikersnaam }} er niet inloggen.

      + + {% for cat, items in categorieen.items() %} +
      +
      + {{ cat }} + + + + +
      +
      + {% set ci = loop.index %} + {% for code, naam in items %} + + {% endfor %} +
      +
      + {% endfor %} + + {% if scholen|length > 1 %} +
      + 📋 Deze rechten ook toepassen op andere scholen… +

      De aangevinkte scholen krijgen exact dezelfde rechten als {{ gekozen.naam }}. Wat {{ u.Gebruikersnaam }} daar nu mag, wordt overschreven.

      + + +
      + {% for s in scholen if s.id != gekozen.id %} + + {% endfor %} +
      +
      + {% endif %} + + +
      + {% endif %} +
      +
      + {% endif %} +
      +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/afwezigheden.html b/templates/afwezigheden.html new file mode 100644 index 0000000..4107d2b --- /dev/null +++ b/templates/afwezigheden.html @@ -0,0 +1,208 @@ +{% extends "base.html" %} + +{% block title %}Afwezigheden{% endblock %} +{% block page_title %}Afwezigheden ({{ codes|join('/') }}-codes){% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{# ---------- Kerncijfers ---------- #} +
      +
      +
      {{ rows|length }}
      +
      Leerlingen met {{ f.code or codes|join('/') }}
      +
      +
      +
      {{ totaal_halve_dagen }}
      +
      Halve dagen
      + {% if rows %}
      gem. {{ '%.1f'|format(totaal_halve_dagen / rows|length) }} per leerling
      {% endif %} +
      +
      +
      + {% if laatste.m %}{{ laatste.m.strftime('%d-%m-%Y %H:%M') }}{% else %}Nog nooit{% endif %} +
      +
      Laatst gesynchroniseerd
      +
      Automatisch elke ochtend
      +
      +
      + +{% if fout %}
      {{ fout }}
      {% endif %} + +{% if not laatste.m and not status.bezig %} +
      + Er zijn nog geen gegevens opgehaald uit Smartschool. Klik op Nu synchroniseren om het huidige schooljaar op te halen + (de eerste keer duurt dit enkele minuten). +
      +{% endif %} + +{# ---------- Synchronisatie ---------- #} +
      +
      +
      + +
      +
      + + {% if status.bezig %}Bezig…{% elif status.laatste_resultaat %}{{ status.laatste_resultaat }}{% endif %} + +
      +
      + +{# ---------- Filters ---------- #} +
      +
      +
      +
      + + +
      +
      + + +
      +
      + + +
      +
      + + +
      + {% if codes|length > 1 %} +
      + + +
      + {% endif %} +
      + + Wissen +
      +
      +
      +
      + +{# ---------- Ranglijst ---------- #} +
      +
      +

      📋 Leerlingen

      +
      + {% if rows %}⬇️ Export CSV{% endif %} +
      +
      +
      + + + + + + + + + + + + + {% for r in rows %} + + + + + + + + + {% else %} + + {% endfor %} + +
      LeerlingInternnummerHalve dagenDagenEersteLaatste
      {% if r.Naam or r.Voornaam %}{{ r.Naam }} {{ r.Voornaam }}{% else %}Onbekend in PIVOT{% endif %} + {% if r.Gebruikersnaam %} · {{ r.Gebruikersnaam }}{% endif %}{{ r.Internnummer }}{{ r.Halve_dagen }}{{ r.Dagen }}{{ r.Eerste.strftime('%d-%m-%Y') }}{{ r.Laatste.strftime('%d-%m-%Y') }}
      + {% if laatste.m %}Geen leerlingen met {{ f.code or codes|join('/') }}-codes in deze periode.{% else %}Nog geen gegevens.{% endif %} +
      +
      +

      Klik op een leerling om de datums te zien. Vanaf 5 halve dagen kleurt het aantal rood.

      +
      +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..281aab0 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,147 @@ + + + + + + {% block title %}PIVOT{% endblock %} – {{ school_name_short|upper or 'PIVOT' }} + + + {% block head %}{% endblock %} + + {% block extra_css %}{% endblock %} + + + + {# ---------- Laadscherm (gedeeld) ---------- #} +
      +
      +
      {% block loader_text %}Verwerken...{% endblock %}
      + {% block loader_sub %}{% endblock %} +
      + + {# ---------- Header ---------- #} + {% block header %} +
      +
      + + + PIVOT + + {% block header_nav %} + 🏠 Home + {% endblock %} +
      + +

      {% block page_title %}{% endblock %}

      + +
      + {% if school %} + {% if is_superbeheerder %} + 🏫 {{ school.naam }} ⇄ + {% elif andere_scholen %} + + {% else %} + 🏫 {{ school.naam }} + {% endif %} + {% endif %} + {% if session.get('user') %} + 👤 {{ session.get('user') }} + {% endif %} +
      + +
      +
      +
      + {% endblock %} + +
      + {# ---------- Flash-berichten (gedeeld) ---------- #} + {% block flashes %} + {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
      + {% for category, message in messages %} + + {% endfor %} +
      + {% endif %} + {% endwith %} + {% endblock %} + + {% block content %}{% endblock %} +
      + + {% block modals %}{% endblock %} + + {% block footer %} +
      + {% if school %}{{ school.naam }} – {% endif %}PIVOT – Versie {{ version }} +
      + {% endblock %} + + + {% block scripts %}{% endblock %} + + diff --git a/templates/bingel.html b/templates/bingel.html new file mode 100644 index 0000000..0dbe38d --- /dev/null +++ b/templates/bingel.html @@ -0,0 +1,179 @@ +{% extends "base.html" %} + +{% block title %}Bingel{% endblock %} +{% block page_title %}Bingel{% endblock %} +{% block main_class %}wide{% endblock %} +{% block loader_text %}Leerlingen ophalen uit Informat...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +
      +

      📗 Bingel · {{ school_naam }}

      +
      + {% if rijen %}⬇️ Excel alle klassen{% endif %} + 🔄 Opnieuw ophalen +
      +
      +

      Alle leerlingen uit Informat, klaar voor de import in Bingel. Kolommen in de Excel: + {{ kolommen|join(', ') }}. Het wachtwoord blijft leeg; het klasnummer is alfabetisch binnen de klas (familienaam, voornaam).

      + + {% if fout %} +
      {{ fout }}
      + {% elif not rijen %} +

      Informat gaf geen leerlingen terug.

      + {% else %} + {% if waarschuwing %}
      {{ waarschuwing }}
      {% endif %} +
      + + + {% if zonder_klas %}{% endif %} + {% if zonder_geslacht %}{% endif %} +
      +
      +
      + Klassen in de lijst + + +
      +
      + {% for k in klassen %} + + {% endfor %} +
      +
      +
      + + +
      +
      + + {% for k in kolommen %}{% endfor %} + + {% for r in rijen %} + + + + + + + + + {% endfor %} + +
      {{ k }}{% if k != 'Wachtwoord' %} {% endif %}
      {{ r.klas }}{{ r.voornaam }}{{ r.naam }}{{ r.klasnummer if r.klasnummer is not none else '' }}{{ r.geslacht }}
      +
      +
      +
      + +
      + {% if (zonder_klas or zonder_nummer or zonder_geslacht) and voorbeeld %} +
      + Velden die Informat teruggeeft (om na te kijken waarom iets leeg blijft) +

      Leerling: {{ voorbeeld.leerling|join(', ') }}

      +

      Inschrijving: {{ voorbeeld.inschrijving|join(', ') or '— geen inschrijvingen ontvangen —' }}

      + {% if voorbeeld.klas_item %}

      Voorbeeld van een klas (inschrKlassen): {{ voorbeeld.klas_item }}

      {% endif %} +
      + {% endif %} + {% endif %} +
      +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/bugreport.html b/templates/bugreport.html new file mode 100644 index 0000000..d51d40d --- /dev/null +++ b/templates/bugreport.html @@ -0,0 +1,53 @@ +{% extends "base.html" %} + +{% block title %}Bug rapporteren{% endblock %} +{% block page_title %}🐞 Bug rapporteren{% endblock %} +{% block header_class %}header--bug{% endblock %} +{% block main_class %}medium{% endblock %} +{% block loader_text %}Bugreport verwerken...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +
      +

      Fout of bug rapporteren

      + +
      +
      + + +
      +
      + + +
      +
      + + +
      + +
      +
      + +
      +

      ℹ️ Informatie

      +

      Heeft de applicatie een probleem of werkt er iets niet naar behoren? Meld het direct aan het supportteam.

      +
      + Automatische gegevens +
        +
      • Gebruiker: wordt automatisch gekoppeld aan jouw account.
      • +
      • Status: staat standaard op Nieuw.
      • +
      +
      +

      + Probeer de omschrijving zo nauwkeurig mogelijk in te vullen, zodat we het probleem snel kunnen reproduceren en oplossen. +

      +
      +
      +{% endblock %} diff --git a/templates/bugreport_overzicht.html b/templates/bugreport_overzicht.html new file mode 100644 index 0000000..939419a --- /dev/null +++ b/templates/bugreport_overzicht.html @@ -0,0 +1,102 @@ +{% extends "base.html" %} + +{% block title %}Bugoverzicht{% endblock %} +{% block page_title %}🐞 Bugoverzicht{% endblock %} +{% block header_class %}header--bug{% endblock %} +{% block main_class %}wide{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +
      +

      Ingediende bugreports

      + +
      + +
      + + + + + + + + + + + + + + {% for bug in results %} + + + + + + + + + + {% else %} + + {% endfor %} + +
      IDGebruikerDatum / tijdOmschrijvingFoutcodeStatusActie
      #{{ bug.Bug_ID }}{{ bug.Gebruiker }}{{ bug.Datum.strftime('%d-%m-%Y %H:%M') if bug.Datum else '' }}{{ bug.Omschrijving }} + {% if bug.Foutcode %}{{ bug.Foutcode }} + {% else %}Geen{% endif %} + + {% if bug.Status == 'Fixed' %}✅ Fixed + {% elif bug.Status == 'In behandeling' %}🧑‍💻 In behandeling + {% else %}ℹ️ Nieuw + {% endif %} + + +
      Er zijn momenteel geen bugreports.
      +
      +
      +{% endblock %} + +{% block modals %} + +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/contacten.html b/templates/contacten.html new file mode 100644 index 0000000..ab46d03 --- /dev/null +++ b/templates/contacten.html @@ -0,0 +1,352 @@ +{% extends "base.html" %} + +{% block title %}Contacten{% endblock %} +{% block page_title %}Contacten{% endblock %} +{% block main_class %}wide{% endblock %} +{% block loader_text %}Bezig met Google...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} + + +{% if fout %}
      {{ fout }}
      {% endif %} + +{# ======================= 1. Contactlijsten ======================= #} +{% if tab == 'lijsten' %} +
      +

      📇 Contactlijsten in de mailboxen

      +

      Een lijst is een label in Google Contacten (bv. "School - Directie") met vaste contacten. + PIVOT zet die contacten in de persoonlijke contacten van iedereen in de gekozen OU's en houdt ze bij: aanpassen of verwijderen + in de lijst doet PIVOT ook in de mailboxen. Andere contacten van de gebruikers blijven onaangeroerd.

      + +
      +
      {{ status.lijst or '' }} · {{ status.voortgang }} / {{ status.totaal }} mailboxen{% if status.fouten %} · ⚠️ {{ status.fouten }}{% endif %}
      +
      +
      {{ status.resultaat or '' }}
      +
      {{ status.fout or '' }}
      +
        {% for f in status.foutvoorbeelden %}
      • {{ f }}
      • {% endfor %}
      +
      + + {% if lijsten is defined %} + + {% endif %} +
      + +{% if gekozen or nieuw %} +{% set l = gekozen or {} %} +
      +
      +

      {{ '✏️ ' ~ l.Naam if gekozen else '➕ Nieuwe contactlijst' }}

      +
      + {% if gekozen %} + + + {% endif %} + +
      +
      + {% if gekozen and gekozen.Resultaat %}

      Laatste keer: {{ gekozen.Resultaat }}

      {% endif %} +
      +
      +
      +
      + {% if gekozen and gekozen.Laatste_sync %}

      Wijzig je de naam of de OU's, dan past PIVOT dat na het bewaren ook in de mailboxen aan.

      {% endif %} +
      +
      + +
      + {% for ou in ous %}{% endfor %} +
      + +
      +
      + +

      Contacten in deze lijst

      +
      + + + +
      VoornaamAchternaamOrganisatieFunctieE-mailTelefoonNotitie
      +
      +
      + + Tip: plak meerdere regels uit Excel (voornaam, achternaam, organisatie, functie, e-mail, telefoon) in het eerste veld. +
      +

      Vereist in de domeinbrede delegatie: https://www.googleapis.com/auth/contacts, en de + People API moet aanstaan in het Google Cloud-project van het serviceaccount.

      +
      +{% endif %} +{% endif %} + +{# ======================= 2. Adresboek ======================= #} +{% if tab == 'adresboek' %} +
      +

      👥 Adresboek van de organisatie

      +

      Wie verborgen is, verschijnt niet meer in het adresboek van de school en niet bij het + aanvullen van e-mailadressen in Gmail (bv. leerlingen verbergen voor elkaar). De mailbox zelf blijft gewoon werken.

      +
      + + + + +
      + + {% if ou and gebruikers is defined %} + {% if gebruikers %} + {% set verborgen = gebruikers|rejectattr('zichtbaar')|list|length %} +
      + + {{ gebruikers|length }} gebruiker(s) · {{ verborgen }} verborgen +
      + + + + +
      +
      +
      + + + + + {% for u in gebruikers %} + + + + + + + + + {% endfor %} + +
      NaamE-mailOUIn het adresboek
      {{ u.naam }}{% if u.geschorst %} geschorst{% endif %}{{ u.email }}{{ u.ou }}{% if u.zichtbaar %}zichtbaar{% else %}verborgen{% endif %}
      +
      + {% else %}

      Geen gebruikers in deze OU.

      {% endif %} + {% elif not fout %}

      Kies een OU.

      {% endif %} +

      Of het adresboek voor iedereen zichtbaar is, stel je in de Admin-console in + (Directory › Instellingen voor directory › Zichtbaarheid); dat kan niet via de API.

      +
      +{% endif %} +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/dashboard.html b/templates/dashboard.html new file mode 100644 index 0000000..0241a15 --- /dev/null +++ b/templates/dashboard.html @@ -0,0 +1,268 @@ +{% extends "base.html" %} + +{% block title %}Dashboard{% endblock %} +{% block page_title %}Dashboard{% endblock %} +{% block header_nav %}{% endblock %} + +{% block content %} + +
      + {% if mag('toestellen_beheren', 'eigendom_bekijken', 'toestellen_uitdelen', 'herstellingen', 'signpost') %} +
      +
      + {# Het icoon van Chrome zelf (google.com/chrome); lukt dat niet, dan het gewone icoon #} + +

      Chromebooks

      + +
      + {% endif %} + + {% if mag('google_wachtwoord', 'google_accounts', 'tweestaps_codes', 'tweestaps_uitzetten', 'google_licenties', 'gedeelde_drives') %} +
      +
      + {# Het icoon van Google zelf (google.com); lukt dat niet, dan het gewone icoon #} + +

      Google

      + +
      + {% endif %} + + {% if mag('gmail_delegatie', 'verzendlijsten', 'gmail_labels', 'gmail_handtekeningen', 'gmail_contacten') %} +
      +
      + {# Het icoon van Gmail zelf; lukt dat niet, dan het gewone icoon #} + +

      Gmail

      + +
      + {% endif %} + + {% if mag('smartschool', 'smartschool_activiteit', 'afwezigheden', 'laatkomers', 'skore', 'sgr_groepen') %} + {% set ss_platform = (school.waarden.get('SS_API_PLATFORM') if school else '') or '' %} + {% set ss_platform = ss_platform.replace('https://', '').replace('http://', '').strip('/') %} +
      +
      + {# Het icoon van het eigen Smartschool-platform; lukt dat niet, dan het gewone icoon #} + {% if ss_platform %}{% else %}🏫{% endif %} +

      Smartschool

      + +
      + {% endif %} + + {% if mag('leerlingen_bekijken', 'leerlingenaantal') %} +
      +
      🎒

      Leerlingen

      + +
      + {% endif %} + + {% if mag('internen', 'internaat_aanwezigheid') %} +
      +
      🛏️

      Internaat

      + +
      + {% endif %} + + {% if school and school.waarden.get('ONDERWIJSNIVEAU') == 'basis' and mag('bingel') %} +
      +
      🎨

      Basisonderwijs

      + +
      + {% endif %} + + {% if mag('leerlingfacturatie') %} +
      +
      🧾

      Leerlingfacturatie

      + +
      + {% endif %} + + {% if mag('gopro', 'personeelsaantal') %} +
      +
      🧑‍🏫

      Personeel

      + +
      + {% endif %} + +
      +
      🗓️

      Afwezigheden & activiteiten

      + +
      + +
      +
      🐞

      Bugs

      + +
      + + {% if mag_handleidingen() %} + {% set hls = handleidingen_lijst() %} +
      +
      📘

      Handleidingen

      + +
      + {% endif %} + +
      +
      + +

      Scholengroep

      + +
      + + {% if mag('qr_codes') %} +
      +
      🧰

      Tools

      + +
      + {% endif %} + + {% if school %} + {% set web_domein = (school.domein or '').strip().lower() %} + {% set ss_url = ((school.waarden.get('SS_API_PLATFORM') or '').replace('https://', '').replace('http://', '').strip().strip('/')) %} +
      +
      🏫

      Links

      + +
      + {% endif %} +
      + +{% if mag('co2', 'koppelingen', 'gebruikersbeheer', 'nieuw_schooljaar', 'ip_whitelist', 'database_toestellen') or is_admin or is_superbeheerder %} +
      ⚙️ Beheer
      + +
      + {% if mag('gebruikersbeheer', 'koppelingen') or is_superbeheerder %} +
      +
      🏢

      PIVOT

      + +
      + {% endif %} + + {% if is_admin or mag('ip_whitelist') %} +
      +
      🛡️

      Beveiliging

      + +
      + {% endif %} + + {% if mag('co2') or is_admin %} +
      +
      🌐

      IoT

      + +
      + {% endif %} + + {% if mag('nieuw_schooljaar') %} +
      +
      📚

      Nieuw schooljaar

      + +
      + {% endif %} + + {% if mag('database_toestellen') %} +
      +
      🗄️

      Database

      + +
      + {% endif %} +
      +{% endif %} +{% endblock %} diff --git a/templates/database_toestellen.html b/templates/database_toestellen.html new file mode 100644 index 0000000..36c15a9 --- /dev/null +++ b/templates/database_toestellen.html @@ -0,0 +1,161 @@ +{% extends "base.html" %} + +{% block title %}Toestellen importeren{% endblock %} +{% block page_title %}Database › Toestellen{% endblock %} +{% block loader_text %}Bestand controleren...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{% if not plan %} +
      +
      +

      1Sjabloon downloaden

      +

      Vul het sjabloon in met één toestel per rij. De kolom Lokaal heeft een keuzelijst met + de lokalen van {{ school.naam if school else 'deze school' }}.

      + ⬇️ Sjabloon downloaden (.xlsx) +
        + {% for k in kolommen %} +
      • {{ k[1] }} {{ k[3] }}
      • + {% endfor %} +
      +
      + +
      +

      2Excel uploaden

      +

      Je krijgt eerst een voorbeeld te zien. Er wordt pas iets bewaard als je bevestigt. + {% if aantal is not none %}Er staan nu {{ aantal }} toestellen in de database.{% endif %}

      +
      +
      + + +
      Max. {{ max_rijen }} rijen. Het tabblad Toestellen wordt gelezen (of anders het eerste tabblad).
      +
      + +
      + + +
      + +
      +
      +
      + +{% else %} +{% set t = plan.tellers %} +
      +
      +

      🔎 Voorbeeld: {{ bestandsnaam }}

      + ↩️ Ander bestand +
      +

      Nog niets bewaard. Bestaande toestellen: + {{ 'ingevulde cellen overschrijven' if plan.modus == 'overschrijven' else 'enkel lege velden aanvullen' }}.

      + {% if onbekend %} +
      Deze kolommen worden genegeerd: {{ onbekend|join(', ') }}.
      + {% endif %} + +
      + + + + + +
      + +
      + + + + + {% for k in kolommen %}{% endfor %} + + + + + {% for r in plan.rijen %} + + + + {% for k in kolommen %}{% endfor %} + + + {% endfor %} + +
      RijActie{{ k[1] }}Wat gebeurt er
      {{ r.rij }} + {% if r.actie == 'nieuw' %}➕ Nieuw + {% elif r.actie == 'bijwerken' %}✏️ Bijwerken + {% elif r.actie == 'ongewijzigd' %}= Ongewijzigd + {% else %}⚠️ Fout{% endif %} + {{ r.invoer[k[0]] }} + {% if r.actie == 'fout' %}{% for m in r.meldingen %}
      {{ m }}
      {% endfor %} + {% else %} + {% if r.actie == 'nieuw' %}
      Wordt toegevoegd{% if not r.invoer.status %} (status Beschikbaar){% endif %}.
      {% endif %} + {% if r.label %}
      Toestel {{ r.label }}
      {% endif %} + {% for w in r.wijzigingen %}
      {{ w }}
      {% endfor %} + {% for m in r.meldingen %}
      {{ m }}
      {% endfor %} + {% endif %} +
      +
      + + {% set te_doen = t.nieuw + t.bijwerken %} +
      + + + + {% if te_doen %}{{ t.nieuw }} nieuw en {{ t.bijwerken }} bij te werken toestel(len). + {% if t.fout %}Rijen met een fout worden overgeslagen; verbeter ze in Excel en upload opnieuw.{% endif %} + {% else %}Er is niets te importeren.{% endif %} + + + Annuleren + + +
      +
      +{% endif %} +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/facturatie.html b/templates/facturatie.html new file mode 100644 index 0000000..76ba698 --- /dev/null +++ b/templates/facturatie.html @@ -0,0 +1,213 @@ +{% extends "base.html" %} + +{% block title %}Leerlingfacturatie{% endblock %} +{% block page_title %}Leerlingfacturatie{% endblock %} +{% block main_class %}wide{% endblock %} +{% block loader_text %}Facturen ophalen uit Informat...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +
      +

      🧾 Facturen leerlingen · {{ school_naam }}

      +
      +
      + +
      + {% if rijen %}⬇️ CSV{% endif %} + 🔄 Opnieuw ophalen +
      +
      + + {% if fout %} +
      {{ fout }}
      + {% elif not rijen %} +

      Geen geboekte facturen gevonden voor schooljaar {{ schooljaar }}{% if groepen %} ({{ groepen|length }} factuurgroep(en) voor leerlingen){% endif %}.

      + {% else %} +
      +
      Facturen0
      +
      Totaal€ 0,00
      +
      Betaald€ 0,00
      +
      Nog te betalen€ 0,00
      +
      + +
      +
      + + + + +
      +
      +
      + + {% if groepen|length > 1 %} + + {% endif %} + + Opgehaald uit Informat op {{ opgehaald }} +
      + +
      + + + + + + + + + + + + + + + + + + {% for r in rijen %} + {% set vervallen = r.status in ('open', 'gedeeltelijk') and r.vervaldag and r.vervaldag < today %} + + + + + + + + + + + + + + {% endfor %} + +
      Leerling Klas Factuurgroep Datum Vervaldag Totaal Betaald Open Status Mededeling
      {{ r.naam }} {{ r.voornaam }}{% if r.stamnummer %}
      stamnr. {{ r.stamnummer }}{% endif %}
      {{ r.klas }}{% if r.klasnummer %} nr. {{ r.klasnummer }}{% endif %}{{ r.groep }}{{ r.datum.strftime('%d-%m-%Y') if r.datum else '' }}{{ r.vervaldag.strftime('%d-%m-%Y') if r.vervaldag else '' }}{{ '− ' if r.teken < 0 }}{{ '€ %.2f'|format(r.totaal)|replace('.', ',') }}{{ '€ %.2f'|format(r.betaald)|replace('.', ',') }}{% if r.open %}{{ '€ %.2f'|format(r.open)|replace('.', ',') }}{% else %}€ 0,00{% endif %} + {% if r.status == 'betaald' %}Betaald + {% elif r.status == 'credit' %}Creditnota + {% elif vervallen %}Vervallen + {% elif r.status == 'gedeeltelijk' %}Gedeeltelijk + {% else %}Open{% endif %} + {% if r.ogm|length == 12 %}+++{{ r.ogm[:3] }}/{{ r.ogm[3:7] }}/{{ r.ogm[7:] }}+++{% else %}{{ r.ogm }}{% endif %} + {%- if r.ogm_factuur %}
      bij {{ r.ogm_factuur }}{% endif %}
      + 📄 PDF +
      +
      +
      +
      + +
      + {% endif %} +
      +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/gedeelde_drives.html b/templates/gedeelde_drives.html new file mode 100644 index 0000000..3f2ed68 --- /dev/null +++ b/templates/gedeelde_drives.html @@ -0,0 +1,320 @@ +{% extends "base.html" %} + +{% block title %}Gedeelde drives{% endblock %} +{% block page_title %}Gedeelde drives{% endblock %} +{% block main_class %}wide{% endblock %} +{% block loader_text %}Gedeelde drives ophalen bij Google...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{% if lid_van is not none %} +{# ======================= Waar is iemand lid van? ======================= #} +
      +
      +

      🔎 {{ lid }}

      + +
      + {% if fout %}
      {{ fout }}
      + {% elif not lid_van %} +

      {{ lid }} is op geen enkele gedeelde drive lid (rechtstreeks; lidmaatschap via een Google-groep telt hier niet mee).

      + {% else %} +

      Lid van {{ lid_van|length }} gedeelde drive(s) (rechtstreeks; lidmaatschap via een Google-groep telt hier niet mee).

      +
      + {% set meerdere = (lid_van|map(attribute='email')|unique|list|length) > 1 or '@' not in lid %} + {% if meerdere %}{% endif %} + {% for d in lid_van %} + + {% if meerdere %}{% endif %} + + + {% endfor %} +
      DriveLidRol
      {{ d.naam }}{{ d.wie }}{% if d.wie != d.email %}
      {{ d.email }}{% endif %}
      {{ d.rol_naam }}Openen in Drive ↗
      + {% if '@' in lid %} +
      + + 🔁 Op al deze drives vervangen door + + +
      + {% endif %} + {% endif %} +
      + +{% elif vervang %} +{# ======================= Gebruiker vervangen ======================= #} +
      +
      +

      🔁 {{ vervang.oud }} → {{ vervang.nieuw or '?' }}

      + +
      + {% if fout %}
      {{ fout }}
      + {% elif resultaat is not none %} + {% set ok = resultaat|selectattr('ok')|list|length %} +
      {{ ok }} van {{ resultaat|length }} drive(s) aangepast.
      +
      + + {% for r in resultaat %}{% endfor %} +
      DriveResultaat
      {{ r.naam }}{{ '✅' if r.ok else '⚠️' }}{{ r.melding }}
      + {% elif not vervang.drives %} +

      {{ vervang.oud }} is op geen enkele gedeelde drive lid.

      + {% else %} +

      {{ vervang.oud }} is lid van {{ vervang.drives|length }} gedeelde drive(s). + {{ vervang.nieuw }} krijgt op elke aangevinkte drive exact dezelfde rol (ook als die er al lid van was).

      +
      + +
      + + + {% for d in vervang.drives %} + + + {% endfor %} +
      DriveRol van {{ vervang.oud }}
      {{ d.naam }}{{ d.rol_naam }}
      +
      + + + +
      +
      + {% endif %} +
      + +{% elif gekozen %} +{# ======================= Detail van één drive ======================= #} +
      +
      +

      🗂️ {{ gekozen.naam }}

      + +
      +

      {{ gekozen.leden }} lid/leden · {{ gekozen.beheerders }} beheerder(s) + {% if gekozen.aangemaakt %} · aangemaakt {{ gekozen.aangemaakt }}{% endif %}

      + {% if not gekozen.beheerders %}
      ⚠️ Deze drive heeft geen beheerder. Voeg hieronder iemand toe als Beheerder.
      {% endif %} + {% if gekozen.extern %}
      🌍 {{ gekozen.extern }} lid/leden van buiten de school.
      {% endif %} + +
      + +
      +
      +
      +
      + + +
      + +
      + + + + {% for l in leden %} + + + + + + + + {% else %} + + {% endfor %} + +
      NaamE-mailSoortRol
      {{ l.naam or '—' }}{% if l.extern %} extern{% endif %} + {% if l.verwijderd %} account verwijderd{% endif %}{{ l.email }}{{ {'user': 'persoon', 'group': 'groep', 'domain': 'domein', 'anyone': 'iedereen met link'}.get(l.type, l.type) }} +
      + + + +
      +
      +
      + + + +
      +
      Deze drive heeft geen leden.
      +
      +

      Beheerder: alles, ook leden beheren · Inhoudsbeheerder: + bestanden toevoegen, bewerken, verplaatsen en verwijderen · Bijdrager: toevoegen en bewerken · + Reageerder: bekijken en reageren · Lezer: enkel bekijken.

      +
      + +{% else %} +{# ======================= Overzicht ======================= #} +
      +
      +

      🗂️ Gedeelde drives ({{ drives|length }})

      +
      + + 🔄 Opnieuw ophalen +
      +
      +
      + 🔎 Waar is iemand lid van? + + +
      +
      + 🔁 Gebruiker vervangen + + → + + +
      + {% if fout %} +
      {{ fout }}
      + {% elif not drives %} +

      Er zijn nog geen gedeelde drives in dit domein.

      + {% else %} + {% set zonder = drives|selectattr('beheerders', 'equalto', 0)|list|length %} + {% set ext = drives|selectattr('extern')|list|length %} +
      + +
      + + {% if zonder %}{% endif %} + {% if ext %}{% endif %} +
      + + Opgehaald op {{ opgehaald }} +
      +
      + + + + + + + + + + + {% for d in drives %} + + + + + + + + + {% endfor %} + +
      Naam Leden Beheerders Groepen Extern Aangemaakt
      {{ d.naam }}{% if d.fout %} leden niet op te halen{% endif %}{{ d.leden }}{% if d.beheerders %}{{ d.beheerders }}{% else %}geen{% endif %}{{ d.groepen or '' }}{% if d.extern %}{{ d.extern }}{% endif %}{{ d.aangemaakt }}
      +
      +
      +
      + +
      + {% endif %} +

      Vereist in de domeinbrede delegatie: https://www.googleapis.com/auth/drive, + en de Google Drive API moet aanstaan in het Cloud-project van het serviceaccount.

      +
      +{% endif %} +{% endblock %} + +{% block modals %} + +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/gmail_delegatie.html b/templates/gmail_delegatie.html new file mode 100644 index 0000000..890ab1a --- /dev/null +++ b/templates/gmail_delegatie.html @@ -0,0 +1,273 @@ +{% extends "base.html" %} + +{% block title %}Mailbox-delegatie{% endblock %} +{% block page_title %}Mailbox-delegatie{% endblock %} +{% block main_class %}medium{% endblock %} +{% block loader_text %}Bezig met Google...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{# ---------- Zoeken ---------- #} +
      +

      ✉️ Welke mailbox?

      + + + {% if zoekresultaten %} +

      Kies een mailbox:

      + + {% endif %} +
      + +{% if fout %} +
      {{ fout }}
      +{% endif %} + +{# ---------- Gedelegeerden van de gekozen mailbox ---------- #} +{% if mailbox %} +
      +
      + {{ (mailbox.naam or mailbox.email)[:1]|upper }} +
      + {{ mailbox.naam or mailbox.email }} + {{ mailbox.email }}{% if mailbox.ou %} · {{ mailbox.ou }}{% endif %} + {% if mailbox.geschorst %}Geschorst{% endif %} +
      + {{ delegates|length }} / {{ max_delegates }} gedelegeerden +
      + +
      + + + + + + {% for d in delegates %} + + + + + + {% else %} + + {% endfor %} + +
      Heeft toegangStatusActie
      {{ d.email }} + {% if d.status == 'accepted' %}{{ d.status_label }} + {% elif d.status == 'pending' %}{{ d.status_label }} + {% else %}{{ d.status_label }}{% endif %} + +
      + + + +
      +
      Niemand anders heeft toegang tot deze mailbox.
      +
      + + {% if delegates|length < max_delegates %} +
      + + + +
      +

      Enkel accounts van jullie eigen Google Workspace. De collega ziet de mailbox binnen ongeveer een minuut via het profielmenu in Gmail.

      + {% else %} +
      Deze mailbox heeft het maximum van {{ max_delegates }} gedelegeerden bereikt.
      + {% endif %} +
      +{% endif %} + +{# ---------- Alle lopende machtigingen ---------- #} +
      +
      +

      📋 Lopende machtigingen ({{ machtigingen|length }})

      +
      + +
      +
      +

      + {% if laatst and laatst.Opgehaald %}Alle mailboxen nagekeken op {{ laatst.Opgehaald.strftime('%d-%m-%Y om %H:%M') }} + ({{ laatst.Mailboxen }} mailboxen{% if laatst.Fouten %}, {{ laatst.Fouten }} niet bevraagbaar{% endif %}). + Wijzigingen via PIVOT staan er meteen in. + {% else %}Nog niet opgehaald.{% endif %} +

      + {% if ov_fout %}
      {{ ov_fout }}
      {% endif %} + {% if ov_status.fout and not ov_status.bezig %}
      Ophalen mislukt: {{ ov_status.fout }}
      {% endif %} +
      + Mailboxen nakijken... +
      +
      + + {% if machtigingen %} +
      + + +
      +
      + + + + + + + + + + + {% for m in machtigingen %} + + + + + + + {% endfor %} + +
      Mailbox Heeft toegang Status
      {{ m.Mailbox_naam or m.Mailbox }}{% if m.Mailbox_naam %}{{ m.Mailbox }}{% endif %}{{ m.Gedelegeerde_naam or m.Gedelegeerde }}{% if m.Gedelegeerde_naam %}{{ m.Gedelegeerde }}{% endif %} + {% if m.Status == 'accepted' %}Actief + {% elif m.Status == 'pending' %}In afwachting + {% elif m.Status == 'rejected' %}Geweigerd + {% elif m.Status == 'expired' %}Verlopen + {% else %}{{ m.Status or '?' }}{% endif %} + Openen
      +
      +
      +
      + +
      + {% elif laatst and laatst.Opgehaald %} +

      Er zijn geen lopende machtigingen.

      + {% endif %} +
      + +{# ---------- Logboek ---------- #} +{% if geschiedenis %} +
      +

      🕑 {{ 'Wijzigingen voor deze mailbox' if mailbox else 'Recente wijzigingen' }}

      +
      + + + + {% for h in geschiedenis %} + + + + + + + + {% endfor %} + +
      TijdstipDoorActieMailboxGedelegeerde
      {{ h.Tijdstip.strftime('%d-%m-%Y %H:%M') if h.Tijdstip else '' }}{{ h.Gebruiker or '?' }}{% if h.Actie == 'toegevoegd' %}Toegevoegd{% else %}Ingetrokken{% endif %}{{ h.Mailbox }}{{ h.Gedelegeerde }}
      +
      +
      +{% endif %} +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/gmail_labels.html b/templates/gmail_labels.html new file mode 100644 index 0000000..3c544d4 --- /dev/null +++ b/templates/gmail_labels.html @@ -0,0 +1,159 @@ +{% extends "base.html" %} + +{% block title %}Mails verplaatsen{% endblock %} +{% block page_title %}Mails verplaatsen{% endblock %} +{% block main_class %}medium{% endblock %} +{% block loader_text %}Bezig met Google...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +

      🏷️ Berichten met een label naar een andere mailbox

      +

      Kies de mailbox en het label. PIVOT kopieert elk bericht met dat label (met bijlagen, + originele datum, gelezen/ongelezen en ster) naar de doelmailbox, onder een label met dezelfde naam.

      + +
      +
      +
      + + +
      + +
      + + {% if bron %} +
      📬 {{ bron.naam or bron.email }} · {{ bron.email }}{% if bron.ou %} · {{ bron.ou }}{% endif %}
      + {% if labels %} +
      + + +
      +
      + + +
      +
      + {% elif not fout %} +

      Deze mailbox heeft geen eigen labels.

      + {% endif %} + {% endif %} +
      + + {% if fout %}
      {{ fout }}
      {% endif %} + + {% if bron and doel and gekozen %} +
      + + + + +
      + + +
      +
      + {{ gekozen.aantal if gekozen.aantal is not none else '?' }} bericht(en) met label {{ gekozen.naam }} + {{ bron.email }} → {{ doel.email }} + +
      +
      + {% endif %} +
      + +{% if status.bezig or status.resultaat or status.fout %} +
      +

      ⏳ Opdracht

      + {% if status.opdracht %}

      Label {{ status.opdracht.label }}: + {{ status.opdracht.bron }} → {{ status.opdracht.doel }} ({{ 'verplaatsen' if status.opdracht.modus == 'verplaatsen' else 'kopiëren' }})

      {% endif %} +
      +
      + {{ status.voortgang }} / {{ status.totaal }} + ✅ {{ status.gelukt }} gelukt + ⏭️ {{ status.overgeslagen }} stonden er al + ⚠️ {{ status.fouten }} mislukt +
      +
      {{ status.resultaat or '' }}
      +
      {{ status.fout or '' }}
      +
        {% for f in status.foutvoorbeelden %}
      • {{ f }}
      • {% endfor %}
      +
      +{% endif %} + +{% if geschiedenis %} +
      +

      🕑 Vorige opdrachten

      +
      + + + + {% for h in geschiedenis %} + + + + + + + + + + {% endfor %} + +
      GestartDoorLabelVan → naarSoortGeluktMislukt
      {{ h.Gestart.strftime('%d-%m-%Y %H:%M') }}{% if not h.Klaar %} bezig{% endif %}{{ h.Door or '' }}{{ h.Label }}{{ h.Bron }} → {{ h.Doel }}{{ 'Verplaatst' if h.Modus == 'verplaatsen' else 'Gekopieerd' }}{{ h.Gelukt if h.Gelukt is not none else '' }}{% if h.Overgeslagen %} (+{{ h.Overgeslagen }}){% endif %}{{ h.Fouten or '' }}
      +
      +
      +{% endif %} + +

      Eenmalig nodig in de Google Admin-console (Beveiliging › API-beheer › Domeinbrede delegatie, bij het + serviceaccount van PIVOT): het bereik {{ scope }}. Een onderbroken opdracht kan je gewoon opnieuw starten: + berichten die al gekopieerd werden, worden overgeslagen.

      +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/google_beheer.html b/templates/google_beheer.html new file mode 100644 index 0000000..8632e44 --- /dev/null +++ b/templates/google_beheer.html @@ -0,0 +1,162 @@ +{% extends "base.html" %} + +{% block title %}Google beheer{% endblock %} +{% block page_title %}Google accountbeheer{% endblock %} +{% block main_class %}medium{% endblock %} +{% block loader_text %}Verzoek verwerken...{% endblock %} + +{% block content %} +
      +
      +

      🔍 Zoek Google-account

      +
      + +
      +
      + + + + {% if results %} +
      + + + + + + + + + + {% for user in results %} + + + + + + {% endfor %} + +
      NaamPrimair e-mailadresActie
      {{ user.name.fullName }}{{ user.primaryEmail }} + +
      +
      + {% elif query %} +

      Geen resultaten gevonden voor "{{ query }}".

      + {% endif %} +
      +{% endblock %} + +{% block modals %} + + + +{% endblock %} + +{% block footer %} +
      {{ school_name_short }} – PIVOT – Versie {{ version }} – Google Admin Tools
      +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/google_licenties.html b/templates/google_licenties.html new file mode 100644 index 0000000..24d70bc --- /dev/null +++ b/templates/google_licenties.html @@ -0,0 +1,269 @@ +{% extends "base.html" %} + +{% block title %}Google-licenties{% endblock %} +{% block page_title %}Google-licenties{% endblock %} +{% block loader_text %}Licenties ophalen bij Google...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +
      +

      🎓 Google Workspace for Education-licenties

      + {% if opgehaald %}
      Gegevens van Google opgehaald om {{ opgehaald }}
      {% endif %} +
      +
      + + {% if data %}⬇️ Export CSV{% endif %} + 🔄 Vernieuwen +
      +
      + +{% if fout %} +
      Licenties konden niet opgehaald worden.
      {{ fout }}
      +{% endif %} + +{% if data %} +
      + {% for s in data.skus %} + {% set state = 'over' if s.aangekocht and s.vrij < 0 else ('low' if s.procent is not none and s.procent >= 90 else '') %} +
      +
      {{ s.naam }}
      +
      SKU {{ s.sku_id }}
      + +
      +
      {{ s.in_gebruik }}
      In gebruik
      +
      {{ s.aangekocht if s.aangekocht else '–' }}
      Aangekocht
      +
      {{ s.vrij if s.aangekocht else '–' }}
      {{ 'Tekort' if state == 'over' else 'Vrij' }}
      +
      + + {% if s.aangekocht %} +
      +
      + {{ s.procent }}% gebruikt + {% if s.bijgewerkt %}aantal: {{ s.bijgewerkt.strftime('%d-%m-%Y') }}{% endif %} +
      + {% else %} +
      Vul het aangekochte aantal in om te zien hoeveel er nog vrij zijn.
      + {% endif %} + + {% if state == 'over' %} +
      {{ -s.vrij }} licentie(s) meer toegewezen dan aangekocht.
      + {% endif %} + {% if s.geschorst %} +
      + {{ s.geschorst }} op geschorste of gearchiveerde accounts – + bekijken +
      + {% endif %} +
      + {% endfor %} +
      + +
      +

      Toegewezen licenties

      + +
      + + + +
      + +
      + + + + + + + + + + + + + {% for u in data.users %} + + + + + + + {# volgorde bij sorteren: actief → geschorst → gearchiveerd → onbekend #} + + + {% else %} + + {% endfor %} + + +
      Naam E-mail Organisatie-eenheid Licentie Laatste login Account
      {{ u.naam }}{{ u.email }}{{ u.ou }}{{ u.sku_naam }}{{ u.laatste_login or 'Nooit' }} + {% if u.gearchiveerd %}Gearchiveerd + {% elif u.geschorst %}Geschorst + {% elif u.onbekend %}Onbekend + {% else %}Actief{% endif %} +
      Er zijn nog geen Education-licenties toegewezen.
      +
      +
      +
      +
      + +
      + +
      +
      +{% endif %} +{% endblock %} + +{% block modals %} + +{% endblock %} + +{% block scripts %} + + +{% endblock %} diff --git a/templates/gopro.html b/templates/gopro.html new file mode 100644 index 0000000..1f8e714 --- /dev/null +++ b/templates/gopro.html @@ -0,0 +1,460 @@ +{% extends "base.html" %} + +{% block title %}GO! Pro{% endblock %} +{% block page_title %}GO! Pro{% endblock %} +{% block loader_text %}Personeel ophalen uit Informat...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +
      +

      🪪 Personeel {{ school_naam }}

      + +
      + +
      +
      + 🌙 Elke nacht automatisch verzamelen + + {% if nacht.aan %}Staat aan: elke nacht tussen 2 en 6 uur worden van alle scholen de groene personeelsleden + naar de verzameltabel gezet (wie op de rode lijst staat niet){% if nacht.door %} · aangezet door {{ nacht.door }}{% endif %}. + {% else %}Staat uit: enkel met de knop ➕ Groene naar verzameltabel, per school.{% endif %} + {% if nacht.bezig %}
      ⏳ Er loopt nu een verzameling voor alle scholen… + {% elif nacht.resultaat %}
      Laatste keer ({{ nacht.resultaat_op.strftime('%d-%m-%Y %H:%M') if nacht.resultaat_op else '?' }}): {{ nacht.resultaat }}{% endif %} +
      +
      +
      +
      + + +
      +
      + + + + +
      +
      +
      + + {% if fout %} +
      {{ fout }}
      + {% else %} +
      + + + + +
      + {% if not domein %} +
      Deze school heeft nog geen e-maildomein: vul het in via 🏫 Alle scholen beheren › Bewerken.
      + {% endif %} + {% if verzameld_hier.groen or verzameld_hier.genegeerd or verzameld_hier.verzonden %} +
      Niet meer getoond: + {% if verzameld_hier.groen %}{{ verzameld_hier.groen }} in de verzameltabel{% endif %} + {%- if verzameld_hier.genegeerd %}{{ ', ' if verzameld_hier.groen }}{{ verzameld_hier.genegeerd }} op de rode lijst{% endif -%} + {%- if verzameld_hier.verzonden %}{{ ', ' if verzameld_hier.groen or verzameld_hier.genegeerd }}{{ verzameld_hier.verzonden }} al verzonden{% endif -%} + .
      + {% endif %} + {% if dubbel %} +
      ⚠️ {{ dubbel }} rij(en) met een e-mailadres dat ook bij een ander personeelslid voorkomt (zelfde naam). Die zijn gemarkeerd.
      + {% endif %} + +
      + + Opgehaald uit Informat op {{ opgehaald }} +
      +
      + Controleren in Google… + +
      + +
      + + + + + + + + + + + + + + + + {% for r in rijen %} + + + + {% for veld in ('email', 'upn') %} + + {% endfor %} + {% for veld, label in (('functie', 'Functie'), ('rol', 'Rol')) %} + + {% endfor %} + + + + + {% else %} + + {% endfor %} + +
      Voornaam Achternaam E-mail UPN Functie Rol Startdatum functie Einddatum functie Telefoon
      {{ r.voornaam }}{{ r.achternaam }} + + {% if veld == 'email' and r.dubbel %}dubbel{% endif %} + + + {{ r.start.strftime('%d-%m-%Y') if r.start else '' }}{{ r.einde.strftime('%d-%m-%Y') if r.einde else '' }}{{ r.telefoon }}
      Informat gaf geen actieve personeelsleden terug.
      +
      +
      +
      +
      + +
      + +
      + {% endif %} +
      + +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/gopro_verzameld.html b/templates/gopro_verzameld.html new file mode 100644 index 0000000..33eb20c --- /dev/null +++ b/templates/gopro_verzameld.html @@ -0,0 +1,291 @@ +{% extends "base.html" %} + +{% block title %}GO! Pro verzameltabel{% endblock %} +{% block page_title %}GO! Pro verzameltabel{% endblock %} +{% block main_class %}wide{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{% set lijstnaam = 'de rode lijst' if rood else ('de lijst met verzonden personeelsleden' if verzonden else 'de verzameltabel') %} + +
      +
      +

      {{ '🚫 Rode lijst GO! Pro' if rood else ('📨 Verzonden naar GO! Pro' if verzonden else '📚 Verzameltabel GO! Pro') }} ({{ rijen|length }})

      +
      + ← Personeel van deze school + {% if rijen and not rood %} + ⬇️ CSV alle scholen + {% endif %} +
      +
      + {% if rood %} +

      Personeelsleden die je met 🚫 naast hun naam op de GO! Pro-pagina hebt + weggezet. Ze worden genegeerd: ze komen niet in de CSV en verschijnen niet meer op de GO! Pro-pagina van hun school, + ook niet na een nieuwe ophaling. Haal je iemand hier weg, dan verschijnt hij daar opnieuw.

      + {% elif verzonden %} +

      Personeelsleden die al naar GO! Pro doorgestuurd zijn (met + ✅ Markeer als verzonden in de verzameltabel). Ze worden nooit opnieuw aan de verzameltabel toegevoegd, + ook niet door de nachtelijke verzameling, en verschijnen niet meer op de GO! Pro-pagina van hun school. Haal je iemand + hier weg, dan verschijnt hij daar opnieuw.

      + {% else %} +

      De groene personeelsleden (account bestaat in Google) van elke school die je hier + verzamelt, komen samen in één tabel voor één grote GO! Pro-import. Wie hier staat, wordt op de GO! Pro-pagina van zijn + school niet meer getoond. Haal je iemand hier weg, dan verschijnt hij daar opnieuw.

      + {% endif %} + + {% if scholen %} +
      + {% for code, naam in scholen %} + + {% endfor %} +
      + {% endif %} + + {% if rijen %} +
      + + + + +
      + +
      + + + + + + + + + + + + + + + + {% for r in rijen %} + + + + + + + + + {% if verzonden and r.Verzonden %} + + {% else %} + + {% endif %} + + + {% endfor %} + +
      School Voornaam Achternaam E-mail / UPN Instelling Functie / rol Periode {{ 'Verzonden' if verzonden else 'Toegevoegd' }}
      {{ r.School_naam or r.School_code }}{{ r.Voornaam or '' }}{{ r.Achternaam or '' }}{{ (r.Email or '')|replace('@', '@\u200b') }}{% if r.UPN and r.UPN != r.Email %}
      UPN: {{ r.UPN }}{% endif %}
      {{ r.Instellingsnummer or '' }}{{ r.Functie or '' }}{% if r.Rol and r.Rol != r.Functie %}
      {{ r.Rol }}{% endif %}
      {{ r.Startdatum.strftime('%d-%m-%Y') if r.Startdatum else '' }}{% if r.Einddatum %}
      tot {{ r.Einddatum.strftime('%d-%m-%Y') }}{% endif %}
      {{ r.Verzonden.strftime('%d-%m-%Y') }}{{ r.Toegevoegd.strftime('%d-%m-%Y') }} + {% if lijst == 'groen' %} + {% set volle_naam = (r.Voornaam or '') ~ ' ' ~ (r.Achternaam or '') %} +
      + + +
      + {% endif %} +
      + + {% if lijst != 'groen' %}{% endif %} + +
      +
      +
      +
      +
      + +
      + +
      + +
      + + {% if lijst != 'groen' %}{% endif %} + +
      + {% if lijst == 'groen' %} +
      + + +
      + {% endif %} +
      + {% else %} + {% if verzonden %} +

      Er is nog niemand als verzonden gemarkeerd.

      + {% elif rood %} +

      De rode lijst is nog leeg. Klik op GO! Pro op 🚫 naast een naam om iemand te negeren.

      + {% else %} +

      De verzameltabel is nog leeg. Open GO! Pro in een school en klik op + ➕ Groene naar verzameltabel.

      + {% endif %} + {% endif %} +
      +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/grafiek.html b/templates/grafiek.html new file mode 100644 index 0000000..b647ed2 --- /dev/null +++ b/templates/grafiek.html @@ -0,0 +1,80 @@ +{% extends "base.html" %} + +{% block title %}CO2-verloop {{ lokaal }}{% endblock %} +{% block page_title %}CO2-verloop: {{ lokaal }}{% endblock %} +{% block main_class %}medium{% endblock %} + +{% block head %} + +{% endblock %} + +{% block content %} +
      +
      +

      📊 {{ lokaal }}

      +
      + ⬅ Terug + +
      +
      + +
      + +
      +
      +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/handleiding.html b/templates/handleiding.html new file mode 100644 index 0000000..5bb533d --- /dev/null +++ b/templates/handleiding.html @@ -0,0 +1,71 @@ +{% extends "base.html" %} + +{% block title %}{{ h.Titel }}{% endblock %} +{% block page_title %}Handleidingen{% endblock %} + +{% block extra_css %} +{% include "_handleiding_stijl.html" %} + +{% endblock %} + +{% block content %} +← Alle handleidingen + +
      + {% if versie %} +
      + Je bekijkt een oudere versie van {{ versie.Opgeslagen_op.strftime('%d-%m-%Y %H:%M') }}{% if versie.Door %} ({{ versie.Door }}){% endif %}. + +
      + +
      + Huidige versie +
      +
      + {% endif %} + +
      +

      {{ versie.Titel if versie else h.Titel }}

      +
      + + {% if is_admin and not versie %} + ✏️ Bewerken + {% endif %} +
      +
      +
      + {% if h.Categorie %}{{ h.Categorie }} · {% endif %} + Bijgewerkt {{ h.Gewijzigd_op.strftime('%d-%m-%Y %H:%M') }}{% if h.Gewijzigd_door %} door {{ h.Gewijzigd_door }}{% endif %} + {% if h.Zichtbaar == 'admins' %} · 🔒 enkel admins{% endif %} +
      + +
      +
      + {{ inhoud|safe }} + {% if not inhoud %}

      Deze handleiding is nog leeg.

      {% endif %} +
      + {% if toc|length > 1 %} + + {% endif %} +
      +
      +{% endblock %} diff --git a/templates/handleiding_bewerken.html b/templates/handleiding_bewerken.html new file mode 100644 index 0000000..844aca8 --- /dev/null +++ b/templates/handleiding_bewerken.html @@ -0,0 +1,271 @@ +{% extends "base.html" %} + +{% block title %}{{ 'Nieuwe handleiding' if nieuw else 'Bewerken: ' ~ h.Titel }}{% endblock %} +{% block page_title %}Handleidingen{% endblock %} + +{% block extra_css %} +{% include "_handleiding_stijl.html" %} + +{% endblock %} + +{% block content %} +← Terug + +
      +

      {{ '➕ Nieuwe handleiding' if nieuw else '✏️ Handleiding bewerken' }}

      + +
      +
      +
      + + +
      +
      + + + {% for c in categorieen %} +
      +
      + + +
      +
      + + +
      +
      +
      + + +
      + + +
      + +
      {{ h.Inhoud|safe if h.Inhoud else '' }}
      + +
      + + +

      Tip: plak een schermafbeelding rechtstreeks met Ctrl+V. Klik op een afbeelding en druk Delete om ze te verwijderen. + Grote afbeeldingen worden automatisch verkleind.

      + +
      + + {% if not nieuw %}{% endif %} + Annuleren +
      +
      + + {% if not nieuw %} +
      + +
      + {% endif %} +
      + +{% if versies %} +
      +

      🕘 Vorige versies

      +

      Bij elke opslag wordt de vorige tekst bewaard (de laatste 30). Open een versie om ze te bekijken of terug te zetten.

      + +
      +{% endif %} +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/handleidingen.html b/templates/handleidingen.html new file mode 100644 index 0000000..0dfe4c7 --- /dev/null +++ b/templates/handleidingen.html @@ -0,0 +1,52 @@ +{% extends "base.html" %} + +{% block title %}Handleidingen{% endblock %} +{% block page_title %}Handleidingen{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
      +
      +

      📘 Handleidingen

      + {% if is_admin %} + ➕ Nieuwe handleiding + {% endif %} +
      + + + + {% for cat, items in per_cat.items() %} +
      {{ cat }}
      + + {% else %} +

      {% if q %}Geen handleidingen gevonden voor "{{ q }}".{% else %}Er zijn nog geen handleidingen.{% endif %}

      + {% endfor %} +
      +{% endblock %} diff --git a/templates/handtekeningen.html b/templates/handtekeningen.html new file mode 100644 index 0000000..102b9e2 --- /dev/null +++ b/templates/handtekeningen.html @@ -0,0 +1,506 @@ +{% extends "base.html" %} + +{% block title %}Handtekeningen{% endblock %} +{% block page_title %}Handtekeningen{% endblock %} +{% block main_class %}wide{% endblock %} +{% block loader_text %}Bezig met Google...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{# ===================== Sjabloon ===================== #} +
      +
      +

      ✍️ Algemene handtekening

      +
      + +
      +
      +

      Eén handtekening voor iedereen in de gekozen OU's. Klik op een veld hieronder om het in te + voegen; PIVOT vult het per persoon in. Zet een stuk tussen {{ '{#functie}' }} en {{ '{/functie}' }} (of + telefoon, ...) om het weg te laten als dat veld leeg is.

      + +
      +
      +
      + + + + + + + + + + + + + + + + + + +
      +
      + +
      + {% for k, uitleg in velden %}{% endfor %} +
      +
      + +
      +
      +
      + 👁 Voorbeeld + +
      +
      +
      Beste collega,

      Zo ziet je e-mail eruit met de handtekening.

      Met vriendelijke groeten,
      +
      --
      +
      +
      +
      +
      +
      +
      + +
      +
      + +
      + {% if inst.heeft_logo and inst.Logo_sleutel %} + Logo + + {% endif %} + +
      +

      PNG, JPG of GIF, max. 512 kB. Of geef hieronder een eigen publieke link (bv. van de schoolwebsite).

      + +
      + + pixels +
      +
      +
      + + +

      Gmail haalt een geüpload logo op via {{ (inst.Publiek_adres or publiek_voorstel) }}/handtekening-logo/.... + Dat adres moet van buitenaf (internet) bereikbaar zijn; de IP-blokkering geldt niet voor het logo. + Is PIVOT enkel intern bereikbaar, gebruik dan een eigen link naar het logo.

      + {% if inst.logo_link %}

      Huidige logolink: {{ inst.logo_link }}

      {% endif %} + +

      {{ school_gegevens.schoolnaam }}
      {{ school_gegevens.schooladres or '— geen adres ingevuld —' }}
      + Aan te passen via 🏫 Alle scholen beheren › Bewerken › Adres.

      +
      +
      + + {% if fout_ou %}
      {{ fout_ou }}
      {% endif %} + +
      + {% for ou in ous %} + + {% endfor %} +
      + +
      +
      +
      + {% if inst.Bijgewerkt %}

      Laatst bewaard op {{ inst.Bijgewerkt.strftime('%d-%m-%Y %H:%M') }}{% if inst.Door %} door {{ inst.Door }}{% endif %}.

      {% endif %} +
      + +{# ===================== Gebruikers ===================== #} +
      +
      +

      👥 Gebruikers ({{ gebruikers|length }})

      + +
      + +
      +
      + 🌙 Elke nacht opnieuw toepassen + {% if inst.Nachtelijk %}Staat aan: elke nacht (tussen 3 en 6 uur) zet PIVOT de handtekening + opnieuw bij wie ze in Gmail zelf gewijzigd heeft, of bij wie de gegevens veranderd zijn.{% else %}Staat uit: de handtekening + wordt enkel gezet met de knoppen hieronder. Gebruikers kunnen ze in Gmail zelf nog aanpassen.{% endif %} + {% if inst.Nacht_resultaat %}
      Laatste keer: {{ inst.Nacht_resultaat }}{% endif %}
      +
      +
      + + +
      +
      + + {% if not inst.ous %} +

      Kies hierboven één of meer OU's en klik op 💾 Bewaren.

      + {% elif fout_gebruikers %} +
      {{ fout_gebruikers }}
      + {% elif not gebruikers %} +

      Geen (actieve) gebruikers in de gekozen OU's.

      + {% else %} +

      Functie en telefoon komen uit Google. Pas je ze hier aan, dan worden ze ook in Google + bewaard (en staan ze in het adresboek van de organisatie).

      +
      + + +
      + + + +
      +
      + +
      +
      +
      {{ status.voortgang }} / {{ status.totaal }} · + ✅ {{ status.gelukt }} · ⏭️ {{ status.ongewijzigd }} · ⚠️ {{ status.fouten }}
      +
      {{ status.resultaat or '' }}
      +
      {{ status.fout or '' }}
      +
        +
        + +
        + + + + + + + + + + {% for u in gebruikers %} + {% set l = logboek.get(u.email) %} + + + + + + + + + + + {% endfor %} + +
        NaamE-mailOUFunctieTelefoonGmail
        {{ u.achternaam }} {{ u.voornaam }}{{ u.email }}{{ u.ou }} + {% if not l %}— + {% elif l.Ok %}✓ + {% else %}✕{% endif %} + + + + +
        +
        +
        +
        + +
        + {% endif %} +
        + +

        Eenmalig nodig in de Google Admin-console (Beveiliging › API-beheer › Domeinbrede delegatie, bij het serviceaccount + van PIVOT): https://www.googleapis.com/auth/gmail.settings.basic (handtekening zetten) en + https://www.googleapis.com/auth/admin.directory.user (functie en telefoon).

        +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/herstellingen.html b/templates/herstellingen.html new file mode 100644 index 0000000..20fd324 --- /dev/null +++ b/templates/herstellingen.html @@ -0,0 +1,235 @@ +{% extends "base.html" %} + +{% block title %}Herstellingen{% endblock %} +{% block page_title %}Herstellingen & Signpost{% endblock %} +{% block loader_text %}Signpost data ophalen... even geduld.{% endblock %} + +{% block content %} +
        +
        + + +
        +
        + {% if active_tab == 'signpost-tab' %} + + {% else %} + + {% endif %} +
        +
        + +
        +

        🛠️ Overzicht herstellingen

        + + + {% if results %} +
        + + + + + + + + + + + + + {% for row in results %} + + + + + + + + + {% endfor %} + +
        Incident nrSerienummerSoort herstellingStatusDatumActies
        {{ row['Incident_nr'] or '' }}{{ row['KAMXM_nummer'] }}{{ row['Soort_herstelling'] or '' }} + {% if row['Status'] == 'In afwachting' %}⏳ In afwachting + {% elif row['Status'] == 'In herstelling' %}🔧 In herstelling + {% elif row['Status'] == 'Voltooid' %}✅ Voltooid + {% else %}{{ row['Status'] }} + {% endif %} + {{ row['Datum'] or '' }} + + +
        +
        + {% elif query %} +

        Geen herstellingen gevonden voor "{{ query }}".

        + {% endif %} +
        + +
        +

        🚩 Signpost schademeldingen

        + + + {% if signpost_results %} +
        + + + + + + + + + + + + {% for case in signpost_results %} + + + + + + + + {% endfor %} + +
        ReferentieStatusOmschrijvingDatumPrijs
        {{ case.get('ourReference', 'N/A') }}{{ case.get('status', 'Onbekend') }}{{ case.get('description', 'Geen omschrijving') }}{{ case.get('createdAt', '')[:10] }}€ {{ case.get('totalPrice', '0.00') }}
        +
        + {% endif %} +
        +{% endblock %} + +{% block modals %} + + + + + + + +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/informat_velden.html b/templates/informat_velden.html new file mode 100644 index 0000000..b26fdcb --- /dev/null +++ b/templates/informat_velden.html @@ -0,0 +1,49 @@ +{% extends "base.html" %} + +{% block title %}Informat-velden{% endblock %} +{% block page_title %}Informat-velden{% endblock %} +{% block loader_text %}Leerlingenlijst ophalen bij Informat...{% endblock %} + +{% block content %} +← Leerlingenaantallen +
        +

        🔎 Welke velden geeft Informat terug?

        +

        Haalt de leerlingenlijst op zoals bij het tellen en toont per veld hoeveel leerlingen een waarde hebben. + Bij velden met weinig verschillende waarden zie je die waarden en hun aantal: zo vind je het veld dat de campus aangeeft. + Namen en andere persoonsgegevens worden niet getoond.

        + + + {% if fout %}
        {{ fout }}
        {% endif %} + + {% if velden is not none %} +

        {{ totaal }} leerlingen ontvangen van Informat voor {{ school.naam }}.

        +
        + + + + {% for v in velden %} + 1 %}style="background:var(--primary-light)"{% endif %}> + + + + + + {% endfor %} + +
        VeldGevuld bijVerschillende waardenWaarden (aantal leerlingen)
        {{ v.pad }}{{ v.gevuld }}{{ v.verschillend }} + {% if v.gevoelig %}persoonsgegeven – niet getoond + {% elif v.waarden %}{% for w, n in v.waarden %}{{ w }} {{ n }}{% if not loop.last %} · {% endif %}{% endfor %} + {% else %}te veel verschillende waarden{% endif %} +
        +
        +

        Gevonden? Vul het veld in bij 🔌 Koppelingen › Informat › Campusveld in de leerlingenlijst + en bij Campussen de waarden met een naam, bv. 1=Campus Kapellen, 3=Campus Stabroek.

        + {% endif %} +
        +{% endblock %} diff --git a/templates/inleveren.html b/templates/inleveren.html new file mode 100644 index 0000000..b4c36ee --- /dev/null +++ b/templates/inleveren.html @@ -0,0 +1,190 @@ +{% extends "base.html" %} + +{% block title %}Inleveren{% endblock %} +{% block page_title %}Toestel inleveren{% endblock %} +{% block main_class %}medium{% endblock %} +{% block loader_text %}Inlevering verwerken...{% endblock %} + +{% block head %} + +{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
        +
        +

        Toestel inleveren

        + + {% if message %} + {% set ok = 'succesvol' in message or 'ingegeven' in message %} +
        {{ message }}
        + {% endif %} + +
        + + +
        + + +
          + {% if request.args.get('naam') %}

          👤 {{ request.args.get('naam') }}

          {% endif %} +
          +
          + + +
            +
            + + + +
            + + +
            + + +
            +
            + +
            +

            📷 Scanner

            + + {# Zonder https geeft de browser geen live camera: dan een foto nemen met de camera-app en de code daaruit lezen #} + + + +
            + +
            +
            Gescande waarde
            + - +
            + + +
            +
            +
            +
            +{% endblock %} + +{% block scripts %} +{% set toestel_voorkeur = 'uitgeleend' %}{% set toestel_vul_intern = true %}{% include '_toestel_zoekveld.html' %} + +{% endblock %} diff --git a/templates/internen.html b/templates/internen.html new file mode 100644 index 0000000..dd5144c --- /dev/null +++ b/templates/internen.html @@ -0,0 +1,217 @@ +{% extends "base.html" %} + +{% block title %}Internen{% endblock %} +{% block page_title %}Internen{% endblock %} +{% block main_class %}wide{% endblock %} +{% block loader_text %}Internen ophalen uit Informat...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +
            +

            🛏️ Internen · {{ school_naam }}

            +
            +
            + + + +
            + {% if rijen %}⬇️ CSV{% endif %} + 🔄 Opnieuw ophalen +
            +
            + + {% if fout %} +
            {{ fout }}
            + {% elif not rijen %} +

            Geen internen ingeschreven op {{ peildatum.strftime('%d-%m-%Y') }} (schooljaar {{ schooljaar }}).

            + {% else %} +
            + Internen {{ rijen|length }} + Jongens {{ rijen|selectattr('geslacht', 'equalto', 'M')|list|length }} + Meisjes {{ rijen|selectattr('geslacht', 'equalto', 'V')|list|length }} + Niet in Smartschool … + +
            +
            + + {% if internaten|length > 1 %} + + {% endif %} + + Opgehaald uit Informat op {{ opgehaald }} +
            + +
            + + + + + + + + + {% if internaten|length > 1 %}{% endif %} + + + + + + + + + {% for r in rijen %} + + + + + + + {% if internaten|length > 1 %}{% endif %} + + + + + + + {% endfor %} + +
            Naam Voornaam Smartschool Geboren M/V Internaat Vestiging Kamer Ingeschreven Woonplaats Contactpersonen
            {{ r.naam }}{% if r.stamnummer %}
            stamnr. {{ r.stamnummer }}{% endif %}
            {{ r.voornaam }}…{{ r.geboortedatum.strftime('%d-%m-%Y') if r.geboortedatum else '' }}{{ r.geslacht }}{{ r.internaat }}{{ r.vestiging }}{{ r.kamer or '–' }}{{ r.begin.strftime('%d-%m-%Y') if r.begin else '' }}{% if r.einde %}
            tot {{ r.einde.strftime('%d-%m-%Y') }}{% endif %} + {% if r.financiering %}
            {{ r.financiering }}{% endif %}
            {{ r.gemeente }} + {% for o in r.ouders[:3] %} + {{ o.naam }}{% if o.type %} ({{ o.type|lower }}){% endif %} + {% if o.gsm %}· {{ o.gsm }}{% endif %} + {% if o.email %}· ✉️{% endif %} + {% endfor %} +
            +
            +
            +
            + +
            + {% endif %} +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/internet_connection.html b/templates/internet_connection.html new file mode 100644 index 0000000..23164b0 --- /dev/null +++ b/templates/internet_connection.html @@ -0,0 +1,56 @@ +{% extends "base.html" %} + +{% block title %}Internetstatus{% endblock %} +{% block page_title %}Internetstatus{% endblock %} +{% block main_class %}narrow{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            + {% set status_text = 'Online' if current_status == 1 else 'Offline' %} + {% set status_class = 'online' if current_status == 1 else 'offline' %} + +
            + Internet: {{ status_text }} +
            + + {% if current_note %} +
            {{ current_note }}
            + {% endif %} + + {% if session.get('security_group')|int == 1 %} +
            +
            + {% if current_status == 1 %} + + {% else %} + + {% endif %} +
            + +
            +
            + + +
            + +
            +
            + {% endif %} +
            +{% endblock %} diff --git a/templates/inventaris.html b/templates/inventaris.html new file mode 100644 index 0000000..621e45d --- /dev/null +++ b/templates/inventaris.html @@ -0,0 +1,310 @@ +{% extends "base.html" %} + +{% block title %}Eigendom{% endblock %} +{% block page_title %}Eigendom{% endblock %} +{% block main_class %}wide{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +

            🏷️ Toestellen bij leerlingen

            + + + + {% if message %} +
            {{ message }}
            + {% endif %} + + {% if results %} + {% set met = results|selectattr('heeft_toestel')|list|length %} +
            + + + +
            +
            + + + + + + + + +
            + +
            + + + + + + + + + + + + + + + + {% for row in results %} + + + + + + + + + + + + {% endfor %} + +
            Internnummer Naam Gebruikersnaam SS_nummer Toestelnummer Serienummer Sinds Status
            {{ row['internnummer'] }}{{ row['Voornaam'] or '' }} {{ row['Naam'] or '' }}{{ row['Gebruikersnaam'] or '' }}{{ row['SS_nummer'] or '' }}{{ row['kamxm_nummer'] or ('' if row['heeft_toestel'] else 'geen toestel') }}{{ row['Serienummer'] or '' }}{{ row['Datum_toekenning'].strftime('%d-%m-%Y') if row['Datum_toekenning'] and row['Datum_toekenning'].strftime is defined else (row['Datum_toekenning'] or '') }} + {% if not row['heeft_toestel'] %}— + {% elif row['locked'] | int == 1 %}🔒 Geblokkeerd + {% else %}🔓 Actief + {% endif %} + + + {% if mag('toestel_blokkeren') and row['heeft_toestel'] %} +
            + + + {% if row['locked'] | int == 1 %} + + {% else %} + + {% endif %} +
            + {% endif %} + {% if mag('toestellen_uitdelen') and row['heeft_toestel'] %} + + {% endif %} + {% if mag('toestellen_uitdelen') %} + {% if row['heeft_toestel'] %} + 📥 Inleveren + {% else %} + 📤 Uitdelen + {% endif %} + {% endif %} + +
            +
            +
            +
            +
            +
            + +
            + +
            + {% elif query %} +

            Geen resultaten gevonden voor "{{ query }}".

            + {% else %} +

            Er zijn nog geen leerlingen.

            + {% endif %} +
            +{% endblock %} + +{% block modals %} + + +{% endblock %} + +{% block scripts %} +{% if mag('toestellen_uitdelen') %} +{% set toestel_voorkeur = 'beschikbaar' %}{% include '_toestel_zoekveld.html' %} + +{% endif %} + +{% endblock %} diff --git a/templates/ipblokkade.html b/templates/ipblokkade.html new file mode 100644 index 0000000..f6d4273 --- /dev/null +++ b/templates/ipblokkade.html @@ -0,0 +1,365 @@ +{% extends "base.html" %} + +{% block title %}IP-blokkades{% endblock %} +{% block page_title %}IP-blokkades{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% macro schoolkiezer(gekozen=[], formid='') %} +
            + — geen school — +
            + {% if scholen|length > 8 %}{% endif %} + {% for s in scholen %} + + {% else %} +
            Er zijn nog geen scholen.
            + {% endfor %} + {% if scholen %}
            {% endif %} +
            +
            +{% endmacro %} + +{% block content %} +
            +
            +

            🚫 IP-blokkades

            + Jouw IP-adres: {{ mijn_ip }} +
            +

            Geldt voor alle scholen. Een geblokkeerd adres krijgt bij elke aanvraag + "Toegang geweigerd", ook op de loginpagina. Een adres bij Altijd toestaan mag altijd, ook als het in een + geblokkeerde reeks valt.

            + +
            +
            + + +
            +
            + + +
            + +
            + + +
            + +
            + + {% if lokaal %} +
            PIVOT ziet jouw adres als {{ mijn_ip }}. + Waarschijnlijk draait PIVOT achter een reverse proxy, en dan lijkt elke bezoeker van dat adres te komen. Zet in + config.ini › [algemeen] proxy_aantal = 1 en herstart PIVOT, anders werken de IP-regels niet zoals bedoeld.
            + {% endif %} + +
            +
            + Enkel "Altijd toestaan" binnenlaten + + {% if enkel_toegestaan %}Staat aan: elk adres dat niet bij Altijd toestaan staat, wordt geweigerd + ({{ modus_geweigerd }} keer sinds de teller begon){% if modus and modus.Door %} · aangezet door {{ modus.Door }}{% endif %}. + {% else %}Staat uit: iedereen mag binnen, behalve de geblokkeerde adressen.{% endif %} + +
            +
            + + + + +
            +
            +
            + +{% for titel, lijst, leeg, sleutel in (('🚫 Geblokkeerd', blokkeren, 'Er is nog niets geblokkeerd.', 'blok'), + ('✅ Altijd toestaan', toestaan, 'Geen uitzonderingen.', 'toe')) %} +
            +
            +

            {{ titel }} ({{ lijst|length }})

            + {% if sleutel == 'blok' and lijst %} +
            + +
            + {% endif %} +
            + {% if lijst|length > 10 %}{% endif %} +
            + + + + + {% if sleutel == 'toe' %}{% endif %} + + + {% if lijst is sameas blokkeren %} + {% endif %} + + + + + {% for r in lijst %} + {% set bf = 'bew-' ~ r.ID %} + + {% if sleutel == 'toe' %} + + + + {% else %} + + + {% endif %} + + {% if lijst is sameas blokkeren %} + + + {% endif %} + + + {% else %} + + {% endfor %} + +
            Reeks School Opmerking Toegevoegd Geweigerd Laatst geweigerd
            {{ r.Reeks }} + {% for n in r.Scholen_namen %}{{ n }}{% else %}–{% endfor %} + {{ schoolkiezer(r.Scholen_codes, bf) }}{{ r.Opmerking or '' }} + {{ r.Reeks }}{{ r.Opmerking or '' }}{{ r.Aangemaakt.strftime('%d-%m-%Y %H:%M') }}{% if r.Door %} · {{ r.Door }}{% endif %}{{ r.Aantal_geweigerd }}{{ r.Laatst_geweigerd.strftime('%d-%m-%Y %H:%M') if r.Laatst_geweigerd else '–' }} + + {% if sleutel == 'toe' %}{% endif %} +
            + +
            +
            + {% if sleutel == 'toe' %} + +
            + +
            + +
            + {% endif %} +
            {{ leeg }}
            +
            + {% if lijst %} +
            +
            +
            + +
            + +
            + {% endif %} +
            +{% endfor %} + +
            +

            🔎 Een adres testen

            +
            + + + {% if test %} + {% if test.geweigerd %} + 🚫 Geweigerd door {{ test.regel.Reeks if test.regel else 'een regel' }} + {% else %} + ✅ Toegelaten + {% endif %} + {% endif %} +
            +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/ipblokkade_school.html b/templates/ipblokkade_school.html new file mode 100644 index 0000000..bc4b786 --- /dev/null +++ b/templates/ipblokkade_school.html @@ -0,0 +1,143 @@ +{% extends "base.html" %} + +{% block title %}Toegestane IP-adressen{% endblock %} +{% block page_title %}Toegestane IP-adressen{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +
            +

            ✅ Toegestane IP-adressen · {{ school_naam }}

            + Jouw IP-adres: {{ mijn_ip }} + {% if not lokaal %}{% endif %} +
            +

            Een adres in deze lijst mag PIVOT altijd openen. Je voegt het toe voor + {{ school_naam }}, met jouw naam ({{ naam }}) als opmerking. Je kan enkel de adressen verwijderen die je zelf toegevoegd hebt.

            + +
            +
            + + +
            + +
            +
            + +
            +

            Lijst ({{ rijen|length }})

            + {% if rijen|length > 10 %}{% endif %} +
            + + + + + + + + + + + {% for r in rijen %} + + + + + + + {% else %} + + {% endfor %} + +
            IP-adres Opmerking Toegevoegd
            {{ r.Reeks }}{{ r.Opmerking or '' }}{{ r.Aangemaakt.strftime('%d-%m-%Y %H:%M') }} + {% if r.Eigen %} +
            + +
            + {% endif %} +
            Er zijn nog geen toegestane adressen voor {{ school_naam }}.
            +
            + {% if rijen %} +
            +
            +
            + +
            + +
            + {% endif %} +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/laatkomers.html b/templates/laatkomers.html new file mode 100644 index 0000000..85bc248 --- /dev/null +++ b/templates/laatkomers.html @@ -0,0 +1,231 @@ +{% extends "base.html" %} + +{% block title %}Laatkomers{% endblock %} +{% block page_title %}Laatkomers{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{# ---------- Kerncijfers ---------- #} +
            +
            +
            {{ rows|length }}
            +
            Leerlingen te laat
            +
            +
            +
            {{ totaal }}
            +
            Keer te laat
            + {% if rows %}
            gem. {{ '%.1f'|format(totaal / rows|length) }} per leerling
            {% endif %} +
            +
            +
            + {% if laatste.m %}{{ laatste.m.strftime('%d-%m-%Y %H:%M') }}{% else %}Nog nooit{% endif %} +
            +
            Laatst gesynchroniseerd
            +
            Automatisch elke ochtend
            +
            +
            + +{% if fout %}
            {{ fout }}
            {% endif %} +{% if not codes %} +
            Er zijn geen codes voor "te laat" ingesteld. Vul ze in bij 🔌 Koppelingen › Smartschool › Codes voor te laat.
            +{% endif %} + +{# ---------- Synchronisatie en periode ---------- #} +
            +
            +
            + + +
            +
            + + + +
            +
            + + {% if status.bezig %}Bezig…{% elif status.laatste_resultaat %}{{ status.laatste_resultaat }}{% endif %} + +
            +
            +
            + + +
            +
            + + +
            + +
            +
            + +{# ---------- Tabel ---------- #} +
            +
            + +
            +
            + + + + + + + + + + + + + {% for r in rows %} + + + + + + + + + {% else %} + + {% endfor %} + +
            Leerling Internnummer Aantal keer te laat Laatst te laat Eerst te laat Data
            + {% if r.Naam or r.Voornaam %}{{ r.Naam }} {{ r.Voornaam }}{% else %}Onbekende leerling{% endif %} + {{ r.Internnummer }}{{ r.Aantal }}{{ r.Laatste.strftime('%d-%m-%Y') }}{{ r.Eerste.strftime('%d-%m-%Y') }} +
            Toon {{ r.Data|length }} +
            + {% for d, dd in r.Data %}{{ ['ma','di','wo','do','vr','za','zo'][d.weekday()] }} {{ d.strftime('%d-%m') }} {{ dd }}{% endfor %} +
            +
            +
            Geen laatkomers in deze periode{% if not laatste.m %} (er is nog niets opgehaald uit Smartschool){% endif %}.
            +
            +
            +
            +
            + +
            + +
            +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/leerlingenaantal.html b/templates/leerlingenaantal.html new file mode 100644 index 0000000..fc07c78 --- /dev/null +++ b/templates/leerlingenaantal.html @@ -0,0 +1,198 @@ +{% extends "base.html" %} + +{% block title %}{{ titel }}{% endblock %} +{% block page_title %}{{ titel }}{% endblock %} +{% block loader_text %}Bezig met tellen via Informat API...{% endblock %} + +{% block content %} + + +{# ---------- Telling op peildatum ---------- #} +
            +
            +

            📅 Telling op peildatum

            + {% if peildata %} + ⬇️ CSV alle peildata + {% endif %} +
            + +
            +
            + + +
            + +
            + + {% if peildata %} + + {% endif %} + + {% if telling %} +
            +

            {{ eenheid }} op {{ peildatum.strftime('%d-%m-%Y') }}

            +
            + ⬇️ CSV-export +
            + + +
            +
            +
            +
            + + + + + + + + + + {% for g in telling_groepen %} + + + {% for row in g.rijen %} + + + + + + + {% for c in row.Campussen %} + + + + + + {% endfor %} + {% endfor %} + {% if g.code %} + + {% endif %} + + {% endfor %} + + + +
            School{{ eenheid }}OpgevraagdActie
            {{ g.label }}
            {{ row.Naam_school }}{{ row.Aantal if row.Aantal is not none else '–' }}{% if row.Opgevraagd_op %}{{ row.Opgevraagd_op.strftime('%d-%m-%Y %H:%M') }}{% if row.Door %} · {{ row.Door }}{% endif %}{% else %}Niet geteld{% endif %} + {% if row.Informat %} +
            + + + +
            + {% else %} + Informat niet ingesteld + {% endif %} +
            ↳ {{ c.naam }}{{ c.aantal }}
            Subtotaal {{ g.label|lower }}{{ g.subtotaal }}
            Totaal scholengroep{{ telling_totaal }}
            +
            + {% endif %} +
            + +{# ---------- Huidig aantal ---------- #} +
            +
            +

            🏢 Scholengroep: huidig aantal

            +
            + ⬇️ CSV-export +
            + + +
            +
            +
            + + + +
            + + + + + + + + + + {% for g in groepen %} + + + {% for row in g.rijen %} + + + + + + + {% for c in row['Campussen'] %} + + + + + + {% endfor %} + {% endfor %} + {% if g.code %} + + {% endif %} + + {% else %} + + {% endfor %} + {% if results %} + + + + {% endif %} +
            School{{ eenheid }}Laatste synchronisatieActie
            {{ g.label }}
            {{ row['Naam_school'] }}{{ row['Huidig'] }}{{ row['Laatste_synchronisatie'] or 'Nog nooit' }} + {% if row['Informat'] %} +
            + + +
            + {% else %} + Informat niet ingesteld + {% endif %} +
            ↳ {{ c.naam }}{{ c.aantal }}
            Subtotaal {{ g.label|lower }}{{ g.subtotaal }}
            Geen scholen gevonden.
            Totaal scholengroep{{ totaal }}
            +
            +
            +{% endblock %} diff --git a/templates/nieuw_schooljaar_accounts.html b/templates/nieuw_schooljaar_accounts.html new file mode 100644 index 0000000..3a4b9eb --- /dev/null +++ b/templates/nieuw_schooljaar_accounts.html @@ -0,0 +1,113 @@ +{% extends "base.html" %} + +{% block title %}Nieuw schooljaar – accounts{% endblock %} +{% block page_title %}Nieuw schooljaar – leerlingaccounts{% endblock %} +{% block main_class %}medium{% endblock %} +{% block loader_text %}Bezig met verwerken... Even geduld.{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            + + + +
            + +
            +

            Gebruikers van OU verplaatsen

            +
            +
            +
            + + +
            + ⟶ +
            + + +
            +
            +
            + + +
            +
            +
            +
            + +
            +

            Gebruikers archiveren

            +
            +
            +
            + + +
            +
            +
            + + +
            +
            +
            +
            + +
            +

            Inactieve gebruikers archiveren

            +

            Gebruikers in de geselecteerde OU die langer dan de gekozen periode niet zijn ingelogd, worden gearchiveerd.

            +
            +
            +
            + + +
            + +
            + + +
            +
            +
            +
            +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/nieuw_schooljaar_toestellen.html b/templates/nieuw_schooljaar_toestellen.html new file mode 100644 index 0000000..b175f5b --- /dev/null +++ b/templates/nieuw_schooljaar_toestellen.html @@ -0,0 +1,93 @@ +{% extends "base.html" %} + +{% block title %}Nieuw schooljaar – toestellen{% endblock %} +{% block page_title %}Nieuw schooljaar – toestellen{% endblock %} +{% block main_class %}medium{% endblock %} +{% block loader_text %}Bezig met verwerken... Even geduld.{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            + + +
            + +
            +

            Chromebooks van OU verplaatsen

            +
            +
            +
            + + +
            + ⟶ +
            + + +
            +
            +
            +
            +
            + +
            +

            Chromebooks blokkeren of deblokkeren

            +

            Selecteer een OU om de status van alle aanwezige Chromebooks te wijzigen.

            +
            +
            +
            + + +
            +
            +
            + + +
            +
            +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/pdf_template_leerkracht.html b/templates/pdf_template_leerkracht.html new file mode 100644 index 0000000..139c4c2 --- /dev/null +++ b/templates/pdf_template_leerkracht.html @@ -0,0 +1,112 @@ + + + + + + + + + + + +
            + + +

            {{ school_name_short|upper }} Google Account

            +
            + +
            +

            Beste {{ naam }},

            + +

            Je account voor de schoolomgeving is aangemaakt op {{ datum }}.

            + + + +

            Hiermee kan je gebruikmaken van alle schoolgebonden google toepassingen (Drive, Gmail, Classroom, Agenda...).

            + +

            Let op: Je zult gevraagd worden om je wachtwoord te wijzigen bij de eerste keer inloggen.

            + + +
            + +

            Met vriendelijke groeten,

            + + + + + + +
            + K. Verbruggen
            + ICT coördinator
            + {{ contact_email }} +
            + B. Elewaut
            + Directeur
            + directie@kamkersem.be +
            + + \ No newline at end of file diff --git a/templates/pdf_template_leerling.html b/templates/pdf_template_leerling.html new file mode 100644 index 0000000..12cd840 --- /dev/null +++ b/templates/pdf_template_leerling.html @@ -0,0 +1,110 @@ + + + + + + + + + + + + +
            + Logo + +

            {{ school_name_short|upper }} Google Account

            +
            + +
            +

            Beste {{ naam }},

            + +

            Je account voor de schoolomgeving is aangemaakt/bijgewerkt op {{ datum }}.

            + + + +

            Hiermee kan je aanmelden op je Chromebook en andere schooldiensten.

            + +

            Let op: Indien dit een nieuw account is, moet je je wachtwoord wijzigen bij de eerste keer inloggen.

            + + +
            + +

            Met vriendelijke groeten,

            + + + + + + +
            + K. Verbruggen
            + ICT coördinator
            + {{ contact_email }} +
            + B. Elewaut
            + Directeur
            + directie@kamkersem.be +
            + + \ No newline at end of file diff --git a/templates/personeel_beoordelen.html b/templates/personeel_beoordelen.html new file mode 100644 index 0000000..1fbe237 --- /dev/null +++ b/templates/personeel_beoordelen.html @@ -0,0 +1,68 @@ +{% extends "base.html" %} +{% from "_personeel.html" import subnav, status_badge, soort_label, periode with context %} + +{% block title %}Te beoordelen{% endblock %} +{% block page_title %}Te beoordelen{% endblock %} +{% block main_class %}medium{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{{ subnav('beoordelen') }} + +{% for i in open_items %} +
            +
            +
            +

            {{ soort_label(i.Soort) }}: {{ i.Titel }}

            +
            {{ i.Naam }} · {{ periode(i) }}{% if i.Kost %} · € {{ '%.2f'|format(i.Kost)|replace('.', ',') }}{% endif %}
            + {% if i.Klassen %}
            {% for k in i.Klassen.split(',') %}{{ k.strip() }}{% endfor %}
            {% endif %} +
            +
            {{ status_badge(i.Status) }}
            + {% if i.Omschrijving %}
            {{ i.Omschrijving }}
            {% endif %} +
            + + + + + +
            +
            +
            +{% else %} +

            🎉 Er wacht niets op een beslissing.

            +{% endfor %} + +{% if recent %} +
            +

            Recent beslist

            +
            + + + + {% for i in recent %} + + + + + + + + {% endfor %} + +
            SoortWieTitelWanneerBeslissing
            {{ soort_label(i.Soort) }}{{ i.Naam }}{{ i.Titel }}{{ periode(i) }}{{ status_badge(i.Status) }}
            +
            +
            +{% endif %} +{% endblock %} diff --git a/templates/personeel_dagoverzicht.html b/templates/personeel_dagoverzicht.html new file mode 100644 index 0000000..2b37682 --- /dev/null +++ b/templates/personeel_dagoverzicht.html @@ -0,0 +1,134 @@ +{% extends "base.html" %} +{% from "_personeel.html" import subnav, status_badge, soort_label with context %} + +{% block title %}Dagoverzicht{% endblock %} +{% block page_title %}Dagoverzicht secretariaat{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{{ subnav('dagoverzicht') }} + + + +{% set weekdagen = ['maandag','dinsdag','woensdag','donderdag','vrijdag','zaterdag','zondag'] %} +{% for d in dagen %} +
            +
            +

            {{ weekdagen[d.datum.weekday()] }} {{ d.datum.strftime('%d/%m') }}

            + {{ d.personen|length }} afwezig · {{ d.klassen|length }} klas(sen) weg + {% if d.open_vervanging %} · {{ d.open_vervanging }} vervanging(en) te regelen{% endif %} +
            +
            +
            +

            👤 Afwezige personeelsleden

            + {% for p in d.personen %} + {% set i = p.item %} +
            +
            +
            {{ p.naam }}
            +
            + {% if p.rol == 'begeleider' %}🚌 begeleider uitstap "{{ i.Titel }}" ({{ i.Naam }}) + {% else %}{{ soort_label(i.Soort) }}{% if i.Soort != 'afwezigheid' %}: {{ i.Titel }}{% endif %}{% endif %} + · {{ DAGDELEN.get(i.Dagdeel) }}{% if i.Dagdeel == 'uren' and i.Lesuren %} ({{ i.Lesuren }}){% endif %} +
            + {% if p.rol != 'begeleider' and i.Soort != 'uitstap' and i.Klassen %} +
            {% for k in i.Klassen.split(',') %}{{ k.strip() }}{% endfor %}
            + {% endif %} + {% if p.rol != 'begeleider' and i.Soort == 'afwezigheid' and i.Omschrijving %}
            💬 {{ i.Omschrijving }}
            {% endif %} +
            +
            + {% if p.rol != 'begeleider' and i.Soort != 'uitstap' and i.Klassen %} +
            + + + {% if i.Vervanging_ok %} + ✓ Vervanging + + {% else %} + Vervanging te regelen + + {% endif %} +
            + {% endif %} + +
            +
            + {% else %} +
            Niemand afwezig. 🎉
            + {% endfor %} +
            +
            +

            🚌 Klassen weg

            + {% for k in d.klassen %} +
            + {{ k.klas }} + {{ k.item.Titel }}{% if k.item.Locatie %} · {{ k.item.Locatie }}{% endif %}
            + {{ DAGDELEN.get(k.item.Dagdeel) }}{% if k.item.Dagdeel == 'uren' and k.item.Lesuren %} ({{ k.item.Lesuren }}){% endif %} · {{ k.item.Naam }}
            +
            + {% else %} +
            Geen klassen weg.
            + {% endfor %} + {% if d.wachtend %} +
            ⏳ Nog niet goedgekeurd: + {% for w in d.wachtend %}{{ SOORTEN[w.Soort].icoon }} {{ w.Naam }} – {{ w.Titel }}{{ ', ' if not loop.last }}{% endfor %} +
            + {% endif %} +
            +
            +
            +{% endfor %} +{% endblock %} diff --git a/templates/personeel_detail.html b/templates/personeel_detail.html new file mode 100644 index 0000000..c72e4c5 --- /dev/null +++ b/templates/personeel_detail.html @@ -0,0 +1,134 @@ +{% extends "base.html" %} +{% from "_personeel.html" import subnav, status_badge, soort_label, periode with context %} + +{% block title %}{{ SOORTEN[item.Soort].label }} – {{ item.Naam }}{% endblock %} +{% block page_title %}{{ SOORTEN[item.Soort].icoon }} {{ SOORTEN[item.Soort].label }}{% endblock %} +{% block main_class %}medium{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{{ subnav('') }} + +
            +
            +
            +

            {{ item.Titel }}

            +
            {{ item.Naam or item.Email }}{% if item.Ingediend_door %} · gemeld door {{ item.Ingediend_door }}{% endif %}
            +
            +
            {{ status_badge(item.Status) }}
            +
            +
            +
            Soort
            {{ soort_label(item.Soort) }}
            +
            Wanneer
            {{ periode(item) }}
            + {% if item.Locatie %}
            Locatie
            {{ item.Locatie }}
            {% endif %} + {% if item.Klassen %}
            {{ 'Klassen mee' if item.Soort == 'uitstap' else 'Klassen' }}
            +
            {% for k in item.Klassen.split(',') %}{{ k.strip() }}{% endfor %}
            {% endif %} + {% if item.Begeleiders %}
            Begeleiders
            {{ item.Begeleiders }}
            {% endif %} + {% if item.Kost %}
            Kost
            € {{ '%.2f'|format(item.Kost)|replace('.', ',') }}
            {% endif %} + {% if item.Omschrijving %}
            {{ 'Opmerking' if item.Soort == 'afwezigheid' else 'Toelichting' }}
            {{ item.Omschrijving }}
            {% endif %} + {% if 'secretariaat' in p_rollen and item.Klassen and item.Soort != 'uitstap' %} +
            Vervanging
            +
            {% if item.Vervanging_ok %}✓ Geregeld{% else %}Nog te regelen{% endif %} + {% if item.Vervanging_info %} · {{ item.Vervanging_info }}{% endif %}
            + {% endif %} +
            +
            + +{# ---------- Directie: beslissen ---------- #} +{% if 'directie' in p_rollen and SOORTEN[item.Soort].goedkeuring and item.Status in ('ingediend', 'vraag') %} +
            +

            Beslissing directie

            + {% if item.Status == 'vraag' %}

            Je hebt een vraag gesteld; de leerkracht heeft nog niet geantwoord. Je kan toch al beslissen.

            {% endif %} +
            +
            + + +
            +
            + + + +
            +
            +
            +{% endif %} + +{# ---------- Leerkracht: antwoorden op vraag ---------- #} +{% if is_eigenaar and item.Status == 'vraag' %} +
            +

            ❓ De directie heeft een vraag

            +
            +
            + +
            +
            +{% endif %} + +{# ---------- Secretariaat: vervanging ---------- #} +{% if 'secretariaat' in p_rollen and item.Status in ('gemeld', 'goedgekeurd') and item.Soort != 'uitstap' %} +
            +

            🔁 Vervanging

            + +
            +{% endif %} + +{# ---------- Verloop + commentaar ---------- #} +
            +

            Verloop

            +
              + {% set labels = {'ingediend': 'diende de aanvraag in', 'gemeld': 'meldde de afwezigheid', 'goedgekeurd': 'keurde goed', + 'geweigerd': 'weigerde', 'vraag': 'stelde een vraag', 'antwoord': 'antwoordde', + 'commentaar': 'schreef', 'geannuleerd': 'annuleerde', 'vervanging': 'vervanging'} %} + {% for r in reacties %} +
            • + + {{ r.Naam or r.Email or '?' }} {{ labels.get(r.Actie, r.Actie) }} + · {{ r.Tijdstip.strftime('%d/%m %H:%M') }} + {% if r.Tekst %}
              {{ r.Tekst }}
              {% endif %} +
            • + {% endfor %} +
            + {% if item.Status not in ('geannuleerd',) %} + + {% endif %} +
            + +{% if (is_eigenaar or 'secretariaat' in p_rollen) and item.Status not in ('geannuleerd', 'geweigerd') and item.Tot_datum >= vandaag %} +
            + +
            +{% endif %} +{% endblock %} diff --git a/templates/personeel_mijn.html b/templates/personeel_mijn.html new file mode 100644 index 0000000..cf76346 --- /dev/null +++ b/templates/personeel_mijn.html @@ -0,0 +1,57 @@ +{% extends "base.html" %} +{% from "_personeel.html" import subnav, status_badge, soort_label, periode with context %} + +{% block title %}Afwezigheden & activiteiten{% endblock %} +{% block page_title %}Afwezigheden & activiteiten{% endblock %} +{% block main_class %}medium{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{{ subnav('mijn') }} + + + +
            +

            Mijn meldingen en aanvragen

            +
            + + + + {% for i in items %} + + + + + + + {% else %} + + {% endfor %} + +
            SoortTitelWanneerStatus
            {{ soort_label(i.Soort) }}{{ i.Titel }} + {% if i.Ingediend_door %}
            gemeld door {{ i.Ingediend_door }}
            {% endif %}
            {{ periode(i) }}{{ status_badge(i.Status) }}
            Je hebt nog geen meldingen of aanvragen.
            +
            +
            +{% endblock %} diff --git a/templates/personeel_nieuw.html b/templates/personeel_nieuw.html new file mode 100644 index 0000000..16a7309 --- /dev/null +++ b/templates/personeel_nieuw.html @@ -0,0 +1,172 @@ +{% extends "base.html" %} +{% from "_personeel.html" import subnav with context %} + +{% block title %}{{ SOORTEN[soort].label }}{% endblock %} +{% block page_title %}{{ SOORTEN[soort].icoon }} {{ 'Afwezigheid melden' if soort == 'afwezigheid' else SOORTEN[soort].label ~ ' aanvragen' }}{% endblock %} +{% block main_class %}medium{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +{{ subnav('') }} + +
            + {% for key, s in SOORTEN.items() %} + {{ s.icoon }} {{ s.label }} + {% endfor %} +
            + +
            + + +
            + {% if soort == 'afwezigheid' %}Het secretariaat ziet je afwezigheid meteen en krijgt een mail. Geen goedkeuring nodig. + {% elif soort == 'nascholing' %}De directie krijgt je aanvraag en kan goedkeuren, weigeren of een vraag stellen. Je krijgt een mail bij elke beslissing. + {% else %}De directie keurt de uitstap goed. Daarna ziet het secretariaat welke klassen en begeleiders weg zijn.{% endif %} +
            + + {% if is_secr %} +
            + + +
            + {% endif %} + + {% if soort != 'afwezigheid' %} +
            + + +
            + {% else %} +
            + + +
            + {% endif %} + +
            +
            + + +
            +
            + + +
            +
            + +
            + +
            + {% for key, label in DAGDELEN.items() %} + + {% endfor %} +
            +
            + + + {% if soort != 'afwezigheid' %} +
            +
            + + +
            +
            + + +
            +
            + {% endif %} + +
            + +
            + {% if klassen %} + +
            + {% set gekozen = form.getlist('klassen') if form else [] %} + {% for k in klassen %} + + {% endfor %} +
            +
            + + {% else %} + +
            De klassenlijst uit Smartschool kon niet geladen worden; typ de klassen in.
            + {% endif %} +
            +
            + + {% if soort == 'uitstap' %} +
            + + +
            Begeleiders verschijnen ook als afwezig in het dagoverzicht van het secretariaat.
            +
            + {% endif %} + +
            + + +
            + + +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/pin.html b/templates/pin.html new file mode 100644 index 0000000..80d0804 --- /dev/null +++ b/templates/pin.html @@ -0,0 +1,50 @@ +{% extends "base.html" %} + +{% block title %}Inloggen{% endblock %} +{% block body_class %}auth-page{% endblock %} +{% block header %}{% endblock %} +{% block main_class %}auth-wrap{% endblock %} +{% block flashes %}{% endblock %} + +{% block content %} + + +
            +

            🔐 Inloggen

            + + {% with messages = get_flashed_messages(with_categories=true) %} + {% for category, message in messages %} +
            {{ message }}
            + {% endfor %} + {% endwith %} + + {% if school_vast %} +

            🏫 {{ gekozen.naam }}

            + {% endif %} + +
            + + +
            +
            + + +
            + + + {% if google_aan %} +
            of
            + + + + Inloggen met Google + + {% endif %} +
            +{% endblock %} + +{% block footer %} +
            + PIVOT – Versie {{ version }} – Kristof Verbruggen +
            +{% endblock %} diff --git a/templates/qr_code.html b/templates/qr_code.html new file mode 100644 index 0000000..79203f6 --- /dev/null +++ b/templates/qr_code.html @@ -0,0 +1,53 @@ +{% extends "base.html" %} + +{% block title %}QR-generator{% endblock %} +{% block page_title %}QR-codegenerator{% endblock %} +{% block main_class %}narrow{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +
            +
            +

            💡 QR-codes maken

            +

            Maak eenvoudig QR-codes aan vanuit een Excel-bestand.

            +
            +
            + +
              +
            1. +

              Download het sjabloon

              + 📥 Sjabloon (.xlsx) +
            2. +
            3. +

              Upload je ingevulde bestand

              +
              + + +
              + + +
              + + +
              +
            4. +
            +
            +{% endblock %} diff --git a/templates/scholen.html b/templates/scholen.html new file mode 100644 index 0000000..48181e0 --- /dev/null +++ b/templates/scholen.html @@ -0,0 +1,100 @@ +{% extends "base.html" %} + +{% block title %}Scholen{% endblock %} + +{% block page_title %}Scholen in PIVOT{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +
            +

            🏫 Scholen

            +
            +
            + +
            + ➕ Nieuwe school +
            +
            + +
            + + {% for g in groepen %} + + + {% for s in g.scholen %} + + + + + + {% endfor %} + + {% else %} + + + + {% endfor %} +
            + +
            + {{ s.naam }} + {% if not s.actief %}inactief{% endif %} + {% if school and school.code == s.code %}huidige{% endif %} + + {% for b in badges[s.code] %} + {{ {'ok': '✓', 'fout': '✗', 'ongetest': '?'}.get(b.toestand, '–') }} {{ b.label }} + {% endfor %} + + {% if s.actief %} + ↪ Openen + {% endif %} + ✏️ Bewerken +
            + +
            +
            Nog geen scholen. Voeg er een toe, of importeer de oude config.ini met python beheer.py importeer-config.
            +
            +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/school_bewerken.html b/templates/school_bewerken.html new file mode 100644 index 0000000..5244632 --- /dev/null +++ b/templates/school_bewerken.html @@ -0,0 +1,201 @@ +{% extends "base.html" %} + +{% block title %}{{ 'Nieuwe school' if nieuw else school.naam }}{% endblock %} +{% block page_title %}{{ 'Nieuwe school' if nieuw else 'Instellingen school' }}{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{# Ingevulde waarde; is er nog niets ingevuld, dan staat de standaardwaarde al klaar in het veld. #} +{% macro waarde(key, standaard='') -%} +{%- if form.get('v_' ~ key) is not none -%}{{ form.get('v_' ~ key) }} +{%- elif school and school.waarden.get(key) not in (none, '') -%}{{ school.waarden.get(key) }} +{%- else -%}{{ standaard }}{%- endif -%} +{%- endmacro %} + +{% block content %} +
            + +
            +
            +

            🏫 {{ 'Nieuwe school' if nieuw else school.naam }}

            + {% if not nieuw %} +
            + +
            + {% endif %} +
            + + {% if mag_alles %} +
            +
            + + {% if nieuw %} + + Korte, vaste afkorting (kleine letters). Kan later niet meer wijzigen. + {% else %} + + {% endif %} +
            +
            + + +
            +
            + + + Hiermee wordt de school herkend bij Google-login. Het eerste domein is het hoofddomein (nieuwe accounts). +
            +
            + + + Wie PIVOT via dit adres opent, komt meteen bij deze school terecht. +
            +
            + + + {% if not nieuw %} + {% if db_status == 'ok' %} + ✓ Database bestaat en heeft de PIVOT-tabellen. + {% elif db_status in ('ontbreekt', 'leeg') %} + ⚠️ {{ 'Deze database bestaat nog niet.' if db_status == 'ontbreekt' else 'Deze database heeft (nog) niet de PIVOT-tabellen.' }} + + {% endif %} + {% endif %} +
            + {% if nieuw %} +
            + + + +
            + + {% endif %} +
            + + +
            +
            + {% else %} +

            Code {{ school.code }} · domein(en) {{ school.domeinen|join(', ') }} · database {{ school.db_naam }}. + Deze gegevens wijzigt de superbeheerder van de scholengroep.

            + {% endif %} +
            + +{% for groep, titel in groepen %} + {% if groep not in enkel_super or mag_alles %} +
            +
            +

            {{ titel }}

            + + {% if groep == 'google' %} +
            + + {% if school and school.google_sleutel %} +

            ✓ ingesteld + {{ school.google_sleutel.client_email }}

            +

            Client-ID voor domeinbrede delegatie (Admin-console › Beveiliging › API-beheer): + {{ school.google_sleutel.client_id }}

            + + {% else %} +

            nog niet ingesteld

            + {% endif %} + + Upload het JSON-bestand van het serviceaccount van deze school. Het wordt versleuteld bewaard en is nooit via de website op te vragen. +
            + {% endif %} + +
            + {% for v in velden if v.groep == groep %} +
            + + {% if v.soort == 'geheim' %} + {% set ingesteld = school and school.waarden.get(v.key) %} + + {% if ingesteld %} + + {% endif %} + {% elif v.soort == 'janee' %} + {% set aan = (school.get(v.key) if school else v.standaard) %} + + {% elif v.soort == 'keuze' %} + {% set gekozen = waarde(v.key) %} + + {% elif v.soort == 'tekstvak' %} + + {% else %} + + {% endif %} + {% if v.hulp %}{{ v.hulp }}{% endif %} +
            + {% endfor %} +
            +
            +
            + {% endif %} +{% endfor %} + +
            + + {% if session.get('superbeheerder') %} + Annuleren + {% else %} + Annuleren + {% endif %} +
            +
            + +{% if not nieuw %} +
            +{% if mag_alles %} +
            +{% endif %} +{% endif %} +{% endblock %} diff --git a/templates/school_test.html b/templates/school_test.html new file mode 100644 index 0000000..99837e7 --- /dev/null +++ b/templates/school_test.html @@ -0,0 +1,40 @@ +{% extends "base.html" %} + +{% block title %}Verbindingstest{% endblock %} +{% block page_title %}Verbindingstest{% endblock %} + +{% block content %} +
            +

            🩺 {{ school.naam }}

            +
            + + + + {% for onderdeel, ok, detail in resultaten %} + + + + + + {% endfor %} + +
            OnderdeelResultaatDetails
            {{ onderdeel }} + {% if ok is none %}niet ingesteld + {% elif ok %}✓ OK + {% else %}✗ Fout{% endif %} + {{ detail }}
            +
            +
            +
            + +
            + {% if session.get('superbeheerder') %} + ✏️ Instellingen + ← Alle scholen + {% else %} + ← Instellingen + {% endif %} +
            +
            +{% endblock %} diff --git a/templates/sgr_groepen.html b/templates/sgr_groepen.html new file mode 100644 index 0000000..a28cf46 --- /dev/null +++ b/templates/sgr_groepen.html @@ -0,0 +1,151 @@ +{% extends "base.html" %} + +{% block title %}SGR groepen{% endblock %} +{% block page_title %}SGR groepen{% endblock %} +{% block main_class %}wide{% endblock %} +{% block loader_text %}Groepen ophalen uit Smartschool...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +
            +

            👥 SGR groep in Smartschool

            +
            +
            + + +
            + {% if groepen %}⬇️ CSV{% endif %} + 🔄 Opnieuw ophalen +
            +
            + + {% if fout %} +
            {{ fout }}
            + {% elif not groepen %} +

            De groep {{ hoofd.naam }} bestaat in Smartschool, maar heeft geen subgroepen.

            + {% else %} +
            + Subgroepen {{ groepen|length }} + Lidmaatschappen {{ aantal_leden }} + Verschillende personen {{ uniek }} + {% set leeg = groepen|selectattr('leden', 'equalto', [])|selectattr('fout', 'none')|list|length %} + {% if leeg %}Zonder leden {{ leeg }}{% endif %} +
            +
            + + + + + Opgehaald uit Smartschool op {{ opgehaald }} +
            + +
            + {% for g in groepen %} +
            + + {{ g.naam }} + {% if g.code and g.code != g.naam %}{{ g.code }}{% endif %} + {% if g.pad %}in {{ g.pad|join(' › ') }}{% endif %} + {% if g.fout %} + leden niet op te halen + {% else %} + {{ g.leden|length }} {{ 'lid' if g.leden|length == 1 else 'leden' }}{% if g.aantal_sub %} · {{ g.aantal_sub }} subgroep{{ 'en' if g.aantal_sub != 1 }}{% endif %} + {% endif %} + +
            + {% if g.omschrijving and g.omschrijving != g.naam %}

            {{ g.omschrijving }}

            {% endif %} + {% if g.fout %} +
            Leden konden niet opgehaald worden: {{ g.fout }}
            + {% elif not g.leden %} +

            Deze groep heeft momenteel geen rechtstreekse leden.

            + {% else %} +
            + + + + {% for l in g.leden %} + + + + + + + + {% endfor %} + +
            NaamVoornaamGebruikersnaamRolE-mail
            {{ l.naam }}{{ l.voornaam }}{{ l.gebruikersnaam }}{% if l.rol %}{{ l.rol }}{% endif %}{{ l.email }}
            +
            + {% endif %} +
            +
            + {% endfor %} +
            + {% endif %} +

            Toont alle groepen onder {{ groep }} in Smartschool met hun huidige, + rechtstreekse leden. De standaard hoofdgroep ({{ standaard }}) stel je in via 🔌 Koppelingen › Smartschool. + Gegevens worden 10 minuten bewaard.

            +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/signpost_devices.html b/templates/signpost_devices.html new file mode 100644 index 0000000..9fe9a02 --- /dev/null +++ b/templates/signpost_devices.html @@ -0,0 +1,61 @@ +{% extends "base.html" %} + +{% block title %}Signpost DB{% endblock %} +{% block page_title %}Signpost-database{% endblock %} +{% block loader_text %}Synchroniseren met Signpost...{% endblock %} + +{% block content %} +
            +
            +

            📋 Signpost-toestellen

            +
            +
            + +
            +
            +
            + + + + {% if message %} +
            {{ message }}
            + {% endif %} + + {% if results %} +
            + + + + + + + + + + + + + {% for row in results %} + + + + + + + + + {% endfor %} + +
            SignpostnummerSerienummerModelAankoopbedragAankoopdatumGarantie
            {{ row['Signpostnummer'] if row['Signpostnummer'] is defined else row[0] }}{{ row['Device_serienummer'] if row['Device_serienummer'] is defined else row[1] }}{{ row['Device_model'] if row['Device_model'] is defined else row[2] }} + {% set bedrag = row['Aankoopbedrag'] if row['Aankoopbedrag'] is defined else row[3] %} + {% if bedrag %}€ {{ bedrag }}{% else %}-{% endif %} + {{ row['Aankoopdatum'] if row['Aankoopdatum'] is defined else row[4] }}{{ row['Garantie'] if row['Garantie'] is defined else row[5] }}
            +
            + {% else %} +

            Geen records gevonden in de database.

            + {% endif %} +
            +{% endblock %} diff --git a/templates/skore.html b/templates/skore.html new file mode 100644 index 0000000..4efc828 --- /dev/null +++ b/templates/skore.html @@ -0,0 +1,122 @@ +{% extends "base.html" %} + +{% block title %}Skore-synchronisatie{% endblock %} +{% block page_title %}Skore-synchronisatie{% endblock %} +{% block main_class %}medium{% endblock %} +{% block head %}{% if loopt %}{% endif %}{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +
            +

            🔁 Skore-synchronisatie

            +
            +
            + +
            +
            +
            +

            Synchroniseert de klassen en leerlingen van Smartschool naar Skore (Smartschool-webservice + startSkoreSync). Smartschool voert de synchronisatie op de achtergrond uit; + PIVOT vraagt de status daarna zelf op tot de synchronisatie klaar is.

            + {% if loopt %}
            ⏳ Er loopt een synchronisatie. Deze pagina ververst elke 20 seconden.
            {% endif %} +
            + +{% if planning %} +
            +

            🗓️ Automatisch synchroniseren

            +
            +
            +
            + + +
            +
            + + +
            +
            + + +
            +
            + +
            + : + +
            +
            +
            +

            + {% if volgende %}Volgende automatische synchronisatie: {{ volgende.strftime('%d-%m-%Y om %H:%M') }}. + {% else %}Er is geen automatische synchronisatie gepland.{% endif %} + PIVOT moet op dat moment draaien; een gemiste synchronisatie wordt nog tot 6 uur later ingehaald. +

            + +
            +
            +{% endif %} + +
            +

            🕑 Laatste synchronisaties

            +
            + + + + {% for r in log %} + + + + + + + + {% else %} + + {% endfor %} + +
            GestartDoorStatusMelding
            {{ r.Gestart.strftime('%d-%m-%Y %H:%M') }}{{ r.Door or '' }}{% if r.Manier == 'gepland' %} gepland{% endif %}{{ r.Status }}{{ r.Melding or '' }}{% if r.Service_ID %}
            taak {{ r.Service_ID }}
            {% endif %}
            + {% if r.Service_ID %} +
            + +
            + {% endif %} +
            Nog geen synchronisaties.
            +
            +
            +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/smartschool_activiteit.html b/templates/smartschool_activiteit.html new file mode 100644 index 0000000..3998a91 --- /dev/null +++ b/templates/smartschool_activiteit.html @@ -0,0 +1,282 @@ +{% extends "base.html" %} + +{% block title %}Co-accounts{% endblock %} +{% block page_title %}Co-accounts{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +
            +
            {{ nooit }}
            +
            Nog nooit aangemeld
            + {% if rows %}
            van {{ rows|length }} co-accounts
            {% endif %} +
            +
            +
            {{ leerlingen }}
            +
            Leerlingen met co-accounts
            +
            +
            +
            {% if laatst %}{{ laatst.strftime('%d-%m-%Y %H:%M') }}{% else %}Nog nooit{% endif %}
            +
            Opgehaald uit Smartschool
            +
            Automatisch één keer per dag
            +
            +
            + +{% if fout %}
            {{ fout }}
            {% endif %} +{% if not ingesteld %} +
            Smartschool is nog niet ingesteld voor deze school (🔌 Koppelingen › Smartschool).
            +{% endif %} + +
            +
            +
            + +
            + {% if rows %}⬇️ CSV-export{% endif %} +
            + + {% if status.bezig %}Bezig met ophalen…{% elif status.fout %}⚠️ {{ status.fout }}{% elif status.resultaat %}{{ status.resultaat }}{% endif %} + +
            +
            + +
            +
            + + +
            +
            + + + + + + + + + + + + + + {% for r in rows %} + + + + + + + + + + {% else %} + + {% endfor %} + +
            Klas Leerling Co-account Type E-mail Laatste aanmelding Actie
            {{ r.Klas or '–' }}{{ r.Leerling_naam }} {{ r.Leerling_voornaam }}{{ r.Voornaam }} {{ r.Naam }}{{ r.Type or '' }}{{ r.Email or '' }} + {% if r.Laatste_login %}{{ r.Laatste_login.strftime('%d-%m-%Y %H:%M') }}{% else %}Nooit{% endif %} + + +
            {% if status.bezig %}De co-accounts worden opgehaald uit Smartschool…{% else %}Nog geen co-accounts opgehaald.{% endif %}
            +
            +
            +
            +
            + +
            + +
            +
            +{% endblock %} + +{% block modals %} + +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/smartschool_beheer.html b/templates/smartschool_beheer.html new file mode 100644 index 0000000..26dc23f --- /dev/null +++ b/templates/smartschool_beheer.html @@ -0,0 +1,180 @@ +{% extends "base.html" %} + +{% block title %}Smartschool beheer{% endblock %} +{% block page_title %}Smartschool beheer{% endblock %} +{% block main_class %}medium{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +

            🏫 Wachtwoord & info

            + + + + {% if results %} +
            + + + + + + + + + + + {% for user in results %} + + + + + + + {% endfor %} + +
            InternnummerNaamGebruikersnaamActies
            {{ user.internnummer }}{{ user.voornaam }} {{ user.naam }}{{ user.gebruikersnaam }} + + +
            +
            + {% elif query %} +

            Geen resultaten gevonden voor "{{ query }}".

            +

            Op een deel van een naam zoekt PIVOT in de leerlingenlijst. Staat die nog leeg, + haal dan eerst de leerlingen op via Leerlingen › Informat & SS sync, of zoek op het volledige internnummer of de gebruikersnaam.

            + {% endif %} +
            +{% endblock %} + +{% block modals %} + + + +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/template_leerkracht.html b/templates/template_leerkracht.html new file mode 100644 index 0000000..49641b0 --- /dev/null +++ b/templates/template_leerkracht.html @@ -0,0 +1,56 @@ + + + + + + +
            +

            Nieuw Google Account

            +
            + +
            +

            Beste {{ naam }},

            + +

            Je account voor de schoolomgeving is aangemaakt op {{ datum }}.

            + + + +

            Hiermee kan je gebruikmaken van alle schoolgebonden google toepassingen (Drive, Gmail, Classroom, Agenda...).

            + +

            Let op: Je zult gevraagd worden om je wachtwoord te wijzigen bij de eerste keer inloggen.

            + + +
            + +

            Met vriendelijke groeten,

            + + + + + + +
            + K. Verbruggen
            + ICT coördinator
            + {{ contact_email }} +
            + B. Elewaut
            + Directeur
            + directie@kamkersem.be +
            + + \ No newline at end of file diff --git a/templates/toestellen.html b/templates/toestellen.html new file mode 100644 index 0000000..b1baa6d --- /dev/null +++ b/templates/toestellen.html @@ -0,0 +1,416 @@ +{% extends "base.html" %} + +{% block title %}Chromebooks{% endblock %} +{% block page_title %}Chromebooks{% endblock %} +{% block main_class %}wide{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +
            +

            💻 Alle toestellen

            +
            + +
            +
            + + + + {% if message %} +
            {{ message }}
            + {% endif %} + + {% if results %} +
            + + + + + + + + +
            + +
            + + + + + + + + + + + + + + + + {% for row in results %} + {% set g = (row['Garantie'] or '').split('-') %} + + + + + + + + + + + + {% endfor %} + +
            Toestelnummer Signpostnummer Serienummer Type Garantie Opmerking Status
            {{ row['KAMXM_nummer'] or '' }}{{ row['Signpostnummer'] or '' }}{{ row['Serienummer'] or '' }}{{ row['Type'] or '' }}{{ row['Garantie'] or '' }}{{ row['Opmerking'] or '' }} + {% if row['Status'] == 'Defect' %}🛠️ Defect + {% elif row['Status'] == 'Uitgeleend' %}🧑‍💻 Uitgeleend + {% else %}✅ Beschikbaar + {% endif %} + 🔒 Geblokkeerd + + + + {% if mag('toestel_blokkeren') and row['Serienummer'] %} + {% set blok = row['Geblokkeerd']|int == 1 %} + + {% endif %} + {% if row['Serienummer'] %} + + {% endif %} + + + + +
            +
            +
            +
            +
            + +
            + +
            + {% elif query %} +

            Geen resultaten gevonden voor "{{ query }}".

            + {% endif %} +
            +{% endblock %} + +{% block modals %} + + + + + + + +{% endblock %} + +{% block scripts %} + + +{% endblock %} diff --git a/templates/tweestaps.html b/templates/tweestaps.html new file mode 100644 index 0000000..7a7f524 --- /dev/null +++ b/templates/tweestaps.html @@ -0,0 +1,354 @@ +{% extends "base.html" %} + +{% block title %}2FA-hulp{% endblock %} +{% block page_title %}2FA-hulp{% endblock %} +{% block main_class %}{{ '' if tab == 'lijst' else 'medium' }}{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} + + +{% if tab != 'lijst' %} +
            + {# ---------- Zoeken ---------- #} + + + {% if zoekresultaten %} + + {% endif %} + + {% if fout %}
            {{ fout }}
            {% endif %} + + {# ---------- Gekozen gebruiker ---------- #} + {% if gebruiker %} +
            +
            + {{ (gebruiker.naam or gebruiker.email)[:1]|upper }} +
            + {{ gebruiker.naam }} + {{ gebruiker.email }} · {{ gebruiker.ou }} +
            +
            + {% if gebruiker.ingesteld %}✓ 2FA ingesteld + {% else %}2FA niet ingesteld{% endif %} + {% if uitzondering %}⏳ Uitzondering tot {{ uitzondering.Tot.strftime('%H:%M') }} + {% elif gebruiker.afgedwongen %}Verplicht{% endif %} + {% if gebruiker.geschorst %}Geschorst{% endif %} +
            +
            + + {# ---------- Codes tonen ---------- #} + {% if codes %} +
            +
            Back-upcode voor {{ gebruiker.email }}
            +
            {{ codes[0][:4] }} {{ codes[0][4:] }}
            +
            Typ deze code bij "Probeer een andere manier" › "Voer een van je back-upcodes van 8 cijfers in". Elke code werkt maar één keer.
            +
            + Alle {{ codes|length }} geldige codes tonen +
            {% for c in codes %}{{ c[:4] }} {{ c[4:] }}{% endfor %}
            +
            +
            + +
            + {% if code_actie == 'nieuw' %}
            Er is een nieuwe set aangemaakt; oudere codes van deze gebruiker werken niet meer.
            {% endif %} +
            + {% endif %} + +
            + {% if mag('tweestaps_codes') %} +
            +

            📱 Telefoon vergeten

            +

            Geef een back-upcode. 2FA blijft gewoon aan; de code werkt één keer.

            +
            + + + + +
            +
            + {% endif %} + + {% if mag('tweestaps_uitzetten') and reset_wacht %} +
            +

            ⏳ 2FA-reset wacht op Google

            +

            Gevraagd om {{ reset_wacht.Gevraagd_op.strftime('%H:%M') }} door {{ reset_wacht.Door or '?' }}. + {{ gebruiker.email }} staat al in de uitzonderingsgroep, maar Google past dat pas na enkele minuten toe. + PIVOT probeert elke minuut opnieuw (al {{ reset_wacht.Pogingen }} poging(en)), tot {{ reset_wacht.Tot.strftime('%H:%M') }}. + Je hoeft niets te doen.

            +

            Google meldt nu: 2FA afgedwongen voor deze gebruiker: {{ 'ja (uitzondering nog niet toegepast)' if gebruiker.afgedwongen else 'nee, de reset volgt bij de volgende poging' }}. + {% if reset_wacht.Laatste_fout %}
            Laatste antwoord van Google: {{ reset_wacht.Laatste_fout }}{% endif %}

            +

            Moet de gebruiker nu meteen binnen? Toon hierboven een back-upcode: daarmee logt hij in en stelt hij zijn nieuwe telefoon in via myaccount.google.com › Beveiliging › Authenticatie in 2 stappen. Dat werkt meteen, ook als 2FA afgedwongen wordt.

            + 🔄 Status vernieuwen +
            + {% elif mag('tweestaps_uitzetten') and gebruiker.ingesteld %} +
            +

            📵 Nieuwe telefoon: 2FA resetten

            +

            💡 Snelste weg bij een nieuwe telefoon: geef de gebruiker een back-upcode (hierboven). Hij logt daarmee in en koppelt zelf zijn nieuwe telefoon. Resetten is pas nodig als dat niet lukt.

            +

            Zet 2FA uit zodat de gebruiker het opnieuw kan instellen met een nieuw toestel. Oude back-upcodes en het oude toestel werken daarna niet meer. + {% if gebruiker.afgedwongen %}Omdat 2FA verplicht is, krijgt hij ook een tijdelijke uitzondering tot vandaag {{ einde.strftime('%H:%M') }} om opnieuw in te stellen.{% endif %}

            +
            + +
            + +
            + +
            +
            + {% endif %} + + {% if mag('tweestaps_uitzetten') %} +
            +

            ⏳ Tijdelijk zonder 2FA

            + {% if uitzondering %} +

            Deze gebruiker kan tot {{ uitzondering.Tot.strftime('%d-%m %H:%M') }} zonder 2FA inloggen. Daarna wordt 2FA automatisch terug verplicht.

            +
            + {% if uitzondering.Tot < einde %} +
            + + +
            + {% endif %} +
            + + +
            +
            + {% elif not groep %} +

            Nog niet ingesteld: vul de Uitzonderingsgroep in bij + {% if mag('koppelingen') %}🔌 Koppelingen van deze school{% else %}🔌 Koppelingen van deze school{% endif %} + › 🛡️ 2FA-hulp (een Google-groep waarvoor 2FA niet afgedwongen wordt).

            + {% else %} +

            Voor wie 2FA nog moet instellen, of als een back-upcode niet lukt. De uitzondering loopt tot + vandaag {{ einde.strftime('%H:%M') }}; daarna zet PIVOT 2FA automatisch terug aan.

            +
            + +
            + +
            + +
            + {% endif %} +
            + {% endif %} +
            +
            + {% endif %} +
            + +{# ---------- Lopende uitzonderingen ---------- #} +
            +

            ⏳ Lopende uitzonderingen

            + {% if actief %} +
            + + + + {% for u in actief %} + + + + + + + + {% endfor %} + +
            GebruikerTotGegeven doorRedenActie
            {{ u.Naam or u.Email }}
            {{ u.Email }}
            + {{ u.Tot.strftime('%H:%M') if u.Tot.date() == nu.date() else u.Tot.strftime('%d-%m %H:%M') }} + {% if u.Tot <= nu %}wordt beëindigd{% endif %} + {{ u.Door or '?' }}{{ u.Reden or '' }} + {% if mag('tweestaps_uitzetten') %} +
            + +
            + {% endif %} +
            +
            + {% else %} +

            Geen lopende uitzonderingen. Iedereen moet 2FA gebruiken.

            + {% endif %} +
            + +{# ---------- Logboek ---------- #} +{% if logboek %} +
            +
            +

            🕑 Recente acties

            + {{ log_totaal }} actie(s) +
            +
            + + + + {% for l in logboek %} + + + + + + + + {% endfor %} + +
            TijdstipDoorActieGebruikerDetails
            {{ l.Tijdstip.strftime('%d-%m %H:%M') }}{{ l.Door or '?' }}{{ l.Actie }}{{ l.Email }}{{ l.Details or '' }}
            +
            + {% set extra = {'email': gebruiker.email} if gebruiker else {} %} +
            +
            + {% if gebruiker %}{% endif %} + +
            + {% if log_paginas > 1 %} + + {% endif %} +
            +
            +{% endif %} + +{% else %} +{# ---------- Tab: nog geen 2FA ingesteld ---------- #} +
            +
            +
            +

            Nog geen 2FA ingesteld

            +
            Actieve accounts in {{ ous }} zonder 2FA
            +
            + +
            + {% if lijst_fout %}
            {{ lijst_fout }}
            {% endif %} + {% if lijst is not none %} +
            + + + + + + + {% set uitz = actief|map(attribute='Email')|list %} + {% for u in lijst %} + + + + + + {# volgorde bij sorteren: kan niet inloggen → uitzondering → nog niet verplicht; daarbinnen op naam #} + + + + {% else %} + + {% endfor %} + +
            Naam E-mail OULaatste login Status
            {{ u.naam }}{{ u.email }}{{ u.ou }}{{ u.laatste_login or 'Nooit' }} + {% if u.email in uitz %}Uitzondering + {% elif u.afgedwongen %}Kan niet inloggen + {% else %}Nog niet verplicht{% endif %} + Helpen
            🎉 Iedereen heeft 2FA ingesteld.
            +
            + {% if lijst %}

            {{ lijst|length }} account(s). "Kan niet inloggen": voor deze mensen wordt 2FA afgedwongen maar ze hebben het nog niet ingesteld. Geef ze een tijdelijke uitzondering zodat ze het kunnen instellen.

            {% endif %} + {% endif %} +
            +{% endif %} +{% endblock %} + +{% block scripts %} + + +{% endblock %} diff --git a/templates/uitdelen.html b/templates/uitdelen.html new file mode 100644 index 0000000..44a9596 --- /dev/null +++ b/templates/uitdelen.html @@ -0,0 +1,158 @@ +{% extends "base.html" %} + +{% block title %}Uitlenen{% endblock %} +{% block page_title %}Toestel uitdelen{% endblock %} +{% block main_class %}medium{% endblock %} + +{% block head %} + +{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
            +
            +

            Toestelgegevens

            +
            +
            + + +
              + {% if request.args.get('naam') %}

              👤 {{ request.args.get('naam') }}

              {% endif %} +
              +
              + + +
                +
                + + + +
                +
                + +
                +

                📷 Scanner

                + + {# Zonder https geeft de browser geen live camera: dan een foto nemen met de camera-app en de code daaruit lezen #} + + + +
                + +
                +
                Gescande waarde
                + - +
                + + +
                +
                +
                +
                +{% endblock %} + +{% block scripts %} +{% set toestel_voorkeur = 'beschikbaar' %}{% include '_toestel_zoekveld.html' %} + +{% endblock %} diff --git a/templates/verzendlijst.html b/templates/verzendlijst.html new file mode 100644 index 0000000..5bc5934 --- /dev/null +++ b/templates/verzendlijst.html @@ -0,0 +1,119 @@ +{% extends "base.html" %} + +{% block title %}{{ groep.naam }}{% endblock %} +{% block page_title %}Verzendlijst{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +

                ← Alle verzendlijsten

                + +
                +
                +

                📮 {{ groep.naam }}

                +

                {{ groep.email }}

                + {% if groep.aliassen %}

                Ook bereikbaar via: {{ groep.aliassen|join(', ') }}

                {% endif %} + +
                +
                + + +
                +
                + + +
                + {% if huidig_wie %} +
                + + +
                + {% else %} +

                "Wie mag mailen" kan hier niet getoond worden: daarvoor moet de scope + apps.groups.settings bij het serviceaccount staan en de Groups Settings API aan staan.

                + {% endif %} + +
                +
                + +
                +
                +

                👥 Leden ({{ leden|length }})

                +
                +
                +
                + + +
                +
                + + +
                +
                + + {% if leden|length > 10 %} + + {% endif %} +
                + + + + {% for m in leden %} + + + + + + {% else %} + + {% endfor %} + +
                E-mailadresSoortRol
                {{ m.email }}{{ {'USER': 'Gebruiker', 'GROUP': 'Verzendlijst', 'CUSTOMER': 'Hele organisatie', 'EXTERNAL': 'Extern'}.get(m.soort, m.soort) }} + +
                + + +
                +
                + + +
                +
                +
                Deze verzendlijst heeft nog geen leden.
                +
                +
                +
                +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/templates/verzendlijsten.html b/templates/verzendlijsten.html new file mode 100644 index 0000000..ff2f0e9 --- /dev/null +++ b/templates/verzendlijsten.html @@ -0,0 +1,166 @@ +{% extends "base.html" %} + +{% block title %}Verzendlijsten{% endblock %} +{% block page_title %}Verzendlijsten{% endblock %} +{% block loader_text %}Verzendlijsten ophalen bij Google...{% endblock %} + +{% block extra_css %} + +{% endblock %} + +{% block content %} +
                +
                + ➕ Nieuwe verzendlijst +
                +
                + +
                + + {% if domeinen %} + @ + + {% endif %} +
                +
                +
                + + +
                +
                + + +
                +
                + + +
                +
                +
                +
                +
                + +
                +
                +

                📮 Verzendlijsten

                + 🔄 Vernieuwen +
                + + {% if fout %} +
                {{ fout }}
                + {% else %} +
                + +
                +
                + + + + + + + + + + + + {% for g in lijsten %} + + + + + + + + {% else %} + + {% endfor %} + +
                Naam E-mailadres Leden Beschrijving
                {{ g.naam }}{{ g.email }}{% if g.aliassen %}
                ook: {{ g.aliassen|join(', ') }}{% endif %}
                {{ g.leden }}{{ g.beschrijving }}✏️ Openen
                Er zijn nog geen verzendlijsten in Google.
                +
                +
                +
                +
                + +
                + +
                + {% endif %} +
                +{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/tenancy.py b/tenancy.py new file mode 100644 index 0000000..67d7813 --- /dev/null +++ b/tenancy.py @@ -0,0 +1,747 @@ +""" +Meerdere scholen in één PIVOT. + +Elke school staat als één rij in de tabel `Scholen` van de CENTRALE database +(config.ini › [database] › centrale_database). Per school worden bijgehouden: + - code, naam, e-maildomein(en) en eventueel eigen hostnamen + - de eigen PIVOT-database van die school + - alle koppelingen (Smartschool, Informat, Google, Signpost, ...) in `instellingen` + - het Google-serviceaccount (JSON-sleutel) +Geheimen (wachtwoorden, client secrets, de Google-sleutel) worden versleuteld +opgeslagen met de sleutel uit de omgevingsvariabele PIVOT_SLEUTEL (of het +bestand geheimen/pivot.key). + +De 'huidige school' wordt per request bepaald (zie app.py) en kan buiten een +request gezet worden met `in_school(school)` (achtergrondtaken). +`Config.SS_API_PW` e.d. geven automatisch de waarde van de huidige school. +""" +import contextlib +import contextvars +import json +import re +import os +import sys +import threading +import time +from dataclasses import dataclass, field +from datetime import date + +from cryptography.fernet import Fernet, InvalidToken + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class GeenSchoolFout(RuntimeError): + """Er is geen school gekozen voor deze actie.""" + + +class KoppelingOntbreekt(RuntimeError): + """Een koppeling (bv. de Google-sleutel) is voor deze school nog niet ingesteld.""" + + +# ===================================================================== +# Velden per school +# ===================================================================== +@dataclass +class Veld: + key: str # naam zoals gebruikt in de code (Config.) + label: str + groep: str + soort: str = 'tekst' # tekst | geheim | getal | janee | tekstvak | keuze + standaard: object = '' + hulp: str = '' + keuzes: tuple = () # bij soort 'keuze': ((waarde, label), ...) + + +GROEPEN = [ + ('algemeen', '🏫 Algemeen'), + ('database', '🗄️ Database'), + ('smartschool', '📘 Smartschool'), + ('informat', '📗 Informat'), + ('google', '🔑 Google Workspace'), + ('tweestaps', '🛡️ 2FA-hulp'), + ('personeel', '👩‍🏫 Personeel'), + ('co2', '🌬️ CO2-sensoren'), + ('m4s', '🔧 Signpost / M4S'), +] + +ONDERWIJSNIVEAUS = (('kleuter', 'Kleuteronderwijs'), ('basis', 'Basisonderwijs'), ('secundair', 'Secundair onderwijs')) + +VELDEN = [ + # --- algemeen --- + Veld('ADRES', 'Adres', 'algemeen', hulp='Straat, nummer, postcode en gemeente'), + Veld('ONDERWIJSNIVEAU', 'Onderwijsniveau', 'algemeen', 'keuze', keuzes=ONDERWIJSNIVEAUS, + hulp='Voor de subtotalen bij de leerlingenaantallen'), + Veld('INSTELLINGSNUMMER', 'Instellingsnummer (officieel)', 'algemeen', + hulp='Officieel instellingsnummer van de school (Onderwijs Vlaanderen)'), + Veld('ADMIN_EMAIL', 'Beheerder (Google-admin)', 'algemeen', + hulp='Account waarin het serviceaccount handelt, bv. ict@school.be'), + Veld('CONTACT_EMAIL', 'Contactadres op brieven/PDF', 'algemeen', + hulp='Leeg = beheerder'), + Veld('SCHOOLYEAR', 'Schooljaar', 'algemeen', + hulp='bv. 2026-27. Leeg = automatisch (wisselt op 1 september)'), + Veld('STANDAARD_WACHTWOORD', 'Startwachtwoord bij Google-reset', 'algemeen', 'tekst', 'Welkom01!', + hulp='Leeg = Welkom01!. Gebruikers moeten het bij de eerste login wijzigen'), + + # --- database --- + Veld('DB_HOST', 'Server', 'database', hulp='Leeg = dezelfde server als de centrale database'), + Veld('DB_USER', 'Gebruiker', 'database', hulp='Leeg = standaardgebruiker uit config.ini'), + Veld('DB_PASSWORD', 'Wachtwoord', 'database', 'geheim', hulp='Leeg = standaardwachtwoord uit config.ini'), + + # --- smartschool --- + Veld('SS_API_PLATFORM', 'Platform', 'smartschool', hulp='bv. school.smartschool.be'), + Veld('SS_API_PW', 'Webservice-wachtwoord', 'smartschool', 'geheim', + hulp='Smartschool › Beheer › Webservices'), + Veld('SS_CLIENT_ID', 'OneRoster client-ID', 'smartschool'), + Veld('SS_CLIENT_SECRET', 'OneRoster client-secret', 'smartschool', 'geheim'), + Veld('AFWEZIGHEID_CODES', 'Afwezigheidscodes bewaren', 'smartschool', standaard='B', + hulp='Komma-gescheiden, bv. B of B,R'), + Veld('LAATKOMER_CODES', 'Codes voor te laat', 'smartschool', standaard='L', + hulp='Afwezigheidscodes in Smartschool die "te laat" betekenen (voor Laatkomers), komma-gescheiden, bv. L'), + Veld('AFWEZIGHEID_SYNC_UUR', 'Uur dagelijkse synchronisatie', 'smartschool', 'getal', 6), + Veld('SS_SGR_GROEP', 'Hoofdgroep SGR groepen', 'smartschool', standaard='groepen GO-Antwerpen', + hulp='Naam of code van de Smartschool-groep waarvan PIVOT de subgroepen en hun leden toont (Smartschool › SGR groepen)'), + + # --- informat --- + Veld('INFORMAT_INST_NUMBER', 'Instellingsnummer Informat', 'informat', + hulp='Nummer waarmee PIVOT zich bij Informat aanmeldt, bv. 040923. Haalt de school haar leerlingen uit ' + 'meer dan één instellingsnummer, zet ze dan allemaal hier met een naam: nummer=naam, gescheiden door ' + 'komma\'s, bv. 040774=Atheneum Irishof, 040791=Middenschool. PIVOT telt ze samen en toont ze apart.'), + Veld('INFORMAT_CAMPUSSEN_RAW', 'Campussen', 'informat', + hulp='Enkel voor een school met meerdere campussen: code=naam per campus, bv. 1=Campus Kapellen, ' + '3=Campus Stabroek. De code is de waarde in het Campusveld hieronder (of anders het Discimus-nummer uit ' + 'iLeerlingen › Algemeen › Structuur).'), + Veld('INFORMAT_ID', 'Client-ID', 'informat'), + Veld('INFORMAT_SECRET', 'Client-secret', 'informat', 'geheim'), + Veld('INFORMAT_SCOPE', 'Scope', 'informat', standaard='api_informat_sas_leerlingen.leerlingen', + hulp='Het instellingsnummer wordt er automatisch achter gezet'), + Veld('INFORMAT_AUTH_URL', 'Token-URL', 'informat', standaard='https://www.identityserver.be/connect/token'), + Veld('INFORMAT_API_BASE', 'API-URL', 'informat', standaard='https://leerlingenapi.informatsoftware.be/1'), + Veld('INFORMAT_CAMPUS_VELD', 'Campusveld in de leerlingenlijst', 'informat', + hulp='Veld in de Informat-leerlingenlijst dat de campus aangeeft, bv. vestnrDiscimus. Ingevuld: PIVOT telt per waarde van dit veld; de namen haalt ' + 'het uit Campussen (waarde=naam).'), + Veld('INFORMAT_STUDENT_API', 'API-URL Student API (campussen)', 'informat', + standaard='https://studentapi.informatsoftware.be/api/v1'), + Veld('INFORMAT_PERSONEEL_API', 'API-URL Personeel API (GO! Pro)', 'informat', + standaard='https://personeelsapi.informatsoftware.be'), + Veld('INFORMAT_PERSONEEL_SCOPE', 'Scope Personeel API', 'informat', standaard='api_informat_sas_personeel.personeel', + hulp='Het instellingsnummer wordt er automatisch achter gezet. De Informat-client moet deze scope hebben'), + Veld('INFORMAT_FACTUUR_API', 'API-URL Rekeningen API (leerlingfacturatie)', 'informat', + standaard='https://api.informatsoftware.be/invoices/v1', + hulp='GraphQL op /graphql, PDF\'s op /download/...'), + Veld('INFORMAT_INTERNAAT_NUMMER', 'Instellingsnummer internaat', 'informat', + hulp='Instellingsnummer van het internaat in Informat (bv. 123456). Meer dan één: 123456=Internaat A, 234567=Internaat B. ' + 'Leeg = het instellingsnummer van de Informat-koppeling hierboven'), + Veld('INFORMAT_INTERNAAT_API', 'API-URL Internaat API', 'informat', standaard='https://internaatapi.informatsoftware.be'), + Veld('INFORMAT_INTERNAAT_SCOPE', 'Scope Internaat API', 'informat', standaard='api_informat_sas_internaat', + hulp='Het instellingsnummer van het internaat wordt er automatisch achter gezet'), + Veld('INFORMAT_FACTUUR_GROEP', 'Toegangsgroep Rekeningen', 'informat', + hulp='Naam van de toegangsgroep in Rekeningen, zoals in Informat (bv. 000448 BS Irishof Kapellen). PIVOT zoekt ' + 'daarmee zelf de juiste scope. Meer dan één: scheiden met een puntkomma'), + Veld('INFORMAT_FACTUUR_SCOPE', 'Scope Rekeningen API', 'informat', + hulp='De volledige scope, bv. api_informat_invoices.invoices.read.2949957b-5dc1-4acc-a7cf-ba322b62cb12_123456 ' + '(toegangsgroep-GUID _ installatie-ID). Informat mailt die naar de eigenaar van de app zodra de school ' + 'toegang geeft tot de rekeningen. Leeg = PIVOT probeert hem zelf te vinden. Meer dan één: komma ertussen'), + + # --- google --- + Veld('GOOGLE_SSO_CLIENTID', 'Google-login client-ID', 'google', + hulp='Leeg = de gedeelde Google-login uit config.ini'), + Veld('GOOGLE_SSO_CLIENTSECRET', 'Google-login client-secret', 'google', 'geheim'), + Veld('STUDENT_OU', 'OU nieuwe leerlingen', 'google', standaard='Leerlingen/Leerlingen', + hulp='Het schooljaar wordt er automatisch achter gezet'), + Veld('OU_NIEUWE_LEERKRACHTEN', 'OU nieuwe leerkrachten', 'google', standaard='/Leerkrachten'), + Veld('CHROMEBOOK_OUS', 'OU\'s van de Chromebooks', 'google', + hulp='Voor "Chromebooks ophalen uit Google": volledige paden, gescheiden door komma\'s (sub-OU\'s tellen mee), ' + 'bv. /ChromeBooks Medewerkers, /ChromeBooks Leerlingen. Leeg = alle Chromebooks van het domein.'), + Veld('GOOGLE_SMTP_SERVER', 'SMTP-server', 'google', standaard='smtp-relay.gmail.com'), + Veld('GOOGLE_SMTP_PORT', 'SMTP-poort', 'google', 'getal', 587), + Veld('GOOGLE_SMTP_SENDER_adres', 'Afzender e-mails', 'google', hulp='bv. noreply@school.be'), + Veld('GOOGLE_SMTP_EMAIL_PASSWORD', 'SMTP-wachtwoord', 'google', 'geheim', + hulp='Leeg bij een relay die op IP-adres werkt'), + Veld('GOOGLE_API_SCOPES_RAW', 'API-scopes', 'google', 'tekstvak', + '\n'.join([ + 'https://www.googleapis.com/auth/admin.directory.user', + 'https://www.googleapis.com/auth/admin.directory.device.chromeos', + 'https://www.googleapis.com/auth/admin.directory.device.mobile', + 'https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly', + 'https://www.googleapis.com/auth/admin.directory.device.mobile.readonly', + 'https://www.googleapis.com/auth/admin.directory.orgunit', + ])), + + # --- 2FA --- + Veld('TWEESTAPS_UITZONDERING_GROEP', 'Uitzonderingsgroep', 'tweestaps', + hulp='Groep waarvoor 2FA NIET wordt afgedwongen'), + Veld('TWEESTAPS_OUS', 'OU\'s voor "nog geen 2FA"', 'tweestaps', standaard='/Leerkrachten'), + + # --- personeel --- + Veld('PERSONEEL_OUS', 'Personeels-OU\'s', 'personeel', standaard='/Leerkrachten'), + Veld('PERSONEEL_DIRECTIE', 'Directie (e-mails)', 'personeel'), + Veld('PERSONEEL_SECRETARIAAT', 'Secretariaat (e-mails)', 'personeel'), + Veld('PERSONEEL_SECRETARIAAT_MAIL', 'Gedeeld secretariaatsadres', 'personeel'), + Veld('PERSONEEL_MAILS', 'E-mails versturen', 'personeel', 'janee', True), + + # --- CO2 --- + Veld('CO2_NETWORK', 'Netwerk (prefix)', 'co2', hulp='bv. 10.166.0. — moet bereikbaar zijn vanaf de PIVOT-server'), + Veld('CO2_START_ADDR', 'Beginadres', 'co2', 'getal', 80), + Veld('CO2_END_ADDR', 'Eindadres', 'co2', 'getal', 155), + Veld('CO2_THRESHOLD', 'Drempel (ppm)', 'co2', 'getal', 900), + Veld('CO2_INTERVAL', 'Scaninterval (min)', 'co2', 'getal', 5), + + # --- M4S / Signpost --- + Veld('M4S_CLIENT_ID', 'Client-ID', 'm4s'), + Veld('M4S_CLIENT_SECRET', 'Client-secret', 'm4s', 'geheim'), + Veld('M4S_INSTITUTIONGUID', 'Institution GUID', 'm4s'), + Veld('M4S_AUTH_URL', 'Token-URL', 'm4s', standaard='https://idp.signpost.eu/oauth2/token'), + Veld('M4S_BASE_URL', 'API-URL', 'm4s', standaard='https://byod-api.signpost.be/v1/field-service'), + Veld('M4S_REPAIR_LOCATION_TYPE', 'Locatietype herstelling', 'm4s', standaard='100'), + Veld('M4S_REPAIR_STATUS', 'Status nieuwe herstelling', 'm4s', standaard='new'), + Veld('M4S_TRUTH_STATEMENT', 'Truth statement', 'm4s', standaard='True'), + Veld('M4S_REPAIR_AT_INTITUTION', 'Herstelling op school', 'm4s', standaard='True'), + Veld('M4S_LANGUAGE_CODE', 'Taalcode', 'm4s', standaard='nl'), + Veld('M4S_CONTACT_FIRST_NAME', 'Contact voornaam', 'm4s'), + Veld('M4S_CONTACT_LAST_NAME', 'Contact achternaam', 'm4s'), + Veld('M4S_CONTACT_EMAIL', 'Contact e-mail', 'm4s'), + Veld('M4S_CONTACT_PHONE', 'Contact telefoon', 'm4s'), + Veld('M4S_REPAIR_STREET', 'Straat', 'm4s'), + Veld('M4S_REPAIR_STREETNUMBER', 'Huisnummer', 'm4s'), + Veld('M4S_REPAIR_ZIPCODE', 'Postcode', 'm4s'), + Veld('M4S_REPAIIR_CITY', 'Gemeente', 'm4s'), + Veld('M4S_REPAIR_COUNTRYCODE', 'Landcode', 'm4s', standaard='BE'), + Veld('M4S_BILLING_FIRST_NAME', 'Facturatie voornaam', 'm4s'), + Veld('M4S_BILLING_LAST_NAME', 'Facturatie achternaam', 'm4s'), + Veld('M4S_BILLING_EMAIL', 'Facturatie e-mail', 'm4s'), + Veld('M4S_BILLING_PHONE', 'Facturatie telefoon', 'm4s'), +] +VELD = {v.key: v for v in VELDEN} + + +def informat_campussen(waarde): + """'040923=Campus Centrum, 041000=Campus Hoogboom' → [('040923', 'Campus Centrum'), ('041000', 'Campus Hoogboom')]. + Zonder naam krijgt een campus 'Campus '; met één nummer is de naam leeg.""" + delen = [d.strip() for d in str(waarde or '').replace(';', ',').split(',') if d.strip()] + uit = [] + for d in delen: + nummer, _, naam = d.partition('=') + nummer, naam = nummer.strip(), naam.strip() + if nummer and nummer not in [n for n, _ in uit]: + uit.append((nummer, naam or (f"Campus {nummer}" if len(delen) > 1 else ''))) + return uit + + +def informat_scope(basis, nummer): + """Informat-scope voor één instellingsnummer: '.'. Eindigt de ingestelde scope al op + '.' (een instellingsnummer), dan wordt dat vervangen.""" + basis = re.sub(r'\.\d+$', '', str(basis or '').strip()) + return f"{basis}.{nummer}" + + +def _automatisch_schooljaar(vandaag=None): + vandaag = vandaag or date.today() + start = vandaag.year if vandaag.month >= 9 else vandaag.year - 1 + return f"{start}-{str(start + 1)[-2:]}" + + +def _lijst(waarde): + return [x.strip() for x in str(waarde or '').replace(';', ',').split(',') if x.strip()] + + +# Afgeleide waarden: oude Config-namen die uit andere velden berekend worden +def _afgeleid(): + return { + 'SCHOOL_DOMAIN': lambda s: s.domein, + 'SCHOOLNAME': lambda s: s.naam, + 'SCHOOLNAME_SHORT': lambda s: s.code, + 'GOOGLE_ADMIN_EMAIL': lambda s: s.get('ADMIN_EMAIL'), + 'CONTACT_EMAIL': lambda s: s.waarden.get('CONTACT_EMAIL') or s.get('ADMIN_EMAIL'), + 'SCHOOLYEAR': lambda s: s.waarden.get('SCHOOLYEAR') or _automatisch_schooljaar(), + 'INFORMAT_SCHOOLYEAR': lambda s: s.get('SCHOOLYEAR'), + 'OU_NEW_STUDENTS': lambda s: f"{s.get('STUDENT_OU')} {s.get('SCHOOLYEAR')}", + 'GOOGLE_API_SCOPES': lambda s: [x.strip() for x in str(s.get('GOOGLE_API_SCOPES_RAW')).split() if x.strip()], + 'SS_API_PLATFORM': lambda s: (s.waarden.get('SS_API_PLATFORM') or '').replace('https://', '') + .replace('http://', '').split('/')[0], + 'SS_WSDL_URL': lambda s: f"https://{s.get('SS_API_PLATFORM')}/Webservices/V3?wsdl", + 'SS_TOKEN_URL': lambda s: f"https://{s.get('SS_API_PLATFORM')}/ims/oneroster/token", + 'SS_BASE_URL': lambda s: f"https://{s.get('SS_API_PLATFORM')}/ims/oneroster/v1p1", + # Eén of meer Informat-instellingsnummers: [(nummer, naam), ...] + 'INFORMAT_CAMPUSSEN': lambda s: informat_campussen(s.waarden.get('INFORMAT_INST_NUMBER')), + # Campussen (vestigingen) binnen het instellingsnummer, op Discimus-nummer: [(discimus_id, naam), ...] + 'INFORMAT_LOCATIES': lambda s: informat_campussen(s.waarden.get('INFORMAT_CAMPUSSEN_RAW')), + # Eerste nummer: voor alles wat maar één nummer kent + 'INFORMAT_INST_NUMBER': lambda s: (informat_campussen(s.waarden.get('INFORMAT_INST_NUMBER')) or [('', '')])[0][0], + 'INFORMAT_FULL_SCOPE': lambda s: informat_scope(s.get('INFORMAT_SCOPE'), s.get('INFORMAT_INST_NUMBER')), + 'DB_NAME': lambda s: s.db_naam, + } + + +AFGELEID = _afgeleid() + + +# ===================================================================== +# Versleuteling +# ===================================================================== +_fernet = None +_ENC = 'enc:' + + +def _sleutelbestand(): + return os.environ.get('PIVOT_SLEUTEL_BESTAND', + os.path.join(os.environ.get('PIVOT_GEHEIMEN', os.path.join(BASE_DIR, 'geheimen')), 'pivot.key')) + + +def fernet(): + global _fernet + if _fernet is None: + sleutel = os.environ.get('PIVOT_SLEUTEL', '').strip() + if not sleutel: + pad = _sleutelbestand() + if os.path.exists(pad): + with open(pad) as f: + sleutel = f.read().strip() + else: + os.makedirs(os.path.dirname(pad), exist_ok=True) + sleutel = Fernet.generate_key().decode() + with open(pad, 'w') as f: + f.write(sleutel) + try: + os.chmod(pad, 0o600) + except OSError: + pass + sys.stderr.write(f"PIVOT: nieuwe versleutelingssleutel aangemaakt in {pad}. " + "MAAK HIER EEN BACK-UP VAN: zonder deze sleutel zijn de opgeslagen geheimen onleesbaar.\n") + _fernet = Fernet(sleutel.encode()) + return _fernet + + +def versleutel(tekst): + if tekst in (None, ''): + return '' + return _ENC + fernet().encrypt(str(tekst).encode()).decode() + + +def ontsleutel(waarde): + if not isinstance(waarde, str) or not waarde.startswith(_ENC): + return waarde + try: + return fernet().decrypt(waarde[len(_ENC):].encode()).decode() + except InvalidToken: + sys.stderr.write("PIVOT: kan een geheim niet ontsleutelen (verkeerde PIVOT_SLEUTEL?).\n") + return '' + + +# ===================================================================== +# School +# ===================================================================== +class School: + def __init__(self, row): + self.id = row['School_ID'] + self.code = row['Code'] + self.naam = row['School_naam'] + self.domeinen = [d.lower().lstrip('@') for d in _lijst(row.get('Domein'))] + self.hostnamen = [h.lower() for h in _lijst(row.get('Hostnamen'))] + self.actief = bool(row.get('Actief', 1)) + self.db_naam = row['Db_naam'] + self.versie = str(row.get('Bijgewerkt') or '') + self.leerlingenaantal = row.get('Leerlingenaantal') + self.leerlingenaantal_sync = row.get('Leerlingenaantal_sync') + self.leerlingenaantal_detail = _json_of_none(row.get('Leerlingenaantal_detail')) + ruw = json.loads(row.get('Instellingen') or '{}') + self.waarden = {k: ontsleutel(v) for k, v in ruw.items()} + for key, kolom in KOLOM_VELDEN.items(): + if row.get(kolom): + self.waarden[key] = row[kolom] + sleutel = ontsleutel(row.get('Google_sleutel') or '') + self.google_sleutel = json.loads(sleutel) if sleutel else None + self.cache = {} # per-school objecten (services, caches); leeg na elke wijziging + self._lock = threading.RLock() # herbruikbaar: een object kan bij aanmaak zelf een object vragen + + @property + def domein(self): + return self.domeinen[0] if self.domeinen else '' + + def get(self, key): + if key in AFGELEID: + return AFGELEID[key](self) + veld = VELD.get(key) + if veld is None: + raise AttributeError(f"Onbekende instelling '{key}'") + waarde = self.waarden.get(key, '') + if waarde in (None, ''): + waarde = veld.standaard + if veld.soort == 'getal': + try: + return int(waarde) + except (TypeError, ValueError): + return int(veld.standaard or 0) + if veld.soort == 'janee': + return str(waarde).lower() in ('1', 'true', 'ja', 'yes', 'on') + return waarde + + def heeft(self, *keys): + """True als alle opgegeven instellingen ingevuld zijn.""" + return all(str(self.waarden.get(k) or '').strip() for k in keys) + + def db_config(self): + from config import Config + return { + 'host': self.waarden.get('DB_HOST') or Config.DB_HOST, + 'user': self.waarden.get('DB_USER') or Config.DB_USER, + 'password': self.waarden.get('DB_PASSWORD') or Config.DB_PASSWORD, + 'database': self.db_naam, + } + + def object(self, sleutel, maak): + """Eén object per school (bv. een service) bijhouden; `maak()` loopt binnen de schoolcontext.""" + obj = self.cache.get(sleutel) + if obj is None: + with self._lock: + obj = self.cache.get(sleutel) + if obj is None: + with in_school(self): + obj = maak() + self.cache[sleutel] = obj + return obj + + def __repr__(self): + return f"" + + +# ===================================================================== +# Register (uit de centrale database) +# ===================================================================== +_register = {'t': 0, 'scholen': {}} +_register_lock = threading.Lock() +CACHE_SECONDEN = 30 + +# Tabel Scholen (zie de PDF-structuur): de velden School_naam, Smartschool_platform_url, Adres, +# Instellingsnummer en Domein staan als echte kolommen; alle andere koppelingen in `Instellingen` (JSON). +SCHEMA = """ +CREATE TABLE IF NOT EXISTS Scholen ( + School_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + Code VARCHAR(32) NOT NULL, + School_naam VARCHAR(255) NOT NULL, + Smartschool_platform_url VARCHAR(255) NULL, + Adres VARCHAR(255) NULL, + Instellingsnummer VARCHAR(20) NULL, + Informat_instellingsnummer VARCHAR(500) NULL, + Onderwijsniveau VARCHAR(20) NULL, + Domein VARCHAR(500) NOT NULL DEFAULT '', + Hostnamen VARCHAR(500) NOT NULL DEFAULT '', + Actief TINYINT NOT NULL DEFAULT 1, + Db_naam VARCHAR(128) NOT NULL, + Instellingen MEDIUMTEXT NULL, + Google_sleutel MEDIUMTEXT NULL, + Leerlingenaantal INT NULL, + Leerlingenaantal_sync DATETIME NULL, + Leerlingenaantal_detail TEXT NULL, + Bijgewerkt DATETIME(6) NULL, + Bijgewerkt_door VARCHAR(255) NULL, + UNIQUE KEY uq_scholen_code (Code) +) ENGINE=InnoDB""" + +# Velden die als eigen kolom in Scholen staan i.p.v. in de JSON `Instellingen` +KOLOM_VELDEN = { + 'SS_API_PLATFORM': 'Smartschool_platform_url', + 'INSTELLINGSNUMMER': 'Instellingsnummer', # officieel nummer + 'INFORMAT_INST_NUMBER': 'Informat_instellingsnummer', # nummer voor de Informat-koppeling + 'ADRES': 'Adres', + 'ONDERWIJSNIVEAU': 'Onderwijsniveau', # kleuter | basis | secundair +} + + +def ensure_schema(): + """Centrale database: Scholen + gebruikers, rechten, logs en bugs (zie rechten.py).""" + from database import central_query + import rechten + # Database die van Windows komt (tabelnamen in kleine letters) op een Linux-server: eerst de namen herstellen, + # anders maakt PIVOT hieronder lege tabellen met hoofdletters aan naast de echte + try: + from services.tabelnamen import herstel_centraal + herstel_centraal() + except Exception as e: + sys.stderr.write(f"PIVOT: tabelnamen centrale database nakijken mislukt: {e}\n") + controleer_oude_tabellen() # eerst controleren, dan pas aanmaken + central_query(SCHEMA, commit=True) + _migreer_informat_nummer() + rechten.ensure_schema() + _kolommen_bijwerken() + + +def _json_of_none(t): + try: + return json.loads(t) if t else None + except ValueError: + return None + + +def _kolommen_bijwerken(): + """Kolommen die later bijkwamen of groter werden (bestaande installaties).""" + from database import central_query + kol = {(r['TABLE_NAME'].lower(), r['COLUMN_NAME'].lower()): r for r in central_query( + "SELECT TABLE_NAME, COLUMN_NAME, CHARACTER_MAXIMUM_LENGTH FROM information_schema.COLUMNS " + "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME IN ('Scholen', 'Leerlingenaantal_tellingen')")} + r = kol.get(('scholen', 'informat_instellingsnummer')) + if r and (r['CHARACTER_MAXIMUM_LENGTH'] or 0) < 500: + central_query("ALTER TABLE Scholen MODIFY Informat_instellingsnummer VARCHAR(500) NULL", commit=True) + if ('scholen', 'leerlingenaantal_detail') not in kol: + central_query("ALTER TABLE Scholen ADD COLUMN Leerlingenaantal_detail TEXT NULL AFTER Leerlingenaantal_sync", + commit=True) + if ('scholen', 'onderwijsniveau') not in kol: + central_query("ALTER TABLE Scholen ADD COLUMN Onderwijsniveau VARCHAR(20) NULL AFTER Informat_instellingsnummer", + commit=True) + if ('leerlingenaantal_tellingen', 'detail') not in kol: + central_query("ALTER TABLE Leerlingenaantal_tellingen ADD COLUMN Detail TEXT NULL AFTER Aantal", commit=True) + + +def _migreer_informat_nummer(): + """Vroeger stond het Informat-nummer in de kolom Instellingsnummer. Die kolom is nu voor het officiële + nummer; het Informat-nummer krijgt een eigen kolom. Eénmalig: enkel als die kolom nog niet bestaat.""" + from database import central_query + bestaat = central_query("SELECT COUNT(*) AS n FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() " + "AND TABLE_NAME = 'Scholen' AND COLUMN_NAME = 'Informat_instellingsnummer'")[0]['n'] + if bestaat: + return + central_query("ALTER TABLE Scholen ADD COLUMN Informat_instellingsnummer VARCHAR(500) NULL AFTER Instellingsnummer", + commit=True) + central_query("UPDATE Scholen SET Informat_instellingsnummer = Instellingsnummer, Instellingsnummer = NULL, " + "Bijgewerkt = NOW(6) WHERE Instellingsnummer IS NOT NULL", commit=True) + + +# Tabel → kolom die in de nieuwe structuur moet bestaan. Ontbreekt die, dan staat er nog een +# oude tabel met dezelfde naam (MySQL op Windows maakt geen onderscheid tussen hoofd- en kleine letters). +NIEUWE_KOLOMMEN = {'Scholen': 'School_ID', 'Gebruikers': 'Gebruiker_ID', 'Logs': 'Log_ID', + 'Status': 'Bugstatus_ID', 'Bugs': 'Bug_ID'} + + +def controleer_oude_tabellen(): + """Stopt als er een tabel met dezelfde naam bestaat, maar zonder de nieuwe structuur (en geen nieuwe ernaast).""" + from database import central_query + oud = [] + for tabel, kolom in NIEUWE_KOLOMMEN.items(): + rows = central_query( + "SELECT COUNT(*) AS n, COALESCE(SUM(LOWER(COLUMN_NAME) = LOWER(%s)), 0) AS heeft " + "FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND LOWER(TABLE_NAME) = LOWER(%s)", + (kolom, tabel)) + if rows and rows[0]['n'] and not int(rows[0]['heeft']): + oud.append(tabel) + if oud: + raise RuntimeError( + f"De centrale database bevat nog oude tabellen met dezelfde naam: {', '.join(oud)}. " + "Gebruik een nieuwe, lege database (config.ini › centrale_database) of hernoem die tabellen eerst.") + + +def herlaad(force=False): + """Leest de scholen opnieuw in. Ongewijzigde scholen behouden hun object (en dus hun caches).""" + from database import central_query + with _register_lock: + if not force and time.time() - _register['t'] < CACHE_SECONDEN: + return _register['scholen'] + try: + rows = central_query("SELECT * FROM Scholen ORDER BY School_naam") + except Exception as e: + sys.stderr.write(f"PIVOT: scholen inlezen mislukt: {e}\n") + return _register['scholen'] + oud = _register['scholen'] + nieuw = {} + for r in rows: + s = oud.get(r['Code']) + if s is None or s.versie != str(r.get('Bijgewerkt') or ''): + try: + s = School(r) + except Exception as e: + sys.stderr.write(f"PIVOT: school {r.get('Code')} kan niet geladen worden: {e}\n") + continue + else: + s.leerlingenaantal = r.get('Leerlingenaantal') + s.leerlingenaantal_sync = r.get('Leerlingenaantal_sync') + s.leerlingenaantal_detail = _json_of_none(r.get('Leerlingenaantal_detail')) + nieuw[r['Code']] = s + _register.update(t=time.time(), scholen=nieuw) + return nieuw + + +def alle_scholen(ook_inactief=False): + return [s for s in herlaad().values() if ook_inactief or s.actief] + + +def school_op_code(code, ook_inactief=False): + s = herlaad().get(code or '') + return s if s and (ook_inactief or s.actief) else None + + +def scholen_voor_email(email): + """Alle (actieve) scholen met het e-maildomein van `email`. Meerdere scholen mogen hetzelfde domein delen.""" + domein = (email or '').lower().rsplit('@', 1)[-1] + return [s for s in alle_scholen() if domein and domein in s.domeinen] + + +def school_voor_email(email): + """De (eerste) school met dit e-maildomein; zie scholen_voor_email als het domein gedeeld wordt.""" + lijst = scholen_voor_email(email) + return lijst[0] if lijst else None + + +def school_voor_host(host): + host = (host or '').lower().split(':')[0] + for s in alle_scholen(): + if host in s.hostnamen: + return s + return None + + +def opslaan(code, naam, domeinen, hostnamen, db_naam, actief, waarden, google_sleutel=None, + gebruiker=None, nieuw=False): + """Schrijft een school weg. `waarden` bevat de leesbare waarden; geheimen worden hier versleuteld.""" + from database import central_query + opgeslagen, kolommen = {}, {k: None for k in KOLOM_VELDEN.values()} + for k, v in waarden.items(): + if k not in VELD or v in (None, ''): + continue + if k in KOLOM_VELDEN: + kolommen[KOLOM_VELDEN[k]] = v + continue + opgeslagen[k] = versleutel(v) if VELD[k].soort == 'geheim' else v + sleutel_enc = versleutel(json.dumps(google_sleutel)) if google_sleutel else None + kol = list(kolommen) + if nieuw: + central_query( + "INSERT INTO Scholen (Code, School_naam, Domein, Hostnamen, Db_naam, Actief, Instellingen, Google_sleutel, " + f"{', '.join(kol)}, Bijgewerkt, Bijgewerkt_door) " + f"VALUES (%s,%s,%s,%s,%s,%s,%s,%s,{','.join(['%s'] * len(kol))},NOW(6),%s)", + (code, naam, domeinen, hostnamen, db_naam, int(bool(actief)), json.dumps(opgeslagen), + sleutel_enc, *[kolommen[k] for k in kol], gebruiker), commit=True) + else: + central_query( + "UPDATE Scholen SET School_naam=%s, Domein=%s, Hostnamen=%s, Db_naam=%s, Actief=%s, Instellingen=%s, " + f"Google_sleutel=COALESCE(%s, Google_sleutel), {', '.join(k + '=%s' for k in kol)}, " + "Bijgewerkt=NOW(6), Bijgewerkt_door=%s WHERE Code=%s", + (naam, domeinen, hostnamen, db_naam, int(bool(actief)), json.dumps(opgeslagen), + sleutel_enc, *[kolommen[k] for k in kol], gebruiker, code), commit=True) + herlaad(force=True) + + +def wis_google_sleutel(code, gebruiker=None): + from database import central_query + central_query("UPDATE Scholen SET Google_sleutel=NULL, Bijgewerkt=NOW(6), Bijgewerkt_door=%s WHERE Code=%s", + (gebruiker, code), commit=True) + herlaad(force=True) + + +# ===================================================================== +# Huidige school +# ===================================================================== +_huidige = contextvars.ContextVar('pivot_school', default=None) + + +def huidige_school(verplicht=True): + s = _huidige.get() + if s is None: + try: + from flask import g, has_request_context + if has_request_context(): + s = g.get('school') + except ImportError: + pass + if s is None and verplicht: + raise GeenSchoolFout("Er is geen school gekozen. Log opnieuw in.") + return s + + +@contextlib.contextmanager +def in_school(school): + token = _huidige.set(school) + try: + yield school + finally: + _huidige.reset(token) + + +def met_school(fn): + """Verpakt `fn` zodat hij in een andere thread in de huidige school loopt.""" + school = huidige_school() + + def wrapper(*a, **kw): + with in_school(school): + return fn(*a, **kw) + return wrapper + + +def voor_elke_school(fn, *, vereist=()): + """Voert fn() uit voor elke actieve school (die de opgegeven instellingen heeft).""" + for s in alle_scholen(): + if vereist and not s.heeft(*vereist): + continue + try: + with in_school(s): + fn() + except Exception as e: + sys.stderr.write(f"[{s.code}] {getattr(fn, '__qualname__', fn)}: {e}\n") + + +class per_school: + """ + Vervanger voor een module-niveau object (bv. `service = per_school(GoogleAdminService)`). + Elke school krijgt een eigen instantie, aangemaakt bij het eerste gebruik. + """ + def __init__(self, maak): + self._maak = maak + + def get(self): + return huidige_school().object(('per_school', id(self)), self._maak) + + def __getattr__(self, naam): + return getattr(self.get(), naam) + + def __setattr__(self, naam, waarde): + if naam.startswith('_'): + object.__setattr__(self, naam, waarde) + else: + setattr(self.get(), naam, waarde) + + +def school_singleton(cls, init): + """Eén instantie van `cls` per school. `init(inst)` zet de begintoestand.""" + def maak(): + inst = object.__new__(cls) + init(inst) + return inst + return huidige_school().object(('singleton', cls.__qualname__), maak) + + +class SchoolLijst: + """Lijst die bij elk gebruik uit de huidige school gelezen wordt (bv. toegangsgroepen).""" + def __init__(self, key): + self.key = key + + def _w(self): + return huidige_school().get(self.key) + + def __contains__(self, x): + return x in self._w() + + def __iter__(self): + return iter(self._w()) + + +# ===================================================================== +# Google-serviceaccount +# ===================================================================== +_GEEN = object() + + +def google_credentials(scopes, subject=_GEEN): + """Credentials van het serviceaccount van de huidige school, gedelegeerd naar `subject`. + Wordt een subject gevraagd maar is het leeg (bv. 'Beheerder (Google-admin)' niet ingevuld), dan stoppen + we met een duidelijke melding: zonder subject geeft Google enkel een vaag 'Invalid Input'.""" + from google.oauth2 import service_account + s = huidige_school() + if not s.google_sleutel: + raise KoppelingOntbreekt(f"Voor {s.naam} is nog geen Google-serviceaccount (JSON-sleutel) ingesteld. " + "Een beheerder kan die toevoegen via 🔌 Koppelingen van deze school.") + if subject is not _GEEN and not (subject or '').strip(): + raise KoppelingOntbreekt(f"Voor {s.naam} is 'Beheerder (Google-admin)' nog niet ingevuld " + "(🔌 Koppelingen van deze school › Algemeen, bv. ict@school.be). " + "PIVOT werkt in Google namens dat account.") + if subject is _GEEN: + subject = None + creds = service_account.Credentials.from_service_account_info(s.google_sleutel, scopes=list(scopes)) + return creds.with_subject(subject) if subject else creds