diff --git a/backend/index.ts b/backend/index.ts index 2e941226..90734550 100644 --- a/backend/index.ts +++ b/backend/index.ts @@ -28,11 +28,13 @@ import { } from "./routes/application_info"; import { createEventPushSubscription, deleteEventPushSubscription, getEventSubscriptions } from "./routes/event_subscriptions" import { getMeetInfo, setMeetInfo } from "./routes/meet_info"; -import { getUsedMeals, setUsedMeals } from "./routes/used_meals"; +import { getMealInfo, setMealInfo } from "./routes/meal_info"; import { getWorkshopList, setWorkshopList } from "./routes/workshop_info"; -import { getCheckIn, setCheckIn } from "./routes/check_in"; +import { getCheckInInfo, setCheckInInfo } from "./routes/check_in_info"; +import { getHardwareInfo, setHardwareInfo } from "./routes/hardware_info"; import { addTeammate, getTeamInfo, removeTeammate, setTeamInfo } from "./routes/team_info"; import { getSubmitInfo, setSubmitInfo } from "./routes/submit_info"; +import { getAllForms } from "./routes/forms"; import { getUserDetail } from "./routes/user_detail"; import { getUserList, getUserStats, getMeetList } from "./routes/user_list"; import { @@ -189,10 +191,12 @@ authenticatedRoute.post( ); authenticatedRoute.get("/users/:userId/forms/meet_info", getMeetInfo); authenticatedRoute.put("/users/:userId/forms/meet_info", setMeetInfo); -authenticatedRoute.get("/users/:userId/forms/used_meals", getUsedMeals); -authenticatedRoute.put("/users/:userId/forms/used_meals", setUsedMeals); -authenticatedRoute.get("/users/:userId/forms/check_in", getCheckIn); -authenticatedRoute.put("/users/:userId/forms/check_in", setCheckIn); +authenticatedRoute.get("/users/:userId/forms/meal_info", getMealInfo); +authenticatedRoute.put("/users/:userId/forms/meal_info", setMealInfo); +authenticatedRoute.get("/users/:userId/forms/check_in_info", getCheckInInfo); +authenticatedRoute.put("/users/:userId/forms/check_in_info", setCheckInInfo); +authenticatedRoute.get("/users/:userId/forms/hardware_info", getHardwareInfo); +authenticatedRoute.put("/users/:userId/forms/hardware_info", setHardwareInfo); authenticatedRoute.get("/users/:userId/forms/submit_info", getSubmitInfo); authenticatedRoute.put("/users/:userId/forms/submit_info", setSubmitInfo); authenticatedRoute.get("/users/:userId/forms/team_info", getTeamInfo); @@ -205,6 +209,7 @@ authenticatedRoute.put("/users/:userId/forms/remove_teammate", removeTeammate); // What permission should this one be? authenticatedRoute.get("/users/:userId/status", getApplicationStatus); authenticatedRoute.get("/users/:userId", getUserDetail); +authenticatedRoute.get("/users/:userId/forms", getAllForms); // Room reservations authenticatedRoute.get("/rooms", getRooms); diff --git a/backend/models/Application.d.ts b/backend/models/Application.d.ts index d18c9cbb..37c2ebc0 100644 --- a/backend/models/Application.d.ts +++ b/backend/models/Application.d.ts @@ -53,8 +53,8 @@ export interface ITransportationInfo { [e: string]: any; } -export interface IUsedMeals { - mealList?: String; +export interface IMealInfo { + usedMeals?: [String]; } export interface ITeamInfo { @@ -62,11 +62,13 @@ export interface ITeamInfo { } export interface IWorkshopInfo { - workshopList?: String; + attendedWorkshops?: [String]; } -export interface ICheckIn { - checkInStatus?: Boolean; +export interface ICheckInInfo { + checkedIn?: Boolean; + checkedInBy?: String; + checkedInAt?: Date; } export interface IMeetInfo { @@ -98,6 +100,15 @@ export interface ISubmitInfo { url?: String; } +export interface IHardwareInfo { + checkedOutBy?: String; + checkedOutAt?: Date; + pendingReturn?: Boolean; + returnedAt?: Date; + returnedBy?: String; + hardwareList?: String; +} + export interface IApplication extends Document { forms: { // can only be modified by user/editors @@ -105,10 +116,11 @@ export interface IApplication extends Document { transportation: ITransportationInfo; meet_info: IMeetInfo; submit_info: ISubmitInfo; - used_meals: IUsedMeals; - check_in: ICheckIn; + meal_info: IMealInfo; + check_in_info: ICheckInInfo; team_info: ITeamInfo; workshop_info: IWorkshopInfo; + hardware_info: IHardwareInfo; // we can conceivably add additional forms here. }; admin_info: { diff --git a/backend/models/ApplicationAnyYear.ts b/backend/models/ApplicationAnyYear.ts index b29851d6..42054c34 100644 --- a/backend/models/ApplicationAnyYear.ts +++ b/backend/models/ApplicationAnyYear.ts @@ -4,11 +4,12 @@ import { IApplication } from "./Application.d" import applicationInfoSchema from "./applicationInfoSchema"; import adminInfoSchema from "./adminInfoSchema"; import meetInfoSchema from "./meetInfoSchema"; -import usedMealsSchema from "./usedMealsSchema"; +import mealInfoSchema from "./mealInfoSchema"; import checkInSchema from "./checkInSchema"; import teamInfoSchema from "./teamInfoSchema"; import workshopInfoSchema from "./workshopInfoSchema"; import submitInfoSchema from "./submitInfoSchema"; +import hardwareInfoSchema from "./hardwareInfoSchema"; import reviewSchema from "./reviewSchema"; import { STATUS, TRANSPORTATION_STATUS } from "../constants"; import {values} from "lodash"; @@ -20,10 +21,11 @@ export const applicationSchema: Schema = new mongoose.Schema({ "application_info": applicationInfoSchema, "transportation": transportationInfoSchema, "meet_info": meetInfoSchema, - "used_meals": usedMealsSchema, - "check_in": checkInSchema, + "meal_info": mealInfoSchema, + "check_in_info": checkInSchema, "team_info": teamInfoSchema, "workshop_info": workshopInfoSchema, + "hardware_info": hardwareInfoSchema, "submit_info": submitInfoSchema }, "admin_info": adminInfoSchema, // Only editable by admin. diff --git a/backend/models/checkInSchema.ts b/backend/models/checkInSchema.ts index 911fe587..35c65764 100644 --- a/backend/models/checkInSchema.ts +++ b/backend/models/checkInSchema.ts @@ -2,7 +2,9 @@ import mongoose from "mongoose"; import { Schema } from "mongoose"; const checkInSchema: Schema = new mongoose.Schema({ - checkInStatus: Boolean, + checkedIn: Boolean, + checkedInBy: String, + checkedInAt: Date }, { _id: false }); export default checkInSchema; \ No newline at end of file diff --git a/backend/models/hardwareInfoSchema.ts b/backend/models/hardwareInfoSchema.ts new file mode 100644 index 00000000..f2be925e --- /dev/null +++ b/backend/models/hardwareInfoSchema.ts @@ -0,0 +1,13 @@ +import mongoose from "mongoose"; +import { Schema } from "mongoose"; + +const hardwareInfoSchema: Schema = new mongoose.Schema({ + checkedOutBy: String, + checkedOutAt: Date, + pendingReturn: Boolean, + returnedAt: Date, + returnedBy: String, + hardwareList: String +}, { _id: false }); + +export default hardwareInfoSchema; \ No newline at end of file diff --git a/backend/models/mealInfoSchema.ts b/backend/models/mealInfoSchema.ts new file mode 100644 index 00000000..ff0badc4 --- /dev/null +++ b/backend/models/mealInfoSchema.ts @@ -0,0 +1,8 @@ +import mongoose from "mongoose"; +import { Schema } from "mongoose"; + +const mealInfoSchema: Schema = new mongoose.Schema({ + usedMeals: [String], +}, { _id: false }); + +export default mealInfoSchema; diff --git a/backend/models/usedMealsSchema.ts b/backend/models/usedMealsSchema.ts deleted file mode 100644 index 98c204ae..00000000 --- a/backend/models/usedMealsSchema.ts +++ /dev/null @@ -1,8 +0,0 @@ -import mongoose from "mongoose"; -import { Schema } from "mongoose"; - -const usedMealsSchema: Schema = new mongoose.Schema({ - mealList: String, -}, { _id: false }); - -export default usedMealsSchema; diff --git a/backend/models/workshopInfoSchema.ts b/backend/models/workshopInfoSchema.ts index 5b404e54..478ac035 100644 --- a/backend/models/workshopInfoSchema.ts +++ b/backend/models/workshopInfoSchema.ts @@ -2,7 +2,7 @@ import mongoose from "mongoose"; import { Schema } from "mongoose"; const workshopInfoSchema: Schema = new mongoose.Schema({ - workshopList: String, + attendedWorkshops: [String], }, { _id: false }); export default workshopInfoSchema; \ No newline at end of file diff --git a/backend/routes/used_meals.ts b/backend/routes/check_in_info.ts similarity index 58% rename from backend/routes/used_meals.ts rename to backend/routes/check_in_info.ts index 44698607..eaec91be 100644 --- a/backend/routes/used_meals.ts +++ b/backend/routes/check_in_info.ts @@ -2,17 +2,17 @@ import { Request, Response } from 'express'; import { getApplicationAttribute, setApplicationAttribute } from "./common"; import { IApplication } from '../models/Application.d'; -export function getUsedMeals(req: Request, res: Response) { +export function getCheckInInfo(req: Request, res: Response) { return getApplicationAttribute(req, res, (e: IApplication) => { - return e.forms.used_meals || {}; + return e.forms.check_in_info || {}; }, true); } -export function setUsedMeals(req: Request, res: Response) { +export function setCheckInInfo(req: Request, res: Response) { return setApplicationAttribute(req, res, (e: IApplication) => { - e.forms.used_meals = req.body; + e.forms.check_in_info = req.body; }, - e => e.forms.used_meals + e => e.forms.check_in_info ); -} +} \ No newline at end of file diff --git a/backend/routes/common.ts b/backend/routes/common.ts index 7b676adf..608e631f 100644 --- a/backend/routes/common.ts +++ b/backend/routes/common.ts @@ -33,6 +33,13 @@ export async function getApplicationAttribute( getter: (e: IApplication) => any, createIfNotFound = false ) { + // prevent non-admins from viewing applications + const groups = res.locals.user["cognito:groups"] || []; + const canView = groups.includes("admin") || groups.includes("organizers_current"); + if (!canView && res.locals.user.sub !== req.params.userId) { + return res.status(403).send("You do not have access to view this application"); + } + let application: IApplication | null = await Application.findOne( { "user.id": req.params.userId }, { __v: 0, reviews: 0 }, @@ -69,6 +76,13 @@ export async function setApplicationAttribute( getter: (e: IApplication) => any = (e) => e, considerDeadline = false ) { + // prevent non-admins from viewing other applications + const groups = res.locals.user["cognito:groups"] || []; + const canEdit = groups.includes("admin") || groups.includes("organizers_current"); + if (!canEdit && res.locals.user.sub !== req.params.userId) { + return res.status(403).send("You do not have access to edit this application"); + } + const application: IApplication | null = await Application.findOne( { "user.id": req.params.userId }, { __v: 0, reviews: 0 } diff --git a/backend/routes/forms.ts b/backend/routes/forms.ts new file mode 100644 index 00000000..21e9087a --- /dev/null +++ b/backend/routes/forms.ts @@ -0,0 +1,9 @@ +import { Request, Response } from 'express'; +import { getApplicationAttribute } from "./common"; +import { IApplication } from '../models/Application.d'; + +export function getAllForms(req: Request, res: Response) { + return getApplicationAttribute(req, res, (e: IApplication) => { + return e.forms || {}; + }, true); +} \ No newline at end of file diff --git a/backend/routes/hardware_info.ts b/backend/routes/hardware_info.ts new file mode 100644 index 00000000..9d190c0f --- /dev/null +++ b/backend/routes/hardware_info.ts @@ -0,0 +1,18 @@ +import { Request, Response } from 'express'; +import { getApplicationAttribute, setApplicationAttribute } from "./common"; +import { IApplication } from '../models/Application.d'; + +export function getHardwareInfo(req: Request, res: Response) { + return getApplicationAttribute(req, res, (e: IApplication) => { + return e.forms.hardware_info || {}; + }, true); +} + +export function setHardwareInfo(req: Request, res: Response) { + return setApplicationAttribute(req, res, + (e: IApplication) => { + e.forms.hardware_info = req.body; + }, + e => e.forms.hardware_info + ); +} \ No newline at end of file diff --git a/backend/routes/check_in.ts b/backend/routes/meal_info.ts similarity index 60% rename from backend/routes/check_in.ts rename to backend/routes/meal_info.ts index e83c2afd..460ed20f 100644 --- a/backend/routes/check_in.ts +++ b/backend/routes/meal_info.ts @@ -2,17 +2,17 @@ import { Request, Response } from 'express'; import { getApplicationAttribute, setApplicationAttribute } from "./common"; import { IApplication } from '../models/Application.d'; -export function getCheckIn(req: Request, res: Response) { +export function getMealInfo(req: Request, res: Response) { return getApplicationAttribute(req, res, (e: IApplication) => { - return e.forms.check_in || {}; + return e.forms.meal_info || {}; }, true); } -export function setCheckIn(req: Request, res: Response) { +export function setMealInfo(req: Request, res: Response) { return setApplicationAttribute(req, res, (e: IApplication) => { - e.forms.check_in = req.body; + e.forms.meal_info = req.body; }, - e => e.forms.check_in + e => e.forms.meal_info ); -} \ No newline at end of file +}