From 7ab1da023c374ed0ba449f992f81a5171c394e98 Mon Sep 17 00:00:00 2001 From: Aydan Pirani Date: Tue, 2 Jul 2024 20:35:46 -0700 Subject: [PATCH] added role checking --- src/services/auth/auth-models.ts | 2 + src/services/auth/auth-utils.ts | 14 ++++++- src/services/events/events-router.ts | 61 +++++++++++++++++++++------- src/services/events/events-schema.ts | 2 +- 4 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/services/auth/auth-models.ts b/src/services/auth/auth-models.ts index 07cfb61..4f615bc 100644 --- a/src/services/auth/auth-models.ts +++ b/src/services/auth/auth-models.ts @@ -6,3 +6,5 @@ export const JwtPayloadValidator = z.object({ userId: z.string(), roles: Role.array(), }); + +export type JwtPayloadType = z.infer; \ No newline at end of file diff --git a/src/services/auth/auth-utils.ts b/src/services/auth/auth-utils.ts index 93fe77a..0540fcd 100644 --- a/src/services/auth/auth-utils.ts +++ b/src/services/auth/auth-utils.ts @@ -2,7 +2,7 @@ import { Strategy as GoogleStrategy } from "passport-google-oauth20"; import { Config } from "../../config"; import { Database } from "../../database"; -import { Role } from "./auth-models"; +import { JwtPayloadType, Role } from "./auth-models"; export function createGoogleStrategy(device: string) { return new GoogleStrategy( @@ -46,3 +46,15 @@ export async function getJwtPayloadFromDatabase(userId: string) { return payload; } + +export function isUser(payload?: JwtPayloadType) { + return payload?.roles.includes(Role.Enum.USER); +} + +export function isStaff(payload?: JwtPayloadType) { + return payload?.roles.includes(Role.Enum.STAFF); +} + +export function isAdmin(payload?: JwtPayloadType) { + return payload?.roles.includes(Role.Enum.ADMIN); +} \ No newline at end of file diff --git a/src/services/events/events-router.ts b/src/services/events/events-router.ts index 8a76777..cc960dd 100644 --- a/src/services/events/events-router.ts +++ b/src/services/events/events-router.ts @@ -3,17 +3,23 @@ import { StatusCodes } from "http-status-codes"; import { publicEventValidator, privateEventValidator } from "./events-schema"; import { Database } from "../../database"; import { checkInUserToEvent } from "./events-utils"; -// import {mongoose} from "mongoose"; +import RoleChecker from "../../middleware/role-checker"; +import { Role } from "../auth/auth-models"; +import { isAdmin, isStaff, isUser } from "../auth/auth-utils"; const eventsRouter = Router(); // Get current or next event based on current time -eventsRouter.get("/currentOrNext", async (req, res, next) => { +eventsRouter.get("/currentOrNext", RoleChecker([], true), async (req, res, next) => { const currentTime = new Date(); + const payload = res.locals.payload; + + const isUser = !(isStaff(payload) || isAdmin(payload)) try { const event = await Database.EVENTS.findOne({ startTime: { $gte: currentTime }, + isVisible: isUser ? { $eq: true } : {}, }).sort({ startTime: 1 }); if (event) { @@ -29,35 +35,63 @@ eventsRouter.get("/currentOrNext", async (req, res, next) => { }); // Get all events -eventsRouter.get("/", async (req, res, next) => { +eventsRouter.get("/", RoleChecker([], true), async (req, res, next) => { + const payload = res.locals.payload; + + var filterFunction; + try { - const unfiltered_events = await Database.EVENTS.find(); - const filtered_events = unfiltered_events.map((unfiltered_event) => { - return publicEventValidator.parse(unfiltered_event.toJSON()); - }); + var unfiltered_events = await Database.EVENTS.find(); + + if (isStaff(payload) || isAdmin(payload)) { + filterFunction = (x: any) => privateEventValidator.parse(x); + } else { + unfiltered_events = unfiltered_events.filter(x => x.isVisible) + filterFunction = (x: any) => publicEventValidator.parse(x); + } + + const filtered_events = unfiltered_events.map(filterFunction); + console.log(filtered_events) return res.status(StatusCodes.OK).json(filtered_events); } catch (error) { next(error); } }); -eventsRouter.get("/:EVENTID", async (req, res, next) => { +eventsRouter.get("/:EVENTID", RoleChecker([], true), async (req, res, next) => { // add RoleChecker here as well const eventId = req.params.EVENTID; + const payload = res.locals.payload; + + var filterFunction; + try { const event = await Database.EVENTS.findOne({ eventId: eventId }); + if (!event) { return res .status(StatusCodes.NOT_FOUND) .json({ error: "DoesNotExist" }); } - const validatedData = publicEventValidator.parse(event.toJSON()); + + if (isStaff(payload) || isAdmin(payload)) { + filterFunction = privateEventValidator.parse; + } else { + filterFunction = publicEventValidator.parse; + if (!event.isVisible) { + return res + .status(StatusCodes.NOT_FOUND) + .json({ error: "DoesNotExist" }); + } + } + + const validatedData = filterFunction(event.toObject()); return res.status(StatusCodes.OK).json(validatedData); } catch (error) { next(error); } }); -eventsRouter.post("/", async (req, res, next) => { +eventsRouter.post("/", RoleChecker([Role.Enum.STAFF]), async (req, res, next) => { try { const validatedData = privateEventValidator.parse(req.body); const event = new Database.EVENTS(validatedData); @@ -68,7 +102,7 @@ eventsRouter.post("/", async (req, res, next) => { } }); -eventsRouter.put("/:EVENTID", async (req, res, next) => { +eventsRouter.put("/:EVENTID", RoleChecker([Role.Enum.STAFF], true), async (req, res, next) => { const eventId = req.params.EVENTID; try { const validatedData = privateEventValidator.parse(req.body); @@ -90,10 +124,9 @@ eventsRouter.put("/:EVENTID", async (req, res, next) => { }); // Delete event -eventsRouter.delete("/:EVENTID", async (req, res, next) => { +eventsRouter.delete("/:EVENTID", RoleChecker([Role.Enum.STAFF], true), async (req, res, next) => { const eventId = req.params.EVENTID; try { - // const objectId = mongoose.Types.ObjectId(eventId) await Database.EVENTS.findOneAndDelete({ eventId: eventId }); return res.sendStatus(StatusCodes.NO_CONTENT); @@ -102,7 +135,7 @@ eventsRouter.delete("/:EVENTID", async (req, res, next) => { } }); -eventsRouter.post("/check-in", async (req, res, next) => { +eventsRouter.post("/check-in", RoleChecker([Role.Enum.STAFF], true), async (req, res, next) => { // add RoleChecker for staff try { const { eventId, userId } = req.body; const result = await checkInUserToEvent(eventId, userId); diff --git a/src/services/events/events-schema.ts b/src/services/events/events-schema.ts index 649b3a5..3c2d6e8 100644 --- a/src/services/events/events-schema.ts +++ b/src/services/events/events-schema.ts @@ -13,12 +13,12 @@ export const publicEventValidator = z.object({ description: z.string(), isVirtual: z.boolean(), imageUrl: z.string().nullable().optional(), - isVisible: z.boolean().default(false), eventType: EventType, }); export const privateEventValidator = publicEventValidator.extend({ attendanceCount: z.number(), + isVisible: z.boolean(), }); export const EventSchema = new Schema({