feat(zuweisungen): Matrix Schluessel x Host mit CSV-Export (#025)
Bisher liess sich nur je Schluessel oder je Host nachsehen, wo ein Key verwaltet ist. Die Matrix zeigt das auf einen Blick, loest Hostgruppen-Zuweisungen je Mitglied auf (P vs. P·G) und macht nicht synchrone Zustaende ohne Farbe erkennbar. Die Matrix plant nur: Zuweisen und Entfernen laufen ueber die vorhandenen Aktionen, ausgerollt wird weiter per Dry-Run auf der Schluesselseite. Der Aufbau ist eine reine Funktion in src/lib, damit Seite und CSV-Export garantiert dasselbe zeigen und die Gruppenaufloesung ohne Datenbank testbar ist. Der CSV-Export entschaerft Formelbeginne, weil Schluesselnamen frei waehlbar sind und Excel sie sonst ausfuehren wuerde. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { prisma } from "@/lib/db";
|
||||
import { matrixAufbauen, type MatrixDaten, type MatrixFilter } from "@/lib/zuweisungsmatrix";
|
||||
|
||||
/**
|
||||
* Lesemodell der Zuweisungsmatrix (#025). Jede angemeldete Rolle darf es sehen – wie die
|
||||
* Verwendungen auf Schluessel- und Hostseite auch.
|
||||
*
|
||||
* Feste `select`-Listen ohne Chiffrat-Felder (CLAUDE.md). Nur aktive Schluessel und nicht
|
||||
* archivierte Hosts: widerrufene oder rotierte Keys haben keine Zukunft auf einem Host, und
|
||||
* ein archivierter Host wird nicht mehr abgeglichen.
|
||||
*/
|
||||
export async function zuweisungsDaten(): Promise<MatrixDaten> {
|
||||
const nichtEntfernt = { zustand: { not: "ENTFERNT" as const } };
|
||||
const [schluessel, hosts, gruppen, oeffentlich, privat] = await Promise.all([
|
||||
prisma.schluessel.findMany({
|
||||
where: { status: "AKTIV" },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
fingerprint: true,
|
||||
kategorie: true,
|
||||
person: { select: { id: true, name: true } },
|
||||
},
|
||||
orderBy: [{ name: "asc" }, { id: "asc" }],
|
||||
}),
|
||||
prisma.host.findMany({
|
||||
where: { archiviertAm: null },
|
||||
select: { id: true, name: true, gruppen: { select: { hostgruppeId: true } } },
|
||||
orderBy: { name: "asc" },
|
||||
}),
|
||||
prisma.hostgruppe.findMany({ select: { id: true, name: true }, orderBy: { name: "asc" } }),
|
||||
prisma.publicVerwendung.findMany({
|
||||
where: { ...nichtEntfernt, schluessel: { status: "AKTIV" } },
|
||||
select: {
|
||||
id: true,
|
||||
schluesselId: true,
|
||||
hostId: true,
|
||||
hostgruppeId: true,
|
||||
zielbenutzer: true,
|
||||
optionen: true,
|
||||
zustand: true,
|
||||
},
|
||||
orderBy: { angelegtAm: "asc" },
|
||||
}),
|
||||
prisma.privateVerwendung.findMany({
|
||||
where: { ...nichtEntfernt, schluessel: { status: "AKTIV" } },
|
||||
select: { id: true, schluesselId: true, hostId: true, zielbenutzer: true, pfad: true, zustand: true },
|
||||
orderBy: { angelegtAm: "asc" },
|
||||
}),
|
||||
]);
|
||||
return {
|
||||
schluessel,
|
||||
hosts: hosts.map((h) => ({ id: h.id, name: h.name, gruppenIds: h.gruppen.map((g) => g.hostgruppeId) })),
|
||||
gruppen,
|
||||
oeffentlich,
|
||||
privat,
|
||||
};
|
||||
}
|
||||
|
||||
export async function zuweisungsMatrix(filter: MatrixFilter = {}) {
|
||||
const daten = await zuweisungsDaten();
|
||||
// Personen fuer den Filter: nur die, denen ein aktiver Schluessel gehoert.
|
||||
const personen = [
|
||||
...new Map(
|
||||
daten.schluessel.flatMap((s) => (s.person ? [[s.person.id, s.person] as const] : [])),
|
||||
).values(),
|
||||
].sort((a, b) => a.name.localeCompare(b.name, "de"));
|
||||
return { matrix: matrixAufbauen(daten, filter), gruppen: daten.gruppen, personen };
|
||||
}
|
||||
Reference in New Issue
Block a user