import { FreshContext, Handlers } from "$fresh/server.ts"; import { db } from "$root/databases/db.ts"; import { ajustements, enseignements, modules, notes, promotions, students, ueModules, ues, } from "$root/databases/schema.ts"; import { AuthenticatedState } from "$root/defaults/interfaces.ts"; import { eq } from "npm:drizzle-orm@0.45.2"; const NOT_FOUND = () => new Response( JSON.stringify({ error: "Ressource introuvable" }), { status: 404, headers: { "content-type": "application/json" } }, ); const FORBIDDEN = () => new Response(null, { status: 403 }); export const handler: Handlers = { // #15 GET /promotions/{idPromo} async GET( _request: Request, context: FreshContext, ): Promise { if (context.state.session.eduPersonPrimaryAffiliation !== "employee") { return FORBIDDEN(); } const promo = await db .select() .from(promotions) .where(eq(promotions.id, context.params.idPromo)) .then((rows) => rows[0] ?? null); if (!promo) return NOT_FOUND(); return new Response(JSON.stringify(promo), { headers: { "content-type": "application/json" }, }); }, // #16 PUT /promotions/{idPromo} async PUT( request: Request, context: FreshContext, ): Promise { if (context.state.session.eduPersonPrimaryAffiliation !== "employee") { return FORBIDDEN(); } const body: { annee: string } = await request.json(); const [updated] = await db .update(promotions) .set({ annee: body.annee }) .where(eq(promotions.id, context.params.idPromo)) .returning(); if (!updated) return NOT_FOUND(); return new Response(JSON.stringify(updated), { headers: { "content-type": "application/json" }, }); }, // #17 DELETE /promotions/{idPromo} // Blocked if students are still assigned (409). // Cascade: deletes linked ue_modules, enseignements, and orphaned // modules (+ their notes) & UEs (+ their ajustements). async DELETE( _request: Request, context: FreshContext, ): Promise { if (context.state.session.eduPersonPrimaryAffiliation !== "employee") { return FORBIDDEN(); } const idPromo = context.params.idPromo; const promo = await db .select() .from(promotions) .where(eq(promotions.id, idPromo)) .then((r) => r[0] ?? null); if (!promo) return NOT_FOUND(); // Block deletion if students are still assigned const assignedStudents = await db .select() .from(students) .where(eq(students.idPromo, idPromo)) .then((r) => r.length); if (assignedStudents > 0) { return new Response( JSON.stringify({ error: `Impossible de supprimer : ${assignedStudents} étudiant(s) encore assigné(s) à cette promotion`, }), { status: 409, headers: { "content-type": "application/json" } }, ); } await db.transaction(async (tx) => { // Collect linked module IDs and UE IDs before deleting junction rows const linkedUeModules = await tx .select({ idModule: ueModules.idModule, idUE: ueModules.idUE }) .from(ueModules) .where(eq(ueModules.idPromo, idPromo)); const linkedEns = await tx .select({ idModule: enseignements.idModule }) .from(enseignements) .where(eq(enseignements.idPromo, idPromo)); const moduleIds = [ ...new Set([ ...linkedUeModules.map((um) => um.idModule), ...linkedEns.map((e) => e.idModule), ]), ]; const ueIds = [...new Set(linkedUeModules.map((um) => um.idUE))]; // Delete junction rows that directly reference this promo await tx.delete(ueModules).where(eq(ueModules.idPromo, idPromo)); await tx.delete(enseignements).where(eq(enseignements.idPromo, idPromo)); // Delete orphaned modules (not used by another promo) and their notes for (const modId of moduleIds) { const stillInUeModules = await tx .select() .from(ueModules) .where(eq(ueModules.idModule, modId)) .then((r) => r.length > 0); const stillInEns = await tx .select() .from(enseignements) .where(eq(enseignements.idModule, modId)) .then((r) => r.length > 0); if (!stillInUeModules && !stillInEns) { await tx.delete(notes).where(eq(notes.idModule, modId)); await tx.delete(modules).where(eq(modules.id, modId)); } } // Delete orphaned UEs (not used by another promo) and their ajustements for (const ueId of ueIds) { const stillUsed = await tx .select() .from(ueModules) .where(eq(ueModules.idUE, ueId)) .then((r) => r.length > 0); if (!stillUsed) { await tx.delete(ajustements).where(eq(ajustements.idUE, ueId)); await tx.delete(ues).where(eq(ues.id, ueId)); } } // Delete the promotion await tx.delete(promotions).where(eq(promotions.id, idPromo)); }); return new Response(null, { status: 204 }); }, };