diff --git a/src/Controllers/participant.controller.ts b/src/Controllers/participant.controller.ts index f5dfaa4..2e0a56a 100644 --- a/src/Controllers/participant.controller.ts +++ b/src/Controllers/participant.controller.ts @@ -1,22 +1,11 @@ import prisma from "../lib/prisma"; import { z } from "zod"; import { Request, Response } from "express"; -import { - AUTH_ERROR, - createInsufficientPermissionsError, - DataType, - generateError, - generateInvalidBodyError, -} from "./common"; -import { Job, Prisma } from "@prisma/client"; +import { DataType, generateError, generateInvalidBodyError } from "./common"; +import { Prisma } from "@prisma/client"; import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; import NotFoundError from "../Middleware/error/NotFoundError"; -import { requireConfiguredAuthentication, requireResponsibleForGroup } from "../Middleware/auth/auth"; - -//TODO: add TeamleaderAuthentification - -// REVIEW: All this code should be able to be executed by the teamleader of the team the participant is in AND -// an admin the group of whom overlaps with the team AND an elevated admin +import { requireLeaderOfTeam } from "../Middleware/auth/teamleaderAuth"; const InitialParticipant = z.object({ firstName: z.string(), @@ -45,7 +34,7 @@ const returnedParticipant = { }, } as const; -// at: POST api/teams/:teamPid/participant/ +// at: POST api/participants/ export const createParticipant = async (req: Request, res: Response) => { const result = ParticipantBody.safeParse(req.body); @@ -64,6 +53,10 @@ export const createParticipant = async (req: Request, res: Response) => { } const body = result.data; + if (req.teamleader?.isAuthenticated) { + requireLeaderOfTeam(req.teamleader, body.teamPid); + } + try { const participant = await prisma.participant.create({ data: { @@ -92,6 +85,12 @@ export const createParticipant = async (req: Request, res: Response) => { // at: PATCH api/participants/:pid/ export const updateParticipant = async (req: Request<{ pid: string }>, res: Response) => { + const { pid } = req.params; + + if (req.teamleader?.isAuthenticated) { + requireLeaderOfTeam(req.teamleader, pid); + } + const result = InitialParticipant.partial().safeParse(req.body); if (result.success === false) { @@ -108,7 +107,6 @@ export const updateParticipant = async (req: Request<{ pid: string }>, res: Resp } const body = result.data; - const { pid } = req.params; try { const participant = await prisma.participant.update({ @@ -138,6 +136,10 @@ export const updateParticipant = async (req: Request<{ pid: string }>, res: Resp export const deleteParticipant = async (req: Request<{ pid: string }>, res: Response) => { const { pid } = req.params; + if (req.teamleader?.isAuthenticated) { + requireLeaderOfTeam(req.teamleader, pid); + } + try { await prisma.participant.delete({ where: { pid } }); diff --git a/src/Controllers/role.controller.ts b/src/Controllers/role.controller.ts index 353965d..294db70 100644 --- a/src/Controllers/role.controller.ts +++ b/src/Controllers/role.controller.ts @@ -56,7 +56,9 @@ export async function createRolesForTeam(teamPid: string) { export async function getRolesForTeam(req: Request<{ teamPid: string }>, res: Response) { const teamPid = req.params.teamPid; - requireLeaderOfTeam(req.teamleader, teamPid); + if (req.teamleader?.isAuthenticated) { + requireLeaderOfTeam(req.teamleader, teamPid); + } const roles = await prisma.role.findMany({ where: { team: { pid: teamPid } }, @@ -82,6 +84,12 @@ const AssignParticipantToRoleBody = z.object({ // requires: auth(leader of the team) export async function assignParticipantToRole(req: Request<{ pid: string }>, res: Response) { + const { pid } = req.params; + + if (req.teamleader?.isAuthenticated) { + requireLeaderOfTeam(req.teamleader, pid); + } + const zBody = AssignParticipantToRoleBody.safeParse(req.body); if (zBody.success === false) { @@ -89,10 +97,9 @@ export async function assignParticipantToRole(req: Request<{ pid: string }>, res } const { participantPid } = zBody.data; - const rolePid = req.params.pid; const schema = await prisma.role.findFirst({ - where: { pid: rolePid, team: { participants: { some: { pid: participantPid } } } }, + where: { pid, team: { participants: { some: { pid: participantPid } } } }, select: { participant: { select: { pid: true, firstName: true, lastName: true } } }, }); @@ -100,18 +107,18 @@ export async function assignParticipantToRole(req: Request<{ pid: string }>, res return res.status(404).json({ type: "error", payload: { - message: `No role with the ID '${rolePid}' could be found in the scope of the participant with the ID '${participantPid}'`, + message: `No role with the ID '${pid}' could be found in the scope of the participant with the ID '${participantPid}'`, }, }); } // No error handling should be neccesary as the existence of the role and participant have already been checked above - await prisma.role.update({ where: { pid: rolePid }, data: { participant: { connect: { pid: participantPid } } } }); + await prisma.role.update({ where: { pid }, data: { participant: { connect: { pid: participantPid } } } }); return res.status(200).json({ type: "success", payload: { - message: `The participant with ID '${participantPid}' was successfully assigned to the role with ID '${rolePid}'`, + message: `The participant with ID '${participantPid}' was successfully assigned to the role with ID '${pid}'`, ...(schema.participant ? { unassigned: schema.participant } : {}), }, }); diff --git a/src/Controllers/team.controller.ts b/src/Controllers/team.controller.ts index 34e03dc..88d1271 100644 --- a/src/Controllers/team.controller.ts +++ b/src/Controllers/team.controller.ts @@ -1,8 +1,7 @@ import { Request, Response } from "express"; import prisma from "../lib/prisma"; -import { createInsufficientPermissionsError, DataType, generateInvalidBodyError } from "./common"; +import { DataType, generateInvalidBodyError } from "./common"; import { requireLeaderOfTeam } from "../Middleware/auth/teamleaderAuth"; -import { z } from "zod"; import { TeamBody } from "./user_auth.controller"; import { Prisma } from "@prisma/client"; import NotFoundError from "../Middleware/error/NotFoundError"; @@ -36,6 +35,10 @@ export const getTeams = async (req: Request, res: Response) => { export const getTeam = async (req: Request, res: Response) => { const { pid } = req.params; + if (req.teamleader?.isAuthenticated) { + requireLeaderOfTeam(req.teamleader, pid); + } + const team = await prisma.team.findUnique({ where: { pid }, select: basicTeam, @@ -45,9 +48,13 @@ export const getTeam = async (req: Request, res: Response) => { }; export const updateTeam = async (req: Request, res: Response) => { - const result = TeamBody.merge(z.object({ pid: z.string().min(1) })) - .omit({ partGroupId: true, partFirstName: true, partLastName: true }) - .safeParse(req.body); + const { pid } = req.params; + + if (req.teamleader?.isAuthenticated) { + requireLeaderOfTeam(req.teamleader, pid); + } + + const result = TeamBody.omit({ partGroupId: true, partFirstName: true, partLastName: true }).safeParse(req.body); if (result.success === false) { return res.status(400).json( @@ -64,12 +71,10 @@ export const updateTeam = async (req: Request, res: Response) => { const body = result.data; - requireLeaderOfTeam(req.teamleader, body.pid); - try { const team = await prisma.team.update({ where: { - pid: body.pid, + pid: pid, }, data: { name: body.teamName, @@ -81,7 +86,7 @@ export const updateTeam = async (req: Request, res: Response) => { res.status(204).json({ type: "success", payload: { team } }); } catch (e) { if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError("team", body.pid); + throw new NotFoundError("team", pid); } throw e; @@ -91,8 +96,9 @@ export const updateTeam = async (req: Request, res: Response) => { export const deleteTeam = async (req: Request, res: Response) => { const { pid } = req.params; - // TODO: accept admin auth - requireLeaderOfTeam(req.teamleader, pid); + if (req.teamleader?.isAuthenticated) { + requireLeaderOfTeam(req.teamleader, pid); + } await prisma.team.delete({ where: { pid } }); diff --git a/src/Routes/participant.routes.ts b/src/Routes/participant.routes.ts index 7ba300f..d35fae6 100644 --- a/src/Routes/participant.routes.ts +++ b/src/Routes/participant.routes.ts @@ -1,6 +1,6 @@ import express from "express"; import { createParticipant, deleteParticipant, updateParticipant } from "../Controllers/participant.controller"; -import { requireAuthentication, requireConfiguredAuthentication } from "../Middleware/auth/auth"; +import { requireConfiguredAuthentication } from "../Middleware/auth/auth"; const router = express.Router(); diff --git a/src/Routes/role.routes.ts b/src/Routes/role.routes.ts index 0ad57ce..6ca39ae 100644 --- a/src/Routes/role.routes.ts +++ b/src/Routes/role.routes.ts @@ -1,6 +1,6 @@ import Express from "express"; import { assignParticipantToRole, getRolesForTeam } from "../Controllers/role.controller"; -import { requireAuthentication, requireConfiguredAuthentication } from "../Middleware/auth/auth"; +import { requireConfiguredAuthentication } from "../Middleware/auth/auth"; const router = Express.Router(); diff --git a/src/Routes/team.routes.ts b/src/Routes/team.routes.ts index a8ffebe..b419c1c 100644 --- a/src/Routes/team.routes.ts +++ b/src/Routes/team.routes.ts @@ -1,6 +1,5 @@ import express from "express"; -import { requireAuthentication, requireConfiguredAuthentication } from "../Middleware/auth/auth"; -import { requireTeamleaderAuthentication } from "../Middleware/auth/teamleaderAuth"; +import { requireConfiguredAuthentication } from "../Middleware/auth/auth"; import { deleteTeam, getTeam, getTeams, updateTeam } from "../Controllers/team.controller"; const router = express.Router(); @@ -12,7 +11,11 @@ router.get( getTeam ); -router.put("/", requireTeamleaderAuthentication, updateTeam); +router.put<"/:pid/", { pid: string }>( + "/:pid/", + requireConfiguredAuthentication({ optional: false, type: { admin: true, teamleader: true } }), + updateTeam +); router.delete<"/:pid/", { pid: string }>( "/:pid/", requireConfiguredAuthentication({ optional: false, type: { admin: true, teamleader: true } }),