154 lines
5.2 KiB
TypeScript
154 lines
5.2 KiB
TypeScript
"use server";
|
|
|
|
import { revalidatePath } from "next/cache";
|
|
import { redirect } from "next/navigation";
|
|
import { getServerSession } from "next-auth";
|
|
import { authOptions } from "@/lib/auth-options";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { slugify } from "@/lib/slug";
|
|
import { BillingInterval } from "@prisma/client";
|
|
|
|
async function assertAdmin() {
|
|
const session = await getServerSession(authOptions);
|
|
if (!session?.user?.id || session.user.role !== "ADMIN") {
|
|
throw new Error("Keine Berechtigung.");
|
|
}
|
|
return session;
|
|
}
|
|
|
|
function parseBilling(v: FormDataEntryValue | null): BillingInterval {
|
|
const s = String(v ?? "NONE");
|
|
if (s === "MONTH" || s === "QUARTER" || s === "YEAR") return s;
|
|
return BillingInterval.NONE;
|
|
}
|
|
|
|
export async function createCourseAction(formData: FormData) {
|
|
const session = await assertAdmin();
|
|
const title = String(formData.get("title") ?? "").trim();
|
|
if (!title) redirect("/admin/courses/new?error=title");
|
|
|
|
let slug = String(formData.get("slug") ?? "").trim();
|
|
if (!slug) slug = slugify(title);
|
|
|
|
const exists = await prisma.course.findUnique({ where: { slug } });
|
|
if (exists) redirect(`/admin/courses/new?error=slug`);
|
|
|
|
const description = String(formData.get("description") ?? "").trim();
|
|
const authorName = String(formData.get("authorName") ?? "").trim() || session.user.name || "Admin";
|
|
const published = String(formData.get("published") ?? "") === "on";
|
|
const priceEuros = Number(String(formData.get("priceEuros") ?? "0").replace(",", "."));
|
|
const priceCents = Number.isFinite(priceEuros) ? Math.max(0, Math.round(priceEuros * 100)) : 0;
|
|
|
|
const course = await prisma.course.create({
|
|
data: {
|
|
slug,
|
|
title,
|
|
description,
|
|
published,
|
|
priceCents,
|
|
billingInterval: parseBilling(formData.get("billingInterval")),
|
|
authorId: session.user.id,
|
|
authorName,
|
|
},
|
|
});
|
|
|
|
revalidatePath("/kurse");
|
|
revalidatePath("/admin/courses");
|
|
redirect(`/admin/courses/${course.id}/edit`);
|
|
}
|
|
|
|
export async function updateCourseAction(courseId: string, formData: FormData) {
|
|
const session = await assertAdmin();
|
|
const title = String(formData.get("title") ?? "").trim();
|
|
if (!title) redirect(`/admin/courses/${courseId}/edit?error=title`);
|
|
|
|
let slug = String(formData.get("slug") ?? "").trim();
|
|
if (!slug) slug = slugify(title);
|
|
|
|
const clash = await prisma.course.findFirst({
|
|
where: { slug, NOT: { id: courseId } },
|
|
});
|
|
if (clash) redirect(`/admin/courses/${courseId}/edit?error=slug`);
|
|
|
|
const description = String(formData.get("description") ?? "").trim();
|
|
const authorName = String(formData.get("authorName") ?? "").trim() || session.user.name || "Admin";
|
|
const published = String(formData.get("published") ?? "") === "on";
|
|
const priceEuros = Number(String(formData.get("priceEuros") ?? "0").replace(",", "."));
|
|
const priceCents = Number.isFinite(priceEuros) ? Math.max(0, Math.round(priceEuros * 100)) : 0;
|
|
|
|
await prisma.course.update({
|
|
where: { id: courseId },
|
|
data: {
|
|
slug,
|
|
title,
|
|
description,
|
|
published,
|
|
priceCents,
|
|
billingInterval: parseBilling(formData.get("billingInterval")),
|
|
authorName,
|
|
},
|
|
});
|
|
|
|
revalidatePath("/kurse");
|
|
revalidatePath("/admin/courses");
|
|
revalidatePath(`/kurse/${slug}`);
|
|
redirect(`/admin/courses/${courseId}/edit?saved=1`);
|
|
}
|
|
|
|
export async function createModuleAction(courseId: string, formData: FormData) {
|
|
await assertAdmin();
|
|
const title = String(formData.get("title") ?? "").trim();
|
|
if (!title) redirect(`/admin/courses/${courseId}/edit?error=module`);
|
|
|
|
const max = await prisma.courseModule.aggregate({
|
|
where: { courseId },
|
|
_max: { sortOrder: true },
|
|
});
|
|
const sortOrder = (max._max.sortOrder ?? -1) + 1;
|
|
|
|
await prisma.courseModule.create({
|
|
data: { courseId, title, sortOrder },
|
|
});
|
|
|
|
revalidatePath(`/admin/courses/${courseId}/edit`);
|
|
redirect(`/admin/courses/${courseId}/edit`);
|
|
}
|
|
|
|
export async function createLessonAction(courseId: string, formData: FormData) {
|
|
await assertAdmin();
|
|
const moduleId = String(formData.get("moduleId") ?? "").trim();
|
|
const title = String(formData.get("lessonTitle") ?? "").trim();
|
|
if (!moduleId || !title) redirect(`/admin/courses/${courseId}/edit?error=lesson`);
|
|
|
|
const mod = await prisma.courseModule.findFirst({
|
|
where: { id: moduleId, courseId },
|
|
});
|
|
if (!mod) redirect(`/admin/courses/${courseId}/edit?error=lesson`);
|
|
|
|
let slug = String(formData.get("lessonSlug") ?? "").trim();
|
|
if (!slug) slug = slugify(title);
|
|
|
|
const contentHtml = String(formData.get("contentHtml") ?? "").trim();
|
|
|
|
const max = await prisma.lesson.aggregate({
|
|
where: { moduleId },
|
|
_max: { sortOrder: true },
|
|
});
|
|
const sortOrder = (max._max.sortOrder ?? -1) + 1;
|
|
|
|
const existing = await prisma.lesson.findUnique({
|
|
where: { moduleId_slug: { moduleId, slug } },
|
|
});
|
|
if (existing) redirect(`/admin/courses/${courseId}/edit?error=lessonSlug`);
|
|
|
|
await prisma.lesson.create({
|
|
data: { moduleId, slug, title, contentHtml, sortOrder, published: true },
|
|
});
|
|
|
|
const course = await prisma.course.findUnique({ where: { id: courseId }, select: { slug: true } });
|
|
if (course?.slug) revalidatePath(`/kurse/${course.slug}`);
|
|
|
|
revalidatePath(`/admin/courses/${courseId}/edit`);
|
|
redirect(`/admin/courses/${courseId}/edit`);
|
|
}
|