From 87f5fa2e9189b8f750f02f459c49c627e8148fca Mon Sep 17 00:00:00 2001 From: Stephan <57194608+stephan418@users.noreply.github.com> Date: Fri, 3 Jun 2022 22:19:09 +0200 Subject: [PATCH] Add various participant and role controllers + Fix issues --- src/Controllers/participant.controller.ts | 114 ++++++++++++++++++++-- src/Middleware/auth/teamleaderAuth.ts | 11 ++- 2 files changed, 114 insertions(+), 11 deletions(-) diff --git a/src/Controllers/participant.controller.ts b/src/Controllers/participant.controller.ts index 08bf4db..84ecef0 100644 --- a/src/Controllers/participant.controller.ts +++ b/src/Controllers/participant.controller.ts @@ -1,12 +1,16 @@ import prisma from "../lib/prisma"; import { string, z } from "zod"; import { Request, Response } from "express"; -import { DataType, generateError, generateInvalidBodyError } from "./common"; +import { DataType, generateError, generateInvalidBodyError, createInsufficientPermissionsError } from "./common"; import { Prisma } from "@prisma/client"; import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; import NotFoundError from "../Middleware/error/NotFoundError"; import { requireLeaderOfTeam, requireResponsibleForParticipant } from "../Middleware/auth/teamleaderAuth"; import { requireResponsibleForGroups } from "../Middleware/auth/auth"; +import { requireConfiguredAuthentication } from "../Middleware/auth/auth"; +import { isTeamleaderJWTPayload, TeamleaderJWTPayload } from "../Middleware/auth/teamleaderAuth"; +import { AuthJWTPayload } from "./admin_auth.controller"; +import AuthError from "../Middleware/error/AuthError"; require("express-async-errors"); @@ -16,17 +20,13 @@ const InitialParticipant = z.object({ groupPid: z.string().min(1).uuid(), }); -const returnedParticipant = { +const ParticipantBody = InitialParticipant.extend({ teamPid: z.string().uuid() }); + +const basicParticipant = { pid: true, firstName: true, lastName: true, relevance: true, - team: { - select: { - pid: true, - name: true, - }, - }, group: { select: { pid: true, @@ -35,11 +35,105 @@ const returnedParticipant = { }, } as const; -// at: POST api/participants/ +const returnedParticipant = { + ...basicParticipant, + team: { + select: { + pid: true, + name: true, + }, + }, +} as const; + +const _getAllParticipants = async ( + res: Response, + authentication: TeamleaderJWTPayload | AuthJWTPayload, + teamPid?: string +) => { + if (isTeamleaderJWTPayload(authentication)) { + teamPid = authentication.team; + } else { + if (authentication.permission_level !== "ELEVATED") { + throw new AuthError(); + } + } + + const participants = await prisma.participant.findMany({ + where: { team: { pid: teamPid } }, + select: basicParticipant, + }); + + return res.status(200).json({ + type: "success", + payload: { + participants, + }, + }); +}; + +export const getAllParticipants = async (req: Request<{}, {}, {}, { teamPid?: string }>, res: Response) => { + const auth = req.auth || req.teamleader; + + if (!auth) { + throw new AuthError("No authentication provided"); + } + + return _getAllParticipants(res, auth, req.query.teamPid); +}; + +export const getAllDisciplinesParams = async (req: Request<{ teamPid: string }>, res: Response) => { + const auth = req.auth || req.teamleader; + + if (!auth) { + throw new AuthError("Not authentication provided"); + } + + return _getAllParticipants(res, auth, req.params.teamPid); +}; + +export const getParticipantForRole = async (req: Request<{ rolePid: string }>, res: Response) => { + let authenticated = false; + + if (req.auth && req.auth.permission_level !== "ELEVATED") { + return res.status(403).json(createInsufficientPermissionsError()); + } else if (req.auth) { + authenticated = true; + } + + const participant = await prisma.participant.findFirst({ + where: { roles: { some: { pid: req.params.rolePid } } }, + select: returnedParticipant, + }); + + if (!authenticated) { + requireLeaderOfTeam(req.teamleader, participant?.team.pid); + authenticated = true; + } + + if (!authenticated) { + throw new AuthError(); // REVIEW: Is this check neccesary? + } + + if (!participant) { + return res.status(404).json({ + type: "error", + payload: { + message: `Could not find a participant for the role with the ID '${req.params.rolePid}'`, + }, + }); + } + + return res.status(200).json({ + type: "success", + payload: { participant }, + }); +}; + +// at: POST api/teams/:teamPid/participant/ export const createParticipant = async (req: Request<{ teamPid: string }>, res: Response) => { const { teamPid } = req.params; - const result = InitialParticipant.safeParse(req.body); + const result = ParticipantBody.safeParse(req.body); if (result.success === false) { return res.status(400).json( diff --git a/src/Middleware/auth/teamleaderAuth.ts b/src/Middleware/auth/teamleaderAuth.ts index 0af4e3a..9b5c745 100644 --- a/src/Middleware/auth/teamleaderAuth.ts +++ b/src/Middleware/auth/teamleaderAuth.ts @@ -10,6 +10,10 @@ export interface TeamleaderJWTPayload { team: string; } +export function isTeamleaderJWTPayload(payload: any): payload is TeamleaderJWTPayload { + return typeof payload.team === "string"; +} + const JWT_SECRET = process.env.JWT_SECRET; export function generateTeamleaderJWT(teamleader: Team) { @@ -86,8 +90,13 @@ export const _requireTeamleaderAuthentication = export const requireTeamleaderAuthentication = _requireTeamleaderAuthentication({ optional: false, controlled: false }); -export async function requireLeaderOfTeam(auth: TeamleaderJWTPayload | undefined, teamPid: string) { +export async function requireLeaderOfTeam(auth: TeamleaderJWTPayload | undefined, teamPid?: string) { + if (!teamPid) { + throw new AuthError("Could not match IDs"); + } + await checkTeamExistence(teamPid); + if (auth?.team !== teamPid) { throw new AuthError("The provided authorization is not valid for the requested team"); }