diff --git a/src/database/models.ts b/src/database/models.ts index 7e838976..b7d033c3 100644 --- a/src/database/models.ts +++ b/src/database/models.ts @@ -6,7 +6,7 @@ import { AttendeeFollowing, AttendeeProfile } from "./attendee-db"; import { AdmissionDecision } from "./admission-db"; import { MentorOfficeHours } from "./mentor-db"; import { Event, EventAttendance, EventFollowers } from "./event-db"; -import { NewsletterSubscription } from "./newsletter-db"; +import { NewsletterSubscription } from "../services/newsletter/newsletter-schemas"; import { RegistrationApplication } from "./registration-db"; import { ShopItem } from "../services/shop/shop-schemas"; import { UserAttendance, UserInfo } from "../services/user/user-schemas"; diff --git a/src/database/newsletter-db.ts b/src/database/newsletter-db.ts deleted file mode 100644 index 50ba297a..00000000 --- a/src/database/newsletter-db.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { prop } from "@typegoose/typegoose"; - -export class NewsletterSubscription { - @prop({ required: true }) - public newsletterId: string; - - @prop({ - required: true, - type: () => String, - }) - public subscribers: string[]; -} diff --git a/src/services/newsletter/newsletter-formats.ts b/src/services/newsletter/newsletter-formats.ts deleted file mode 100644 index bbbcf52a..00000000 --- a/src/services/newsletter/newsletter-formats.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Request format for subscribe API calls -export interface SubscribeRequest { - listName: string; - emailAddress: string; -} diff --git a/src/services/newsletter/newsletter-router.ts b/src/services/newsletter/newsletter-router.ts index 1bb0dd7a..8247f679 100644 --- a/src/services/newsletter/newsletter-router.ts +++ b/src/services/newsletter/newsletter-router.ts @@ -1,50 +1,36 @@ -import { Request, Response, Router } from "express"; -import { SubscribeRequest } from "./newsletter-formats"; -import { NewsletterSubscription } from "../../database/newsletter-db"; +import { Router } from "express"; +import { NewsletterSubscription, SubscribeRequestSchema } from "./newsletter-schemas"; import Models from "../../database/models"; import { UpdateQuery } from "mongoose"; import { StatusCode } from "status-code-enum"; -import { RouterError } from "../../middleware/error-handler"; -import { NextFunction } from "express-serve-static-core"; +import specification, { Tag } from "../../middleware/specification"; +import { SuccessResponseSchema } from "../../common/schemas"; const newsletterRouter = Router(); -/** - * @api {post} /newsletter/subscribe/ POST /newsletter/subscribe/ - * @apiGroup Newsletter - * @apiDescription Subscribe an email address to a newsletter. Will create a newsleter if it doesn't exist. - * - * @apiBody {String} listName Name of the list to add the user to - * @apiBody {String} emailAddress Email address to add to the list - * @apiParamExample {json} Example Request: - * {"listName": "testingList", "emailAddress": "example@hackillinois.org" } - * - * @apiSuccess {String} status Status of the request - * @apiSuccessExample Example Success Response: - * HTTP/1.1 200 OK - * {"status": "Succesful"} - * - * @apiError (400: Bad Request) {String} InvalidParams Invalid input passed in (missing name or email) - * @apiError (400: Bad Request) {String} ListNotFound List doesn't exist within the database - * - * @apiErrorExample Example Error Response: - * HTTP/1.1 400 Bad Request - * {"error": "InvalidParams"} - */ -newsletterRouter.post("/subscribe/", async (request: Request, res: Response, next: NextFunction) => { - const requestBody = request.body as SubscribeRequest; - const listName = requestBody.listName as string | undefined; - const emailAddress = requestBody.emailAddress as string | undefined; +newsletterRouter.post( + "/subscribe/", + specification({ + method: "post", + path: "/newsletter/subscribe/", + tag: Tag.NEWSLETTER, + role: null, + summary: "Subscribes the requested email to the requested newsletter", + body: SubscribeRequestSchema, + responses: { + [StatusCode.SuccessOK]: { + description: "Successfully added email to newsletter", + schema: SuccessResponseSchema, + }, + }, + }), + async (request, res) => { + const { listName, emailAddress } = request.body; - // Verify that both parameters do exist - if (!listName || !emailAddress) { - return next(new RouterError(StatusCode.ClientErrorBadRequest, "InvalidParams")); - } - - // Perform a lazy delete - const updateQuery: UpdateQuery = { $addToSet: { subscribers: emailAddress } }; - await Models.NewsletterSubscription.findOneAndUpdate({ newsletterId: listName }, updateQuery, { upsert: true }); - return res.status(StatusCode.SuccessOK).send({ status: "Success" }); -}); + const updateQuery: UpdateQuery = { $addToSet: { subscribers: emailAddress } }; + await Models.NewsletterSubscription.findOneAndUpdate({ newsletterId: listName }, updateQuery, { upsert: true }); + return res.status(StatusCode.SuccessOK).send({ success: true }); + }, +); export default newsletterRouter; diff --git a/src/services/newsletter/newsletter-schemas.ts b/src/services/newsletter/newsletter-schemas.ts new file mode 100644 index 00000000..72414bb2 --- /dev/null +++ b/src/services/newsletter/newsletter-schemas.ts @@ -0,0 +1,25 @@ +import { prop } from "@typegoose/typegoose"; +import { z } from "zod"; + +export class NewsletterSubscription { + @prop({ required: true }) + public newsletterId: string; + + @prop({ + required: true, + type: () => String, + }) + public subscribers: string[]; +} + +export const SubscribeRequestSchema = z + .object({ + listName: z.string(), + emailAddress: z.string(), + }) + .openapi("SubscribeRequest", { + example: { + listName: "recruitment_interest", + emailAddress: "example@example.com", + }, + });