Files
vans-diy-bastelbedarf/functions/api/verwaltung/orders/[id].js
T
qciganoandClaude Sonnet 5 aff961816b Zweite, tägliche Zugangsschranke nur für die Bestellverwaltung
Auf ausdrücklichen Wunsch: /verwaltung/ + /api/verwaltung/* verlangen jetzt ZUSÄTZLICH zum
normalen 90-Tage-Seitenzugang einen zweiten, eigenen Code, den nur qciga und VanVan kennen —
und der nach 24 Stunden automatisch abläuft (muss also einmal täglich neu eingegeben werden).
Der Rest der Seite ist davon unberührt, nur die Bestellübersicht ist betroffen.

Bewusst als eigenständiges System (eigenes Cookie vandiy_verwaltung_session, eigenes Geheimnis
VERWALTUNG_SESSION_SECRET, eigener HMAC-Signaturcode statt geteiltem mit dem normalen
Seitenzugang) — gleiches Trennungsprinzip wie bei den Kundenkonten: ein Leck bei einer
Sitzungsart darf nie die andere gefährden.

Neue Dateien: functions/_shared/verwaltung-auth.js (Session-Logik), public/verwaltung-code.html
(Eingabemaske im selben Stil wie die Haupt-Zugangsseite). functions/_middleware.js prüft nach
erfolgreicher Haupt-Sitzung zusätzlich diese zweite Sitzung für /verwaltung*-Pfade. Beide
API-Routen (orders.js, orders/[id].js) prüfen die zweite Schranke zusätzlich eigenständig,
nach demselben Verteidigungs-in-der-Tiefe-Prinzip wie die bestehende Haupt-Prüfung.

Lokal vollständig durchgetestet (wrangler pages dev): kompletter Ablauf ohne jeden Zugang ->
Haupt-Gate -> Redirect zum Tages-Code -> falscher Code abgelehnt -> richtiger Code setzt
24-Stunden-Cookie -> Seite und API danach erreichbar. Bestätigt: der Rest der Seite bleibt
unberührt (kein Tages-Code nötig), UND dass VanVan mit nur dem Haupt-Zugang (ohne Tages-Code)
ebenfalls noch ausgesperrt bleibt, wie gewünscht.

Zwei neue Cloudflare-Secrets in Produktion gesetzt: VERWALTUNG_SESSION_SECRET (zufällig
erzeugt) und VERWALTUNG_ACCESS_CODE (der eigentliche Tages-Code, an qciga und VanVan zu
verteilen).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-04 11:45:31 +02:00

74 lines
2.6 KiB
JavaScript

/* =====================================================================
PATCH /api/verwaltung/orders/:id — Status (und/oder Tracking-Nummer) einer Bestellung
ändern, direkt aus der Verwaltungsseite heraus (siehe src/pages/verwaltung/index.astro).
Genau wie bei GET /api/verwaltung/orders: zusätzlich zur Middleware-Sperre wird die
Sitzung hier noch einmal eigenständig geprüft — beide Schranken (normaler Seitenzugang UND
Verwaltungs-Tages-Code). ===================================================================== */
import { getGateRole, unauthorizedJson } from "../../../_shared/auth.js";
import { hatGueltigeVerwaltungSitzung } from "../../../_shared/verwaltung-auth.js";
import { json } from "../../../_shared/http.js";
const ERLAUBTE_STATUS = ["zahlungOffen", "bezahlt", "bearbeitung", "versandVorbereitet", "versendet", "abgeschlossen", "storniert"];
export async function onRequestPatch(context) {
const { request, env, params } = context;
const role = await getGateRole(request, env);
if (!role) return unauthorizedJson();
if (!(await hatGueltigeVerwaltungSitzung(request, env))) {
return json(401, { ok: false, error: "Tages-Code für die Verwaltung erforderlich." });
}
if (!env.DB) {
return json(500, { ok: false, error: "Datenbank nicht verbunden." });
}
const id = Number(params.id);
if (!Number.isInteger(id) || id <= 0) {
return json(400, { ok: false, error: "Ungültige Bestell-ID." });
}
let body;
try {
body = await request.json();
} catch {
return json(400, { ok: false, error: "Ungültige Anfrage." });
}
const updates = [];
const values = [];
if (body.status !== undefined) {
if (!ERLAUBTE_STATUS.includes(body.status)) {
return json(400, { ok: false, error: "Ungültiger Status." });
}
updates.push("status = ?");
values.push(body.status);
}
if (body.tracking !== undefined) {
updates.push("tracking = ?");
values.push(String(body.tracking || ""));
}
if (updates.length === 0) {
return json(400, { ok: false, error: "Nichts zu ändern übergeben." });
}
updates.push("updated_at = ?");
values.push(new Date().toISOString());
values.push(id);
try {
const result = await env.DB.prepare(`UPDATE orders SET ${updates.join(", ")} WHERE id = ?`)
.bind(...values)
.run();
if (result.meta.changes === 0) {
return json(404, { ok: false, error: "Bestellung nicht gefunden." });
}
return json(200, { ok: true });
} catch (err) {
return json(500, { ok: false, error: "Bestellung konnte nicht aktualisiert werden." });
}
}