diff --git a/src/db/services/announcement.service.ts b/src/db/services/announcement.service.ts index 73689ed..f584d74 100644 --- a/src/db/services/announcement.service.ts +++ b/src/db/services/announcement.service.ts @@ -2,7 +2,7 @@ import { db } from ".." import { IAnnouncementService } from "../../types/abstracts/announcement-service.abstract" import { Announcement } from "../../types/entities/Announcement" import { InsertAnnouncement, SelectAnnouncement, announcements } from "../models/announcement.model" -import { desc } from "drizzle-orm" +import { desc, eq } from "drizzle-orm" export const announcementService: IAnnouncementService = { async addAnnouncement(text: string): Promise { @@ -35,4 +35,8 @@ export const announcementService: IAnnouncementService = { date: record.createdAt, })) }, + + async deleteAnnouncement(id: number): Promise { + await db.delete(announcements).where(eq(announcements.id, id)) + }, } diff --git a/src/routers/announcement.router.ts b/src/routers/announcement.router.ts index 78a46b9..92c7eca 100644 --- a/src/routers/announcement.router.ts +++ b/src/routers/announcement.router.ts @@ -124,3 +124,85 @@ export const announcement = new Elysia({ prefix: "/announcement" }) }, }, ) + .delete( + "/admin/:id", + async ({ params }) => { + const id = Number(params.id) + + if (isNaN(id) || id <= 0) { + return { error: "Invalid announcement ID" } + } + + // Check if announcement exists before deleting + const allAnnouncements = await announcementService.getAllAnnouncements() + const announcementExists = allAnnouncements.some((ann) => ann.id === id) + + if (!announcementExists) { + return { error: "Announcement not found" } + } + + await announcementService.deleteAnnouncement(id) + return { success: true } + }, + { + tags: ["Announcement"], + detail: { + description: "Deletes an announcement by its ID (admin endpoint).", + security: [ + { + basicAuth: [], + }, + ], + responses: { + "200": { + description: "Successfully deleted the announcement.", + content: { + "application/json": { + schema: { + type: "object", + properties: { + success: { + type: "boolean", + description: "Indicates if the operation was successful", + }, + }, + }, + }, + }, + }, + "400": { + description: "Bad request (e.g., invalid announcement ID).", + content: { + "application/json": { + schema: { + type: "object", + properties: { + error: { + type: "string", + description: "Error message", + }, + }, + }, + }, + }, + }, + "404": { + description: "Announcement not found.", + content: { + "application/json": { + schema: { + type: "object", + properties: { + error: { + type: "string", + description: "Error message", + }, + }, + }, + }, + }, + }, + }, + }, + }, + ) \ No newline at end of file diff --git a/src/routers/queue.router.ts b/src/routers/queue.router.ts index c70930c..95df7c8 100644 --- a/src/routers/queue.router.ts +++ b/src/routers/queue.router.ts @@ -28,6 +28,9 @@ export const queue = new Elysia({ prefix: "/queue" }) addStudentToQueue: t.Object({ idNumber: t.String({ description: "The student's ID number" }), }), + dequeueStudent: t.Object({ + idNumber: t.String({ description: "The student's ID number to remove from the queue" }), + }), }) .delete("/admin/reset", () => queueNumberService.resetAll(), { tags: ["Queue"], @@ -35,34 +38,36 @@ export const queue = new Elysia({ prefix: "/queue" }) description: "Deletes all the queue numbers for every course.", }, }) - .delete( - "/number", - async ({ headers }: QueueContext) => { - const studentId = headers.idNumber + // TODO: Student dequeue feature has been disabled. Students cannot remove themselves from the queue. + // If you need to remove a student from the queue, use the admin endpoint or contact a coordinator. + // .delete( + // "/number", + // async ({ headers }: QueueContext) => { + // const studentId = headers.idNumber - if (!studentId) { - return error(400, "Student ID not found") - } + // if (!studentId) { + // return error(400, "Student ID not found") + // } - return await queueNumberService.dequeueById(studentId) - }, - { - // @ts-expect-error TODO: Change this to an updated version of the basicAuth middleware once my patch is merged - beforeHandle: [validateQueueToken], - tags: ["Queue"], - detail: { - description: "Deletes a student's own queue number.", - responses: { - "200": { - description: "Successfully deleted the student's queue number.", - }, - "401": { - description: "Unauthorized.", - }, - }, - }, - }, - ) + // return await queueNumberService.dequeueById(studentId) + // }, + // { + // // @ts-expect-error TODO: Change this to an updated version of the basicAuth middleware once my patch is merged + // beforeHandle: [validateQueueToken], + // tags: ["Queue"], + // detail: { + // description: "Deletes a student's own queue number.", + // responses: { + // "200": { + // description: "Successfully deleted the student's queue number.", + // }, + // "401": { + // description: "Unauthorized.", + // }, + // }, + // }, + // }, + // ) .get( "/number", async ({ headers }: QueueContext) => { @@ -281,6 +286,89 @@ export const queue = new Elysia({ prefix: "/queue" }) }, }, ) + .delete( + "/admin/number", + async ({ body }) => { + const studentId = body.idNumber + + if (!studentId) { + return { error: "Student ID is required" } + } + + // Check if student has a queue number + const queueNumber = await queueNumberService.findByStudentId(studentId) + if (!queueNumber) { + return { error: "Student does not have a queue number" } + } + + await queueNumberService.dequeueById(studentId) + return { success: true } + }, + { + body: "dequeueStudent", + tags: ["Queue"], + detail: { + description: "Removes a student from the queue by their ID number (admin endpoint).", + security: [ + { + basicAuth: [], + }, + ], + requestBody: { + required: true, + description: "The student's ID number.", + content: { + "application/json": { + schema: { + type: "object", + properties: { + idNumber: { + type: "string", + description: "The student's ID number to remove from the queue", + }, + }, + required: ["idNumber"], + }, + }, + }, + }, + responses: { + "200": { + description: "Successfully removed the student from the queue.", + content: { + "application/json": { + schema: { + type: "object", + properties: { + success: { + type: "boolean", + description: "Indicates if the operation was successful", + }, + }, + }, + }, + }, + }, + "400": { + description: "Bad request (e.g., student ID missing or student does not have a queue number).", + content: { + "application/json": { + schema: { + type: "object", + properties: { + error: { + type: "string", + description: "Error message", + }, + }, + }, + }, + }, + }, + }, + }, + }, + ) // TODO: Uncomment when you wish to re-enable self-enqueueing for students // .post( // "/:course/number", diff --git a/src/types/abstracts/announcement-service.abstract.ts b/src/types/abstracts/announcement-service.abstract.ts index 821955d..ac46dd5 100644 --- a/src/types/abstracts/announcement-service.abstract.ts +++ b/src/types/abstracts/announcement-service.abstract.ts @@ -3,4 +3,5 @@ import { Announcement } from "../entities/Announcement" export type IAnnouncementService = { addAnnouncement(text: string): Promise getAllAnnouncements(): Promise + deleteAnnouncement(id: number): Promise }