Verwaltung: QR-Typen einzeln freigeben oder ausblenden
Neue Seite Verwaltung -> QR-Typen mit einem Schalter je Typ. Abgeschaltete Typen verschwinden vollstaendig von der Startseite und lassen sich nicht mehr neu anlegen. - Neue Tabelle QrTypeSetting; fehlender Eintrag heisst freigegeben, damit eine frische Installation ohne Vorbelegung laeuft und spaetere Typen automatisch erscheinen. - Registry-Feld 'active' heisst jetzt 'implemented' und beschreibt nur noch, ob der Typ ausprogrammiert ist. Ob er erscheint, entscheidet zusaetzlich die Freigabe aus der Datenbank (src/lib/qr/availability.ts). - Bestehende dynamische Codes bleiben von einer Abschaltung unberuehrt: die Weiterleitung funktioniert weiter und Bearbeiten bleibt moeglich. Ein gedruckter Code darf durch einen Schalter nicht ungueltig werden. - resolveQrRequest ist dadurch asynchron geworden; QrRequestError liegt jetzt in type-module.ts, sonst gaebe es einen Ringschluss mit availability.ts. - Startseite meldet jetzt auch den Fall, dass nur noch Platzhalter freigegeben sind - vorher standen dort 14 tote Kacheln ohne Erklaerung. - Kopfzeile: Schriftzug auf schmalen Geraeten ausgeblendet, sonst passte die dritte Navigationsschaltflaeche nicht mehr in die Zeile (7px Ueberlauf).
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
import "server-only";
|
||||
|
||||
import { prisma } from "@/lib/db";
|
||||
import { getQrType, qrTypeList } from "@/lib/qr/registry";
|
||||
import {
|
||||
isQrTypeId,
|
||||
QrRequestError,
|
||||
type QrTypeId,
|
||||
type QrTypeModule,
|
||||
} from "@/lib/qr/type-module";
|
||||
|
||||
/**
|
||||
* Freigabe der QR-Typen durch die Verwaltung.
|
||||
*
|
||||
* Zwei voneinander unabhängige Eigenschaften bestimmen, was ein Typ kann:
|
||||
*
|
||||
* - `implemented` — steht in der Registry und sagt, ob der Typ überhaupt
|
||||
* ausprogrammiert ist. In V1 gilt das nur für „Website“.
|
||||
* - `enabled` — kommt aus der Datenbank und sagt, ob die Verwaltung den Typ
|
||||
* freigegeben hat. Fehlt der Eintrag, ist der Typ freigegeben.
|
||||
*
|
||||
* Ein abgeschalteter Typ verschwindet aus der Oberfläche und lässt sich nicht
|
||||
* mehr neu anlegen. **Bereits bestehende Codes dieses Typs funktionieren
|
||||
* weiter** — sie sind gedruckt und verteilt, und ein Schalter in der
|
||||
* Verwaltung darf sie nicht ins Leere laufen lassen.
|
||||
*/
|
||||
|
||||
export type QrTypeAvailability = {
|
||||
qrType: QrTypeModule;
|
||||
/** Der Typ ist in dieser Version ausprogrammiert. */
|
||||
implemented: boolean;
|
||||
/** Die Verwaltung hat den Typ freigegeben. */
|
||||
enabled: boolean;
|
||||
/** Freigegeben und ausprogrammiert — nur dann ist er benutzbar. */
|
||||
usable: boolean;
|
||||
/** Freigegeben, aber noch nicht ausprogrammiert — „Bald verfügbar“. */
|
||||
announced: boolean;
|
||||
};
|
||||
|
||||
/** Abschaltungen aus der Datenbank; alles nicht Genannte ist freigegeben. */
|
||||
async function loadDisabledTypes(): Promise<ReadonlySet<string>> {
|
||||
try {
|
||||
const rows = await prisma.qrTypeSetting.findMany({
|
||||
where: { enabled: false },
|
||||
select: { type: true },
|
||||
});
|
||||
return new Set(rows.map((row) => row.type));
|
||||
} catch (error) {
|
||||
// Ohne Datenbank ist die Anwendung für statische Codes weiterhin
|
||||
// brauchbar. Lieber alles anzeigen als eine leere Startseite.
|
||||
console.error(
|
||||
"Freigaben der QR-Typen konnten nicht geladen werden — es gilt die Voreinstellung (alle freigegeben):",
|
||||
error,
|
||||
);
|
||||
return new Set();
|
||||
}
|
||||
}
|
||||
|
||||
/** Verfügbarkeit aller Typen in Anzeigereihenfolge. */
|
||||
export async function getQrTypeAvailability(): Promise<QrTypeAvailability[]> {
|
||||
const disabled = await loadDisabledTypes();
|
||||
|
||||
return qrTypeList.map((qrType) => {
|
||||
const enabled = !disabled.has(qrType.id);
|
||||
return {
|
||||
qrType,
|
||||
implemented: qrType.implemented,
|
||||
enabled,
|
||||
usable: enabled && qrType.implemented,
|
||||
announced: enabled && !qrType.implemented,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/** Nur die Typen, die in der Oberfläche erscheinen sollen. */
|
||||
export async function getVisibleQrTypes(): Promise<QrTypeAvailability[]> {
|
||||
return (await getQrTypeAvailability()).filter((entry) => entry.enabled);
|
||||
}
|
||||
|
||||
export async function getQrTypeState(
|
||||
id: string,
|
||||
): Promise<QrTypeAvailability | undefined> {
|
||||
if (!isQrTypeId(id)) return undefined;
|
||||
return (await getQrTypeAvailability()).find((entry) => entry.qrType.id === id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert den Typ für das Anlegen neuer Codes — oder wirft mit einer
|
||||
* Meldung, die unverändert in die Oberfläche gehen kann.
|
||||
*/
|
||||
export async function requireAvailableQrType(
|
||||
id: string,
|
||||
): Promise<QrTypeModule> {
|
||||
const state = await getQrTypeState(id);
|
||||
|
||||
if (!state) {
|
||||
throw new QrRequestError("Unbekannter QR-Typ.", 404);
|
||||
}
|
||||
if (!state.implemented) {
|
||||
throw new QrRequestError(
|
||||
`Der QR-Typ „${state.qrType.title}“ ist in dieser Version noch nicht verfügbar.`,
|
||||
404,
|
||||
);
|
||||
}
|
||||
if (!state.enabled) {
|
||||
throw new QrRequestError(
|
||||
`Der QR-Typ „${state.qrType.title}“ ist in der Verwaltung abgeschaltet.`,
|
||||
403,
|
||||
);
|
||||
}
|
||||
|
||||
return state.qrType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Typ eines bestehenden Codes. Hier zählt nur, ob der Typ ausprogrammiert
|
||||
* ist — eine Abschaltung in der Verwaltung darf bestehende Codes nicht
|
||||
* unbearbeitbar machen.
|
||||
*/
|
||||
export function requireImplementedQrType(id: string): QrTypeModule {
|
||||
const qrType = getQrType(id);
|
||||
if (!qrType?.implemented) {
|
||||
throw new QrRequestError(
|
||||
"Der Typ dieses Codes wird in dieser Version nicht unterstützt.",
|
||||
404,
|
||||
);
|
||||
}
|
||||
return qrType;
|
||||
}
|
||||
|
||||
/** Freigabe eines Typs setzen. */
|
||||
export async function setQrTypeEnabled(
|
||||
id: QrTypeId,
|
||||
enabled: boolean,
|
||||
): Promise<void> {
|
||||
await prisma.qrTypeSetting.upsert({
|
||||
where: { type: id },
|
||||
create: { type: id, enabled },
|
||||
update: { enabled },
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user