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.
40 lines
1.3 KiB
TypeScript
40 lines
1.3 KiB
TypeScript
import type { Metadata } from "next";
|
|
import Link from "next/link";
|
|
|
|
import { Icon } from "@/components/icons";
|
|
import { SettingsAdmin } from "@/components/settings-admin";
|
|
import { requirePagePermission } from "@/lib/auth/guard";
|
|
import { getSettings } from "@/lib/settings";
|
|
|
|
export const metadata: Metadata = { title: "Einstellungen" };
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export default async function SettingsPage() {
|
|
await requirePagePermission("instance:manage");
|
|
const settings = await getSettings();
|
|
|
|
return (
|
|
<div className="mx-auto max-w-3xl px-4 py-8 sm:px-6 sm:py-10">
|
|
<Link
|
|
href="/verwaltung"
|
|
className="mb-5 inline-flex items-center gap-1.5 rounded-lg text-sm font-medium text-slate-600 transition-colors hover:text-slate-900"
|
|
>
|
|
<Icon name="arrowLeft" className="size-4" />
|
|
Zur Verwaltung
|
|
</Link>
|
|
|
|
<div className="mb-7">
|
|
<h1 className="text-2xl font-bold tracking-tight text-slate-900 sm:text-3xl">
|
|
Einstellungen
|
|
</h1>
|
|
<p className="mt-2 text-slate-600">
|
|
Was Bearbeiter dürfen und was Administratoren vorbehalten bleibt.
|
|
</p>
|
|
</div>
|
|
|
|
<SettingsAdmin initial={{ editorsMaySetSlug: settings.editorsMaySetSlug }} />
|
|
</div>
|
|
);
|
|
}
|