first commit
Docker-Images bauen und veroeffentlichen / build-and-push (push) Failing after 1m32s

This commit is contained in:
Nick Szaunig committed 2026-09-27 06:06:56 +02:00
commit 59bb5a38a3
132 files changed
+19435

No files matched your search

+152
View File
@@ -0,0 +1,152 @@
"use server";
/**
* Server-Actions des Adminbereichs. JEDE Action prueft zuerst selbst die
* Anmeldung inkl. 2FA (requireAdminAction) — unabhaengig davon, ob die
* Seite geschuetzt ist, denn Actions sind eigenstaendig aufrufbar.
*/
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { adminActor, requireAdminAction } from "@/lib/admin-auth";
import {
campInputSchema,
cancelBooking,
confirmReviewedBooking,
refundInstallment,
resendConfirmation,
saveVoucher,
updateCamp,
voucherInputSchema,
type ActionResult,
} from "@/lib/admin-service";
import { getDb } from "@/lib/db";
import { requireAppSecret } from "@/lib/env";
import { getGateway } from "@/lib/payment-gateway";
function back(path: string, result: ActionResult): never {
const param = result.ok ? "ok" : "fehler";
redirect(`${path}?${param}=${encodeURIComponent(result.message)}`);
}
function str(form: FormData, key: string): string {
const value = form.get(key);
return typeof value === "string" ? value : "";
}
function bool(form: FormData, key: string): boolean {
return form.get(key) === "on";
}
function firstIssue(error: { issues: { message: string }[] }): string {
return error.issues[0]?.message ?? "Ungültige Eingabe.";
}
const ID = /^[A-Za-z0-9_-]{8,64}$/;
export async function cancelBookingAction(form: FormData) {
const admin = await requireAdminAction();
const id = str(form, "bookingId");
if (!ID.test(id)) back("/admin/buchungen", { ok: false, message: "Ungültige Buchung." });
const result = await cancelBooking(getDb(), getGateway(), { bookingId: id, reason: str(form, "reason") }, adminActor(admin));
revalidatePath(`/admin/buchungen/${id}`);
back(`/admin/buchungen/${id}`, result);
}
export async function refundAction(form: FormData) {
const admin = await requireAdminAction();
const bookingId = str(form, "bookingId");
const installmentId = str(form, "installmentId");
const requestKey = str(form, "requestKey");
if (!ID.test(bookingId) || !ID.test(installmentId) || !/^[0-9a-f-]{36}$/.test(requestKey)) {
back("/admin/buchungen", { ok: false, message: "Ungültige Anfrage." });
}
const euros = Number(str(form, "amount").replace(",", "."));
const amountCents = Math.round(euros * 100);
const result = await refundInstallment(
getDb(),
getGateway(),
{ installmentId, amountCents, requestKey, reason: str(form, "reason") },
adminActor(admin),
);
revalidatePath(`/admin/buchungen/${bookingId}`);
back(`/admin/buchungen/${bookingId}`, result);
}
export async function confirmReviewAction(form: FormData) {
const admin = await requireAdminAction();
const id = str(form, "bookingId");
if (!ID.test(id)) back("/admin/buchungen", { ok: false, message: "Ungültige Buchung." });
const result = await confirmReviewedBooking(getDb(), id, adminActor(admin));
revalidatePath(`/admin/buchungen/${id}`);
back(`/admin/buchungen/${id}`, result);
}
export async function resendConfirmationAction(form: FormData) {
const admin = await requireAdminAction();
const id = str(form, "bookingId");
if (!ID.test(id)) back("/admin/buchungen", { ok: false, message: "Ungültige Buchung." });
const result = await resendConfirmation(getDb(), id, requireAppSecret(), adminActor(admin));
back(`/admin/buchungen/${id}`, result);
}
export async function saveVoucherAction(form: FormData) {
const admin = await requireAdminAction();
const id = str(form, "voucherId") || null;
if (id && !ID.test(id)) back("/admin/gutscheine", { ok: false, message: "Ungültiger Gutschein." });
const parsed = voucherInputSchema.safeParse({
code: str(form, "code"),
active: bool(form, "active"),
validFrom: str(form, "validFrom"),
validUntil: str(form, "validUntil"),
maxRedemptions: str(form, "maxRedemptions"),
boundEmail: str(form, "boundEmail"),
internalNote: str(form, "internalNote"),
});
const target = id ? `/admin/gutscheine/${id}` : "/admin/gutscheine";
if (!parsed.success) back(target, { ok: false, message: firstIssue(parsed.error) });
const result = await saveVoucher(getDb(), id, parsed.data, adminActor(admin));
revalidatePath("/admin/gutscheine");
back(result.ok && result.id ? `/admin/gutscheine/${result.id}` : target, result);
}
export async function updateCampAction(form: FormData) {
const admin = await requireAdminAction();
const parsed = campInputSchema.safeParse({
salesEnabled: bool(form, "salesEnabled"),
capacity: str(form, "capacity"),
capacityConfirmed: bool(form, "capacityConfirmed"),
stammmodelQuota: str(form, "stammmodelQuota"),
stammmodelQuotaConfirmed: bool(form, "stammmodelQuotaConfirmed"),
campStartDate: str(form, "campStartDate"),
campEndDate: str(form, "campEndDate"),
dateConfirmed: bool(form, "dateConfirmed"),
locationName: str(form, "locationName"),
locationRegion: str(form, "locationRegion"),
locationConfirmed: bool(form, "locationConfirmed"),
accommodationText: str(form, "accommodationText"),
accommodationConfirmed: bool(form, "accommodationConfirmed"),
servicesConfirmed: bool(form, "servicesConfirmed"),
organizerName: str(form, "organizerName"),
organizerAddress: str(form, "organizerAddress"),
organizerEmail: str(form, "organizerEmail"),
organizerPhone: str(form, "organizerPhone"),
organizerConfirmed: bool(form, "organizerConfirmed"),
taxNote: str(form, "taxNote"),
taxConfirmed: bool(form, "taxConfirmed"),
termsVersion: str(form, "termsVersion"),
termsUrl: str(form, "termsUrl"),
termsApproved: bool(form, "termsApproved"),
travelLawChecked: bool(form, "travelLawChecked"),
installmentsApproved: bool(form, "installmentsApproved"),
installmentRuleApproved: bool(form, "installmentRuleApproved"),
reservationMinutes: str(form, "reservationMinutes"),
finalInstallmentLeadDays: str(form, "finalInstallmentLeadDays"),
minInstallmentGapDays: str(form, "minInstallmentGapDays"),
testPhaseOverride: str(form, "testPhaseOverride"),
});
if (!parsed.success) back("/admin/einstellungen", { ok: false, message: firstIssue(parsed.error) });
const result = await updateCamp(getDb(), parsed.data, adminActor(admin));
revalidatePath("/admin", "layout");
revalidatePath("/");
back("/admin/einstellungen", result);
}