Skip to content

Commit

Permalink
Merge pull request #115 from ReflectionsProjections/dev/aydan/puzzlebang
Browse files Browse the repository at this point in the history
Refactor API + PuzzleBang Changes
  • Loading branch information
AydanPirani authored Jul 31, 2024
2 parents 94fd5c8 + e9e9e4a commit fa205e1
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 63 deletions.
2 changes: 2 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import s3Router from "./services/s3/s3-router";
import statsRouter from "./services/stats/stats-router";
import subscriptionRouter from "./services/subscription/subscription-router";
import speakersRouter from "./services/speakers/speakers-router";
import puzzlebangRouter from "./services/puzzlebang/puzzlebang-router";

AWS.config.update({
region: Config.S3_REGION,
Expand Down Expand Up @@ -49,6 +50,7 @@ app.use("/auth", databaseMiddleware, authRouter);
app.use("/checkin", databaseMiddleware, checkinRouter);
app.use("/events", databaseMiddleware, eventsRouter);
app.use("/notifications", databaseMiddleware, notificationsRouter);
app.use("/puzzlebang", databaseMiddleware, puzzlebangRouter);
app.use("/registration", databaseMiddleware, registrationRouter);
app.use("/s3", databaseMiddleware, s3Router);
app.use("/stats", databaseMiddleware, statsRouter);
Expand Down
13 changes: 4 additions & 9 deletions src/database.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import mongoose, { Schema, Document } from "mongoose";
import {
AttendeeSchema,
AttendeeValidator,
} from "./services/attendee/attendee-schema";
import {
AttendeeAttendanceSchema,
AttendeeAttendanceValidator,
AttendeeSchema,
} from "./services/attendee/attendee-schema";
import {
EventSchema,
Expand Down Expand Up @@ -80,11 +76,10 @@ export const Database = {
EventAttendanceSchema,
EventAttendanceValidator
),
ATTENDEE: initializeModel("attendee", AttendeeSchema, AttendeeValidator),
ATTENDEE_ATTENDANCE: initializeModel(
ATTENDEE: mongoose.model("attendee", AttendeeSchema),
ATTENDEE_ATTENDANCE: mongoose.model(
"attendee_attendance",
AttendeeAttendanceSchema,
AttendeeAttendanceValidator
AttendeeAttendanceSchema
),
SUBSCRIPTIONS: initializeModel(
"subscriptions",
Expand Down
7 changes: 7 additions & 0 deletions src/middleware/role-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ export default function RoleChecker(
return next();
}

// PuzzleBang JWT can access puzzlebang endpoints
if (requiredRoles.includes(Role.Enum.PUZZLEBANG)) {
if (userRoles.includes(Role.Enum.PUZZLEBANG)) {
return next();
}
}

// Corporate role can access corporate only endpoints
if (requiredRoles.includes(Role.Enum.CORPORATE)) {
if (userRoles.includes(Role.Enum.CORPORATE)) {
Expand Down
10 changes: 5 additions & 5 deletions src/services/attendee/attendee-router.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Router } from "express";
import { StatusCodes } from "http-status-codes";
import { AttendeeValidator, EventIdValidator } from "./attendee-schema";
import {
AttendeeCreateValidator,
EventIdValidator,
} from "./attendee-validators";
import { Database } from "../../database";
import RoleChecker from "../../middleware/role-checker";
import { Role } from "../auth/auth-models";
import dotenv from "dotenv";
import { generateQrHash } from "../checkin/checkin-utils";

dotenv.config();

const attendeeRouter = Router();

// Favorite an event for an attendee
Expand Down Expand Up @@ -98,7 +98,7 @@ attendeeRouter.get(
// Create a new attendee
attendeeRouter.post("/", async (req, res, next) => {
try {
const attendeeData = AttendeeValidator.parse(req.body);
const attendeeData = AttendeeCreateValidator.parse(req.body);
const attendee = new Database.ATTENDEE(attendeeData);
await attendee.save();

Expand Down
46 changes: 1 addition & 45 deletions src/services/attendee/attendee-schema.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,4 @@
import { Schema } from "mongoose";
import { z } from "zod";

// Zod schema for attendee
export const AttendeeValidator = z.object({
userId: z.string(),
name: z.string(),
email: z.string().email(),
events: z.array(z.string()).default([]),
dietaryRestrictions: z.string().array(),
allergies: z.string().array(),
hasCheckedIn: z.boolean().default(false),
points: z.number().min(0).default(0),
foodWave: z.number().int().min(0).default(0),
hasPriority: z
.object({
Mon: z.boolean().default(false),
Tue: z.boolean().default(false),
Wed: z.boolean().default(false),
Thu: z.boolean().default(false),
Fri: z.boolean().default(false),
Sat: z.boolean().default(false),
Sun: z.boolean().default(false),
})
.default({
Mon: false,
Tue: false,
Wed: false,
Thu: false,
Fri: false,
Sat: false,
Sun: false,
}),
});

// Mongoose schema for attendee
export const AttendeeSchema = new Schema({
Expand Down Expand Up @@ -68,6 +35,7 @@ export const AttendeeSchema = new Schema({
},
},
favorites: [{ type: String }],
puzzlesCompleted: [{ type: String, default: [] }],
});

export const AttendeeAttendanceSchema = new Schema({
Expand All @@ -78,15 +46,3 @@ export const AttendeeAttendanceSchema = new Schema({
},
eventsAttended: [{ type: String, ref: "Event", required: true }],
});

export const AttendeeAttendanceValidator = z.object({
userId: z.string(),
eventsAttended: z.array(z.string()),
});

export const EventIdValidator = z.object({
eventId: z.string().uuid(),
});

// Partial schema for attendee filter
export const PartialAttendeeValidator = AttendeeValidator.partial();
14 changes: 14 additions & 0 deletions src/services/attendee/attendee-validators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { z } from "zod";

// Zod schema for attendee
export const AttendeeCreateValidator = z.object({
userId: z.string(),
name: z.string(),
email: z.string().email(),
dietaryRestrictions: z.string().array(),
allergies: z.string().array(),
});

export const EventIdValidator = z.object({
eventId: z.string().uuid(),
});
8 changes: 7 additions & 1 deletion src/services/auth/auth-models.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { z } from "zod";

export const Role = z.enum(["USER", "STAFF", "ADMIN", "CORPORATE"]);
export const Role = z.enum([
"USER",
"STAFF",
"ADMIN",
"CORPORATE",
"PUZZLEBANG",
]);

export const JwtPayloadValidator = z.object({
userId: z.string(),
Expand Down
40 changes: 40 additions & 0 deletions src/services/puzzlebang/puzzlebang-router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Router } from "express";
import { StatusCodes } from "http-status-codes";
import { Database } from "../../database";
import RoleChecker from "../../middleware/role-checker";
import { Role } from "../auth/auth-models";
import { PuzzlebangCompleteRequestValidator } from "./puzzlebang-validators";

const puzzlebangRouter = Router();

puzzlebangRouter.post(
"/",
RoleChecker([Role.Enum.PUZZLEBANG]),
async (req, res, next) => {
try {
const requestInfo = PuzzlebangCompleteRequestValidator.parse(
req.body
);

const attendeeData = await Database.ATTENDEE.findOneAndUpdate(
{ email: requestInfo.email },
{ $addToSet: { puzzlesCompleted: requestInfo.puzzleId } },
{ new: false }
);

if (!attendeeData) {
return res.sendStatus(StatusCodes.NOT_FOUND);
}

if (attendeeData.puzzlesCompleted.includes(requestInfo.puzzleId)) {
return res.sendStatus(StatusCodes.UNAUTHORIZED);
}

return res.sendStatus(StatusCodes.OK);
} catch (error) {
next(error);
}
}
);

export default puzzlebangRouter;
7 changes: 7 additions & 0 deletions src/services/puzzlebang/puzzlebang-validators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { z } from "zod";

export const PuzzlebangCompleteRequestValidator = z.object({
// userId: z.string(),
email: z.string().email(),
puzzleId: z.string(),
});
4 changes: 2 additions & 2 deletions src/services/registration/registration-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import { Database } from "../../database";
import RoleChecker from "../../middleware/role-checker";
import { Role } from "../auth/auth-models";
import { AttendeeValidator } from "../attendee/attendee-schema";
import { AttendeeCreateValidator } from "../attendee/attendee-validators";
import { registrationExists } from "./registration-utils";

const registrationRouter = Router();
Expand Down Expand Up @@ -79,7 +79,7 @@ registrationRouter.post("/submit", RoleChecker([]), async (req, res, next) => {
{ upsert: true }
);

const attendeeData = AttendeeValidator.parse(registrationData);
const attendeeData = AttendeeCreateValidator.parse(registrationData);

await Database.ATTENDEE.findOneAndUpdate(
{ userId: payload.userId },
Expand Down
2 changes: 1 addition & 1 deletion src/services/registration/registration-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const RegistrationValidator = z.object({
userId: z.coerce.string().regex(/user[0-9]*/),
name: z.string(),
email: z.string().email(),
university: z.string().nonempty(),
university: z.string(),
graduation: z.string().nullable().optional(),
major: z.string().nullable().optional(),
dietaryRestrictions: z.string().array(),
Expand Down

0 comments on commit fa205e1

Please sign in to comment.