From 92294758363ca7c7cffdfff783b022fcd76ff256 Mon Sep 17 00:00:00 2001 From: ajdj100 Date: Sun, 14 Dec 2025 11:38:45 -0500 Subject: [PATCH] finished state and role based auth across the full API --- api/src/middleware/auth.ts | 2 +- api/src/routes/calendar.ts | 13 +++++++------ api/src/routes/course.ts | 5 ++++- api/src/routes/members.js | 2 +- api/src/routes/ranks.js | 5 +++-- api/src/routes/roles.js | 13 +++++++------ 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/api/src/middleware/auth.ts b/api/src/middleware/auth.ts index 19240ab..395c200 100644 --- a/api/src/middleware/auth.ts +++ b/api/src/middleware/auth.ts @@ -14,7 +14,7 @@ export function requireMemberState(state: MemberState) { if (req.user?.state === state) next(); else - res.status(403).send("You must be a member of the 17th RBN to access this resource"); + res.status(403).send(`You must be a ${state} of the 17th RBN to access this resource`); } } diff --git a/api/src/routes/calendar.ts b/api/src/routes/calendar.ts index 3b9f119..d3f91d8 100644 --- a/api/src/routes/calendar.ts +++ b/api/src/routes/calendar.ts @@ -1,7 +1,8 @@ import { Request, Response } from "express"; import { createEvent, getEventAttendance, getEventDetails, getShortEventsInRange, setAttendanceStatus, setEventCancelled, updateEvent } from "../services/calendarService"; import { CalendarAttendance, CalendarEvent } from "@app/shared/types/calendar"; -import { requireLogin } from "../middleware/auth"; +import { requireLogin, requireMemberState, requireRole } from "../middleware/auth"; +import { MemberState } from "../services/memberService"; const express = require('express'); const r = express.Router(); @@ -36,7 +37,7 @@ r.get('/upcoming', async (req, res) => { res.sendStatus(501); }) -r.post('/:id/cancel', [requireLogin], async (req: Request, res: Response) => { +r.post('/:id/cancel', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => { try { const eventID = Number(req.params.id); setEventCancelled(eventID, true); @@ -46,7 +47,7 @@ r.post('/:id/cancel', [requireLogin], async (req: Request, res: Response) => { res.status(500).send('Error setting cancel status'); } }) -r.post('/:id/uncancel', [requireLogin], async (req: Request, res: Response) => { +r.post('/:id/uncancel', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => { try { const eventID = Number(req.params.id); setEventCancelled(eventID, false); @@ -58,7 +59,7 @@ r.post('/:id/uncancel', [requireLogin], async (req: Request, res: Response) => { }) -r.post('/:id/attendance', [requireLogin], async (req: Request, res: Response) => { +r.post('/:id/attendance', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => { try { let member = req.user.id; let event = Number(req.params.id); @@ -86,7 +87,7 @@ r.get('/:id', async (req: Request, res: Response) => { //post a new calendar event -r.post('/', [requireLogin], async (req: Request, res: Response) => { +r.post('/', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => { try { const member = req.user.id; let event: CalendarEvent = req.body; @@ -101,7 +102,7 @@ r.post('/', [requireLogin], async (req: Request, res: Response) => { } }) -r.put('/', [requireLogin], async (req: Request, res: Response) => { +r.put('/', [requireLogin, requireMemberState(MemberState.Member)], async (req: Request, res: Response) => { try { let event: CalendarEvent = req.body; event.start = new Date(event.start); diff --git a/api/src/routes/course.ts b/api/src/routes/course.ts index e1a9103..6e86c23 100644 --- a/api/src/routes/course.ts +++ b/api/src/routes/course.ts @@ -1,13 +1,16 @@ import { CourseAttendee, CourseEventDetails } from "@app/shared/types/course"; import { getAllCourses, getCourseEventAttendees, getCourseEventDetails, getCourseEventRoles, getCourseEvents, insertCourseEvent } from "../services/CourseSerivce"; import { Request, Response, Router } from "express"; -import { requireLogin } from "../middleware/auth"; +import { requireLogin, requireMemberState } from "../middleware/auth"; +import { MemberState } from "../services/memberService"; const courseRouter = Router(); const eventRouter = Router(); courseRouter.use(requireLogin) eventRouter.use(requireLogin) +courseRouter.use(requireMemberState(MemberState.Member)) +eventRouter.use(requireMemberState(MemberState.Member)) courseRouter.get('/', async (req, res) => { try { diff --git a/api/src/routes/members.js b/api/src/routes/members.js index 24b75c3..207fd86 100644 --- a/api/src/routes/members.js +++ b/api/src/routes/members.js @@ -74,7 +74,7 @@ router.get('/:id', async (req, res) => { //update a user's display name (stub) router.put('/:id/displayname', async (req, res) => { // Stub: not implemented yet - return res.status(501).json({ error: 'Update display name not implemented' }); + return res.status(501); }); diff --git a/api/src/routes/ranks.js b/api/src/routes/ranks.js index 75e48b7..81ca611 100644 --- a/api/src/routes/ranks.js +++ b/api/src/routes/ranks.js @@ -2,13 +2,14 @@ const express = require('express'); const r = express.Router(); const ur = express.Router(); const { getAllRanks, insertMemberRank } = require('../services/rankService'); -const { requireLogin } = require('../middleware/auth'); +const { requireLogin, requireMemberState, requireRole } = require('../middleware/auth'); +const { MemberState } = require('../services/memberService'); r.use(requireLogin) ur.use(requireLogin) //insert a new latest rank for a user -ur.post('/', async (req, res) => { +ur.post('/', [requireRole(["17th Command", "17th Administrator", "17th HQ"]),requireMemberState(MemberState.Member)], async (req, res) => { 3 try { const change = req.body?.change; diff --git a/api/src/routes/roles.js b/api/src/routes/roles.js index 332d140..283c707 100644 --- a/api/src/routes/roles.js +++ b/api/src/routes/roles.js @@ -3,14 +3,15 @@ const r = express.Router(); const ur = express.Router(); import pool from '../db'; -import { requireLogin } from '../middleware/auth'; +import { requireLogin, requireMemberState, requireRole } from '../middleware/auth'; +import { MemberState } from '../services/memberService'; import { assignUserGroup, createGroup } from '../services/rolesService'; r.use(requireLogin) ur.use(requireLogin) //manually assign a member to a group -ur.post('/', async (req, res) => { +ur.post('/', [requireMemberState(MemberState.member), requireRole("17th Administrator")], async (req, res) => { try { const body = req.body; @@ -24,7 +25,7 @@ ur.post('/', async (req, res) => { }); //manually remove member from group -ur.delete('/', async (req, res) => { +ur.delete('/', [requireMemberState(MemberState.member), requireRole("17th Administrator")], async (req, res) => { try { const body = req.body; console.log(body); @@ -42,7 +43,7 @@ ur.delete('/', async (req, res) => { }) //get all roles -r.get('/', async (req, res) => { +r.get('/', [requireMemberState(MemberState.member)], async (req, res) => { try { const con = await pool.getConnection(); @@ -81,7 +82,7 @@ r.get('/', async (req, res) => { }); //create a new role -r.post('/', async (req, res) => { +r.post('/', [requireMemberState(MemberState.member), requireRole("17th Administrator")], async (req, res) => { try { const { name, color, description } = req.body; console.log('Creating role:', { name, color, description }); @@ -103,7 +104,7 @@ r.post('/', async (req, res) => { } }) -r.delete('/:id', async (req, res) => { +r.delete('/:id', [requireMemberState(MemberState.member), requireRole("17th Administrator")], async (req, res) => { try { const id = req.params.id;