Schliesst Issue #1. Der Wunsch betraf den Kurz-Link, nicht das Ziel: Er soll sich von Anfang an bestimmen und spaeter aendern lassen. Beim Anlegen gibt es dafuer ein Feld, im Bearbeiten-Dialog laesst er sich aendern. Erlaubt sind Kleinbuchstaben, Ziffern, Bindestriche und „/" als Trenner — damit sind Adressen wie kunde-a/sommer moeglich. Umlaute bleiben draussen, weil sie in Adressen unleserlich kodiert werden; Gross- und Kleinschreibung ist beim Aufrufen egal. Beim Aendern bleibt die vorherige Adresse gueltig. Das ist der Kern: Auf gedruckten Codes steht die alte, und genau deren Bestand ist der Sinn eines dynamischen Codes. Frueher vergebene Adressen stehen im Dialog und lassen sich einzeln freigeben — fuer den Tippfehler, mit dem noch nichts gedruckt ist. Solange eine Adresse gehalten wird, kann sie kein anderer Code uebernehmen; sonst liessen sich fremde gedruckte Codes umlenken. Vergeben und Aendern ist standardmaessig Administratoren vorbehalten. Ein Kurz-Link ist eine oeffentliche Adresse, und wer ihn aendert, kann Aushaenge entwerten. Unter Verwaltung -> Einstellungen laesst sich das fuer Bearbeiter freigeben; ohne das Recht erscheint das Feld gar nicht, Codes anlegen und deren Ziel aendern geht weiterhin. Eigene Aktion in der Policy statt Teil von codes:update, weil sie mehr wiegt. Technisch: /r und /s sind Sammelrouten, weil ein Kurz-Link „/" enthalten darf. Die Eindeutigkeit gilt zusaetzlich auf der kleingeschriebenen Form; die Migration bricht ab, falls der Bestand das nicht zulaesst, statt still Daten zu verlieren. Der bestehende exakte Index bleibt — er traegt den haeufigen Fall, den gescannten Code.
46 lines
1.3 KiB
TypeScript
46 lines
1.3 KiB
TypeScript
import "server-only";
|
|
|
|
import { prisma } from "@/lib/db";
|
|
|
|
export type InstanceSettings = {
|
|
/** Dürfen Bearbeiter den Kurz-Link selbst vergeben und ändern? */
|
|
editorsMaySetSlug: boolean;
|
|
};
|
|
|
|
export const DEFAULT_SETTINGS: InstanceSettings = {
|
|
editorsMaySetSlug: false,
|
|
};
|
|
|
|
/**
|
|
* Bewusst ohne Zwischenspeicher — dieselbe Erfahrung wie beim
|
|
* Erscheinungsbild: API-Route und Seite laufen in getrennten Modulinstanzen,
|
|
* ein Puffer wäre nach dem Speichern veraltet. Es ist eine Abfrage auf den
|
|
* Primärschlüssel einer Tabelle mit einer einzigen Zeile.
|
|
*/
|
|
export async function getSettings(): Promise<InstanceSettings> {
|
|
try {
|
|
const zeile = await prisma.instanceSetting.findUnique({
|
|
where: { id: "instance" },
|
|
});
|
|
return zeile
|
|
? { editorsMaySetSlug: zeile.editorsMaySetSlug }
|
|
: DEFAULT_SETTINGS;
|
|
} catch (error) {
|
|
// Ein Datenbankproblem darf nicht dazu führen, dass keine Seite erscheint.
|
|
// Im Zweifel gilt die zurückhaltendere Einstellung.
|
|
console.error("Einstellungen konnten nicht geladen werden:", error);
|
|
return DEFAULT_SETTINGS;
|
|
}
|
|
}
|
|
|
|
export async function saveSettings(
|
|
update: Partial<InstanceSettings>,
|
|
): Promise<InstanceSettings> {
|
|
await prisma.instanceSetting.upsert({
|
|
where: { id: "instance" },
|
|
update,
|
|
create: { id: "instance", ...update },
|
|
});
|
|
return getSettings();
|
|
}
|