- BUG-1: Strip HTML tags in sanitizeName (prevent stored XSS) - BUG-2: Strip HTML tags in notes via sanitizeText across all 3 booking APIs - BUG-3: Dashboard excludes archived/past MCs and expired Open Day events from counts - BUG-4: Truncate long names in booking cards to prevent overflow
63 lines
2.6 KiB
TypeScript
63 lines
2.6 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import {
|
|
getOpenDayBookings,
|
|
toggleOpenDayNotification,
|
|
deleteOpenDayBooking,
|
|
setOpenDayBookingStatus,
|
|
updateBookingNotes,
|
|
} from "@/lib/db";
|
|
import { sanitizeText } from "@/lib/validation";
|
|
|
|
export async function GET(request: NextRequest) {
|
|
const eventIdStr = request.nextUrl.searchParams.get("eventId");
|
|
if (!eventIdStr) return NextResponse.json({ error: "eventId is required" }, { status: 400 });
|
|
const eventId = parseInt(eventIdStr, 10);
|
|
if (isNaN(eventId)) return NextResponse.json({ error: "Invalid eventId" }, { status: 400 });
|
|
return NextResponse.json(getOpenDayBookings(eventId));
|
|
}
|
|
|
|
export async function PUT(request: NextRequest) {
|
|
try {
|
|
const body = await request.json();
|
|
if (body.action === "set-status") {
|
|
const { id, status } = body;
|
|
if (!id || !status) return NextResponse.json({ error: "id, status required" }, { status: 400 });
|
|
if (!["new", "contacted", "confirmed", "declined"].includes(status)) {
|
|
return NextResponse.json({ error: "Invalid status" }, { status: 400 });
|
|
}
|
|
setOpenDayBookingStatus(id, status);
|
|
return NextResponse.json({ ok: true });
|
|
}
|
|
if (body.action === "set-notes") {
|
|
const { id, notes } = body;
|
|
if (!id) return NextResponse.json({ error: "id is required" }, { status: 400 });
|
|
updateBookingNotes("open_day_bookings", id, sanitizeText(notes, 1000) ?? "");
|
|
return NextResponse.json({ ok: true });
|
|
}
|
|
if (body.action === "toggle-notify") {
|
|
const { id, field, value } = body;
|
|
if (!id || !field || typeof value !== "boolean") {
|
|
return NextResponse.json({ error: "id, field, value required" }, { status: 400 });
|
|
}
|
|
if (field !== "notified_confirm" && field !== "notified_reminder") {
|
|
return NextResponse.json({ error: "Invalid field" }, { status: 400 });
|
|
}
|
|
toggleOpenDayNotification(id, field, value);
|
|
return NextResponse.json({ ok: true });
|
|
}
|
|
return NextResponse.json({ error: "Unknown action" }, { status: 400 });
|
|
} catch (err) {
|
|
console.error("[admin/open-day/bookings] error:", err);
|
|
return NextResponse.json({ error: "Internal error" }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
export async function DELETE(request: NextRequest) {
|
|
const idStr = request.nextUrl.searchParams.get("id");
|
|
if (!idStr) return NextResponse.json({ error: "id is required" }, { status: 400 });
|
|
const id = parseInt(idStr, 10);
|
|
if (isNaN(id)) return NextResponse.json({ error: "Invalid id" }, { status: 400 });
|
|
deleteOpenDayBooking(id);
|
|
return NextResponse.json({ ok: true });
|
|
}
|