From f3e1c7aea935c27dd2d20f1f95bb7644c8fa55ef Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Mon, 1 Apr 2024 18:08:54 -0500 Subject: [PATCH 01/11] starting attendee api routes --- src/app.ts | 44 +++++++++++++++++++++++ src/services/attendees/attendee-schema.ts | 20 +++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/services/attendees/attendee-schema.ts diff --git a/src/app.ts b/src/app.ts index 7f9f4b5..232ecad 100644 --- a/src/app.ts +++ b/src/app.ts @@ -12,6 +12,9 @@ import authRouter from "./services/auth/auth-router"; import eventRouter from "./services/events/events-router"; import subscriptionRouter from "./services/subscription/subscription-router"; +import { CreateAttendeeSchema } from "./services/attendees/attendee-schema"; +import { AttendeeModel } from "./services/attendees/attendee-schema"; + const app = express(); // to prevent server-side caching/returning status code 200 @@ -30,6 +33,47 @@ app.use("/auth", authRouter); app.use("/event", eventRouter); app.use("/subscription", subscriptionRouter); +// Create a new attendee +app.post("/attendees", async (req, res) => { + try { + const { name, email } = CreateAttendeeSchema.parse(req.body); + console.log("Name:", name); + console.log("Email:", email); + + // Save attendee to the database + const attendee = new AttendeeModel({ name, email }); + await attendee.save(); + + res.status(201).send("Attendee created successfully."); + } catch (error) { + console.error("Error:", error); + res.status(400).send("Error creating attendee."); + } +}); + +// Check if a user email exists +app.get("/attendees/:email", async (req, res) => { + try { + const { email } = req.params; + + // Check if the user exists in the database + const userExists = await AttendeeModel.exists({ email }); + + if (!userExists) { + return res + .status(StatusCodes.NOT_FOUND) + .send("User with that email does not exist."); + } + + return res.status(StatusCodes.OK).send("User exists."); + } catch (error) { + console.error("Error:", error); + return res + .status(StatusCodes.INTERNAL_SERVER_ERROR) + .send("Internal server error."); + } +}); + app.get("/status", (_, res) => { return res.status(StatusCodes.OK).send("API is alive!"); }); diff --git a/src/services/attendees/attendee-schema.ts b/src/services/attendees/attendee-schema.ts new file mode 100644 index 0000000..8e936bc --- /dev/null +++ b/src/services/attendees/attendee-schema.ts @@ -0,0 +1,20 @@ +import mongoose from "mongoose"; +import { z } from "zod"; + + +// Zod schema for attendee +const CreateAttendeeSchema = z.object({ + name: z.string(), + email: z.string().email(), +}); + + +// Mongoose schema for attendee +const AttendeeSchema = new mongoose.Schema({ + name: { type: String, required: true }, + email: { type: String, required: true, unique: true }, +}); + + +export const AttendeeModel = mongoose.model("Attendee", AttendeeSchema); +export { CreateAttendeeSchema }; \ No newline at end of file From 2ec7f39883bfba243116c426a5800baceecf29de Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Sun, 7 Apr 2024 12:17:19 -0500 Subject: [PATCH 02/11] continuing attendee schema and event schema --- src/app.ts | 48 +------------ src/services/attendees/attendee-router.ts | 49 +++++++++++++ src/services/attendees/attendee-schema.ts | 43 ++++++++++-- src/services/events/event-router.ts | 86 +++++++++++++++++++++++ src/services/events/event-schema.ts | 50 +++++++++++++ 5 files changed, 226 insertions(+), 50 deletions(-) create mode 100644 src/services/attendees/attendee-router.ts create mode 100644 src/services/events/event-router.ts create mode 100644 src/services/events/event-schema.ts diff --git a/src/app.ts b/src/app.ts index 232ecad..2c66856 100644 --- a/src/app.ts +++ b/src/app.ts @@ -9,11 +9,10 @@ import bodyParser from "body-parser"; import errorHandler from "./middleware/error-handler"; import authRouter from "./services/auth/auth-router"; -import eventRouter from "./services/events/events-router"; import subscriptionRouter from "./services/subscription/subscription-router"; -import { CreateAttendeeSchema } from "./services/attendees/attendee-schema"; -import { AttendeeModel } from "./services/attendees/attendee-schema"; +import attendeeRouter from "./services/attendees/attendee-router"; +import eventRouter from "./services/events/event-router"; const app = express(); @@ -30,49 +29,8 @@ app.use("/", bodyParser.json()); // API routes app.use("/auth", authRouter); +app.use("/attendee", attendeeRouter); app.use("/event", eventRouter); -app.use("/subscription", subscriptionRouter); - -// Create a new attendee -app.post("/attendees", async (req, res) => { - try { - const { name, email } = CreateAttendeeSchema.parse(req.body); - console.log("Name:", name); - console.log("Email:", email); - - // Save attendee to the database - const attendee = new AttendeeModel({ name, email }); - await attendee.save(); - - res.status(201).send("Attendee created successfully."); - } catch (error) { - console.error("Error:", error); - res.status(400).send("Error creating attendee."); - } -}); - -// Check if a user email exists -app.get("/attendees/:email", async (req, res) => { - try { - const { email } = req.params; - - // Check if the user exists in the database - const userExists = await AttendeeModel.exists({ email }); - - if (!userExists) { - return res - .status(StatusCodes.NOT_FOUND) - .send("User with that email does not exist."); - } - - return res.status(StatusCodes.OK).send("User exists."); - } catch (error) { - console.error("Error:", error); - return res - .status(StatusCodes.INTERNAL_SERVER_ERROR) - .send("Internal server error."); - } -}); app.get("/status", (_, res) => { return res.status(StatusCodes.OK).send("API is alive!"); diff --git a/src/services/attendees/attendee-router.ts b/src/services/attendees/attendee-router.ts new file mode 100644 index 0000000..6c27a72 --- /dev/null +++ b/src/services/attendees/attendee-router.ts @@ -0,0 +1,49 @@ +import { Router } from "express"; +import { StatusCodes } from "http-status-codes"; +import { AttendeeValidator } from "./attendee-schema"; +import { AttendeeModel } from "./attendee-schema"; + +const attendeeRouter = Router(); + +// Create a new attendee +attendeeRouter.post("/", async (req, res) => { + try { + const { name, email } = AttendeeValidator.parse(req.body); + console.log("Name:", name); + console.log("Email:", email); + + // Save attendee to the database + const attendee = new AttendeeModel({ name, email }); + await attendee.save(); + + res.status(201).send("Attendee created successfully."); + } catch (error) { + console.error("Error:", error); + res.status(400).send("Error creating attendee."); + } +}); + +// Check if a user email exists +attendeeRouter.get("/:email", async (req, res) => { + try { + const { email } = req.params; + + // Check if the user exists in the database + const userExists = await AttendeeModel.exists({ email }); + + if (!userExists) { + return res + .status(StatusCodes.NOT_FOUND) + .send("User with that email does not exist."); + } + + return res.status(StatusCodes.OK).send("User exists."); + } catch (error) { + console.error("Error:", error); + return res + .status(StatusCodes.INTERNAL_SERVER_ERROR) + .send("Internal server error."); + } +}); + +export default attendeeRouter; diff --git a/src/services/attendees/attendee-schema.ts b/src/services/attendees/attendee-schema.ts index 8e936bc..c82a490 100644 --- a/src/services/attendees/attendee-schema.ts +++ b/src/services/attendees/attendee-schema.ts @@ -1,20 +1,53 @@ import mongoose from "mongoose"; import { z } from "zod"; - // Zod schema for attendee -const CreateAttendeeSchema = z.object({ +const AttendeeValidator = z.object({ name: z.string(), email: z.string().email(), + studentInfo: z.object({ + university: z.string().nonempty(), + graduation: z.string().nullable().optional(), + major: z.string().nullable().optional(), + }), + events: z.array(z.string()), + dietary_restrictions: z.string(), + age: z.number().nullable().optional(), + gender: z.string().nullable().optional(), + race: z.array(z.string()).nullable().optional(), + ethnicity: z.string().nullable().optional(), + first_gen: z.string().nullable().optional(), + hear_about_rp: z.array(z.string()).nullable().optional(), + portfolio: z.string().nullable().optional(), + job_interest: z.array(z.string()).nullable().optional(), + interest_mech_puzzle: z.array(z.string()).nullable().optional(), + priority_expiry: z.date().nullable().optional(), + has_resume: z.boolean().optional(), }); - // Mongoose schema for attendee const AttendeeSchema = new mongoose.Schema({ name: { type: String, required: true }, email: { type: String, required: true, unique: true }, + studentInfo: { + university: { type: String, required: true }, + graduation: { type: String, default: null }, + major: { type: String, default: null }, + }, + events: [{ type: mongoose.Schema.Types.ObjectId, ref: "Event" }], + dietary_restrictions: { type: String, required: true }, + age: { type: Number, default: null }, + gender: { type: String, default: null }, + race: [{ type: String }], + ethnicity: { type: String, default: null }, + first_gen: { type: String, default: null }, + hear_about_rp: [{ type: String }], + portfolio: { type: String, default: null }, + job_interest: [{ type: String }], + interest_mech_puzzle: [{ type: String }], + priority_expiry: { type: Date, default: null }, + has_resume: { type: Boolean, default: false }, }); - export const AttendeeModel = mongoose.model("Attendee", AttendeeSchema); -export { CreateAttendeeSchema }; \ No newline at end of file +export { AttendeeValidator }; diff --git a/src/services/events/event-router.ts b/src/services/events/event-router.ts new file mode 100644 index 0000000..360b1b3 --- /dev/null +++ b/src/services/events/event-router.ts @@ -0,0 +1,86 @@ +import { Router } from "express"; +import { StatusCodes } from "http-status-codes"; +import { EventValidator } from "./event-schema"; +import { EventModel } from "./event-schema"; + +const eventRouter = Router(); + +// Create a new event +eventRouter.post("/", async (req, res) => { + try { + const eventData = EventValidator.parse(req.body); + const event = new EventModel(eventData); + await event.save(); + res.status(StatusCodes.CREATED).json(event); + } catch (error) { + console.error("Error:", error); + res.status(StatusCodes.BAD_REQUEST).send("Error creating event."); + } +}); + +// Get all events +eventRouter.get("/", async (req, res) => { + try { + const events = await EventModel.find(); + res.status(StatusCodes.OK).json(events); + } catch (error) { + console.error("Error:", error); + res.status(StatusCodes.INTERNAL_SERVER_ERROR).send( + "Internal server error." + ); + } +}); + +// Get event by ID +eventRouter.get("/:id", async (req, res) => { + try { + const event = await EventModel.findById(req.params.id); + if (!event) { + return res.status(StatusCodes.NOT_FOUND).send("Event not found."); + } + res.status(StatusCodes.OK).json(event); + } catch (error) { + console.error("Error:", error); + res.status(StatusCodes.INTERNAL_SERVER_ERROR).send( + "Internal server error." + ); + } +}); + +// Update event +eventRouter.patch("/:id", async (req, res) => { + try { + const event = await EventModel.findByIdAndUpdate( + req.params.id, + req.body, + { new: true } + ); + if (!event) { + return res.status(StatusCodes.NOT_FOUND).send("Event not found."); + } + res.status(StatusCodes.OK).json(event); + } catch (error) { + console.error("Error:", error); + res.status(StatusCodes.INTERNAL_SERVER_ERROR).send( + "Internal server error." + ); + } +}); + +// Delete event +eventRouter.delete("/:id", async (req, res) => { + try { + const event = await EventModel.findByIdAndDelete(req.params.id); + if (!event) { + return res.status(StatusCodes.NOT_FOUND).send("Event not found."); + } + res.status(StatusCodes.NO_CONTENT).send(); + } catch (error) { + console.error("Error:", error); + res.status(StatusCodes.INTERNAL_SERVER_ERROR).send( + "Internal server error." + ); + } +}); + +export default eventRouter; diff --git a/src/services/events/event-schema.ts b/src/services/events/event-schema.ts new file mode 100644 index 0000000..db29a3d --- /dev/null +++ b/src/services/events/event-schema.ts @@ -0,0 +1,50 @@ +import mongoose from "mongoose"; +import { z } from "zod"; + +// Zod schema for event +const EventValidator = z.object({ + name: z.string(), + description: z.string(), + start_time: z.date(), + end_time: z.date(), + attendees: z.array(z.string()), + location: z.array( + z.object({ + description: z.string(), + tags: z.array(z.string()), + latitude: z.number(), + longitude: z.number(), + }) + ), + virtual: z.boolean(), + upgrade: z.boolean().default(false), + downgrade: z.boolean().default(false), + imageUrl: z.string().nullable().optional(), + visible: z.boolean().default(false), +}); + +// Mongoose schema for location +const LocationSchema = new mongoose.Schema({ + description: { type: String, required: true }, + tags: [{ type: String }], + latitude: { type: Number, required: true }, + longitude: { type: Number, required: true }, +}); + +// Mongoose schema for event +const EventSchema = new mongoose.Schema({ + name: { type: String, required: true }, + description: { type: String, required: true }, + start_time: { type: Date, required: true }, + end_time: { type: Date, required: true }, + attendees: [{ type: mongoose.Schema.Types.ObjectId, ref: "Attendee" }], + location: [LocationSchema], + virtual: { type: Boolean, required: true }, + upgrade: { type: Boolean, default: false }, + downgrade: { type: Boolean, default: false }, + imageUrl: { type: String, default: null }, + visible: { type: Boolean, default: false }, +}); + +export const EventModel = mongoose.model("Event", EventSchema); +export { EventValidator }; From 425bcd6f189537fdda3f233332b3862a0a437297 Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Tue, 9 Apr 2024 17:57:42 -0500 Subject: [PATCH 03/11] request changes --- src/app.ts | 2 +- src/database.ts | 5 +++ src/services/attendees/attendee-router.ts | 24 ++++++----- src/services/attendees/attendee-schema.ts | 3 +- src/services/events/event-router.ts | 52 ++++++++++++----------- src/services/events/event-schema.ts | 3 +- 6 files changed, 49 insertions(+), 40 deletions(-) diff --git a/src/app.ts b/src/app.ts index 2c66856..3ca3745 100644 --- a/src/app.ts +++ b/src/app.ts @@ -28,8 +28,8 @@ app.use("/", morgan("dev")); app.use("/", bodyParser.json()); // API routes -app.use("/auth", authRouter); app.use("/attendee", attendeeRouter); +app.use("/auth", authRouter); app.use("/event", eventRouter); app.get("/status", (_, res) => { diff --git a/src/database.ts b/src/database.ts index 7e0a9e6..bf1a1e6 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1,4 +1,8 @@ import mongoose, { Schema } from "mongoose"; +import { + AttendeeSchema, + AttendeeValidator, +} from "./services/attendees/attendee-schema"; import { RoleValidator, RoleSchema } from "./services/auth/auth-schema"; import { EventSchema, EventValidator } from "./services/events/events-schema"; import { @@ -43,4 +47,5 @@ export const Database = { SubscriptionSchema, SubscriptionSchemaValidator ), + ATTENDEES: initializeModel("attendees", AttendeeSchema, AttendeeValidator), }; diff --git a/src/services/attendees/attendee-router.ts b/src/services/attendees/attendee-router.ts index 6c27a72..a5ebfac 100644 --- a/src/services/attendees/attendee-router.ts +++ b/src/services/attendees/attendee-router.ts @@ -1,25 +1,23 @@ import { Router } from "express"; import { StatusCodes } from "http-status-codes"; import { AttendeeValidator } from "./attendee-schema"; -import { AttendeeModel } from "./attendee-schema"; +import { Database } from "../../database"; const attendeeRouter = Router(); // Create a new attendee attendeeRouter.post("/", async (req, res) => { try { - const { name, email } = AttendeeValidator.parse(req.body); - console.log("Name:", name); - console.log("Email:", email); - - // Save attendee to the database - const attendee = new AttendeeModel({ name, email }); + const attendeeData = AttendeeValidator.parse(req.body); + const attendee = new Database.ATTENDEES(attendeeData); await attendee.save(); - res.status(201).send("Attendee created successfully."); + return res.status(StatusCodes.CREATED).json(attendeeData); } catch (error) { console.error("Error:", error); - res.status(400).send("Error creating attendee."); + return res + .status(StatusCodes.INTERNAL_SERVER_ERROR) + .send("Error creating attendee."); } }); @@ -29,7 +27,7 @@ attendeeRouter.get("/:email", async (req, res) => { const { email } = req.params; // Check if the user exists in the database - const userExists = await AttendeeModel.exists({ email }); + const userExists = await Database.ATTENDEES.exists({ email }); if (!userExists) { return res @@ -37,7 +35,11 @@ attendeeRouter.get("/:email", async (req, res) => { .send("User with that email does not exist."); } - return res.status(StatusCodes.OK).send("User exists."); + const user = await Database.ATTENDEES.findOne({ + email, + }); + + return res.status(StatusCodes.OK).json(user); } catch (error) { console.error("Error:", error); return res diff --git a/src/services/attendees/attendee-schema.ts b/src/services/attendees/attendee-schema.ts index c82a490..279a125 100644 --- a/src/services/attendees/attendee-schema.ts +++ b/src/services/attendees/attendee-schema.ts @@ -49,5 +49,4 @@ const AttendeeSchema = new mongoose.Schema({ has_resume: { type: Boolean, default: false }, }); -export const AttendeeModel = mongoose.model("Attendee", AttendeeSchema); -export { AttendeeValidator }; +export { AttendeeSchema, AttendeeValidator }; diff --git a/src/services/events/event-router.ts b/src/services/events/event-router.ts index 360b1b3..f365ea1 100644 --- a/src/services/events/event-router.ts +++ b/src/services/events/event-router.ts @@ -1,7 +1,7 @@ import { Router } from "express"; import { StatusCodes } from "http-status-codes"; import { EventValidator } from "./event-schema"; -import { EventModel } from "./event-schema"; +import { Database } from "../../database"; const eventRouter = Router(); @@ -9,77 +9,81 @@ const eventRouter = Router(); eventRouter.post("/", async (req, res) => { try { const eventData = EventValidator.parse(req.body); - const event = new EventModel(eventData); + const event = new Database.EVENTS(eventData); await event.save(); - res.status(StatusCodes.CREATED).json(event); + return res.status(StatusCodes.CREATED).json(event); } catch (error) { console.error("Error:", error); - res.status(StatusCodes.BAD_REQUEST).send("Error creating event."); + return res + .status(StatusCodes.BAD_REQUEST) + .send("Error creating event."); } }); // Get all events eventRouter.get("/", async (req, res) => { try { - const events = await EventModel.find(); - res.status(StatusCodes.OK).json(events); + const events = await Database.EVENTS.find(); + return res.status(StatusCodes.OK).json(events); } catch (error) { console.error("Error:", error); - res.status(StatusCodes.INTERNAL_SERVER_ERROR).send( - "Internal server error." - ); + return res + .status(StatusCodes.INTERNAL_SERVER_ERROR) + .send("Internal server error."); } }); // Get event by ID eventRouter.get("/:id", async (req, res) => { try { - const event = await EventModel.findById(req.params.id); + const event = await Database.EVENTS.findById(req.params.id); if (!event) { return res.status(StatusCodes.NOT_FOUND).send("Event not found."); } - res.status(StatusCodes.OK).json(event); + return res.status(StatusCodes.OK).json(event); } catch (error) { console.error("Error:", error); - res.status(StatusCodes.INTERNAL_SERVER_ERROR).send( - "Internal server error." - ); + return res + .status(StatusCodes.INTERNAL_SERVER_ERROR) + .send("Internal server error."); } }); // Update event eventRouter.patch("/:id", async (req, res) => { try { - const event = await EventModel.findByIdAndUpdate( + const event = await Database.EVENTS.findByIdAndUpdate( req.params.id, req.body, { new: true } ); + if (!event) { return res.status(StatusCodes.NOT_FOUND).send("Event not found."); } - res.status(StatusCodes.OK).json(event); + + return res.status(StatusCodes.OK).json(event); } catch (error) { console.error("Error:", error); - res.status(StatusCodes.INTERNAL_SERVER_ERROR).send( - "Internal server error." - ); + return res + .status(StatusCodes.INTERNAL_SERVER_ERROR) + .send("Internal server error."); } }); // Delete event eventRouter.delete("/:id", async (req, res) => { try { - const event = await EventModel.findByIdAndDelete(req.params.id); + const event = await Database.EVENTS.findByIdAndDelete(req.params.id); if (!event) { return res.status(StatusCodes.NOT_FOUND).send("Event not found."); } - res.status(StatusCodes.NO_CONTENT).send(); + return res.status(StatusCodes.NO_CONTENT).send(); } catch (error) { console.error("Error:", error); - res.status(StatusCodes.INTERNAL_SERVER_ERROR).send( - "Internal server error." - ); + return res + .status(StatusCodes.INTERNAL_SERVER_ERROR) + .send("Internal server error."); } }); diff --git a/src/services/events/event-schema.ts b/src/services/events/event-schema.ts index db29a3d..768be72 100644 --- a/src/services/events/event-schema.ts +++ b/src/services/events/event-schema.ts @@ -46,5 +46,4 @@ const EventSchema = new mongoose.Schema({ visible: { type: Boolean, default: false }, }); -export const EventModel = mongoose.model("Event", EventSchema); -export { EventValidator }; +export { EventSchema, EventValidator, LocationSchema }; From 5df67e01f33b6553dc3949602e79e9d11b4233ec Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Tue, 9 Apr 2024 18:14:33 -0500 Subject: [PATCH 04/11] error messages --- src/services/attendees/attendee-router.ts | 18 ++------ src/services/events/event-router.ts | 56 ++++++++++------------- 2 files changed, 29 insertions(+), 45 deletions(-) diff --git a/src/services/attendees/attendee-router.ts b/src/services/attendees/attendee-router.ts index a5ebfac..8006361 100644 --- a/src/services/attendees/attendee-router.ts +++ b/src/services/attendees/attendee-router.ts @@ -6,7 +6,7 @@ import { Database } from "../../database"; const attendeeRouter = Router(); // Create a new attendee -attendeeRouter.post("/", async (req, res) => { +attendeeRouter.post("/", async (req, res, next) => { try { const attendeeData = AttendeeValidator.parse(req.body); const attendee = new Database.ATTENDEES(attendeeData); @@ -14,15 +14,12 @@ attendeeRouter.post("/", async (req, res) => { return res.status(StatusCodes.CREATED).json(attendeeData); } catch (error) { - console.error("Error:", error); - return res - .status(StatusCodes.INTERNAL_SERVER_ERROR) - .send("Error creating attendee."); + next(error); } }); // Check if a user email exists -attendeeRouter.get("/:email", async (req, res) => { +attendeeRouter.get("/:email", async (req, res, next) => { try { const { email } = req.params; @@ -30,9 +27,7 @@ attendeeRouter.get("/:email", async (req, res) => { const userExists = await Database.ATTENDEES.exists({ email }); if (!userExists) { - return res - .status(StatusCodes.NOT_FOUND) - .send("User with that email does not exist."); + return { error: "DoesNotExist" }; } const user = await Database.ATTENDEES.findOne({ @@ -41,10 +36,7 @@ attendeeRouter.get("/:email", async (req, res) => { return res.status(StatusCodes.OK).json(user); } catch (error) { - console.error("Error:", error); - return res - .status(StatusCodes.INTERNAL_SERVER_ERROR) - .send("Internal server error."); + next(error); } }); diff --git a/src/services/events/event-router.ts b/src/services/events/event-router.ts index f365ea1..f7e154a 100644 --- a/src/services/events/event-router.ts +++ b/src/services/events/event-router.ts @@ -6,84 +6,76 @@ import { Database } from "../../database"; const eventRouter = Router(); // Create a new event -eventRouter.post("/", async (req, res) => { +eventRouter.post("/", async (req, res, next) => { try { const eventData = EventValidator.parse(req.body); const event = new Database.EVENTS(eventData); await event.save(); return res.status(StatusCodes.CREATED).json(event); } catch (error) { - console.error("Error:", error); - return res - .status(StatusCodes.BAD_REQUEST) - .send("Error creating event."); + next(error); } }); // Get all events -eventRouter.get("/", async (req, res) => { +eventRouter.get("/", async (req, res, next) => { try { const events = await Database.EVENTS.find(); return res.status(StatusCodes.OK).json(events); } catch (error) { - console.error("Error:", error); - return res - .status(StatusCodes.INTERNAL_SERVER_ERROR) - .send("Internal server error."); + next(error); } }); // Get event by ID -eventRouter.get("/:id", async (req, res) => { +eventRouter.get("/:id", async (req, res, next) => { try { - const event = await Database.EVENTS.findById(req.params.id); + const event = await Database.EVENTS.findOneAndUpdate( + { _id: req.params.id }, + { new: true } + ); + if (!event) { - return res.status(StatusCodes.NOT_FOUND).send("Event not found."); + return { error: "DoesNotExist" }; } + return res.status(StatusCodes.OK).json(event); } catch (error) { - console.error("Error:", error); - return res - .status(StatusCodes.INTERNAL_SERVER_ERROR) - .send("Internal server error."); + next(error); } }); // Update event -eventRouter.patch("/:id", async (req, res) => { +eventRouter.patch("/:id", async (req, res, next) => { try { - const event = await Database.EVENTS.findByIdAndUpdate( - req.params.id, + const event = await Database.EVENTS.findOneAndUpdate( + { _id: req.params.id }, req.body, { new: true } ); if (!event) { - return res.status(StatusCodes.NOT_FOUND).send("Event not found."); + return { error: "DoesNotExist" }; } return res.status(StatusCodes.OK).json(event); } catch (error) { - console.error("Error:", error); - return res - .status(StatusCodes.INTERNAL_SERVER_ERROR) - .send("Internal server error."); + next(error); } }); // Delete event -eventRouter.delete("/:id", async (req, res) => { +eventRouter.delete("/:id", async (req, res, next) => { try { const event = await Database.EVENTS.findByIdAndDelete(req.params.id); + if (!event) { - return res.status(StatusCodes.NOT_FOUND).send("Event not found."); + return { error: "DoesNotExist" }; } - return res.status(StatusCodes.NO_CONTENT).send(); + + return res.status(StatusCodes.OK).json(event); } catch (error) { - console.error("Error:", error); - return res - .status(StatusCodes.INTERNAL_SERVER_ERROR) - .send("Internal server error."); + next(error); } }); From 201007f6dc35a61d10fb21e379b5168f1d3b772b Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Tue, 9 Apr 2024 18:17:35 -0500 Subject: [PATCH 05/11] event points --- src/services/events/event-schema.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/services/events/event-schema.ts b/src/services/events/event-schema.ts index 768be72..73890cd 100644 --- a/src/services/events/event-schema.ts +++ b/src/services/events/event-schema.ts @@ -17,8 +17,7 @@ const EventValidator = z.object({ }) ), virtual: z.boolean(), - upgrade: z.boolean().default(false), - downgrade: z.boolean().default(false), + points: z.number().min(0).default(0), imageUrl: z.string().nullable().optional(), visible: z.boolean().default(false), }); @@ -40,8 +39,7 @@ const EventSchema = new mongoose.Schema({ attendees: [{ type: mongoose.Schema.Types.ObjectId, ref: "Attendee" }], location: [LocationSchema], virtual: { type: Boolean, required: true }, - upgrade: { type: Boolean, default: false }, - downgrade: { type: Boolean, default: false }, + points: { type: Number, default: 0 }, imageUrl: { type: String, default: null }, visible: { type: Boolean, default: false }, }); From 849126624d3334ccceb3b1b44733d8dcc1f70891 Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Tue, 9 Apr 2024 18:32:52 -0500 Subject: [PATCH 06/11] registration schema --- src/app.ts | 2 ++ src/database.ts | 9 ++++++++ src/services/attendees/attendee-schema.ts | 2 ++ .../registration/registration-router.ts | 10 +++++++++ .../registration/registration-schema.ts | 22 +++++++++++++++++++ 5 files changed, 45 insertions(+) create mode 100644 src/services/registration/registration-router.ts create mode 100644 src/services/registration/registration-schema.ts diff --git a/src/app.ts b/src/app.ts index 3ca3745..e413531 100644 --- a/src/app.ts +++ b/src/app.ts @@ -13,6 +13,7 @@ import subscriptionRouter from "./services/subscription/subscription-router"; import attendeeRouter from "./services/attendees/attendee-router"; import eventRouter from "./services/events/event-router"; +import registrationRouter from "./services/registration/registration-router"; const app = express(); @@ -31,6 +32,7 @@ app.use("/", bodyParser.json()); app.use("/attendee", attendeeRouter); app.use("/auth", authRouter); app.use("/event", eventRouter); +app.use("/registration", registrationRouter); app.get("/status", (_, res) => { return res.status(StatusCodes.OK).send("API is alive!"); diff --git a/src/database.ts b/src/database.ts index bf1a1e6..ba30eab 100644 --- a/src/database.ts +++ b/src/database.ts @@ -9,6 +9,10 @@ import { SubscriptionSchemaValidator, SubscriptionSchema, } from "./services/subscription/subscription-schema"; +import { + RegistrationSchema, + RegistrationValidator, +} from "./services/registration/registration-schema"; mongoose.set("toObject", { versionKey: false }); @@ -48,4 +52,9 @@ export const Database = { SubscriptionSchemaValidator ), ATTENDEES: initializeModel("attendees", AttendeeSchema, AttendeeValidator), + REGISTRATION: initializeModel( + "registration", + RegistrationSchema, + RegistrationValidator + ), }; diff --git a/src/services/attendees/attendee-schema.ts b/src/services/attendees/attendee-schema.ts index 279a125..79baebe 100644 --- a/src/services/attendees/attendee-schema.ts +++ b/src/services/attendees/attendee-schema.ts @@ -23,6 +23,7 @@ const AttendeeValidator = z.object({ interest_mech_puzzle: z.array(z.string()).nullable().optional(), priority_expiry: z.date().nullable().optional(), has_resume: z.boolean().optional(), + points: z.number().min(0).default(0), // }); // Mongoose schema for attendee @@ -47,6 +48,7 @@ const AttendeeSchema = new mongoose.Schema({ interest_mech_puzzle: [{ type: String }], priority_expiry: { type: Date, default: null }, has_resume: { type: Boolean, default: false }, + points: { type: Number, default: 0 }, }); export { AttendeeSchema, AttendeeValidator }; diff --git a/src/services/registration/registration-router.ts b/src/services/registration/registration-router.ts new file mode 100644 index 0000000..18d0210 --- /dev/null +++ b/src/services/registration/registration-router.ts @@ -0,0 +1,10 @@ +import { Router } from "express"; +import { StatusCodes } from "http-status-codes"; +import { RegistrationValidator } from "./registration-schema"; +import { Database } from "../../database"; + +const registrationRouter = Router(); + +// TODO: registration routes + +export default registrationRouter; diff --git a/src/services/registration/registration-schema.ts b/src/services/registration/registration-schema.ts new file mode 100644 index 0000000..2a35c14 --- /dev/null +++ b/src/services/registration/registration-schema.ts @@ -0,0 +1,22 @@ +import mongoose from "mongoose"; +import { z } from "zod"; + +// Zod schema for registration +const RegistrationValidator = z.object({ + name: z.string(), + email: z.string().email(), + events: z.array(z.string()), + dietary_restrictions: z.string(), + points: z.number().min(0).default(0), +}); + +// Mongoose schema for registration +const RegistrationSchema = new mongoose.Schema({ + name: { type: String, required: true }, + email: { type: String, required: true, unique: true }, + events: [{ type: mongoose.Schema.Types.ObjectId, ref: "Event" }], + dietary_restrictions: { type: String, required: true }, + points: { type: Number, default: 0 }, +}); + +export { RegistrationSchema, RegistrationValidator }; From cb2a33958d46cbcf1108da0b8b9d49852e8b06f4 Mon Sep 17 00:00:00 2001 From: Jacob Chang Date: Tue, 9 Apr 2024 19:04:24 -0500 Subject: [PATCH 07/11] subscription basic --- .github/workflows/lint.yml | 24 +++++++++---------- .github/workflows/prettier.yml | 36 ++++++++++++++-------------- README.md | 13 +++++----- appspec.yml | 44 +++++++++++++++++----------------- src/app.ts | 6 ++--- src/database.ts | 8 +++---- 6 files changed, 66 insertions(+), 65 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c477b00..992d3fd 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,18 +1,18 @@ name: Lint on: - push: + push: jobs: lint: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: '18.x' - - name: Install dependencies - run: yarn - - name: Run ESLint - run: npx eslint . \ No newline at end of file + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "18.x" + - name: Install dependencies + run: yarn + - name: Run ESLint + run: npx eslint . diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml index 150599e..f4c3651 100644 --- a/.github/workflows/prettier.yml +++ b/.github/workflows/prettier.yml @@ -1,18 +1,18 @@ -name: Prettier - -on: - push: - -jobs: - prettier: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: "18.x" - - name: Install dependencies - run: yarn - - name: Run Prettier - run: npx prettier --write . +name: Prettier + +on: + push: + +jobs: + prettier: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "18.x" + - name: Install dependencies + run: yarn + - name: Run Prettier + run: npx prettier --write . diff --git a/README.md b/README.md index 781821c..cb79c58 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # API for Reflections | Projections 2024 Contributors: -- Aydan Pirani -- Divya Koya -- Riya Patel -- Jacob Chang -- Alex Yang -- Shreenija Daggavolu + +- Aydan Pirani +- Divya Koya +- Riya Patel +- Jacob Chang +- Alex Yang +- Shreenija Daggavolu diff --git a/appspec.yml b/appspec.yml index 2e74e8d..7e68363 100644 --- a/appspec.yml +++ b/appspec.yml @@ -1,22 +1,22 @@ -version: 0.0 -os: linux -files: - - source: / - destination: /home/ubuntu/rp-api -file_exists_behavior: OVERWRITE -hooks: - BeforeInstall: - - location: scripts/install_dependencies.sh - timeout: 300 - runas: root - AfterInstall: - - location: scripts/build.sh - timeout: 300 - runas: root - ApplicationStart: - - location: scripts/install_dependencies.sh - timeout: 300 - runas: root - - location: scripts/reload_server.sh - timeout: 300 - runas: root \ No newline at end of file +version: 0.0 +os: linux +files: + - source: / + destination: /home/ubuntu/rp-api +file_exists_behavior: OVERWRITE +hooks: + BeforeInstall: + - location: scripts/install_dependencies.sh + timeout: 300 + runas: root + AfterInstall: + - location: scripts/build.sh + timeout: 300 + runas: root + ApplicationStart: + - location: scripts/install_dependencies.sh + timeout: 300 + runas: root + - location: scripts/reload_server.sh + timeout: 300 + runas: root diff --git a/src/app.ts b/src/app.ts index e413531..ea6d818 100644 --- a/src/app.ts +++ b/src/app.ts @@ -8,12 +8,11 @@ import morgan from "morgan"; import bodyParser from "body-parser"; import errorHandler from "./middleware/error-handler"; -import authRouter from "./services/auth/auth-router"; -import subscriptionRouter from "./services/subscription/subscription-router"; - import attendeeRouter from "./services/attendees/attendee-router"; +import authRouter from "./services/auth/auth-router"; import eventRouter from "./services/events/event-router"; import registrationRouter from "./services/registration/registration-router"; +import subscriptionRouter from "./services/subscription/subscription-router"; const app = express(); @@ -33,6 +32,7 @@ app.use("/attendee", attendeeRouter); app.use("/auth", authRouter); app.use("/event", eventRouter); app.use("/registration", registrationRouter); +app.use("/subscription", subscriptionRouter); app.get("/status", (_, res) => { return res.status(StatusCodes.OK).send("API is alive!"); diff --git a/src/database.ts b/src/database.ts index ba30eab..b1e4efa 100644 --- a/src/database.ts +++ b/src/database.ts @@ -5,14 +5,14 @@ import { } from "./services/attendees/attendee-schema"; import { RoleValidator, RoleSchema } from "./services/auth/auth-schema"; import { EventSchema, EventValidator } from "./services/events/events-schema"; -import { - SubscriptionSchemaValidator, - SubscriptionSchema, -} from "./services/subscription/subscription-schema"; import { RegistrationSchema, RegistrationValidator, } from "./services/registration/registration-schema"; +import { + SubscriptionSchemaValidator, + SubscriptionSchema, +} from "./services/subscription/subscription-schema"; mongoose.set("toObject", { versionKey: false }); From 9b451b8de74c108265c4eb51286b519329f211b8 Mon Sep 17 00:00:00 2001 From: Aydan Pirani Date: Sat, 20 Apr 2024 12:31:13 -0500 Subject: [PATCH 08/11] Fixed build errors --- src/services/registration/registration-router.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/registration/registration-router.ts b/src/services/registration/registration-router.ts index 18d0210..8b18e65 100644 --- a/src/services/registration/registration-router.ts +++ b/src/services/registration/registration-router.ts @@ -1,7 +1,7 @@ import { Router } from "express"; -import { StatusCodes } from "http-status-codes"; -import { RegistrationValidator } from "./registration-schema"; -import { Database } from "../../database"; +// import { StatusCodes } from "http-status-codes"; +// import { RegistrationValidator } from "./registration-schema"; +// import { Database } from "../../database"; const registrationRouter = Router(); From 4558a8a8cdadaae78ef81b257601b870330d9c89 Mon Sep 17 00:00:00 2001 From: Aydan Pirani Date: Sat, 20 Apr 2024 13:00:35 -0500 Subject: [PATCH 09/11] Fixed schemas --- src/services/attendees/attendee-schema.ts | 34 ++--------------- .../registration/registration-schema.ts | 38 ++++++++++++++++--- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/services/attendees/attendee-schema.ts b/src/services/attendees/attendee-schema.ts index 79baebe..358795d 100644 --- a/src/services/attendees/attendee-schema.ts +++ b/src/services/attendees/attendee-schema.ts @@ -3,51 +3,23 @@ import { z } from "zod"; // Zod schema for attendee const AttendeeValidator = z.object({ + userId: z.string(), name: z.string(), email: z.string().email(), - studentInfo: z.object({ - university: z.string().nonempty(), - graduation: z.string().nullable().optional(), - major: z.string().nullable().optional(), - }), events: z.array(z.string()), dietary_restrictions: z.string(), - age: z.number().nullable().optional(), - gender: z.string().nullable().optional(), - race: z.array(z.string()).nullable().optional(), - ethnicity: z.string().nullable().optional(), - first_gen: z.string().nullable().optional(), - hear_about_rp: z.array(z.string()).nullable().optional(), - portfolio: z.string().nullable().optional(), - job_interest: z.array(z.string()).nullable().optional(), - interest_mech_puzzle: z.array(z.string()).nullable().optional(), priority_expiry: z.date().nullable().optional(), - has_resume: z.boolean().optional(), - points: z.number().min(0).default(0), // + points: z.number().min(0).default(0), }); // Mongoose schema for attendee const AttendeeSchema = new mongoose.Schema({ + userId: { type: String, required: true, unique: true }, name: { type: String, required: true }, email: { type: String, required: true, unique: true }, - studentInfo: { - university: { type: String, required: true }, - graduation: { type: String, default: null }, - major: { type: String, default: null }, - }, events: [{ type: mongoose.Schema.Types.ObjectId, ref: "Event" }], dietary_restrictions: { type: String, required: true }, - age: { type: Number, default: null }, - gender: { type: String, default: null }, - race: [{ type: String }], - ethnicity: { type: String, default: null }, - first_gen: { type: String, default: null }, - hear_about_rp: [{ type: String }], - portfolio: { type: String, default: null }, - job_interest: [{ type: String }], - interest_mech_puzzle: [{ type: String }], priority_expiry: { type: Date, default: null }, - has_resume: { type: Boolean, default: false }, points: { type: Number, default: 0 }, }); diff --git a/src/services/registration/registration-schema.ts b/src/services/registration/registration-schema.ts index 2a35c14..ede0edc 100644 --- a/src/services/registration/registration-schema.ts +++ b/src/services/registration/registration-schema.ts @@ -1,22 +1,50 @@ import mongoose from "mongoose"; -import { z } from "zod"; +import { boolean, z } from "zod"; // Zod schema for registration const RegistrationValidator = z.object({ + userId: z.string(), name: z.string(), email: z.string().email(), - events: z.array(z.string()), + studentInfo: z.object({ + university: z.string().nonempty(), + graduation: z.string().nullable().optional(), + major: z.string().nullable().optional(), + }), dietary_restrictions: z.string(), - points: z.number().min(0).default(0), + age: z.number().nullable().optional(), + gender: z.string().nullable().optional(), + race: z.array(z.string()).nullable().optional(), + ethnicity: z.array(z.string()).nullable().optional(), + first_gen: z.string().nullable().optional(), + hear_about_rp: z.array(z.string()).nullable().optional(), + portfolio: z.string().nullable().optional(), + job_interest: z.array(z.string()).nullable().optional(), + interest_mech_puzzle: z.array(z.string()).nullable().optional(), + has_resume: z.boolean() }); // Mongoose schema for registration const RegistrationSchema = new mongoose.Schema({ + userId: {type: String, required: true, unique: true }, name: { type: String, required: true }, email: { type: String, required: true, unique: true }, - events: [{ type: mongoose.Schema.Types.ObjectId, ref: "Event" }], + studentInfo: { + university: { type: String, required: true }, + graduation: { type: String, default: null }, + major: { type: String, default: null }, + }, dietary_restrictions: { type: String, required: true }, - points: { type: Number, default: 0 }, + age: { type: Number, default: null }, + gender: { type: String, default: null }, + race: [{ type: String }], + ethnicity: [{ type: String }], + first_gen: { type: String, default: null }, + hear_about_rp: [{ type: String }], + portfolio: { type: String, default: null }, + job_interest: [{ type: String }], + interest_mech_puzzle: [{ type: String }], + has_resume: { type: Boolean, default: false }, }); export { RegistrationSchema, RegistrationValidator }; From 53d2c643c36cd3e2beb2901bc3d6d3cca77284ce Mon Sep 17 00:00:00 2001 From: divinedab Date: Sat, 20 Apr 2024 13:19:31 -0500 Subject: [PATCH 10/11] fixing linting issues --- src/services/registration/registration-schema.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/registration/registration-schema.ts b/src/services/registration/registration-schema.ts index ede0edc..1d0345e 100644 --- a/src/services/registration/registration-schema.ts +++ b/src/services/registration/registration-schema.ts @@ -1,5 +1,5 @@ import mongoose from "mongoose"; -import { boolean, z } from "zod"; +import { z } from "zod"; // Zod schema for registration const RegistrationValidator = z.object({ @@ -21,7 +21,7 @@ const RegistrationValidator = z.object({ portfolio: z.string().nullable().optional(), job_interest: z.array(z.string()).nullable().optional(), interest_mech_puzzle: z.array(z.string()).nullable().optional(), - has_resume: z.boolean() + has_resume: z.boolean(), }); // Mongoose schema for registration @@ -43,7 +43,7 @@ const RegistrationSchema = new mongoose.Schema({ hear_about_rp: [{ type: String }], portfolio: { type: String, default: null }, job_interest: [{ type: String }], - interest_mech_puzzle: [{ type: String }], + interest_mech_puzzle: [{ type: String }], has_resume: { type: Boolean, default: false }, }); From ef1dbe678ab53a34295961e18302bb52376e0ba6 Mon Sep 17 00:00:00 2001 From: divinedab Date: Sat, 20 Apr 2024 13:22:04 -0500 Subject: [PATCH 11/11] one last linting error --- src/services/registration/registration-schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/registration/registration-schema.ts b/src/services/registration/registration-schema.ts index 1d0345e..ab19968 100644 --- a/src/services/registration/registration-schema.ts +++ b/src/services/registration/registration-schema.ts @@ -26,7 +26,7 @@ const RegistrationValidator = z.object({ // Mongoose schema for registration const RegistrationSchema = new mongoose.Schema({ - userId: {type: String, required: true, unique: true }, + userId: { type: String, required: true, unique: true }, name: { type: String, required: true }, email: { type: String, required: true, unique: true }, studentInfo: {