roosterwijs/backend/modules/importexport/views.py
bes-r c845588e5e
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
Add roles modules audit logging and CI
2026-07-04 23:01:06 +02:00

101 lines
3.7 KiB
Python

import csv
import io
from django.http import HttpResponse
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from core.audit import audit_log
from core.models import Afwezigheid, Groep, Persoon, Roosterblok
from core.permissions import CoreDataPermission, StaffDataPermission, module_permission_class
ImportExportModuleEnabled = module_permission_class("importexport")
def _doel_naam(blok):
if blok.groep_id:
return blok.groep.naam
if blok.subgroep_id:
return blok.subgroep.naam
if blok.leerling_id:
return blok.leerling.volledige_naam
return ""
EXPORTS = {
"personen": (
["id", "voornaam", "achternaam", "rol", "groep"],
lambda: Persoon.objects.select_related("groep").all(),
lambda p: [p.id, p.voornaam, p.achternaam, p.rol, p.groep.naam if p.groep_id else ""],
),
"groepen": (
["id", "naam", "actief"],
lambda: Groep.objects.all(),
lambda g: [g.id, g.naam, g.actief],
),
"roosterblokken": (
["id", "schooljaar", "tijdslot", "activiteit", "doel_type", "doel", "begeleiders"],
lambda: Roosterblok.objects.select_related(
"schooljaar", "tijdslot", "activiteit", "groep", "subgroep", "leerling"
).prefetch_related("begeleiders"),
lambda b: [
b.id,
b.schooljaar.naam,
str(b.tijdslot),
b.activiteit.naam,
b.doel_type,
_doel_naam(b),
", ".join(p.volledige_naam for p in b.begeleiders.all()),
],
),
"afwezigheden": (
["id", "persoon", "start_datum", "eind_datum", "reden"],
lambda: Afwezigheid.objects.select_related("persoon").all(),
lambda a: [a.id, a.persoon.volledige_naam, a.start_datum, a.eind_datum, a.reden],
),
}
@api_view(["GET"])
@permission_classes([StaffDataPermission, ImportExportModuleEnabled])
def export_csv(request, resource):
if resource not in EXPORTS:
return Response({"detail": "Onbekende export."}, status=404)
headers, queryset_factory, row_factory = EXPORTS[resource]
response = HttpResponse(content_type="text/csv; charset=utf-8")
response["Content-Disposition"] = f'attachment; filename="{resource}.csv"'
response.write("\ufeff")
writer = csv.writer(response)
writer.writerow(headers)
for obj in queryset_factory():
writer.writerow(row_factory(obj))
audit_log(request, "export", f"CSV:{resource}")
return response
@api_view(["POST"])
@permission_classes([CoreDataPermission, ImportExportModuleEnabled])
def import_personen(request):
tekst = request.data.get("csv") or ""
if not tekst.strip():
return Response({"detail": "CSV-inhoud ontbreekt."}, status=400)
reader = csv.DictReader(io.StringIO(tekst))
aangemaakt = 0
meldingen = []
for nummer, row in enumerate(reader, start=2):
voornaam = (row.get("voornaam") or row.get("Voornaam") or "").strip()
achternaam = (row.get("achternaam") or row.get("Achternaam") or "").strip()
rol = (row.get("rol") or row.get("Rol") or "leerling").strip()
groep_naam = (row.get("groep") or row.get("Groep") or "").strip()
if not voornaam and not achternaam:
continue
groep = None
if groep_naam:
groep, _ = Groep.objects.get_or_create(naam=groep_naam)
try:
Persoon.objects.create(voornaam=voornaam, achternaam=achternaam, rol=rol, groep=groep)
aangemaakt += 1
except Exception as exc:
meldingen.append(f"Rij {nummer}: {exc}")
audit_log(request, "import", "Persoon", {"aangemaakt": aangemaakt, "meldingen": len(meldingen)})
return Response({"aangemaakt": aangemaakt, "meldingen": meldingen})