Skip to content

Commit

Permalink
Merge pull request #296 from TreeHacks/connorff/update-form-api
Browse files Browse the repository at this point in the history
feat: restrict scope access to forms, add/modify form schemas
  • Loading branch information
akjadhav authored Jan 14, 2025
2 parents 47be7e2 + bc1ecf8 commit 0b6b965
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 38 deletions.
17 changes: 11 additions & 6 deletions backend/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
26 changes: 19 additions & 7 deletions backend/models/Application.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,22 @@ export interface ITransportationInfo {
[e: string]: any;
}

export interface IUsedMeals {
mealList?: String;
export interface IMealInfo {
usedMeals?: [String];
}

export interface ITeamInfo {
teamList?: String;
}

export interface IWorkshopInfo {
workshopList?: String;
attendedWorkshops?: [String];
}

export interface ICheckIn {
checkInStatus?: Boolean;
export interface ICheckInInfo {
checkedIn?: Boolean;
checkedInBy?: String;
checkedInAt?: Date;
}

export interface IMeetInfo {
Expand Down Expand Up @@ -98,17 +100,27 @@ 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
application_info: IApplicationInfo;
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: {
Expand Down
8 changes: 5 additions & 3 deletions backend/models/ApplicationAnyYear.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion backend/models/checkInSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
13 changes: 13 additions & 0 deletions backend/models/hardwareInfoSchema.ts
Original file line number Diff line number Diff line change
@@ -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;
8 changes: 8 additions & 0 deletions backend/models/mealInfoSchema.ts
Original file line number Diff line number Diff line change
@@ -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;
8 changes: 0 additions & 8 deletions backend/models/usedMealsSchema.ts

This file was deleted.

2 changes: 1 addition & 1 deletion backend/models/workshopInfoSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
12 changes: 6 additions & 6 deletions backend/routes/used_meals.ts → backend/routes/check_in_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}
}
14 changes: 14 additions & 0 deletions backend/routes/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down Expand Up @@ -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 }
Expand Down
9 changes: 9 additions & 0 deletions backend/routes/forms.ts
Original file line number Diff line number Diff line change
@@ -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);
}
18 changes: 18 additions & 0 deletions backend/routes/hardware_info.ts
Original file line number Diff line number Diff line change
@@ -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
);
}
12 changes: 6 additions & 6 deletions backend/routes/check_in.ts → backend/routes/meal_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}
}

0 comments on commit 0b6b965

Please sign in to comment.