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

+201
View File
@@ -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 %}
<style>
.veld-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 0 20px; }
.veld-grid .field.breed { grid-column: 1 / -1; }
details.groep { margin-top: 20px; }
details.groep > summary { cursor: pointer; list-style: none; }
details.groep > summary::-webkit-details-marker { display: none; }
details.groep > summary h3 { display: inline; font-size: 1.05rem; }
details.groep > summary::after { content: ' ▸'; color: var(--text-muted); }
details.groep[open] > summary::after { content: ' ▾'; }
details.groep > .veld-grid { margin-top: 14px; }
.geheim-status { font-size: 12.5px; }
.wis-check { display: inline-flex; gap: 6px; align-items: center; font-size: 13px; color: var(--text-muted); margin-top: 4px; }
.wis-check input { width: auto; }
.sticky-acties { position: sticky; bottom: 0; background: var(--surface); padding: 14px 0 4px; border-top: 1px solid var(--border); margin-top: 20px; display: flex; gap: 10px; flex-wrap: wrap; }
textarea.mono { font-size: 12.5px; }
</style>
{% 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 %}
<form method="POST" enctype="multipart/form-data" autocomplete="off"
action="{{ url_for('scholen.nieuw') if nieuw else (url_for('scholen.bewerken', code=school.code) if mag_alles and request.endpoint == 'scholen.bewerken' else url_for('scholen.mijn_school')) }}">
<div class="card">
<div class="page-head">
<h2>🏫 {{ 'Nieuwe school' if nieuw else school.naam }}</h2>
{% if not nieuw %}
<div class="actions">
<button type="submit" form="testform" class="btn-sm btn-light">🩺 Verbindingen testen</button>
</div>
{% endif %}
</div>
{% if mag_alles %}
<div class="veld-grid">
<div class="field">
<label for="code">Code</label>
{% if nieuw %}
<input type="text" id="code" name="code" required pattern="[a-z0-9_-]{2,32}" value="{{ form.get('code', '') }}" placeholder="bv. kamxm">
<span class="field-hint">Korte, vaste afkorting (kleine letters). Kan later niet meer wijzigen.</span>
{% else %}
<input type="text" value="{{ school.code }}" readonly class="mono">
{% endif %}
</div>
<div class="field">
<label for="naam">Naam</label>
<input type="text" id="naam" name="naam" required value="{{ form.get('naam', school.naam if school else '') }}" placeholder="Koninklijk Atheneum ...">
</div>
<div class="field">
<label for="domeinen">E-maildomein(en)</label>
<input type="text" id="domeinen" name="domeinen" required value="{{ form.get('domeinen', school.domeinen|join(', ') if school else '') }}" placeholder="school.be, leerling.school.be">
<span class="field-hint">Hiermee wordt de school herkend bij Google-login. Het eerste domein is het hoofddomein (nieuwe accounts).</span>
</div>
<div class="field">
<label for="hostnamen">Eigen webadres(sen) <span class="muted">(optioneel)</span></label>
<input type="text" id="hostnamen" name="hostnamen" value="{{ form.get('hostnamen', school.hostnamen|join(', ') if school else '') }}" placeholder="pivot.school.be">
<span class="field-hint">Wie PIVOT via dit adres opent, komt meteen bij deze school terecht.</span>
</div>
<div class="field">
<label for="db_naam">Database</label>
<input type="text" id="db_naam" name="db_naam" required class="mono" value="{{ form.get('db_naam', school.db_naam if school else '') }}" placeholder="pivot_kamxm">
{% if not nieuw %}
{% if db_status == 'ok' %}
<span class="field-hint">✓ Database bestaat en heeft de PIVOT-tabellen.</span>
{% elif db_status in ('ontbreekt', 'leeg') %}
<span class="field-hint" style="color:var(--danger-text)">⚠️ {{ 'Deze database bestaat nog niet.' if db_status == 'ontbreekt' else 'Deze database heeft (nog) niet de PIVOT-tabellen.' }}</span>
<button type="submit" form="dbform" class="btn-sm btn-warning" style="margin-top:6px"
onclick="return confirm('Database {{ school.db_naam }} aanmaken met de standaardstructuur 2026-27? Bestaande tabellen en gegevens blijven behouden.')">🗄️ Database nu aanmaken</button>
{% endif %}
{% endif %}
</div>
{% if nieuw %}
<div class="field">
<label for="kopieer_schema_van">Database aanmaken?</label>
<select id="kopieer_schema_van" name="kopieer_schema_van">
<option value="">Nee, de database bestaat al</option>
<option value="__standaard__" {% if form.get('kopieer_schema_van') == '__standaard__' %}selected{% endif %}>Ja, nieuwe lege PIVOT-database (standaardstructuur 2026-27)</option>
{% for s in andere_scholen %}
<option value="{{ s.code }}" {% if form.get('kopieer_schema_van') == s.code %}selected{% endif %}>Ja, kopie van {{ s.naam }} (met gegevens)</option>
{% endfor %}
</select>
<div id="kopieOpties" class="field-hint" style="display:none;margin-top:8px">
<label class="check-box" style="margin:0 0 4px"><input type="checkbox" name="kopie_koppelingen" value="1" style="width:auto"
{% if not form or form.get('kopie_koppelingen') %}checked{% endif %}> Ook koppelingen en instellingen overnemen
(Smartschool, Informat, Google-sleutel, …)</label>
<label class="check-box" style="margin:0 0 4px"><input type="checkbox" name="kopie_rechten" value="1" style="width:auto"
{% if not form or form.get('kopie_rechten') %}checked{% endif %}> Ook de gebruikersrechten overnemen</label>
Alle tabellen en gegevens worden gekopieerd naar een <strong>nieuwe</strong> database.
<div class="alert alert-warning" style="margin:8px 0 0;font-size:13px">
💡 <strong>Testkopie?</strong> Vink dan <em>School is actief</em> uit. Een actieve kopie met dezelfde koppelingen
voert de geplande taken (afwezigheden, Skore, 2FA-opruiming) een tweede keer uit, op dezelfde Smartschool en
Google-omgeving. Wordt het een echte nieuwe school, pas dan eerst de koppelingen aan en zet ze pas daarna actief.
</div>
</div>
</div>
<script>
(function () {
var sel = document.getElementById('kopieer_schema_van'), box = document.getElementById('kopieOpties');
function toon() { box.style.display = (sel.value && sel.value !== '__standaard__') ? '' : 'none'; }
sel.addEventListener('change', toon); toon();
})();
</script>
{% endif %}
<div class="field">
<label>&nbsp;</label>
<label class="check-box"><input type="checkbox" name="actief" value="1" style="width:auto" {% if (form.get('actief') if form else (school.actief if school else True)) %}checked{% endif %}> School is actief</label>
</div>
</div>
{% else %}
<p class="muted">Code <span class="mono">{{ school.code }}</span> · domein(en) {{ school.domeinen|join(', ') }} · database <span class="mono">{{ school.db_naam }}</span>.
Deze gegevens wijzigt de superbeheerder van de scholengroep.</p>
{% endif %}
</div>
{% for groep, titel in groepen %}
{% if groep not in enkel_super or mag_alles %}
<div class="card">
<details class="groep" {% if groep in ('algemeen', 'smartschool', 'informat', 'google') or nieuw %}open{% endif %} style="margin-top:0">
<summary><h3>{{ titel }}</h3></summary>
{% if groep == 'google' %}
<div class="field breed" style="margin-top:14px">
<label>Serviceaccount (JSON-sleutel)</label>
{% if school and school.google_sleutel %}
<p class="geheim-status"><span class="badge badge-success">✓ ingesteld</span>
<span class="mono">{{ school.google_sleutel.client_email }}</span></p>
<p class="field-hint">Client-ID voor domeinbrede delegatie (Admin-console › Beveiliging › API-beheer):
<strong class="mono">{{ school.google_sleutel.client_id }}</strong></p>
<label class="wis-check"><input type="checkbox" name="wis_google_sleutel" value="1"> sleutel verwijderen</label>
{% else %}
<p class="geheim-status"><span class="badge badge-warning">nog niet ingesteld</span></p>
{% endif %}
<input type="file" name="google_sleutel" accept=".json,application/json" style="margin-top:8px">
<span class="field-hint">Upload het JSON-bestand van het serviceaccount van deze school. Het wordt versleuteld bewaard en is nooit via de website op te vragen.</span>
</div>
{% endif %}
<div class="veld-grid">
{% for v in velden if v.groep == groep %}
<div class="field {{ 'breed' if v.soort == 'tekstvak' }}">
<label for="v_{{ v.key }}">{{ v.label }}</label>
{% if v.soort == 'geheim' %}
{% set ingesteld = school and school.waarden.get(v.key) %}
<input type="password" id="v_{{ v.key }}" name="v_{{ v.key }}" autocomplete="new-password"
placeholder="{{ '•••••••• ingesteld – leeg laten = ongewijzigd' if ingesteld else 'niet ingesteld' }}">
{% if ingesteld %}
<label class="wis-check"><input type="checkbox" name="wis_{{ v.key }}" value="1"> wissen</label>
{% endif %}
{% elif v.soort == 'janee' %}
{% set aan = (school.get(v.key) if school else v.standaard) %}
<label class="check-box"><input type="checkbox" id="v_{{ v.key }}" name="v_{{ v.key }}" value="1" style="width:auto" {% if aan %}checked{% endif %}> Ja</label>
{% elif v.soort == 'keuze' %}
{% set gekozen = waarde(v.key) %}
<select id="v_{{ v.key }}" name="v_{{ v.key }}">
<option value="">– kies –</option>
{% for w, l in v.keuzes %}<option value="{{ w }}" {% if gekozen == w %}selected{% endif %}>{{ l }}</option>{% endfor %}
</select>
{% elif v.soort == 'tekstvak' %}
<textarea id="v_{{ v.key }}" name="v_{{ v.key }}" rows="5" class="mono">{{ waarde(v.key, v.standaard) }}</textarea>
{% else %}
<input type="{{ 'number' if v.soort == 'getal' else 'text' }}" id="v_{{ v.key }}" name="v_{{ v.key }}"
value="{{ waarde(v.key, v.standaard) }}">
{% endif %}
{% if v.hulp %}<span class="field-hint">{{ v.hulp }}</span>{% endif %}
</div>
{% endfor %}
</div>
</details>
</div>
{% endif %}
{% endfor %}
<div class="sticky-acties">
<button type="submit" class="btn-success">💾 Opslaan</button>
{% if session.get('superbeheerder') %}
<a href="{{ url_for('scholen.overzicht') }}" class="btn btn-light">Annuleren</a>
{% else %}
<a href="{{ url_for('main.dashboard') }}" class="btn btn-light">Annuleren</a>
{% endif %}
</div>
</form>
{% if not nieuw %}
<form id="testform" method="POST" action="{{ url_for('scholen.test', code=school.code) }}" onsubmit="showLoader('Verbindingen testen...')"></form>
{% if mag_alles %}
<form id="dbform" method="POST" action="{{ url_for('scholen.database_aanmaken', code=school.code) }}" onsubmit="showLoader('Database aanmaken...')"></form>
{% endif %}
{% endif %}
{% endblock %}