Skip to content

Commit

Permalink
Merge branch 'main' into dev/alex/mentor-office-hours-qr
Browse files Browse the repository at this point in the history
  • Loading branch information
aletya committed Jan 25, 2024
2 parents 07ef9f5 + 7a61a30 commit 90d5d69
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/database/event-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class Event {
@prop({ required: false })
sponsor?: string;

@prop({ required: false })
@prop({ default: 0 })
points?: number;

@prop({ required: false })
Expand Down
14 changes: 11 additions & 3 deletions src/database/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { RegistrationApplication } from "./registration-db.js";
import { ShopItem } from "./shop-db.js";
import { UserAttendance, UserInfo } from "./user-db.js";
import { AnyParamConstructor, IModelOptions } from "@typegoose/typegoose/lib/types.js";
import { StaffShift } from "./staff-db.js";

// Groups for collections
export enum Group {
Expand All @@ -23,6 +24,7 @@ export enum Group {
NEWSLETTER = "newsletter",
REGISTRATION = "registration",
SHOP = "shop",
STAFF = "staff",
}

// Collections for each database, where models will be stored
Expand All @@ -43,8 +45,7 @@ enum AdmissionCollection {
enum EventCollection {
METADATA = "metadata",
ATTENDANCE = "attendance",
STAFF_EVENTS = "staffevents",
PUBLIC_EVENTS = "publicevents",
EVENTS = "events",
FOLLOWERS = "followers",
}

Expand All @@ -69,6 +70,10 @@ enum UserCollection {
ATTENDANCE = "attendance",
}

enum StaffCollection {
SHIFT = "shift",
}

export function generateConfig(collection: string): IModelOptions {
return {
schemaOptions: { collection: collection, versionKey: false },
Expand Down Expand Up @@ -103,7 +108,7 @@ export default class Models {
);

// Event
static Event: Model<Event> = getModel(Event, Group.EVENT, EventCollection.STAFF_EVENTS);
static Event: Model<Event> = getModel(Event, Group.EVENT, EventCollection.EVENTS);
static EventAttendance: Model<EventAttendance> = getModel(EventAttendance, Group.EVENT, EventCollection.ATTENDANCE);
static EventFollowers: Model<EventFollowers> = getModel(EventFollowers, Group.EVENT, EventCollection.FOLLOWERS);

Expand All @@ -130,4 +135,7 @@ export default class Models {
// User
static UserInfo: Model<UserInfo> = getModel(UserInfo, Group.USER, UserCollection.INFO);
static UserAttendance: Model<UserAttendance> = getModel(UserAttendance, Group.USER, UserCollection.ATTENDANCE);

// Staff
static StaffShift: Model<StaffShift> = getModel(StaffShift, Group.STAFF, StaffCollection.SHIFT);
}
12 changes: 12 additions & 0 deletions src/database/staff-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { prop } from "@typegoose/typegoose";

export class StaffShift {
@prop({ required: true })
public userId?: string;

@prop({
required: true,
type: () => String,
})
public shifts: string[];
}
2 changes: 1 addition & 1 deletion src/services/auth/auth-router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ describe("GET /auth/token/refresh", () => {

const jwtReturned = generateJwtToken.mock.results[generateJwtToken.mock.results.length - 1]!.value as string;
expect(JSON.parse(response.text)).toMatchObject({

Check failure on line 424 in src/services/auth/auth-router.test.ts

View workflow job for this annotation

GitHub Actions / test

GET /auth/token/refresh › refreshes the user's token

expect(received).toMatchObject(expected) - Expected - 1 + Received + 1 Object { - "Authorization": "***", + "token": "***", } at services/auth/auth-router.test.ts:424:43 at fulfilled (services/auth/auth-router.test.ts:28:58)
token: jwtReturned,
Authorization: jwtReturned,
});
});
});
15 changes: 15 additions & 0 deletions src/services/staff/staff-formats.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { StaffShift } from "../../database/staff-db.js";
import { isArrayOfType, isString } from "../../formatTools.js";

// Format for default staff attendance input
export interface AttendanceFormat {
eventId: string;
Expand All @@ -6,3 +9,15 @@ export interface AttendanceFormat {
export function isValidAttendanceFormat(obj: AttendanceFormat): boolean {
return typeof obj.eventId === "string";
}

export function isValidStaffShiftFormat(obj: StaffShift): boolean {
if (!isString(obj.userId)) {
return false;
}

if (!isArrayOfType(obj.shifts, isString)) {
return false;
}

return true;
}
62 changes: 60 additions & 2 deletions src/services/staff/staff-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import { Router, Request, Response } from "express";

import { strongJwtVerification } from "../../middleware/verify-jwt.js";
import { JwtPayload } from "../auth/auth-models.js";
import { hasStaffPerms } from "../auth/auth-lib.js";
import { hasAdminPerms, hasStaffPerms } from "../auth/auth-lib.js";

import { AttendanceFormat } from "./staff-formats.js";
import { AttendanceFormat, isValidStaffShiftFormat } from "./staff-formats.js";
import Config from "../../config.js";

import Models from "../../database/models.js";
import { StatusCode } from "status-code-enum";
import { NextFunction } from "express-serve-static-core";
import { RouterError } from "../../middleware/error-handler.js";
import { StaffShift } from "database/staff-db.js";

import { Event } from "../../database/event-db.js";

const staffRouter: Router = Router();

Expand Down Expand Up @@ -74,4 +77,59 @@ staffRouter.post("/attendance/", strongJwtVerification, async (req: Request, res
return res.status(StatusCode.SuccessOK).send({ status: "Success" });
});

staffRouter.get("/shift/", strongJwtVerification, async (_: Request, res: Response, next: NextFunction) => {
const payload: JwtPayload | undefined = res.locals.payload as JwtPayload;

if (!hasStaffPerms(payload)) {
return next(new RouterError(StatusCode.ClientErrorForbidden, "Forbidden"));
}

const data: StaffShift | null = await Models.StaffShift.findOne({ userId: payload.id });

if (!data) {
return next(new RouterError(StatusCode.ServerErrorInternal, "ShiftNotFound"));
}

const shiftIds: string[] = data.shifts;

const events: Event[] = await Models.Event.find({
isStaff: true,
eventId: { $in: shiftIds },
});

return res.status(StatusCode.SuccessOK).json(events);
});

staffRouter.post("/shift/", strongJwtVerification, async (req: Request, res: Response, next: NextFunction) => {
const payload: JwtPayload | undefined = res.locals.payload as JwtPayload;

if (!hasStaffPerms(payload)) {
return next(new RouterError(StatusCode.ClientErrorForbidden, "Forbidden"));
}

const shift: StaffShift = req.body as StaffShift;

if (!hasAdminPerms(payload) || !shift.userId) {
shift.userId = payload.id;
}

if (!isValidStaffShiftFormat(shift)) {
return next(new RouterError(StatusCode.ClientErrorBadRequest, "InvalidParams"));
}

await Models.StaffShift.updateOne(
{ userId: shift.userId },
{
$push: {
shifts: {
$each: shift.shifts,
},
},
},
{ upsert: true, new: true },
);

return res.status(StatusCode.SuccessOK).json({ success: true });
});

export default staffRouter;

0 comments on commit 90d5d69

Please sign in to comment.