Phase 11: Freigabereife (#16)
This commit was merged in pull request #16.
This commit is contained in:
@@ -3,6 +3,9 @@ import { TRPCError } from "@trpc/server";
|
||||
import { Dienstgrad, Prisma } from "@prisma/client";
|
||||
import { router, angemeldet, mitRecht } from "@/server/trpc";
|
||||
import { AuditAktion, protokolliereIn } from "@/lib/audit";
|
||||
import { auskunftSammeln, auskunftUmfang } from "@/lib/dsgvo/auskunft";
|
||||
import { auskunftPdf } from "@/lib/dsgvo/bericht";
|
||||
import { hochladen, objektSchluessel } from "@/lib/storage";
|
||||
import { darfPersonSehen, KeinZugriffFehler } from "@/lib/authz";
|
||||
import {
|
||||
blaettern,
|
||||
@@ -55,6 +58,87 @@ const personDaten = z.object({
|
||||
});
|
||||
|
||||
export const personRouter = router({
|
||||
/**
|
||||
* Auskunft nach Art. 15 DSGVO.
|
||||
*
|
||||
* Eine Mutation, obwohl sie im Kern nur liest — und das mit Absicht: das
|
||||
* Erstellen der Auskunft **ist** die Offenlegung, und die gehört ins
|
||||
* Protokoll. Als Abfrage würde sie zwischengespeichert, mehrfach ausgeführt
|
||||
* und wäre entweder nicht oder zwanzigmal vermerkt.
|
||||
*
|
||||
* Ein Durchgang liefert alles auf einmal: die Angaben für die Anzeige, das
|
||||
* PDF für die Akte und die JSON-Fassung nach Art. 20. Wer eine Auskunft
|
||||
* verlangt, bekommt sie vollständig oder gar nicht — nicht in drei Schritten,
|
||||
* von denen zwei vergessen werden können.
|
||||
*/
|
||||
auskunft: mitRecht("person.export")
|
||||
.input(idEingabe)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const auskunft = await ctx.db((db) => auskunftSammeln(db, input.id));
|
||||
|
||||
const organisation = await ctx.db((db) =>
|
||||
db.organisation.findUnique({
|
||||
where: { id: ctx.sitzung.organisationId },
|
||||
select: { slug: true },
|
||||
}),
|
||||
);
|
||||
|
||||
const pdf = await auskunftPdf(auskunft);
|
||||
|
||||
const schluessel = objektSchluessel({
|
||||
organisationSlug: organisation?.slug ?? ctx.sitzung.organisationId,
|
||||
entitaet: "auskunft",
|
||||
entitaetId: input.id,
|
||||
dateiname: `auskunft-${auskunft.erstelltAm.toISOString().slice(0, 10)}.pdf`,
|
||||
});
|
||||
|
||||
const abgelegt = await hochladen(schluessel, pdf, "application/pdf", {
|
||||
kategorie: "dsgvo-auskunft",
|
||||
person: input.id,
|
||||
});
|
||||
|
||||
const datei = await ctx.db(async (db) => {
|
||||
const angelegt = await db.datei.create({
|
||||
data: {
|
||||
organisationId: ctx.sitzung.organisationId,
|
||||
bucket: abgelegt.bucket,
|
||||
objektSchluessel: abgelegt.objektSchluessel,
|
||||
dateiname: `Auskunft ${auskunft.person.name}.pdf`,
|
||||
mimeTyp: "application/pdf",
|
||||
groesseBytes: BigInt(pdf.byteLength),
|
||||
pruefsumme: abgelegt.pruefsumme,
|
||||
hochgeladenVonId: ctx.sitzung.personId,
|
||||
},
|
||||
});
|
||||
|
||||
// Die Offenlegung selbst — mit Umfang, damit später nachvollziehbar
|
||||
// ist, was ausgehändigt wurde, ohne die Daten zu wiederholen.
|
||||
await protokolliereIn(db, {
|
||||
organisationId: ctx.sitzung.organisationId,
|
||||
sitzung: ctx.sitzung,
|
||||
aktion: AuditAktion.EXPORTIERT,
|
||||
entitaet: "Person",
|
||||
entitaetId: input.id,
|
||||
beschreibung:
|
||||
`Datenauskunft nach Art. 15 DSGVO für ${auskunft.person.name} erstellt `
|
||||
+ `(${auskunftUmfang(auskunft)} Angaben in ${auskunft.abschnitte.length} Abschnitten)`,
|
||||
nachher: {
|
||||
abschnitte: auskunft.abschnitte.length,
|
||||
angaben: auskunftUmfang(auskunft),
|
||||
dateiId: angelegt.id,
|
||||
},
|
||||
});
|
||||
|
||||
return angelegt;
|
||||
});
|
||||
|
||||
return {
|
||||
auskunft,
|
||||
umfang: auskunftUmfang(auskunft),
|
||||
dateiId: datei.id,
|
||||
};
|
||||
}),
|
||||
|
||||
liste: mitRecht("person.lesen")
|
||||
.input(
|
||||
listenEingabe(SORTIERFELDER).extend({
|
||||
|
||||
Reference in New Issue
Block a user