Stage 1: Course/Module/Lesson CRUD admin UI with TipTap editor
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
"use server";
|
||||
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { headers } from "next/headers";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { redirect } from "next/navigation";
|
||||
import { revalidatePath } from "next/cache";
|
||||
|
||||
async function requireAdmin() {
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
if (!session || session.user.role !== "admin") throw new Error("Forbidden");
|
||||
}
|
||||
|
||||
function slugify(str: string): string {
|
||||
const map: Record<string, string> = {
|
||||
а:"a",б:"b",в:"v",г:"g",д:"d",е:"e",ё:"yo",ж:"zh",з:"z",и:"i",й:"y",
|
||||
к:"k",л:"l",м:"m",н:"n",о:"o",п:"p",р:"r",с:"s",т:"t",у:"u",ф:"f",
|
||||
х:"kh",ц:"ts",ч:"ch",ш:"sh",щ:"shch",ъ:"",ы:"y",ь:"",э:"e",ю:"yu",я:"ya",
|
||||
};
|
||||
return str.toLowerCase()
|
||||
.replace(/[а-яё]/g, (c) => map[c] ?? c)
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-|-$/g, "");
|
||||
}
|
||||
|
||||
export async function createCourse(formData: FormData) {
|
||||
await requireAdmin();
|
||||
const title = formData.get("title") as string;
|
||||
const slug = (formData.get("slug") as string).trim() || slugify(title);
|
||||
const description = (formData.get("description") as string) || null;
|
||||
|
||||
const course = await prisma.course.create({
|
||||
data: { title, slug, description },
|
||||
});
|
||||
|
||||
revalidatePath("/admin/courses");
|
||||
redirect(`/admin/courses/${course.id}`);
|
||||
}
|
||||
|
||||
export async function updateCourse(courseId: string, formData: FormData) {
|
||||
await requireAdmin();
|
||||
const title = formData.get("title") as string;
|
||||
const slug = formData.get("slug") as string;
|
||||
const description = (formData.get("description") as string) || null;
|
||||
const published = formData.get("published") === "true";
|
||||
const coverImage = (formData.get("coverImage") as string) || null;
|
||||
|
||||
await prisma.course.update({
|
||||
where: { id: courseId },
|
||||
data: { title, slug, description, published, coverImage },
|
||||
});
|
||||
|
||||
revalidatePath("/admin/courses");
|
||||
revalidatePath(`/admin/courses/${courseId}`);
|
||||
}
|
||||
|
||||
export async function deleteCourse(courseId: string) {
|
||||
await requireAdmin();
|
||||
await prisma.course.delete({ where: { id: courseId } });
|
||||
revalidatePath("/admin/courses");
|
||||
redirect("/admin/courses");
|
||||
}
|
||||
Reference in New Issue
Block a user