From 5349e1394b08cde301d6fa83fafe883736550038 Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Sun, 14 Jul 2024 18:36:42 -0700 Subject: [PATCH 1/2] speaker service --- src/app.ts | 2 + src/database.ts | 5 ++ src/services/speakers/speakers-router.ts | 104 +++++++++++++++++++++++ src/services/speakers/speakers-schema.ts | 48 +++++++++++ src/services/speakers/speakers-utils.ts | 0 5 files changed, 159 insertions(+) create mode 100644 src/services/speakers/speakers-router.ts create mode 100644 src/services/speakers/speakers-schema.ts create mode 100644 src/services/speakers/speakers-utils.ts diff --git a/src/app.ts b/src/app.ts index 31442ba..a756f6e 100644 --- a/src/app.ts +++ b/src/app.ts @@ -19,6 +19,7 @@ import s3Router from "./services/s3/s3-router"; import statsRouter from "./services/stats/stats-router"; import sponsorRouter from "./services/sponsor/sponsor-router"; import subscriptionRouter from "./services/subscription/subscription-router"; +import speakersRouter from "./services/speakers/speakers-router"; const app = express(); @@ -45,6 +46,7 @@ app.use("/s3", databaseMiddleware, s3Router); app.use("/stats", databaseMiddleware, statsRouter); app.use("/sponsor", databaseMiddleware, sponsorRouter); app.use("/subscription", databaseMiddleware, subscriptionRouter); +app.use("/speakers", databaseMiddleware, speakersRouter); app.get("/status", (_, res) => { return res.status(StatusCodes.OK).send("API is alive!"); diff --git a/src/database.ts b/src/database.ts index 128408c..c68d14f 100644 --- a/src/database.ts +++ b/src/database.ts @@ -28,6 +28,10 @@ import { NotificationsSchema, NotificationsValidator, } from "./services/notifications/notifications-schema"; +import { + SpeakerSchema, + SpeakerValidator, +} from "./services/speakers/speakers-schema"; mongoose.set("toObject", { versionKey: false }); @@ -89,4 +93,5 @@ export const Database = { NotificationsSchema, NotificationsValidator ), + SPEAKERS: initializeModel("speakers", SpeakerSchema, SpeakerValidator), }; diff --git a/src/services/speakers/speakers-router.ts b/src/services/speakers/speakers-router.ts new file mode 100644 index 0000000..1eddac0 --- /dev/null +++ b/src/services/speakers/speakers-router.ts @@ -0,0 +1,104 @@ +import { Router } from "express"; +import { StatusCodes } from "http-status-codes"; +import { SpeakerValidator } from "./speakers-schema"; +import { Database } from "../../database"; +import RoleChecker from "../../middleware/role-checker"; +import { Role } from "../auth/auth-models"; + +const speakersRouter = Router(); + +// Get all speakers +speakersRouter.get("/", RoleChecker([], true), async (req, res, next) => { + try { + const speakers = await Database.SPEAKERS.find(); + return res.status(StatusCodes.OK).json(speakers); + } catch (error) { + next(error); + } +}); + +// Get a specific speaker +speakersRouter.get( + "/:SPEAKERID", + RoleChecker([], true), + async (req, res, next) => { + const speakerId = req.params.SPEAKERID; + + try { + const speaker = await Database.SPEAKERS.findOne({ speakerId }); + + if (!speaker) { + return res + .status(StatusCodes.NOT_FOUND) + .json({ error: "DoesNotExist" }); + } + + return res.status(StatusCodes.OK).json(speaker); + } catch (error) { + next(error); + } + } +); + +// Create a new speaker +speakersRouter.post( + "/", + RoleChecker([Role.Enum.STAFF]), + async (req, res, next) => { + try { + const validatedData = SpeakerValidator.parse(req.body); + const speaker = new Database.SPEAKERS(validatedData); + await speaker.save(); + return res.status(StatusCodes.CREATED).json(speaker); + } catch (error) { + next(error); + } + } +); + +// Update a speaker +speakersRouter.put( + "/:SPEAKERID", + RoleChecker([Role.Enum.STAFF], true), + async (req, res, next) => { + const speakerId = req.params.SPEAKERID; + + try { + const validatedData = SpeakerValidator.parse(req.body); + const speaker = await Database.SPEAKERS.findOneAndUpdate( + { speakerId }, + { $set: validatedData }, + { new: true, runValidators: true } + ); + + if (!speaker) { + return res + .status(StatusCodes.NOT_FOUND) + .json({ error: "DoesNotExist" }); + } + + return res.status(StatusCodes.OK).json(speaker); + } catch (error) { + next(error); + } + } +); + +// Delete a speaker +speakersRouter.delete( + "/:SPEAKERID", + RoleChecker([Role.Enum.STAFF], true), + async (req, res, next) => { + const speakerId = req.params.SPEAKERID; + + try { + await Database.SPEAKERS.findOneAndDelete({ speakerId }); + + return res.sendStatus(StatusCodes.NO_CONTENT); + } catch (error) { + next(error); + } + } +); + +export default speakersRouter; diff --git a/src/services/speakers/speakers-schema.ts b/src/services/speakers/speakers-schema.ts new file mode 100644 index 0000000..bf69b4f --- /dev/null +++ b/src/services/speakers/speakers-schema.ts @@ -0,0 +1,48 @@ +import { Schema } from "mongoose"; +import { z } from "zod"; +import { v4 as uuidv4 } from "uuid"; + +// Zod schema for speaker +export const SpeakerValidator = z.object({ + speakerId: z.coerce.string().default(() => uuidv4()), + name: z.string(), + title: z.string(), + bio: z.string(), + eventTitle: z.string(), + eventDescription: z.string(), + imgUrl: z.string(), +}); + +// Mongoose schema for speaker +export const SpeakerSchema = new Schema({ + speakerId: { + type: String, + required: true, + unique: true, + default: () => uuidv4(), + }, + name: { + type: String, + required: true, + }, + title: { + type: String, + required: true, + }, + bio: { + type: String, + required: true, + }, + eventTitle: { + type: String, + required: true, + }, + eventDescription: { + type: String, + required: true, + }, + imgUrl: { + type: String, + required: true, + }, +}); diff --git a/src/services/speakers/speakers-utils.ts b/src/services/speakers/speakers-utils.ts new file mode 100644 index 0000000..e69de29 From b1b4fd40026f9a94491b6e04fd7ce55232d7b1bf Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Sun, 14 Jul 2024 18:41:02 -0700 Subject: [PATCH 2/2] remove wrong file --- src/services/attendee/attendee-router.ts | 206 ----------------------- 1 file changed, 206 deletions(-) delete mode 100644 src/services/attendee/attendee-router.ts diff --git a/src/services/attendee/attendee-router.ts b/src/services/attendee/attendee-router.ts deleted file mode 100644 index 7a200b7..0000000 --- a/src/services/attendee/attendee-router.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { Router } from "express"; -import { StatusCodes } from "http-status-codes"; -import { - AttendeeValidator, - EventIdValidator, - PartialAttendeeValidator, -} from "./attendee-schema"; -import { Database } from "../../database"; -import RoleChecker from "../../middleware/role-checker"; -import { Role } from "../auth/auth-models"; -import dotenv from "dotenv"; -import { generateQrHash } from "./attendee-utils"; - -dotenv.config(); - -const attendeeRouter = Router(); - -// Favorite an event for an attendee -attendeeRouter.post( - "/favorites/:eventId", - RoleChecker([Role.Enum.USER]), - async (req, res, next) => { - const payload = res.locals.payload; - const userId = payload.userId; - const { eventId } = EventIdValidator.parse(req.params); - - try { - const attendee = await Database.ATTENDEE.findOne({ userId }); - - if (!attendee) { - return res - .status(StatusCodes.NOT_FOUND) - .json({ error: "UserNotFound" }); - } - - await Database.ATTENDEE.updateOne( - { userId: userId }, - { $addToSet: { favorites: eventId } } - ); - - return res.status(StatusCodes.OK).json(attendee); - } catch (error) { - next(error); - } - } -); - -// Unfavorite an event for an attendee -attendeeRouter.delete( - "/favorites/:eventId", - RoleChecker([Role.Enum.USER]), - async (req, res, next) => { - const payload = res.locals.payload; - const userId = payload.userId; - const { eventId } = EventIdValidator.parse(req.params); - - try { - const attendee = await Database.ATTENDEE.findOne({ userId }); - - if (!attendee) { - return res - .status(StatusCodes.NOT_FOUND) - .json({ error: "UserNotFound" }); - } - - await Database.ATTENDEE.updateOne( - { userId: userId }, - { $pull: { favorites: eventId } } - ); - - return res.status(StatusCodes.OK).json(attendee); - } catch (error) { - next(error); - } - } -); - -// Get favorite events for an attendee -attendeeRouter.get( - "/favorites", - RoleChecker([Role.Enum.USER]), - async (req, res, next) => { - const payload = res.locals.payload; - const userId = payload.userId; - - try { - const attendee = await Database.ATTENDEE.findOne({ userId }); - - if (!attendee) { - return res - .status(StatusCodes.NOT_FOUND) - .json({ error: "UserNotFound" }); - } - - return res.status(StatusCodes.OK).json(attendee); - } catch (error) { - next(error); - } - } -); - -// Create a new attendee -attendeeRouter.post("/", async (req, res, next) => { - try { - const attendeeData = AttendeeValidator.parse(req.body); - const attendee = new Database.ATTENDEE(attendeeData); - await attendee.save(); - - return res.status(StatusCodes.CREATED).json(attendeeData); - } catch (error) { - next(error); - } -}); - -// generates a unique QR code for each attendee -attendeeRouter.get( - "/qr/", - RoleChecker([Role.Enum.USER]), - async (req, res, next) => { - const payload = res.locals.payload; - - try { - const userId = payload.userId; - const expTime = Math.floor(Date.now() / 1000) + 20; // Current epoch time in seconds + 20 seconds - const qrCodeString = generateQrHash(userId, expTime); - return res.status(StatusCodes.OK).json({ qrCode: qrCodeString }); - } catch (error) { - next(error); - } - } -); - -attendeeRouter.get( - "/", - RoleChecker([Role.Enum.USER]), - async (req, res, next) => { - try { - const payload = res.locals.payload; - const userId = payload.userId; - - // Check if the user exists in the database - const user = await Database.ATTENDEE.findOne({ userId }); - - if (!user) { - return res - .status(StatusCodes.NOT_FOUND) - .json({ error: "UserNotFound" }); - } - - return res.status(StatusCodes.OK).json(user); - } catch (error) { - next(error); - } - } -); - -// Get attendees based on a partial filter in body -attendeeRouter.get( - "/filter", - RoleChecker([Role.Enum.STAFF, Role.Enum.CORPORATE]), - async (req, res, next) => { - try { - const attendeeData = PartialAttendeeValidator.parse(req.body); - const attendees = await Database.ATTENDEE.find( - attendeeData, - "userId" - ); - - return res.status(StatusCodes.OK).json(attendees); - } catch (error) { - next(error); - } - } -); - -// Update an attendee with partial data -attendeeRouter.put( - "/update", - RoleChecker([Role.Enum.USER]), - async (req, res, next) => { - const payload = res.locals.payload; - const userId = payload.userId; - - try { - const updateData = PartialAttendeeValidator.parse(req.body); - - const attendee = await Database.ATTENDEE.findOneAndUpdate( - { userId }, - { $set: updateData }, - { new: true, runValidators: true } - ); - - if (!attendee) { - return res - .status(StatusCodes.NOT_FOUND) - .json({ error: "UserNotFound" }); - } - - return res.status(StatusCodes.OK).json(attendee); - } catch (error) { - next(error); - } - } -); - -export default attendeeRouter;