Zeilenenden der 24 verbliebenen Dateien normalisieren
Ausschliesslich Zeilenenden. Nachgewiesen mit "git diff --cached --ignore-cr-at-eol": Der Diff ist leer, es hat sich kein Zeichen Inhalt geaendert. Deshalb ein eigener Commit: 7448 geaenderte Zeilen in einem Commit mit echten Aenderungen zu verstecken, macht die Historie an dieser Stelle unlesbar. So laesst er sich beim Durchsehen ueberspringen. Refs #26
This commit is contained in:
+293
-293
@@ -1,293 +1,293 @@
|
||||
'use server'
|
||||
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import type { Modul } from '@prisma/client'
|
||||
import { db, papierkorbGrenze } from '@/lib/db'
|
||||
import { protokollieren } from '@/lib/audit'
|
||||
import { erfordereFrischeAnmeldung, erfordereZugang } from '@/lib/auth/sitzung'
|
||||
import { entfernen } from '@/lib/speicher'
|
||||
import { papierkorbSchema } from '@/lib/validierung/freigaben'
|
||||
|
||||
/**
|
||||
* Papierkorb.
|
||||
*
|
||||
* Loeschen heisst in dieser Anwendung: "geloeschtAm" setzen. Der Datensatz
|
||||
* bleibt 30 Tage sichtbar und wiederherstellbar. Das ist kein Luxus - in
|
||||
* einer Betreuungsakte ist ein versehentlich geloeschter Bescheid ein
|
||||
* echtes Problem, und der Nachweis gegenueber dem Gericht haengt daran.
|
||||
*
|
||||
* Endgueltig geloescht wird nur hier, nur einzeln und nur nach frischer
|
||||
* Anmeldung. Danach ist der Datensatz weg; im Audit-Log bleibt stehen, dass
|
||||
* es ihn gab und wer ihn entfernt hat.
|
||||
*/
|
||||
|
||||
export type Aktionszustand = {
|
||||
fehler?: string
|
||||
erfolg?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Was im Papierkorb auftauchen kann. Bewusst eine feste Liste und keine
|
||||
* dynamische Modellsuche: Der Entitaetsname kommt aus einem Formular, und
|
||||
* daraus darf niemals ein beliebiger Datenbankzugriff werden.
|
||||
*/
|
||||
type Eintragsart = {
|
||||
bezeichnung: string
|
||||
mehrzahl: string
|
||||
modul: Modul
|
||||
laden: (betreuteId: string, seit: Date) => Promise<PapierkorbEintrag[]>
|
||||
wiederherstellen: (id: string, betreuteId: string) => Promise<void>
|
||||
endgueltigLoeschen: (id: string, betreuteId: string) => Promise<void>
|
||||
}
|
||||
|
||||
export type PapierkorbEintrag = {
|
||||
id: string
|
||||
entitaet: string
|
||||
bezeichnung: string
|
||||
geloeschtAm: Date
|
||||
}
|
||||
|
||||
/** Kleine Hilfe, damit die Tabelle unten nicht 20-mal dasselbe wiederholt. */
|
||||
function einfach<T extends { id: string; geloeschtAm: Date | null }>(
|
||||
entitaet: string,
|
||||
bezeichnung: string,
|
||||
mehrzahl: string,
|
||||
modul: Modul,
|
||||
zugriff: {
|
||||
findMany: (args: unknown) => Promise<T[]>
|
||||
update: (args: unknown) => Promise<unknown>
|
||||
delete: (args: unknown) => Promise<unknown>
|
||||
},
|
||||
titelFeld: string,
|
||||
): Eintragsart {
|
||||
return {
|
||||
bezeichnung,
|
||||
mehrzahl,
|
||||
modul,
|
||||
laden: async (betreuteId, seit) => {
|
||||
const treffer = await zugriff.findMany({
|
||||
where: { betreuteId, geloeschtAm: { gte: seit } },
|
||||
orderBy: { geloeschtAm: 'desc' },
|
||||
})
|
||||
return treffer.map((datensatz) => ({
|
||||
id: datensatz.id,
|
||||
entitaet,
|
||||
bezeichnung:
|
||||
String((datensatz as unknown as Record<string, unknown>)[titelFeld] ?? '(ohne Titel)'),
|
||||
geloeschtAm: datensatz.geloeschtAm!,
|
||||
}))
|
||||
},
|
||||
wiederherstellen: async (id, betreuteId) => {
|
||||
await zugriff.update({ where: { id, betreuteId }, data: { geloeschtAm: null } })
|
||||
},
|
||||
endgueltigLoeschen: async (id, betreuteId) => {
|
||||
await zugriff.delete({ where: { id, betreuteId } })
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function eintragsarten(): Record<string, Eintragsart> {
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
const z = db as any
|
||||
return {
|
||||
Vorgang: einfach('Vorgang', 'Vorgang', 'Vorgänge', 'VORGAENGE', z.vorgang, 'titel'),
|
||||
Frist: einfach('Frist', 'Frist', 'Fristen', 'FRISTEN', z.frist, 'titel'),
|
||||
Dokument: einfach('Dokument', 'Dokument', 'Dokumente', 'DOKUMENTE', z.dokument, 'titel'),
|
||||
Konto: einfach('Konto', 'Konto', 'Konten', 'FINANZEN', z.konto, 'bezeichnung'),
|
||||
Buchung: einfach('Buchung', 'Buchung', 'Buchungen', 'FINANZEN', z.buchung, 'gegenstelle'),
|
||||
Vermoegensposten: einfach(
|
||||
'Vermoegensposten',
|
||||
'Vermögensposten',
|
||||
'Vermögensposten',
|
||||
'FINANZEN',
|
||||
z.vermoegensposten,
|
||||
'bezeichnung',
|
||||
),
|
||||
Immobilie: einfach('Immobilie', 'Immobilie', 'Immobilien', 'IMMOBILIE', z.immobilie, 'bezeichnung'),
|
||||
Vertrag: einfach('Vertrag', 'Vertrag', 'Verträge', 'VERTRAEGE', z.vertrag, 'bezeichnung'),
|
||||
Schreibvorlage: einfach(
|
||||
'Schreibvorlage',
|
||||
'Vorlage',
|
||||
'Vorlagen',
|
||||
'DOKUMENTE',
|
||||
z.schreibvorlage,
|
||||
'name',
|
||||
),
|
||||
Kontakt: einfach('Kontakt', 'Kontakt', 'Kontakte', 'KONTAKTE', z.kontakt, 'name'),
|
||||
Kontaktprotokoll: einfach(
|
||||
'Kontaktprotokoll',
|
||||
'Kontaktprotokoll',
|
||||
'Kontaktprotokolle',
|
||||
'KONTAKTE',
|
||||
z.kontaktprotokoll,
|
||||
'gespraechspartner',
|
||||
),
|
||||
Gesundheitsereignis: einfach(
|
||||
'Gesundheitsereignis',
|
||||
'Gesundheitsereignis',
|
||||
'Gesundheitsereignisse',
|
||||
'GESUNDHEIT',
|
||||
z.gesundheitsereignis,
|
||||
'titel',
|
||||
),
|
||||
Genehmigung: einfach(
|
||||
'Genehmigung',
|
||||
'Genehmigung',
|
||||
'Genehmigungen',
|
||||
'VORGAENGE',
|
||||
z.genehmigung,
|
||||
'titel',
|
||||
),
|
||||
SozialhilfeAntrag: einfach(
|
||||
'SozialhilfeAntrag',
|
||||
'Sozialhilfeantrag',
|
||||
'Sozialhilfeanträge',
|
||||
'SOZIALHILFE',
|
||||
z.sozialhilfeAntrag,
|
||||
'leistungsart',
|
||||
),
|
||||
Leistung: einfach('Leistung', 'Leistung', 'Leistungen', 'SOZIALHILFE', z.leistung, 'bezeichnung'),
|
||||
Bericht: einfach('Bericht', 'Bericht', 'Berichte', 'BERICHTE', z.bericht, 'titel'),
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
}
|
||||
|
||||
/** Alles, was in den letzten 30 Tagen geloescht wurde. */
|
||||
export async function papierkorbLaden(betreuteId: string): Promise<
|
||||
{ art: string; bezeichnung: string; eintraege: PapierkorbEintrag[] }[]
|
||||
> {
|
||||
const { zugang } = await erfordereZugang(betreuteId, 'STAMMDATEN', 'lesen')
|
||||
const seit = papierkorbGrenze()
|
||||
|
||||
const gruppen: { art: string; bezeichnung: string; eintraege: PapierkorbEintrag[] }[] = []
|
||||
for (const [art, beschreibung] of Object.entries(eintragsarten())) {
|
||||
// Ein Mitleser sieht auch im Papierkorb nur, was ihm freigegeben ist.
|
||||
if (zugang.rolle === 'MITLESER' && !zugang.freigegebeneModule.includes(beschreibung.modul)) {
|
||||
continue
|
||||
}
|
||||
const eintraege = await beschreibung.laden(betreuteId, seit)
|
||||
if (eintraege.length > 0) {
|
||||
gruppen.push({ art, bezeichnung: beschreibung.mehrzahl, eintraege })
|
||||
}
|
||||
}
|
||||
return gruppen
|
||||
}
|
||||
|
||||
/**
|
||||
* Haengt an diesem Datensatz eine Datei im Objektspeicher?
|
||||
*
|
||||
* Die beiden Faelle werden ausdruecklich getrennt abgefragt statt ueber
|
||||
* eine gemeinsam gehaltene Tabellenvariable: Prisma gibt jedem Modell
|
||||
* eigene Signaturen, und eine Variable, die mal das eine und mal das
|
||||
* andere Delegate haelt, laesst sich nicht mehr aufrufen.
|
||||
*/
|
||||
async function objektSchluesselFinden(
|
||||
entitaet: string,
|
||||
entitaetId: string,
|
||||
betreuteId: string,
|
||||
): Promise<string | null> {
|
||||
if (entitaet === 'Dokument') {
|
||||
const dokument = await db.dokument.findFirst({
|
||||
where: { id: entitaetId, betreuteId },
|
||||
select: { objektSchluessel: true },
|
||||
})
|
||||
return dokument?.objektSchluessel ?? null
|
||||
}
|
||||
if (entitaet === 'Bericht') {
|
||||
const bericht = await db.bericht.findFirst({
|
||||
where: { id: entitaetId, betreuteId },
|
||||
select: { objektSchluessel: true },
|
||||
})
|
||||
return bericht?.objektSchluessel ?? null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export async function wiederherstellen(
|
||||
_zustand: Aktionszustand,
|
||||
formular: FormData,
|
||||
): Promise<Aktionszustand> {
|
||||
const gelesen = papierkorbSchema.safeParse({
|
||||
betreuteId: formular.get('betreuteId'),
|
||||
entitaet: formular.get('entitaet'),
|
||||
entitaetId: formular.get('entitaetId'),
|
||||
})
|
||||
if (!gelesen.success) return { fehler: 'Diese Angaben ergeben keinen Sinn.' }
|
||||
|
||||
const art = eintragsarten()[gelesen.data.entitaet]
|
||||
if (!art) return { fehler: 'Diese Art von Datensatz kennt der Papierkorb nicht.' }
|
||||
|
||||
const { benutzer, zugang } = await erfordereZugang(gelesen.data.betreuteId, art.modul, 'schreiben')
|
||||
if (zugang.rolle === 'MITLESER') return { fehler: 'Als Mitleser darfst du nichts wiederherstellen.' }
|
||||
|
||||
await art.wiederherstellen(gelesen.data.entitaetId, gelesen.data.betreuteId)
|
||||
|
||||
await protokollieren({
|
||||
aktion: 'WIEDERHERGESTELLT',
|
||||
entitaet: gelesen.data.entitaet,
|
||||
entitaetId: gelesen.data.entitaetId,
|
||||
bezeichnung: `${art.bezeichnung} aus dem Papierkorb geholt`,
|
||||
betreuteId: gelesen.data.betreuteId,
|
||||
userId: benutzer.id,
|
||||
userEmail: benutzer.email,
|
||||
userName: benutzer.name,
|
||||
})
|
||||
|
||||
revalidatePath('/einstellungen/papierkorb')
|
||||
return { erfolg: `${art.bezeichnung} ist wieder da.` }
|
||||
}
|
||||
|
||||
/**
|
||||
* Endgueltig loeschen. Danach ist der Datensatz weg - auch die Datei im
|
||||
* Objektspeicher, falls es eine gibt. Nur nach frischer Anmeldung.
|
||||
*/
|
||||
export async function endgueltigLoeschen(
|
||||
_zustand: Aktionszustand,
|
||||
formular: FormData,
|
||||
): Promise<Aktionszustand> {
|
||||
const gelesen = papierkorbSchema.safeParse({
|
||||
betreuteId: formular.get('betreuteId'),
|
||||
entitaet: formular.get('entitaet'),
|
||||
entitaetId: formular.get('entitaetId'),
|
||||
})
|
||||
if (!gelesen.success) return { fehler: 'Diese Angaben ergeben keinen Sinn.' }
|
||||
|
||||
const art = eintragsarten()[gelesen.data.entitaet]
|
||||
if (!art) return { fehler: 'Diese Art von Datensatz kennt der Papierkorb nicht.' }
|
||||
|
||||
const { benutzer, zugang } = await erfordereZugang(gelesen.data.betreuteId, art.modul, 'schreiben')
|
||||
if (zugang.rolle === 'MITLESER') return { fehler: 'Als Mitleser darfst du nichts löschen.' }
|
||||
await erfordereFrischeAnmeldung(benutzer, '/einstellungen/papierkorb')
|
||||
|
||||
// Bei Dokumenten und Berichten haengt eine Datei daran. Sie wird zuerst
|
||||
// entfernt: Bliebe sie liegen, waere sie eine verwaiste Kopie von Daten,
|
||||
// die ausdruecklich verschwinden sollten.
|
||||
const schluessel = await objektSchluesselFinden(
|
||||
gelesen.data.entitaet,
|
||||
gelesen.data.entitaetId,
|
||||
gelesen.data.betreuteId,
|
||||
)
|
||||
if (schluessel) {
|
||||
try {
|
||||
await entfernen(schluessel)
|
||||
} catch (fehler) {
|
||||
console.error('[papierkorb] Datei konnte nicht entfernt werden:', fehler)
|
||||
}
|
||||
}
|
||||
|
||||
await art.endgueltigLoeschen(gelesen.data.entitaetId, gelesen.data.betreuteId)
|
||||
|
||||
await protokollieren({
|
||||
aktion: 'ENDGUELTIG_GELOESCHT',
|
||||
entitaet: gelesen.data.entitaet,
|
||||
entitaetId: gelesen.data.entitaetId,
|
||||
bezeichnung: `${art.bezeichnung} endgültig gelöscht`,
|
||||
betreuteId: gelesen.data.betreuteId,
|
||||
userId: benutzer.id,
|
||||
userEmail: benutzer.email,
|
||||
userName: benutzer.name,
|
||||
})
|
||||
|
||||
revalidatePath('/einstellungen/papierkorb')
|
||||
return { erfolg: `${art.bezeichnung} ist endgültig entfernt.` }
|
||||
}
|
||||
'use server'
|
||||
|
||||
import { revalidatePath } from 'next/cache'
|
||||
import type { Modul } from '@prisma/client'
|
||||
import { db, papierkorbGrenze } from '@/lib/db'
|
||||
import { protokollieren } from '@/lib/audit'
|
||||
import { erfordereFrischeAnmeldung, erfordereZugang } from '@/lib/auth/sitzung'
|
||||
import { entfernen } from '@/lib/speicher'
|
||||
import { papierkorbSchema } from '@/lib/validierung/freigaben'
|
||||
|
||||
/**
|
||||
* Papierkorb.
|
||||
*
|
||||
* Loeschen heisst in dieser Anwendung: "geloeschtAm" setzen. Der Datensatz
|
||||
* bleibt 30 Tage sichtbar und wiederherstellbar. Das ist kein Luxus - in
|
||||
* einer Betreuungsakte ist ein versehentlich geloeschter Bescheid ein
|
||||
* echtes Problem, und der Nachweis gegenueber dem Gericht haengt daran.
|
||||
*
|
||||
* Endgueltig geloescht wird nur hier, nur einzeln und nur nach frischer
|
||||
* Anmeldung. Danach ist der Datensatz weg; im Audit-Log bleibt stehen, dass
|
||||
* es ihn gab und wer ihn entfernt hat.
|
||||
*/
|
||||
|
||||
export type Aktionszustand = {
|
||||
fehler?: string
|
||||
erfolg?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Was im Papierkorb auftauchen kann. Bewusst eine feste Liste und keine
|
||||
* dynamische Modellsuche: Der Entitaetsname kommt aus einem Formular, und
|
||||
* daraus darf niemals ein beliebiger Datenbankzugriff werden.
|
||||
*/
|
||||
type Eintragsart = {
|
||||
bezeichnung: string
|
||||
mehrzahl: string
|
||||
modul: Modul
|
||||
laden: (betreuteId: string, seit: Date) => Promise<PapierkorbEintrag[]>
|
||||
wiederherstellen: (id: string, betreuteId: string) => Promise<void>
|
||||
endgueltigLoeschen: (id: string, betreuteId: string) => Promise<void>
|
||||
}
|
||||
|
||||
export type PapierkorbEintrag = {
|
||||
id: string
|
||||
entitaet: string
|
||||
bezeichnung: string
|
||||
geloeschtAm: Date
|
||||
}
|
||||
|
||||
/** Kleine Hilfe, damit die Tabelle unten nicht 20-mal dasselbe wiederholt. */
|
||||
function einfach<T extends { id: string; geloeschtAm: Date | null }>(
|
||||
entitaet: string,
|
||||
bezeichnung: string,
|
||||
mehrzahl: string,
|
||||
modul: Modul,
|
||||
zugriff: {
|
||||
findMany: (args: unknown) => Promise<T[]>
|
||||
update: (args: unknown) => Promise<unknown>
|
||||
delete: (args: unknown) => Promise<unknown>
|
||||
},
|
||||
titelFeld: string,
|
||||
): Eintragsart {
|
||||
return {
|
||||
bezeichnung,
|
||||
mehrzahl,
|
||||
modul,
|
||||
laden: async (betreuteId, seit) => {
|
||||
const treffer = await zugriff.findMany({
|
||||
where: { betreuteId, geloeschtAm: { gte: seit } },
|
||||
orderBy: { geloeschtAm: 'desc' },
|
||||
})
|
||||
return treffer.map((datensatz) => ({
|
||||
id: datensatz.id,
|
||||
entitaet,
|
||||
bezeichnung:
|
||||
String((datensatz as unknown as Record<string, unknown>)[titelFeld] ?? '(ohne Titel)'),
|
||||
geloeschtAm: datensatz.geloeschtAm!,
|
||||
}))
|
||||
},
|
||||
wiederherstellen: async (id, betreuteId) => {
|
||||
await zugriff.update({ where: { id, betreuteId }, data: { geloeschtAm: null } })
|
||||
},
|
||||
endgueltigLoeschen: async (id, betreuteId) => {
|
||||
await zugriff.delete({ where: { id, betreuteId } })
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function eintragsarten(): Record<string, Eintragsart> {
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
const z = db as any
|
||||
return {
|
||||
Vorgang: einfach('Vorgang', 'Vorgang', 'Vorgänge', 'VORGAENGE', z.vorgang, 'titel'),
|
||||
Frist: einfach('Frist', 'Frist', 'Fristen', 'FRISTEN', z.frist, 'titel'),
|
||||
Dokument: einfach('Dokument', 'Dokument', 'Dokumente', 'DOKUMENTE', z.dokument, 'titel'),
|
||||
Konto: einfach('Konto', 'Konto', 'Konten', 'FINANZEN', z.konto, 'bezeichnung'),
|
||||
Buchung: einfach('Buchung', 'Buchung', 'Buchungen', 'FINANZEN', z.buchung, 'gegenstelle'),
|
||||
Vermoegensposten: einfach(
|
||||
'Vermoegensposten',
|
||||
'Vermögensposten',
|
||||
'Vermögensposten',
|
||||
'FINANZEN',
|
||||
z.vermoegensposten,
|
||||
'bezeichnung',
|
||||
),
|
||||
Immobilie: einfach('Immobilie', 'Immobilie', 'Immobilien', 'IMMOBILIE', z.immobilie, 'bezeichnung'),
|
||||
Vertrag: einfach('Vertrag', 'Vertrag', 'Verträge', 'VERTRAEGE', z.vertrag, 'bezeichnung'),
|
||||
Schreibvorlage: einfach(
|
||||
'Schreibvorlage',
|
||||
'Vorlage',
|
||||
'Vorlagen',
|
||||
'DOKUMENTE',
|
||||
z.schreibvorlage,
|
||||
'name',
|
||||
),
|
||||
Kontakt: einfach('Kontakt', 'Kontakt', 'Kontakte', 'KONTAKTE', z.kontakt, 'name'),
|
||||
Kontaktprotokoll: einfach(
|
||||
'Kontaktprotokoll',
|
||||
'Kontaktprotokoll',
|
||||
'Kontaktprotokolle',
|
||||
'KONTAKTE',
|
||||
z.kontaktprotokoll,
|
||||
'gespraechspartner',
|
||||
),
|
||||
Gesundheitsereignis: einfach(
|
||||
'Gesundheitsereignis',
|
||||
'Gesundheitsereignis',
|
||||
'Gesundheitsereignisse',
|
||||
'GESUNDHEIT',
|
||||
z.gesundheitsereignis,
|
||||
'titel',
|
||||
),
|
||||
Genehmigung: einfach(
|
||||
'Genehmigung',
|
||||
'Genehmigung',
|
||||
'Genehmigungen',
|
||||
'VORGAENGE',
|
||||
z.genehmigung,
|
||||
'titel',
|
||||
),
|
||||
SozialhilfeAntrag: einfach(
|
||||
'SozialhilfeAntrag',
|
||||
'Sozialhilfeantrag',
|
||||
'Sozialhilfeanträge',
|
||||
'SOZIALHILFE',
|
||||
z.sozialhilfeAntrag,
|
||||
'leistungsart',
|
||||
),
|
||||
Leistung: einfach('Leistung', 'Leistung', 'Leistungen', 'SOZIALHILFE', z.leistung, 'bezeichnung'),
|
||||
Bericht: einfach('Bericht', 'Bericht', 'Berichte', 'BERICHTE', z.bericht, 'titel'),
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
}
|
||||
|
||||
/** Alles, was in den letzten 30 Tagen geloescht wurde. */
|
||||
export async function papierkorbLaden(betreuteId: string): Promise<
|
||||
{ art: string; bezeichnung: string; eintraege: PapierkorbEintrag[] }[]
|
||||
> {
|
||||
const { zugang } = await erfordereZugang(betreuteId, 'STAMMDATEN', 'lesen')
|
||||
const seit = papierkorbGrenze()
|
||||
|
||||
const gruppen: { art: string; bezeichnung: string; eintraege: PapierkorbEintrag[] }[] = []
|
||||
for (const [art, beschreibung] of Object.entries(eintragsarten())) {
|
||||
// Ein Mitleser sieht auch im Papierkorb nur, was ihm freigegeben ist.
|
||||
if (zugang.rolle === 'MITLESER' && !zugang.freigegebeneModule.includes(beschreibung.modul)) {
|
||||
continue
|
||||
}
|
||||
const eintraege = await beschreibung.laden(betreuteId, seit)
|
||||
if (eintraege.length > 0) {
|
||||
gruppen.push({ art, bezeichnung: beschreibung.mehrzahl, eintraege })
|
||||
}
|
||||
}
|
||||
return gruppen
|
||||
}
|
||||
|
||||
/**
|
||||
* Haengt an diesem Datensatz eine Datei im Objektspeicher?
|
||||
*
|
||||
* Die beiden Faelle werden ausdruecklich getrennt abgefragt statt ueber
|
||||
* eine gemeinsam gehaltene Tabellenvariable: Prisma gibt jedem Modell
|
||||
* eigene Signaturen, und eine Variable, die mal das eine und mal das
|
||||
* andere Delegate haelt, laesst sich nicht mehr aufrufen.
|
||||
*/
|
||||
async function objektSchluesselFinden(
|
||||
entitaet: string,
|
||||
entitaetId: string,
|
||||
betreuteId: string,
|
||||
): Promise<string | null> {
|
||||
if (entitaet === 'Dokument') {
|
||||
const dokument = await db.dokument.findFirst({
|
||||
where: { id: entitaetId, betreuteId },
|
||||
select: { objektSchluessel: true },
|
||||
})
|
||||
return dokument?.objektSchluessel ?? null
|
||||
}
|
||||
if (entitaet === 'Bericht') {
|
||||
const bericht = await db.bericht.findFirst({
|
||||
where: { id: entitaetId, betreuteId },
|
||||
select: { objektSchluessel: true },
|
||||
})
|
||||
return bericht?.objektSchluessel ?? null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export async function wiederherstellen(
|
||||
_zustand: Aktionszustand,
|
||||
formular: FormData,
|
||||
): Promise<Aktionszustand> {
|
||||
const gelesen = papierkorbSchema.safeParse({
|
||||
betreuteId: formular.get('betreuteId'),
|
||||
entitaet: formular.get('entitaet'),
|
||||
entitaetId: formular.get('entitaetId'),
|
||||
})
|
||||
if (!gelesen.success) return { fehler: 'Diese Angaben ergeben keinen Sinn.' }
|
||||
|
||||
const art = eintragsarten()[gelesen.data.entitaet]
|
||||
if (!art) return { fehler: 'Diese Art von Datensatz kennt der Papierkorb nicht.' }
|
||||
|
||||
const { benutzer, zugang } = await erfordereZugang(gelesen.data.betreuteId, art.modul, 'schreiben')
|
||||
if (zugang.rolle === 'MITLESER') return { fehler: 'Als Mitleser darfst du nichts wiederherstellen.' }
|
||||
|
||||
await art.wiederherstellen(gelesen.data.entitaetId, gelesen.data.betreuteId)
|
||||
|
||||
await protokollieren({
|
||||
aktion: 'WIEDERHERGESTELLT',
|
||||
entitaet: gelesen.data.entitaet,
|
||||
entitaetId: gelesen.data.entitaetId,
|
||||
bezeichnung: `${art.bezeichnung} aus dem Papierkorb geholt`,
|
||||
betreuteId: gelesen.data.betreuteId,
|
||||
userId: benutzer.id,
|
||||
userEmail: benutzer.email,
|
||||
userName: benutzer.name,
|
||||
})
|
||||
|
||||
revalidatePath('/einstellungen/papierkorb')
|
||||
return { erfolg: `${art.bezeichnung} ist wieder da.` }
|
||||
}
|
||||
|
||||
/**
|
||||
* Endgueltig loeschen. Danach ist der Datensatz weg - auch die Datei im
|
||||
* Objektspeicher, falls es eine gibt. Nur nach frischer Anmeldung.
|
||||
*/
|
||||
export async function endgueltigLoeschen(
|
||||
_zustand: Aktionszustand,
|
||||
formular: FormData,
|
||||
): Promise<Aktionszustand> {
|
||||
const gelesen = papierkorbSchema.safeParse({
|
||||
betreuteId: formular.get('betreuteId'),
|
||||
entitaet: formular.get('entitaet'),
|
||||
entitaetId: formular.get('entitaetId'),
|
||||
})
|
||||
if (!gelesen.success) return { fehler: 'Diese Angaben ergeben keinen Sinn.' }
|
||||
|
||||
const art = eintragsarten()[gelesen.data.entitaet]
|
||||
if (!art) return { fehler: 'Diese Art von Datensatz kennt der Papierkorb nicht.' }
|
||||
|
||||
const { benutzer, zugang } = await erfordereZugang(gelesen.data.betreuteId, art.modul, 'schreiben')
|
||||
if (zugang.rolle === 'MITLESER') return { fehler: 'Als Mitleser darfst du nichts löschen.' }
|
||||
await erfordereFrischeAnmeldung(benutzer, '/einstellungen/papierkorb')
|
||||
|
||||
// Bei Dokumenten und Berichten haengt eine Datei daran. Sie wird zuerst
|
||||
// entfernt: Bliebe sie liegen, waere sie eine verwaiste Kopie von Daten,
|
||||
// die ausdruecklich verschwinden sollten.
|
||||
const schluessel = await objektSchluesselFinden(
|
||||
gelesen.data.entitaet,
|
||||
gelesen.data.entitaetId,
|
||||
gelesen.data.betreuteId,
|
||||
)
|
||||
if (schluessel) {
|
||||
try {
|
||||
await entfernen(schluessel)
|
||||
} catch (fehler) {
|
||||
console.error('[papierkorb] Datei konnte nicht entfernt werden:', fehler)
|
||||
}
|
||||
}
|
||||
|
||||
await art.endgueltigLoeschen(gelesen.data.entitaetId, gelesen.data.betreuteId)
|
||||
|
||||
await protokollieren({
|
||||
aktion: 'ENDGUELTIG_GELOESCHT',
|
||||
entitaet: gelesen.data.entitaet,
|
||||
entitaetId: gelesen.data.entitaetId,
|
||||
bezeichnung: `${art.bezeichnung} endgültig gelöscht`,
|
||||
betreuteId: gelesen.data.betreuteId,
|
||||
userId: benutzer.id,
|
||||
userEmail: benutzer.email,
|
||||
userName: benutzer.name,
|
||||
})
|
||||
|
||||
revalidatePath('/einstellungen/papierkorb')
|
||||
return { erfolg: `${art.bezeichnung} ist endgültig entfernt.` }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user