Initial commit

This commit is contained in:
Kristof committed 2026-10-14 12:29:29 +02:00
commit 536ff43ce4
158 files changed
+30355

No files matched your search

+199
View File
@@ -0,0 +1,199 @@
# 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 <gebruiker> -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_<school>`
3. **Met de hand**: `CREATE DATABASE pivot_<school>;` 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_<kopie>` (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 |
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/<school>/<sleutel>`), 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<ID>:<item-ID>#<hash>`. 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`.
- **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`.