using System.Text.Encodings.Web; using System.Text.Json; using LehrerApp.Core.Interfaces; namespace LehrerApp.Core.Services; /// /// Datenauskunft für einen Schüler (5.4.3, Art. 15 DSGVO) — sammelt alle über die Person /// gespeicherten Daten aus den einzelnen Repositories zu einem Export. /// /// Enthält bewusst auch als vertraulich markierte Dokumentationseinträge: das /// Vertraulich-Kennzeichen in dieser App blendet Inhalte in der laufenden Ansicht aus, /// ist aber keine rechtliche Ausnahme vom Auskunftsanspruch der betroffenen Person selbst. /// Ob im Einzelfall doch eine Ausnahme greift (z.B. schutzwürdige Belange Dritter nach /// Landes-Schulrecht), muss die verantwortliche Lehrkraft/Schule selbst prüfen. /// public class PersonalDataExportService( IStudentRepository students, IGroupRepository groups, IGroupMembershipRepository memberships, IGradeRepository grades, IExamResultRepository examResults, IParticipationRepository participation, IDocumentationRepository documentation) { public string ExportAsJson(Guid studentId) { var student = students.GetById(studentId) ?? throw new InvalidOperationException("Schüler nicht gefunden."); var studentMemberships = memberships.GetByStudent(studentId); var studentGroups = studentMemberships .Select(m => groups.GetById(m.GroupId)) .Where(g => g is not null) .ToList(); var dto = new { ExportedAt = DateTime.UtcNow, Student = student, Gruppenzuordnungen = studentMemberships, Noten = studentGroups.SelectMany(g => grades.GetByStudentAndGroup(studentId, g!.Id)).ToList(), Klausurergebnisse = examResults.GetByStudent(studentId), Mitarbeit = participation.GetByStudent(studentId), Dokumentation = documentation.GetByStudent(studentId), }; return JsonSerializer.Serialize(dto, new JsonSerializerOptions { WriteIndented = true, // Ohne diese Option würden Umlaute als \uXXXX escaped — schlecht lesbar für den // eigentlichen Zweck dieses Exports (Auskunft an die betroffene Person). Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, }); } }