From 4555d46902a05bf355befb8cbfedfbbc2276ffaf Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Wed, 18 May 2022 12:16:47 +0200 Subject: [PATCH 1/9] modified event responses and updated discipline briefDescription + fullDescription --- prisma/schema.prisma | 14 +++-- src/Controllers/discipline.controller.ts | 15 ++++- src/Controllers/event.controller.ts | 71 ++++++++++++++++-------- 3 files changed, 67 insertions(+), 33 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9557922..9d1b73c 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -34,11 +34,13 @@ model Admin { } model Discipline { - id Int @id @default(autoincrement()) - pid String @unique @default(dbgenerated("gen_random_uuid()")) @db.Uuid - name String - minTeamSize Int - maxTeamSize Int + id Int @id @default(autoincrement()) + pid String @unique @default(dbgenerated("gen_random_uuid()")) @db.Uuid + name String + briefDescription String + fullDescription String? + minTeamSize Int + maxTeamSize Int roles RoleSchema[] teams Team[] @@ -121,7 +123,7 @@ model Group { model Media { id Int @id @default(autoincrement()) pid String @unique - description String + description String @default("visual") events Event[] disciplines Discipline[] diff --git a/src/Controllers/discipline.controller.ts b/src/Controllers/discipline.controller.ts index de8abbd..163ba0a 100644 --- a/src/Controllers/discipline.controller.ts +++ b/src/Controllers/discipline.controller.ts @@ -21,6 +21,8 @@ const basicDiscipline = { visual: { select: { pid: true } }, maxTeamSize: true, minTeamSize: true, + briefDescription: true, + fullDescription: true, event: { select: { pid: true, name: true } }, roles: { select: { pid: true, name: true } }, } as const; @@ -117,6 +119,8 @@ interface CreateDisciplineBody { name?: string; minTeamSize?: number; maxTeamSize?: number; + briefDescription: string; + fullDescription: string; } // require: auth(ELEVATED) @@ -126,9 +130,14 @@ export const createDiscipline = async (req: Request<{ eventPid: string }, {}, Cr return res.status(403).json(createInsufficientPermissionsError()); } - const { name, minTeamSize, maxTeamSize } = req.body; + const { name, minTeamSize, maxTeamSize, briefDescription, fullDescription } = req.body; - if (typeof name !== "string" || typeof minTeamSize !== "number" || typeof maxTeamSize !== "number") { + if (typeof name !== "string" || + typeof minTeamSize !== "number" || + typeof maxTeamSize !== "number" || + typeof briefDescription !== "string" || + (fullDescription && typeof fullDescription !== "string") + ) { return res.status(400).json( generateInvalidBodyError({ name: DataType.STRING, @@ -144,7 +153,7 @@ export const createDiscipline = async (req: Request<{ eventPid: string }, {}, Cr try { const discipline = await prisma.discipline.create({ - data: { name, minTeamSize, maxTeamSize, event: { connect: { pid: req.params.eventPid } } }, + data: { name, minTeamSize, maxTeamSize, briefDescription, fullDescription, event: { connect: { pid: req.params.eventPid } } }, select: { pid: true, name: true, diff --git a/src/Controllers/event.controller.ts b/src/Controllers/event.controller.ts index 3193c37..a2de88c 100644 --- a/src/Controllers/event.controller.ts +++ b/src/Controllers/event.controller.ts @@ -1,6 +1,6 @@ import { Prisma } from "@prisma/client"; import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; -import { Request, Response } from "express"; +import e, { Request, Response } from "express"; import { z } from "zod"; import prisma from "../lib/prisma"; import NotFoundError from "../Middleware/error/NotFoundError"; @@ -8,16 +8,39 @@ import { createInsufficientPermissionsError, DataType, generateError, generateIn require("express-async-errors"); +const EventBody = z.object({ + name: z.string(), + date: z.string(), + briefDescription: z.string(), + fullDescription: z.string(), +}); + +const UpdateBody = EventBody.partial(); + +const CreateEventBody = EventBody.partial({ + fullDescription: true, +}); + export const getAllEvents = async (req: Request, res: Response) => { const events = await prisma.event.findMany({ select: { + pid: true, name: true, + date: true, briefDescription: true, fullDescription: true, visual: { select: { pid: true, description: true } }, - date: true, - pid: true, - id: false, + disciplines: { + select: { + pid: true, + name: true, + }}, + organisations: { + select: { + pid: true, + name: true, + } + } }, }); @@ -46,13 +69,25 @@ export const getEvent = async (req: Request, res: Response) => { pid: eventId, }, select: { + pid: true, name: true, + date: true, briefDescription: true, fullDescription: true, - date: true, - pid: true, - id: false, visual: { select: { pid: true, description: true } }, + disciplines: { + select: { + pid: true, + name: true, + briefDescription: true, + fullDescription: true, + }}, + organisations: { + select: { + pid: true, + name: true, + } + } }, }); @@ -96,12 +131,10 @@ export const addEvent = async (req: Request, res: Response) => { if (req.auth?.permission_level !== "ELEVATED") { res.status(403).json(createInsufficientPermissionsError()); } - if ( - typeof req.body.name !== "string" || - typeof req.body.date !== "string" || - typeof req.body.briefDescription !== "string" || - (req.body.fullDescription && typeof req.body.fullDescription !== "string") - ) { + + const result = CreateEventBody.safeParse(req.body); + + if(result.success === false){ return res.status(400).json( generateInvalidBodyError({ name: DataType.STRING, @@ -122,10 +155,9 @@ export const addEvent = async (req: Request, res: Response) => { fullDescription: req.body.fullDescription, }, select: { + pid: true, name: true, date: true, - pid: true, - id: false, briefDescription: true, fullDescription: true, }, @@ -139,15 +171,6 @@ export const addEvent = async (req: Request, res: Response) => { }); }; -const EventBody = z.object({ - name: z.string(), - date: z.string(), - briefDescription: z.string(), - fullDescription: z.string(), -}); - -const UpdateBody = EventBody.partial(); - export const updateEvent = async (req: Request<{ pid: string }>, res: Response) => { if (req.auth?.permission_level !== "ELEVATED") { res.status(403).json(createInsufficientPermissionsError()); From 4e77d3c66dafa09b90ea47a2eced981831ae2795 Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Sun, 22 May 2022 12:48:37 +0200 Subject: [PATCH 2/9] Event zod add pid/id; rm comented MediaRouter --- src/Controllers/event.controller.ts | 2 ++ src/app.ts | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Controllers/event.controller.ts b/src/Controllers/event.controller.ts index a2de88c..7975165 100644 --- a/src/Controllers/event.controller.ts +++ b/src/Controllers/event.controller.ts @@ -9,6 +9,8 @@ import { createInsufficientPermissionsError, DataType, generateError, generateIn require("express-async-errors"); const EventBody = z.object({ + pid: z.string().max(0), + id: z.string().max(0), name: z.string(), date: z.string(), briefDescription: z.string(), diff --git a/src/app.ts b/src/app.ts index ae0c0ec..aed343f 100644 --- a/src/app.ts +++ b/src/app.ts @@ -65,9 +65,6 @@ async function main() { // Error handling app.use(defaultErrorHandler); // This has to be the LAST ROUTE - // Disable the media router for now - // app.use("/api/media", mediaRouter); - app.listen(process.env.PORT, () => { logger.info(`Listening on port ${process.env.PORT}`); }); From cc57c513899684fb97178eb6c2453084b432f09b Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Tue, 24 May 2022 18:50:30 +0200 Subject: [PATCH 3/9] Added updateDiscipline --- src/Controllers/discipline.controller.ts | 94 +++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/src/Controllers/discipline.controller.ts b/src/Controllers/discipline.controller.ts index 163ba0a..f6ea601 100644 --- a/src/Controllers/discipline.controller.ts +++ b/src/Controllers/discipline.controller.ts @@ -4,6 +4,7 @@ import { Request, Response } from "express"; import prisma from "../lib/prisma"; import ForwardableError from "../Middleware/error/ForwardableError"; import NotFoundError from "../Middleware/error/NotFoundError"; +import { number, z } from "zod"; import { createInsufficientPermissionsError, DataType, @@ -15,6 +16,17 @@ import { require("express-async-errors"); +const DisciplineBody = z.object({ + name: z.string(), + maxTeamSize: z.number(), + minTeamSize: z.number(), + briefDescription: z.string(), + fullDescription: z.string(), + eventPid: z.string(), +}) + +const UpdateDisciplineBody = DisciplineBody.partial(); + const basicDiscipline = { pid: true, name: true, @@ -115,12 +127,90 @@ export const getDiscipline = async (req: Request, res: }); }; +export const updateDiscipline = async (req: Request<{ pid: string }>, res: Response) => { + if (req.auth?.permission_level !== "ELEVATED") { + res.status(403).json(createInsufficientPermissionsError()); + } + + const { pid } = req.params; + + const result = UpdateDisciplineBody.safeParse(req.body); + + if (result.success === false) { + return res.status(400).json( + generateInvalidBodyError({ + name: DataType.STRING, + minTeamSize: DataType.NUMBER, + maxTeamSize: DataType.NUMBER, + briefDescription: DataType.STRING, + ["fullDescription?"]: DataType.STRING, + }) + ); + } + + const body = result.data; + + try { + const discipline = await prisma.discipline.update({ + where: { pid }, + data: { + name: body.name, + minTeamSize: body.minTeamSize, + maxTeamSize: body.maxTeamSize, + briefDescription: body.briefDescription, + fullDescription: body.fullDescription, + }, + select: { + pid: true, + name: true, + minTeamSize: true, + maxTeamSize: true, + briefDescription: true, + fullDescription: true, + }, + }); + + if (!discipline) { + throw new NotFoundError("discipline", pid); + } + + res.status(200).json({ + type: "success", + payload: { + discipline, + }, + }); + } catch (e) { + if (e instanceof Prisma.PrismaClientKnownRequestError) { + return res.status(500).json({ + type: "error", + payload: { + message: `Internal Server error occured. Try again later`, + }, + }); + } + if (e instanceof Prisma.PrismaClientUnknownRequestError) { + return res.status(500).json({ + type: "error", + payload: { + message: "Unknown error occurred with your request. Check if your parameters are correct", + schema: { + eventId: DataType.UUID, + }, + }, + }); + } + + throw e; + } +}; + interface CreateDisciplineBody { name?: string; minTeamSize?: number; maxTeamSize?: number; - briefDescription: string; - fullDescription: string; + briefDescription?: string; + fullDescription?: string; } // require: auth(ELEVATED) From 4f94bf074c8cc5b21e3c2bfd9d936e12535ddf84 Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Sat, 28 May 2022 15:50:05 +0200 Subject: [PATCH 4/9] created Role controller/routes --- src/Controllers/role.controller.ts | 0 src/Routes/team.routes.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/Controllers/role.controller.ts create mode 100644 src/Routes/team.routes.ts diff --git a/src/Controllers/role.controller.ts b/src/Controllers/role.controller.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/Routes/team.routes.ts b/src/Routes/team.routes.ts new file mode 100644 index 0000000..e69de29 From 1cb345c316a3a5ed18cdcf8892cdfe2e600aec2a Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Sun, 29 May 2022 17:15:12 +0200 Subject: [PATCH 5/9] de-duplicated (un-)linkMedia --- src/Controllers/discipline.controller.ts | 58 -------------- src/Controllers/event.controller.ts | 64 --------------- src/Controllers/media.controller.ts | 95 +++++++++++++++++++++++ src/Controllers/role_schema.controller.ts | 58 -------------- src/Routes/discipline.routes.ts | 14 ---- src/Routes/event.routes.ts | 10 --- src/Routes/media.routes.ts | 26 ++++++- src/Routes/role_schema.routes.ts | 10 --- 8 files changed, 120 insertions(+), 215 deletions(-) diff --git a/src/Controllers/discipline.controller.ts b/src/Controllers/discipline.controller.ts index f6ea601..25bd7ae 100644 --- a/src/Controllers/discipline.controller.ts +++ b/src/Controllers/discipline.controller.ts @@ -286,61 +286,3 @@ export const deleteDiscipline = async (req: Request throw e; } }; - -interface visualParams { - disciplinePid: string; -} - -interface visualBody { - mediaPid: string; -} - -export const addVisual = async (req: Request, res: Response) => { - if (req.auth?.permission_level != "ELEVATED") { - res.status(403).json(createInsufficientPermissionsError()); - } - - const { disciplinePid } = req.params; - - const discipline = await prisma.discipline.update({ - where: { pid: disciplinePid }, - data: { - visual: { connect: { pid: req.body.mediaPid } }, - }, - }); - - if (!discipline) { - throw new NotFoundError("discipline", disciplinePid); - } - - return res.status(200).json({ - type: "success", - payload: {}, - }); -}; - -export const deleteVisual = async (req: Request, res: Response) => { - if (req.auth?.permission_level != "ELEVATED") { - res.status(403).json(createInsufficientPermissionsError()); - } - - const { disciplinePid, pid } = req.params; - - try { - await prisma.discipline.update({ - where: { - pid: disciplinePid, - }, - data: { - visual: { disconnect: { pid } }, - }, - }); - return res.status(204).end(); - } catch (e) { - if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError("discipline", disciplinePid); - } - - throw e; - } -}; diff --git a/src/Controllers/event.controller.ts b/src/Controllers/event.controller.ts index 7975165..70cdc57 100644 --- a/src/Controllers/event.controller.ts +++ b/src/Controllers/event.controller.ts @@ -272,67 +272,3 @@ export const deleteEvent = async (req: Request, res: Res throw e; } }; - -// REVIEW: This code **will** need to be de-duplicated - -interface visualParams { - eventPid: string; -} - -interface visualBody { - mediaPid: string; -} - -export const addVisual = async (req: Request, res: Response) => { - if (req.auth?.permission_level != "ELEVATED") { - res.status(403).json(createInsufficientPermissionsError()); - } - - const { eventPid } = req.params; - - if (typeof req.body.mediaPid !== "string") { - res.status(400).json(generateInvalidBodyError({ mediaPid: DataType.STRING })); - } - - const event = await prisma.event.update({ - where: { pid: eventPid }, - data: { - visual: { connect: { pid: req.body.mediaPid } }, - }, - }); - - if (!event) { - throw new NotFoundError("event", eventPid); - } - - return res.status(200).json({ - type: "success", - payload: {}, - }); -}; - -export const deleteVisual = async (req: Request, res: Response) => { - if (req.auth?.permission_level != "ELEVATED") { - res.status(403).json(createInsufficientPermissionsError()); - } - - const { eventPid, pid } = req.params; - - try { - await prisma.event.update({ - where: { - pid: eventPid, - }, - data: { - visual: { disconnect: { pid } }, - }, - }); - return res.status(204).end(); - } catch (e) { - if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError("discipline", eventPid); - } - - throw e; - } -}; diff --git a/src/Controllers/media.controller.ts b/src/Controllers/media.controller.ts index eb78bc3..83a34c3 100644 --- a/src/Controllers/media.controller.ts +++ b/src/Controllers/media.controller.ts @@ -12,9 +12,18 @@ import { type } from "os"; import { unlink } from "fs/promises"; import ForwardableError from "../Middleware/error/ForwardableError"; import SchemaError from "../Middleware/error/SchemaError"; +import { z } from "zod"; +import { updateEvent } from "./event.controller"; require("express-async-errors"); +const linkMediaBody = z.object({ + tableToUpdate: z.enum(["EVENT", "ROLE_SCHEMA", "DISCIPLINE"]), + mediaPid: z.string(), +}); + +const unlinkMediaBody = linkMediaBody.omit({ mediaPid: true, }); + function createMediaLinks(fileName: string) { return [{ rel: "self", type: "GET", href: `/api/media/${fileName}` }]; } @@ -189,3 +198,89 @@ export const deleteMedia = async (req: Request, res: Response) => { throw e; } }; + +//TODO: maybe create a function that adds the tableToUpdate based on path +// and call it before calling (un)linkMedia + +export const linkMedia = async ( + req: Request<{ pid: string }, {}, { mediaPid: string, tableToUpdate: string }>, + res: Response) => { + if (req.auth?.permission_level != "ELEVATED") { + res.status(403).json(createInsufficientPermissionsError()); + } + + const zBody = linkMediaBody.safeParse(req.body); + + if(zBody.success === false) { + return res.status(400).json( + generateInvalidBodyError({ + mediaPid: DataType.UUID, + tableToUpdate: DataType.STRING, + }) + ); + } + + const { pid } = req.params; + const { mediaPid, tableToUpdate } = zBody.data; + + const updatedRec = await getPrismaUpdateFKT(tableToUpdate)({ + where: { pid }, + data: { + visual: { connect: { pid: mediaPid } }, + }, + }); + + if (!updatedRec) { + throw new NotFoundError(tableToUpdate, pid); + } + + return res.status(200).json({ + type: "success", + payload: {}, + }); +}; + +export const unlinkMedia = async ( + req: Request<{ pid: string, mediaPid: string }, {}, { tableToUpdate: string }>, + res: Response) => { + if (req.auth?.permission_level != "ELEVATED") { + res.status(403).json(createInsufficientPermissionsError()); + } + + const zBody = linkMediaBody.safeParse(req.body); + + if(zBody.success === false) { + return res.status(400).json( + generateInvalidBodyError({ + mediaPid: DataType.UUID, + tableToUpdate: DataType.STRING, + }) + ); + } + + const { pid } = req.params; + const { mediaPid, tableToUpdate } = zBody.data; + + try { + await getPrismaUpdateFKT(tableToUpdate)({ + where: pid, + data: { visual: { disconnect: { pid: mediaPid } }, + }, + }); + return res.status(204).end(); + } catch (e) { + if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { + throw new NotFoundError(tableToUpdate, pid); + } + + throw e; + } +}; + +function getPrismaUpdateFKT( tableToUpdate: string ): Function { + switch(tableToUpdate) { + case "EVENT": return prisma.event.update; + case "DISCIPLINE": return prisma.discipline.update; + default: return prisma.roleSchema.update; + } +} diff --git a/src/Controllers/role_schema.controller.ts b/src/Controllers/role_schema.controller.ts index 36265de..78951d0 100644 --- a/src/Controllers/role_schema.controller.ts +++ b/src/Controllers/role_schema.controller.ts @@ -123,61 +123,3 @@ export const createRoleSchema = async ( throw e; } }; - -interface visualParams { - schemaPid: string; -} - -interface visualBody { - mediaPid: string; -} - -export const addVisual = async (req: Request, res: Response) => { - if (req.auth?.permission_level != "ELEVATED") { - res.status(403).json(createInsufficientPermissionsError()); - } - - const { schemaPid } = req.params; - - const schema = await prisma.roleSchema.update({ - where: { pid: schemaPid }, - data: { - visual: { connect: { pid: req.body.mediaPid } }, - }, - }); - - if (!schema) { - throw new NotFoundError("role_schema", schemaPid); - } - - return res.status(200).json({ - type: "success", - payload: {}, - }); -}; - -export const deleteVisual = async (req: Request, res: Response) => { - if (req.auth?.permission_level != "ELEVATED") { - res.status(403).json(createInsufficientPermissionsError()); - } - - const { schemaPid, pid } = req.params; - - try { - await prisma.roleSchema.update({ - where: { - pid: schemaPid, - }, - data: { - visual: { disconnect: { pid } }, - }, - }); - return res.status(204).end(); - } catch (e) { - if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError("role_schema", schemaPid); - } - - throw e; - } -}; diff --git a/src/Routes/discipline.routes.ts b/src/Routes/discipline.routes.ts index 2d97a8e..288cc30 100644 --- a/src/Routes/discipline.routes.ts +++ b/src/Routes/discipline.routes.ts @@ -1,10 +1,8 @@ import express from "express"; import eventRouter from "./event.routes"; import { - addVisual, createDiscipline, deleteDiscipline, - deleteVisual, getAllDisciplines, getDiscipline, } from "../Controllers/discipline.controller"; @@ -18,18 +16,6 @@ router.get("/:pid", getDiscipline); router.delete<"/:pid", { pid: string }>("/:pid", requireAuthentication, deleteDiscipline); -router.post<"/:disciplinePid/images", { disciplinePid: string }>( - "/:disciplinePid/images", - requireAuthentication, - addVisual -); - -router.delete<"/:disciplinePid/images/:pid", { disciplinePid: string; pid: string }>( - "/:disciplinePid/images/:pid", - requireAuthentication, - deleteVisual -); - eventRouter.post("/:eventPid/disciplines", requireAuthentication, createDiscipline); export default router; diff --git a/src/Routes/event.routes.ts b/src/Routes/event.routes.ts index 5e68bd8..7c2d34d 100644 --- a/src/Routes/event.routes.ts +++ b/src/Routes/event.routes.ts @@ -2,9 +2,7 @@ import Express from "express"; import { string } from "zod"; import { addEvent, - addVisual, deleteEvent, - deleteVisual, getAllEvents, getEvent, updateEvent, @@ -22,12 +20,4 @@ router.patch<"/:pid/", { pid: string }>("/:pid/", requireAuthentication, updateE router.delete<"/:pid/", { pid: string }>("/:pid/", requireAuthentication, deleteEvent); -router.post<"/:eventPid/media", { eventPid: string }>("/:eventPid/media", requireAuthentication, addVisual); - -router.delete<"/:eventPid/media/:pid", { eventPid: string; pid: string }>( - "/:eventPid/media/:pid", - requireAuthentication, - deleteVisual -); - export default router; diff --git a/src/Routes/media.routes.ts b/src/Routes/media.routes.ts index f340de1..e4c633a 100644 --- a/src/Routes/media.routes.ts +++ b/src/Routes/media.routes.ts @@ -1,7 +1,7 @@ import express from "express"; import fileUpload from "express-fileupload"; import { requireAuthentication } from "../Middleware/auth/auth"; -import { deleteMedia, getAllMedia, getMediaMeta, uploadImage } from "../Controllers/media.controller"; +import { deleteMedia, getAllMedia, getMediaMeta, linkMedia, unlinkMedia, uploadImage } from "../Controllers/media.controller"; import eventRouter from "./event.routes"; import disciplineRouter from "./discipline.routes"; import roleSchemaRouter from "./role_schema.routes"; @@ -19,4 +19,28 @@ router.get("/:pid/meta", getMediaMeta); router.delete("/:pid", requireAuthentication, deleteMedia); +eventRouter.post<"/:pid/media", { pid: string }>( + "/:pid/media", requireAuthentication, linkMedia +); + +eventRouter.delete<"/:pid/media/:mediaPid", { pid: string, mediaPid: string }>( + "/:pid/media/:mediaPid", requireAuthentication, unlinkMedia +); + +disciplineRouter.post<"/:pid/media", { pid: string }>( + "/:pid/media", requireAuthentication, linkMedia +); + +disciplineRouter.delete<"/:pid/media/:mediaPid", { pid: string, mediaPid: string }>( + "/:pid/media/:mediaPid", requireAuthentication, unlinkMedia +); + +roleSchemaRouter.post<"/:pid/media", { pid: string }>( + "/:pid/media", requireAuthentication, linkMedia +); + +roleSchemaRouter.delete<"/:pid/media/:mediaPid", { pid: string, mediaPid: string }>( + "/:pid/media/:mediaPid", requireAuthentication, unlinkMedia +); + export default router; diff --git a/src/Routes/role_schema.routes.ts b/src/Routes/role_schema.routes.ts index f6ada5f..688dafc 100644 --- a/src/Routes/role_schema.routes.ts +++ b/src/Routes/role_schema.routes.ts @@ -1,9 +1,7 @@ import express from "express"; import disciplineRouter from "./discipline.routes"; import { - addVisual, createRoleSchema, - deleteVisual, getAllRoleSchemas, getAllRoleSchemasWithParam, getRoleSchema, @@ -20,12 +18,4 @@ disciplineRouter.get("/:disciplinePid/role-schemas", getAllRoleSchemasWithParam) disciplineRouter.post("/:disciplinePid/role-schemas", requireAuthentication, createRoleSchema); -router.post<"/:schemaPid/images", { schemaPid: string }>("/:schemaPid/images", requireAuthentication, addVisual); - -router.delete<"/:schemaPid/images/:pid", { schemaPid: string; pid: string }>( - "/:schemaPid/images/:pid", - requireAuthentication, - deleteVisual -); - export default router; From ba1d09d1813cfa4dccf63d715ac4aa70f59c5d78 Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Sun, 29 May 2022 21:08:40 +0200 Subject: [PATCH 6/9] media bugfixes --- src/Controllers/event.controller.ts | 2 - src/Controllers/media.controller.ts | 67 +++++++++++++---------------- 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/Controllers/event.controller.ts b/src/Controllers/event.controller.ts index 70cdc57..9480148 100644 --- a/src/Controllers/event.controller.ts +++ b/src/Controllers/event.controller.ts @@ -9,8 +9,6 @@ import { createInsufficientPermissionsError, DataType, generateError, generateIn require("express-async-errors"); const EventBody = z.object({ - pid: z.string().max(0), - id: z.string().max(0), name: z.string(), date: z.string(), briefDescription: z.string(), diff --git a/src/Controllers/media.controller.ts b/src/Controllers/media.controller.ts index 83a34c3..22802a7 100644 --- a/src/Controllers/media.controller.ts +++ b/src/Controllers/media.controller.ts @@ -1,4 +1,4 @@ -import { Request, response, Response } from "express"; +import { NextFunction, Request, response, Response } from "express"; import fs from "fs"; import isSvg from "is-svg"; import { fromBuffer as fileTypeFromBuffer } from "file-type"; @@ -17,13 +17,6 @@ import { updateEvent } from "./event.controller"; require("express-async-errors"); -const linkMediaBody = z.object({ - tableToUpdate: z.enum(["EVENT", "ROLE_SCHEMA", "DISCIPLINE"]), - mediaPid: z.string(), -}); - -const unlinkMediaBody = linkMediaBody.omit({ mediaPid: true, }); - function createMediaLinks(fileName: string) { return [{ rel: "self", type: "GET", href: `/api/media/${fileName}` }]; } @@ -203,27 +196,25 @@ export const deleteMedia = async (req: Request, res: Response) => { // and call it before calling (un)linkMedia export const linkMedia = async ( - req: Request<{ pid: string }, {}, { mediaPid: string, tableToUpdate: string }>, + req: Request<{ pid: string }, {}, { mediaPid: string }>, res: Response) => { if (req.auth?.permission_level != "ELEVATED") { res.status(403).json(createInsufficientPermissionsError()); } - const zBody = linkMediaBody.safeParse(req.body); + const { pid } = req.params; + const { mediaPid } = req.body; + const tableToUpdate = req.originalUrl.split("/"); - if(zBody.success === false) { + if(typeof mediaPid !== "string") { return res.status(400).json( generateInvalidBodyError({ mediaPid: DataType.UUID, - tableToUpdate: DataType.STRING, }) ); } - const { pid } = req.params; - const { mediaPid, tableToUpdate } = zBody.data; - - const updatedRec = await getPrismaUpdateFKT(tableToUpdate)({ + const updatedRec = await getPrismaUpdateFKT(tableToUpdate[2])({ where: { pid }, data: { visual: { connect: { pid: mediaPid } }, @@ -231,7 +222,7 @@ export const linkMedia = async ( }); if (!updatedRec) { - throw new NotFoundError(tableToUpdate, pid); + throw new NotFoundError(tableToUpdate[2], pid); } return res.status(200).json({ @@ -241,36 +232,36 @@ export const linkMedia = async ( }; export const unlinkMedia = async ( - req: Request<{ pid: string, mediaPid: string }, {}, { tableToUpdate: string }>, + req: Request<{ pid: string, mediaPid: string }>, res: Response) => { if (req.auth?.permission_level != "ELEVATED") { res.status(403).json(createInsufficientPermissionsError()); } - const zBody = linkMediaBody.safeParse(req.body); - - if(zBody.success === false) { - return res.status(400).json( - generateInvalidBodyError({ - mediaPid: DataType.UUID, - tableToUpdate: DataType.STRING, - }) - ); - } - - const { pid } = req.params; - const { mediaPid, tableToUpdate } = zBody.data; + const { pid, mediaPid } = req.params; + const tableToUpdate = req.originalUrl.split("/"); try { - await getPrismaUpdateFKT(tableToUpdate)({ - where: pid, - data: { visual: { disconnect: { pid: mediaPid } }, - }, + await getPrismaUpdateFKT(tableToUpdate[2])({ + where: { pid }, + data: { visual: { disconnect: { pid: mediaPid } } }, }); return res.status(204).end(); } catch (e) { if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError(tableToUpdate, pid); + console.log("not found error"); + throw new NotFoundError(tableToUpdate[2], pid); + } + if (e instanceof Prisma.PrismaClientUnknownRequestError) { + return res.status(500).json({ + type: "error", + payload: { + message: "Unknown error occurred with your request. Check if your parameters are correct", + schema: { + eventId: DataType.UUID, + }, + }, + }); } throw e; @@ -279,8 +270,8 @@ export const unlinkMedia = async ( function getPrismaUpdateFKT( tableToUpdate: string ): Function { switch(tableToUpdate) { - case "EVENT": return prisma.event.update; - case "DISCIPLINE": return prisma.discipline.update; + case "events": return prisma.event.update; + case "disciplines": return prisma.discipline.update; default: return prisma.roleSchema.update; } } From 569695245fd787079e1d67a771a68b68e2cfa0ee Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Thu, 2 Jun 2022 00:09:51 +0200 Subject: [PATCH 7/9] patching complications after merging and review suggestions --- src/Controllers/discipline.controller.ts | 90 ++------------- src/Controllers/event.controller.ts | 122 ++++++++------------- src/Controllers/media.controller.ts | 45 ++------ src/Controllers/organisation.controller.ts | 13 +-- src/Controllers/participant.controller.ts | 32 ++---- src/Controllers/role.controller.ts | 87 ++++----------- src/Controllers/role_schema.controller.ts | 50 ++++++++- src/Controllers/team.controller.ts | 32 ++++-- src/Routes/participant.routes.ts | 21 ++-- src/Routes/role.routes.ts | 2 + 10 files changed, 185 insertions(+), 309 deletions(-) diff --git a/src/Controllers/discipline.controller.ts b/src/Controllers/discipline.controller.ts index bc85a7e..bef8240 100644 --- a/src/Controllers/discipline.controller.ts +++ b/src/Controllers/discipline.controller.ts @@ -1,7 +1,6 @@ import { Prisma, Organisation, Admin, AdminLevel, Team } from "@prisma/client"; import { PrismaClientKnownRequestError, PrismaClientUnknownRequestError } from "@prisma/client/runtime"; import { Request, Response } from "express"; -import { z } from "zod"; import prisma from "../lib/prisma"; import ForwardableError from "../Middleware/error/ForwardableError"; import NotFoundError from "../Middleware/error/NotFoundError"; @@ -17,11 +16,12 @@ import { require("express-async-errors"); - const InitialDisciplineBody = z.object({ name: z.string().min(1), minTeamSize: z.number(), maxTeamSize: z.number(), + briefDescription: z.string(), + fullDescription: z.string(), }); const disciplineRefiner = [ @@ -29,7 +29,9 @@ const disciplineRefiner = [ { message: "The minTeamSize must be smaller or equal to the maxTeamSize" }, ] as const; -const DisciplineBody = InitialDisciplineBody.refine(...disciplineRefiner); +const DisciplineBody = InitialDisciplineBody.partial({ briefDescription: true, fullDescription: true }).refine( + ...disciplineRefiner +); const updateDisciplineBody = InitialDisciplineBody.partial().refine(...disciplineRefiner); const basicDiscipline = { @@ -132,84 +134,6 @@ export const getDiscipline = async (req: Request, res: }); }; -export const updateDiscipline = async (req: Request<{ pid: string }>, res: Response) => { - if (req.auth?.permission_level !== "ELEVATED") { - res.status(403).json(createInsufficientPermissionsError()); - } - - const { pid } = req.params; - - const result = UpdateDisciplineBody.safeParse(req.body); - - if (result.success === false) { - return res.status(400).json( - generateInvalidBodyError({ - name: DataType.STRING, - minTeamSize: DataType.NUMBER, - maxTeamSize: DataType.NUMBER, - briefDescription: DataType.STRING, - ["fullDescription?"]: DataType.STRING, - }) - ); - } - - const body = result.data; - - try { - const discipline = await prisma.discipline.update({ - where: { pid }, - data: { - name: body.name, - minTeamSize: body.minTeamSize, - maxTeamSize: body.maxTeamSize, - briefDescription: body.briefDescription, - fullDescription: body.fullDescription, - }, - select: { - pid: true, - name: true, - minTeamSize: true, - maxTeamSize: true, - briefDescription: true, - fullDescription: true, - }, - }); - - if (!discipline) { - throw new NotFoundError("discipline", pid); - } - - res.status(200).json({ - type: "success", - payload: { - discipline, - }, - }); - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - return res.status(500).json({ - type: "error", - payload: { - message: `Internal Server error occured. Try again later`, - }, - }); - } - if (e instanceof Prisma.PrismaClientUnknownRequestError) { - return res.status(500).json({ - type: "error", - payload: { - message: "Unknown error occurred with your request. Check if your parameters are correct", - schema: { - eventId: DataType.UUID, - }, - }, - }); - } - - throw e; - } -}; - interface CreateDisciplineBody { name?: string; minTeamSize?: number; @@ -272,6 +196,8 @@ export const updateDiscipline = async (req: Request<{ pid: string }>, res: Respo name: DataType.STRING, minTeamSize: DataType.NUMBER, maxTeamSize: DataType.NUMBER, + briefDescription: DataType.STRING, + ["fullDescription?"]: DataType.STRING, }, result.error ) @@ -288,6 +214,8 @@ export const updateDiscipline = async (req: Request<{ pid: string }>, res: Respo name: body.name, minTeamSize: body.minTeamSize, maxTeamSize: body.maxTeamSize, + briefDescription: body.briefDescription, + fullDescription: body.fullDescription, }, select: basicDiscipline, }); diff --git a/src/Controllers/event.controller.ts b/src/Controllers/event.controller.ts index 1e558c7..3dfcd84 100644 --- a/src/Controllers/event.controller.ts +++ b/src/Controllers/event.controller.ts @@ -8,9 +8,13 @@ import { createInsufficientPermissionsError, DataType, generateError, generateIn require("express-async-errors"); +export const dateSchema = z.preprocess((arg) => { + if (typeof arg == "string" || arg instanceof Date) return new Date(arg); +}, z.date()); + const EventBody = z.object({ - name: z.string(), - date: z.string(), + name: z.string().min(1), + date: dateSchema, briefDescription: z.string(), fullDescription: z.string(), }); @@ -21,27 +25,32 @@ const CreateEventBody = EventBody.partial({ fullDescription: true, }); -export const getAllEvents = async (req: Request, res: Response) => { - const events = await prisma.event.findMany({ +const basicEvent = { + pid: true, + name: true, + date: true, + briefDescription: true, + fullDescription: true, +} as const; + +const detailedEvent = { + pid: true, + name: true, + date: true, + briefDescription: true, + fullDescription: true, + visual: { select: { pid: true, description: true } }, + disciplines: { select: { pid: true, name: true, - date: true, - briefDescription: true, - fullDescription: true, - visual: { select: { pid: true, description: true } }, - disciplines: { - select: { - pid: true, - name: true, - }}, - organisations: { - select: { - pid: true, - name: true, - } - } }, + }, +} as const; + +export const getAllEvents = async (req: Request, res: Response) => { + const events = await prisma.event.findMany({ + select: detailedEvent, }); res.status(200).json({ @@ -68,27 +77,7 @@ export const getEvent = async (req: Request, res: Response) => { where: { pid: eventId, }, - select: { - pid: true, - name: true, - date: true, - briefDescription: true, - fullDescription: true, - visual: { select: { pid: true, description: true } }, - disciplines: { - select: { - pid: true, - name: true, - briefDescription: true, - fullDescription: true, - }}, - organisations: { - select: { - pid: true, - name: true, - } - } - }, + select: detailedEvent, }); if (!event) { @@ -134,19 +123,20 @@ export const addEvent = async (req: Request, res: Response) => { const result = CreateEventBody.safeParse(req.body); - if(result.success === false){ + if (result.success === false) { return res.status(400).json( - generateInvalidBodyError({ - name: DataType.STRING, - date: DataType.DATETIME, - briefDescription: DataType.STRING, - ["fullDescription?"]: DataType.STRING, - }) + generateInvalidBodyError( + { + name: DataType.STRING, + date: DataType.DATETIME, + briefDescription: DataType.STRING, + ["fullDescription?"]: DataType.STRING, + }, + result.error + ) ); } - //TODO: Check if date is valid - const event = await prisma.event.create({ data: { name: req.body.name, @@ -154,13 +144,7 @@ export const addEvent = async (req: Request, res: Response) => { briefDescription: req.body.briefDescription, fullDescription: req.body.fullDescription, }, - select: { - pid: true, - name: true, - date: true, - briefDescription: true, - fullDescription: true, - }, + select: basicEvent, }); res.status(201).json({ @@ -214,10 +198,6 @@ export const updateEvent = async (req: Request<{ pid: string }>, res: Response) }, }); - if (!event) { - throw new NotFoundError("event", pid); - } - res.status(200).json({ type: "success", payload: { @@ -225,24 +205,8 @@ export const updateEvent = async (req: Request<{ pid: string }>, res: Response) }, }); } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError) { - return res.status(500).json({ - type: "error", - payload: { - message: `Internal Server error occured. Try again later`, - }, - }); - } - if (e instanceof Prisma.PrismaClientUnknownRequestError) { - return res.status(500).json({ - type: "error", - payload: { - message: "Unknown error occurred with your request. Check if your parameters are correct", - schema: { - eventId: DataType.UUID, - }, - }, - }); + if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { + throw new NotFoundError("discipline", pid); } throw e; @@ -267,7 +231,7 @@ export const deleteEvent = async (req: Request, res: Res return res.status(204).end(); } catch (e) { if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { - return res.status(404).json(generateError(`The event with the ID ${pid} could not be found`)); + throw new NotFoundError("discipline", pid); } throw e; diff --git a/src/Controllers/media.controller.ts b/src/Controllers/media.controller.ts index 22802a7..11a2cc7 100644 --- a/src/Controllers/media.controller.ts +++ b/src/Controllers/media.controller.ts @@ -1,4 +1,4 @@ -import { NextFunction, Request, response, Response } from "express"; +import { Request, Response } from "express"; import fs from "fs"; import isSvg from "is-svg"; import { fromBuffer as fileTypeFromBuffer } from "file-type"; @@ -8,12 +8,8 @@ import prisma from "../lib/prisma"; import NotFoundError from "../Middleware/error/NotFoundError"; import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; import { generateInvalidBodyError, DataType } from "./common"; -import { type } from "os"; import { unlink } from "fs/promises"; import ForwardableError from "../Middleware/error/ForwardableError"; -import SchemaError from "../Middleware/error/SchemaError"; -import { z } from "zod"; -import { updateEvent } from "./event.controller"; require("express-async-errors"); @@ -101,7 +97,6 @@ export const uploadImage = async (req: Request, res: Response) => { const fileName = file.md5 + (fileIsSvg ? ".svg" : "." + fileType?.ext); try { - //generate record const media = await prisma.media.create({ data: { pid: fileName, @@ -192,12 +187,7 @@ export const deleteMedia = async (req: Request, res: Response) => { } }; -//TODO: maybe create a function that adds the tableToUpdate based on path -// and call it before calling (un)linkMedia - -export const linkMedia = async ( - req: Request<{ pid: string }, {}, { mediaPid: string }>, - res: Response) => { +export const linkMedia = async (req: Request<{ pid: string }, {}, { mediaPid: string }>, res: Response) => { if (req.auth?.permission_level != "ELEVATED") { res.status(403).json(createInsufficientPermissionsError()); } @@ -206,7 +196,7 @@ export const linkMedia = async ( const { mediaPid } = req.body; const tableToUpdate = req.originalUrl.split("/"); - if(typeof mediaPid !== "string") { + if (typeof mediaPid !== "string") { return res.status(400).json( generateInvalidBodyError({ mediaPid: DataType.UUID, @@ -231,9 +221,7 @@ export const linkMedia = async ( }); }; -export const unlinkMedia = async ( - req: Request<{ pid: string, mediaPid: string }>, - res: Response) => { +export const unlinkMedia = async (req: Request<{ pid: string; mediaPid: string }>, res: Response) => { if (req.auth?.permission_level != "ELEVATED") { res.status(403).json(createInsufficientPermissionsError()); } @@ -249,29 +237,20 @@ export const unlinkMedia = async ( return res.status(204).end(); } catch (e) { if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { - console.log("not found error"); throw new NotFoundError(tableToUpdate[2], pid); } - if (e instanceof Prisma.PrismaClientUnknownRequestError) { - return res.status(500).json({ - type: "error", - payload: { - message: "Unknown error occurred with your request. Check if your parameters are correct", - schema: { - eventId: DataType.UUID, - }, - }, - }); - } throw e; } }; -function getPrismaUpdateFKT( tableToUpdate: string ): Function { - switch(tableToUpdate) { - case "events": return prisma.event.update; - case "disciplines": return prisma.discipline.update; - default: return prisma.roleSchema.update; +function getPrismaUpdateFKT(tableToUpdate: string): Function { + switch (tableToUpdate) { + case "events": + return prisma.event.update; + case "disciplines": + return prisma.discipline.update; + default: + return prisma.roleSchema.update; } } diff --git a/src/Controllers/organisation.controller.ts b/src/Controllers/organisation.controller.ts index 146594e..6007947 100644 --- a/src/Controllers/organisation.controller.ts +++ b/src/Controllers/organisation.controller.ts @@ -12,6 +12,7 @@ import { } from "./common"; import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; import { Prisma } from "@prisma/client"; +import NotFoundError from "../Middleware/error/NotFoundError"; function validateOranisationName(name: string) { return name.length > 0; @@ -187,16 +188,12 @@ export const updateOrganisation = async ( }, }); } catch (e) { - if (e instanceof PrismaClientKnownRequestError) { - if (e.code === "P2025") { - return res.status(404).json(generateError(`The organisation with the ID ${pid} could not be found`)); - } - } else if (e instanceof PrismaClientUnknownRequestError) { - return res.status(400).send(generateError("Unkonwn error occured. This could be due to malformed IDs")); + if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { + throw new NotFoundError("discipline", pid); } - } - return res.status(500).json(genericError); + throw e; + } }; interface DeleteOrganisationQueryParams { diff --git a/src/Controllers/participant.controller.ts b/src/Controllers/participant.controller.ts index cfc6e59..5c7a338 100644 --- a/src/Controllers/participant.controller.ts +++ b/src/Controllers/participant.controller.ts @@ -11,7 +11,7 @@ import { import { Job, Prisma } from "@prisma/client"; import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; import NotFoundError from "../Middleware/error/NotFoundError"; -import { requireResponsibleForGroup } from "../Middleware/auth/auth"; +import { requireConfiguredAuthentication, requireResponsibleForGroup } from "../Middleware/auth/auth"; //TODO: add TeamleaderAuthentification @@ -44,8 +44,8 @@ const returnedParticipant = { }, } as const; -// REVIEW: Location of this endpoints (/groups, /teams, /participants, ...?) -export const createParticipant = async (req: Request<{ pid: string }>, res: Response) => { +// at: POST api/teams/:teamPid/participant/ +export const createParticipant = async (req: Request<{ teamPid: string }>, res: Response) => { const result = ParticipantBody.safeParse(req.body); if (result.success === false) { @@ -61,17 +61,7 @@ export const createParticipant = async (req: Request<{ pid: string }>, res: Resp ); } const body = result.data; - const { pid } = req.params; - - /* - if (!req.auth?.isAuthenticated || req.teamleader?.team != pid) { - return res.status(500).json(AUTH_ERROR); - } - if (req.teamleader?.team != pid) { - return res.status(500).json(AUTH_ERROR); - } - requireResponsibleForGroup(req.auth, req.body.groupId); - */ + const { teamPid } = req.params; try { const participant = await prisma.participant.create({ @@ -80,7 +70,7 @@ export const createParticipant = async (req: Request<{ pid: string }>, res: Resp lastName: body.lastName, relevance: "MEMBER", group: { connect: { pid: body.groupId } }, - team: { connect: { pid } }, + team: { connect: { pid: teamPid } }, }, select: returnedParticipant, }); @@ -93,16 +83,15 @@ export const createParticipant = async (req: Request<{ pid: string }>, res: Resp if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { return res .status(404) - .json(generateError(`Could not link to team with ID '${pid}, or group with ID ${body.groupId}'`)); + .json(generateError(`Could not link to team with ID '${teamPid}, or group with ID ${body.groupId}'`)); } throw e; } }; +// at: PATCH api/participants/:pid/ export const updateParticipant = async (req: Request<{ pid: string }>, res: Response) => { - //insert TeamleaderAuth - - const result = ParticipantBody.partial().safeParse(req.body); // Should be partial, right? + const result = ParticipantBody.partial().safeParse(req.body); if (result.success === false) { return res.status(400).json( @@ -144,9 +133,8 @@ export const updateParticipant = async (req: Request<{ pid: string }>, res: Resp } }; +// at: DELETE api/participants/:pid/ export const deleteParticipant = async (req: Request<{ pid: string }>, res: Response) => { - //insert TeamleaderAuth - const { pid } = req.params; try { @@ -155,7 +143,7 @@ export const deleteParticipant = async (req: Request<{ pid: string }>, res: Resp return res.status(204).end(); } catch (e) { if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { - return res.status(404).json(generateError(`The participant with the ID ${pid} could not be found`)); + throw new NotFoundError("participant", pid); } throw e; diff --git a/src/Controllers/role.controller.ts b/src/Controllers/role.controller.ts index feff325..a55fd17 100644 --- a/src/Controllers/role.controller.ts +++ b/src/Controllers/role.controller.ts @@ -8,6 +8,30 @@ import { createInsufficientPermissionsError, DataType, generateInvalidBodyError require("express-async-errors"); +const detailedRole = { + pid: true, + score: true, + schema: { + select: { + pid: true, + name: true, + }, + }, + participant: { + select: { + pid: true, + firstName: true, + lastName: true, + }, + }, + team: { + select: { + pid: true, + name: true, + }, + }, +}; + /** * * @param teamPid: Pid of the team to add the roles to @@ -94,66 +118,3 @@ export async function assignParticipantToRole(req: Request<{ pid: string }>, res }, }); } - -export const updateRoleScore = async (req: Request<{ pid: string }, {}, { score: string }>, res: Response) => { - if (req.auth?.permission_level != "ELEVATED") { - res.status(403).json(createInsufficientPermissionsError()); - } - - const { score } = req.body; - - if (typeof score !== "string") { - res.status(400).json(generateInvalidBodyError({ score: DataType.STRING })); - } - - const { pid } = req.params; - - try { - const role = await prisma.role.update({ - where: { pid }, - data: { score }, - select: { - pid: true, - score: true, - schema: { - select: { - pid: true, - name: true, - }, - }, - participant: { - select: { - pid: true, - firstName: true, - lastName: true, - }, - }, - team: { - select: { - pid: true, - name: true, - }, - }, - }, - }); - - res.status(200).json({ - type: "success", - payload: { - role, - }, - }); - } catch (e) { - if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { - throw new NotFoundError("role", pid); - } - - throw e; - } -}; - -export async function deleteRolesFromTeam(teamPid: string) { - await prisma.role.deleteMany({ - where: { team: { pid: teamPid } }, - }); -} diff --git a/src/Controllers/role_schema.controller.ts b/src/Controllers/role_schema.controller.ts index 8b05caf..f375451 100644 --- a/src/Controllers/role_schema.controller.ts +++ b/src/Controllers/role_schema.controller.ts @@ -20,7 +20,7 @@ const RoleSchemaBody = z.object({ schema: z.string(), }); -const UpdateRoleSchema = RoleSchemaBody.partial(); +const UpdateBody = RoleSchemaBody.partial(); const roleSchema = { pid: true, @@ -133,3 +133,51 @@ export const createRoleSchema = async ( throw e; } }; + +export const UpdateRoleSchema = async (req: Request<{ pid: string }>, res: Response) => { + if (req.auth?.permission_level !== "ELEVATED") { + res.status(403).json(createInsufficientPermissionsError()); + } + + const { pid } = req.params; + + const result = UpdateBody.safeParse(req.body); + + if (result.success === false) { + return res.status(400).json( + generateInvalidBodyError( + { + name: DataType.STRING, + schema: DataType.STRING, + }, + result.error + ) + ); + } + + const body = result.data; + + try { + const schema = await prisma.roleSchema.update({ + where: { pid }, + data: { + name: body.name, + schema: body.schema, + }, + select: roleSchema, + }); + + res.status(200).json({ + type: "success", + payload: { + schema, + }, + }); + } catch (e) { + if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { + throw new NotFoundError("discipline", pid); + } + + throw e; + } +}; diff --git a/src/Controllers/team.controller.ts b/src/Controllers/team.controller.ts index 1f2a5dd..35d6101 100644 --- a/src/Controllers/team.controller.ts +++ b/src/Controllers/team.controller.ts @@ -3,6 +3,8 @@ import prisma from "../lib/prisma"; import { createInsufficientPermissionsError, DataType, generateInvalidBodyError } from "./common"; import { requireLeaderOfTeam } from "../Middleware/auth/teamleaderAuth"; import { z } from "zod"; +import { Prisma } from "@prisma/client"; +import NotFoundError from "../Middleware/error/NotFoundError"; const TeamBody = z.object({ teamName: z.string().min(1), @@ -69,18 +71,26 @@ export const updateTeam = async (req: Request, res: Response) => { return res.status(401).json(createInsufficientPermissionsError("STANDARD")); } - const team = prisma.team.update({ - where: { - pid: body.pid, - }, - data: { - name: body.teamName, - discipline: { connect: { pid: body.disciplineId } }, - leaderEmail: body.leaderEmail, - }, - }); + try { + const team = prisma.team.update({ + where: { + pid: body.pid, + }, + data: { + name: body.teamName, + discipline: { connect: { pid: body.disciplineId } }, + leaderEmail: body.leaderEmail, + }, + }); - res.status(204).json(team); + res.status(204).json(team); + } catch (e) { + if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") { + throw new NotFoundError("discipline", body.pid); + } + + throw e; + } }; export const deleteTeam = async (req: Request, res: Response) => { diff --git a/src/Routes/participant.routes.ts b/src/Routes/participant.routes.ts index 21937a2..532387a 100644 --- a/src/Routes/participant.routes.ts +++ b/src/Routes/participant.routes.ts @@ -1,29 +1,28 @@ import express from "express"; import teamRouter from "./team.routes"; import { createParticipant, deleteParticipant, updateParticipant } from "../Controllers/participant.controller"; -import { requireAuthentication } from "../Middleware/auth/auth"; -import { requireTeamleaderAuthentication } from "../Middleware/auth/teamleaderAuth"; +import { requireAuthentication, requireConfiguredAuthentication } from "../Middleware/auth/auth"; const router = express.Router(); -teamRouter.post<"/:pid/participant/", { pid: string }>( - "/:pid/participant/", +teamRouter.post<"/:teamPid/participant/", { teamPid: string }>( + "/:teamPid/participant/", requireAuthentication, - requireTeamleaderAuthentication, + requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), createParticipant ); -teamRouter.patch<"/:pid/participant/", { pid: string }>( - "/:pid/participant/", +router.patch<"/:pid/", { pid: string }>( + "/:pid/", requireAuthentication, - requireTeamleaderAuthentication, + requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), updateParticipant ); -teamRouter.delete<"/:pid/participant/", { pid: string }>( - "/:pid/participant/", +router.delete<"/:pid/", { pid: string }>( + "/:pid/", requireAuthentication, - requireTeamleaderAuthentication, + requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), deleteParticipant ); diff --git a/src/Routes/role.routes.ts b/src/Routes/role.routes.ts index 5bbd03e..dff8cc7 100644 --- a/src/Routes/role.routes.ts +++ b/src/Routes/role.routes.ts @@ -7,3 +7,5 @@ const router = Express.Router(); router.get<"team/:teamPid/", { teamPid: string }>("team/:teamPid/", getRolesForTeam); router.put<"/:pid/participant", { pid: string }>("/:pid/participant", assignParticipantToRole); + +export default router; From 0f0da062c68499bddd95e0859ba126624ea7f1df Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Fri, 3 Jun 2022 19:57:43 +0200 Subject: [PATCH 8/9] patched issues found during testing --- src/Controllers/discipline.controller.ts | 12 +++---- src/Controllers/group.controllers.ts | 2 +- src/Controllers/organisation.controller.ts | 2 +- src/Controllers/role.controller.ts | 2 -- src/Controllers/team.controller.ts | 40 ++++++++++++++-------- src/Controllers/user_auth.controller.ts | 6 ++-- src/Middleware/error/defaultRoutes.ts | 2 +- src/Routes/participant.routes.ts | 4 +-- src/Routes/role.routes.ts | 15 ++++++-- src/Routes/team.routes.ts | 14 ++++++-- src/app.ts | 10 ++++-- src/lib/mail.ts | 1 + 12 files changed, 74 insertions(+), 36 deletions(-) diff --git a/src/Controllers/discipline.controller.ts b/src/Controllers/discipline.controller.ts index bef8240..c898603 100644 --- a/src/Controllers/discipline.controller.ts +++ b/src/Controllers/discipline.controller.ts @@ -20,7 +20,7 @@ const InitialDisciplineBody = z.object({ name: z.string().min(1), minTeamSize: z.number(), maxTeamSize: z.number(), - briefDescription: z.string(), + briefDescription: z.string().min(1), fullDescription: z.string(), }); @@ -29,9 +29,7 @@ const disciplineRefiner = [ { message: "The minTeamSize must be smaller or equal to the maxTeamSize" }, ] as const; -const DisciplineBody = InitialDisciplineBody.partial({ briefDescription: true, fullDescription: true }).refine( - ...disciplineRefiner -); +const DisciplineBody = InitialDisciplineBody.partial({ fullDescription: true }).refine(...disciplineRefiner); const updateDisciplineBody = InitialDisciplineBody.partial().refine(...disciplineRefiner); const basicDiscipline = { @@ -158,17 +156,19 @@ export const createDiscipline = async (req: Request<{ eventPid: string }, {}, Cr name: DataType.STRING, minTeamSize: DataType.NUMBER, maxTeamSize: DataType.NUMBER, + briefDescription: DataType.STRING, + ["fullDescription?"]: DataType.STRING, }, result.error ) ); } - const { name, minTeamSize, maxTeamSize } = result.data; + const { name, minTeamSize, maxTeamSize, briefDescription } = result.data; try { const discipline = await prisma.discipline.create({ - data: { name, minTeamSize, maxTeamSize, event: { connect: { pid: req.params.eventPid } } }, + data: { name, minTeamSize, maxTeamSize, briefDescription, event: { connect: { pid: req.params.eventPid } } }, select: basicDiscipline, }); diff --git a/src/Controllers/group.controllers.ts b/src/Controllers/group.controllers.ts index 686ed7a..355a997 100644 --- a/src/Controllers/group.controllers.ts +++ b/src/Controllers/group.controllers.ts @@ -192,7 +192,7 @@ export const deleteGroup = async (req: Request, res: Res const { pid } = req.params; try { - prisma.group.delete({ where: { pid } }); + await prisma.group.delete({ where: { pid } }); return res.status(204).end(); } catch (e) { diff --git a/src/Controllers/organisation.controller.ts b/src/Controllers/organisation.controller.ts index 6007947..5a701fe 100644 --- a/src/Controllers/organisation.controller.ts +++ b/src/Controllers/organisation.controller.ts @@ -213,7 +213,7 @@ export const deleteOrganisation = async (req: Request, res const { participantPid } = zBody.data; const rolePid = req.params.pid; - requireResponsibleForParticipant(req.teamleader, participantPid); - const schema = await prisma.role.findFirst({ where: { pid: rolePid, team: { participants: { some: { pid: participantPid } } } }, select: { participant: { select: { pid: true, firstName: true, lastName: true } } }, diff --git a/src/Controllers/team.controller.ts b/src/Controllers/team.controller.ts index 35d6101..b49e2cb 100644 --- a/src/Controllers/team.controller.ts +++ b/src/Controllers/team.controller.ts @@ -24,8 +24,28 @@ interface CreateTeamBody { partGroupId: string; } +export const basicTeam = { + pid: true, + name: true, + discipline: { select: { pid: true } }, + roles: { + select: { + pid: true, + schema: { select: { name: true } }, + participant: { select: { pid: true } }, + }, + }, + participants: { + select: { + pid: true, + firstName: true, + lastName: true, + }, + }, +}; + export const getTeams = async (req: Request, res: Response) => { - const teams = prisma.team.findMany({ select: { pid: true, name: true, disciplineId: true } }); + const teams = await prisma.team.findMany({ select: basicTeam }); res.status(200).json(teams); }; @@ -33,13 +53,9 @@ export const getTeams = async (req: Request, res: Response) => { export const getTeam = async (req: Request, res: Response) => { const { pid } = req.params; - const team = prisma.team.findUnique({ + const team = await prisma.team.findUnique({ where: { pid }, - select: { - disciplineId: true, - name: true, - pid: true, - }, + select: basicTeam, }); res.status(200).json(team); @@ -72,7 +88,7 @@ export const updateTeam = async (req: Request, res: Response) => { } try { - const team = prisma.team.update({ + const team = await prisma.team.update({ where: { pid: body.pid, }, @@ -96,13 +112,7 @@ export const updateTeam = async (req: Request, res: Response) => { export const deleteTeam = async (req: Request, res: Response) => { const { pid } = req.params; - try { - requireLeaderOfTeam(req.teamleader, pid); - } catch { - return res.status(401).json(createInsufficientPermissionsError("STANDARD")); - } - - prisma.team.delete({ where: { pid } }); + await prisma.team.delete({ where: { pid } }); res.status(204).json("Welp its gone"); }; diff --git a/src/Controllers/user_auth.controller.ts b/src/Controllers/user_auth.controller.ts index 4205a20..64bb176 100644 --- a/src/Controllers/user_auth.controller.ts +++ b/src/Controllers/user_auth.controller.ts @@ -7,6 +7,7 @@ import { createInsufficientPermissionsError, DataType, generateInvalidBodyError import { generateTeamleaderJWT, requireLeaderOfTeam } from "../Middleware/auth/teamleaderAuth"; import { createRolesForTeam } from "./role.controller"; import { any, z } from "zod"; +import { basicTeam } from "./team.controller"; const TeamBody = z.object({ teamName: z.string().min(1), @@ -70,13 +71,13 @@ export const register = async (req: Request<{}, {}, CreateTeamBody>, res: Respon }, }); - //TODO: maybe use returned amount of created use? - createRolesForTeam(team.pid); + await createRolesForTeam(team.pid); const usid = nanoid(); (await mailClient).set(usid, team.pid); + // TODO: fix "eventname" verificationMail(req.body.leaderEmail, "eventname", usid); res.status(201).json({ type: "success", payload: { team } }); @@ -103,6 +104,7 @@ export const requestToken = async (req: Request, res: Response) => { (await mailClient).set(usid, team.pid); + // TODO: fix "eventname" verificationMail(team.leaderEmail, "eventname", usid); res.status(200).json({ type: "sucess", message: "Email sent!" }); diff --git a/src/Middleware/error/defaultRoutes.ts b/src/Middleware/error/defaultRoutes.ts index 4a15997..0050727 100644 --- a/src/Middleware/error/defaultRoutes.ts +++ b/src/Middleware/error/defaultRoutes.ts @@ -5,7 +5,7 @@ export function notFoundHandler(req: Request, res: Response) { return res.status(404).json({ type: "error", payload: { - message: `The ${req.method} HTTP method is implemented for '${req.path}'`, + message: `The ${req.method} HTTP method is not implemented for '${req.path}'`, _links: [ { rel: "root", diff --git a/src/Routes/participant.routes.ts b/src/Routes/participant.routes.ts index 532387a..fc30af0 100644 --- a/src/Routes/participant.routes.ts +++ b/src/Routes/participant.routes.ts @@ -5,8 +5,8 @@ import { requireAuthentication, requireConfiguredAuthentication } from "../Middl const router = express.Router(); -teamRouter.post<"/:teamPid/participant/", { teamPid: string }>( - "/:teamPid/participant/", +teamRouter.post<"/:teamPid/participants/", { teamPid: string }>( + "/:teamPid/participants/", requireAuthentication, requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), createParticipant diff --git a/src/Routes/role.routes.ts b/src/Routes/role.routes.ts index dff8cc7..c2bc58f 100644 --- a/src/Routes/role.routes.ts +++ b/src/Routes/role.routes.ts @@ -1,11 +1,22 @@ import Express from "express"; import { assignParticipantToRole, getRolesForTeam } from "../Controllers/role.controller"; +import { requireAuthentication, requireConfiguredAuthentication } from "../Middleware/auth/auth"; const router = Express.Router(); //TO DO: maybe transfer getRolesForTeam to team router -> Seconded -router.get<"team/:teamPid/", { teamPid: string }>("team/:teamPid/", getRolesForTeam); +router.get<"team/:teamPid/", { teamPid: string }>( + "team/:teamPid/", + requireAuthentication, + requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + getRolesForTeam +); -router.put<"/:pid/participant", { pid: string }>("/:pid/participant", assignParticipantToRole); +router.put<"/:pid/participant", { pid: string }>( + "/:pid/participant", + requireAuthentication, + requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + assignParticipantToRole +); export default router; diff --git a/src/Routes/team.routes.ts b/src/Routes/team.routes.ts index a12afb1..ff1ebac 100644 --- a/src/Routes/team.routes.ts +++ b/src/Routes/team.routes.ts @@ -6,9 +6,19 @@ import { deleteTeam, getTeam, getTeams, updateTeam } from "../Controllers/team.c const router = express.Router(); router.get("/", requireConfiguredAuthentication({ type: "admin", optional: false }), getTeams); -router.get("/:id", getTeam); +router.get( + "/:id", + requireAuthentication, + requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + getTeam +); router.put("/", requireTeamleaderAuthentication, updateTeam); -router.delete<"/:pid/", { pid: string }>("/:pid/", requireAuthentication, requireTeamleaderAuthentication, deleteTeam); +router.delete<"/:pid/", { pid: string }>( + "/:pid/", + requireAuthentication, + requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + deleteTeam +); export default router; diff --git a/src/app.ts b/src/app.ts index 9121346..d41ffba 100644 --- a/src/app.ts +++ b/src/app.ts @@ -14,7 +14,9 @@ import logger from "./Middleware/error/logger"; import debugLogger from "./Middleware/debug/logger"; import mediaRouter from "./Routes/media.routes"; import userRouter from "./Routes/user_auth.routes"; -import TeamRouter from "./Routes/team.routes"; +import teamRouter from "./Routes/team.routes"; +import roleRouter from "./Routes/role.routes"; +import participantRouter from "./Routes/participant.routes"; import { notFoundHandler, rootHandler } from "./Middleware/error/defaultRoutes"; // Set up async error handling @@ -87,7 +89,11 @@ async function main() { app.use("/api/users", userRouter); - app.use("/api/teams", TeamRouter); + app.use("/api/teams", teamRouter); + + app.use("/api/roles", roleRouter); + + app.use("/api/participants", participantRouter); app.get("/", rootHandler); app.get("/api", rootHandler); diff --git a/src/lib/mail.ts b/src/lib/mail.ts index c55fd8e..7c96463 100644 --- a/src/lib/mail.ts +++ b/src/lib/mail.ts @@ -66,6 +66,7 @@ const sendMail = async (from: string, to: string, subject: string, text?: string export const verificationMail = async (to: string, eventName: string, verificationLink: string) => { const raw = mjml.getTemplate("emailVerification"); + // TODO: the process.env.DOMAIN is undefined in Development mode !! verificationLink = "https://" + ("api." + process.env.DOMAIN ?? "localhost:3000/api") + "/users/verify/" + verificationLink; const message = Handlebars.compile(raw); From b3a1ec5fa531624c827835a6b460301bba8058f1 Mon Sep 17 00:00:00 2001 From: Laurin <60652077+Flexla54@users.noreply.github.com> Date: Fri, 3 Jun 2022 22:25:21 +0200 Subject: [PATCH 9/9] small fixes --- src/Controllers/participant.controller.ts | 25 ++++++++++++----------- src/Routes/participant.routes.ts | 14 +++++-------- src/Routes/role.routes.ts | 6 ++---- src/Routes/team.routes.ts | 6 ++---- 4 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/Controllers/participant.controller.ts b/src/Controllers/participant.controller.ts index 5c7a338..f5dfaa4 100644 --- a/src/Controllers/participant.controller.ts +++ b/src/Controllers/participant.controller.ts @@ -18,13 +18,14 @@ import { requireConfiguredAuthentication, requireResponsibleForGroup } from "../ // 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 -const ParticipantBody = z.object({ +const InitialParticipant = z.object({ firstName: z.string(), lastName: z.string(), - groupId: z.string().uuid(), - //job: z.enum(["TEAMLEADER", "MEMBER"]), + groupPid: z.string().uuid(), }); +const ParticipantBody = InitialParticipant.extend({ teamPid: z.string().uuid() }); + const returnedParticipant = { pid: true, firstName: true, @@ -45,7 +46,7 @@ const returnedParticipant = { } as const; // at: POST api/teams/:teamPid/participant/ -export const createParticipant = async (req: Request<{ teamPid: string }>, res: Response) => { +export const createParticipant = async (req: Request, res: Response) => { const result = ParticipantBody.safeParse(req.body); if (result.success === false) { @@ -54,14 +55,14 @@ export const createParticipant = async (req: Request<{ teamPid: string }>, res: { firstname: DataType.STRING, lastName: DataType.STRING, - groupId: DataType.UUID, + groupPid: DataType.UUID, + teamPid: DataType.UUID, }, result.error ) ); } const body = result.data; - const { teamPid } = req.params; try { const participant = await prisma.participant.create({ @@ -69,8 +70,8 @@ export const createParticipant = async (req: Request<{ teamPid: string }>, res: firstName: body.firstName, lastName: body.lastName, relevance: "MEMBER", - group: { connect: { pid: body.groupId } }, - team: { connect: { pid: teamPid } }, + group: { connect: { pid: body.groupPid } }, + team: { connect: { pid: body.teamPid } }, }, select: returnedParticipant, }); @@ -83,7 +84,7 @@ export const createParticipant = async (req: Request<{ teamPid: string }>, res: if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") { return res .status(404) - .json(generateError(`Could not link to team with ID '${teamPid}, or group with ID ${body.groupId}'`)); + .json(generateError(`Could not link to team with ID '${body.teamPid}, or group with ID ${body.groupPid}'`)); } throw e; } @@ -91,7 +92,7 @@ export const createParticipant = async (req: Request<{ teamPid: string }>, res: // at: PATCH api/participants/:pid/ export const updateParticipant = async (req: Request<{ pid: string }>, res: Response) => { - const result = ParticipantBody.partial().safeParse(req.body); + const result = InitialParticipant.partial().safeParse(req.body); if (result.success === false) { return res.status(400).json( @@ -99,7 +100,7 @@ export const updateParticipant = async (req: Request<{ pid: string }>, res: Resp { firstname: DataType.STRING, lastName: DataType.STRING, - groupId: DataType.UUID, + groupPid: DataType.UUID, }, result.error ) @@ -115,7 +116,7 @@ export const updateParticipant = async (req: Request<{ pid: string }>, res: Resp data: { firstName: body.firstName, lastName: body.lastName, - group: { connect: { pid: body.groupId } }, + group: { connect: { pid: body.groupPid } }, }, select: returnedParticipant, }); diff --git a/src/Routes/participant.routes.ts b/src/Routes/participant.routes.ts index fc30af0..7ba300f 100644 --- a/src/Routes/participant.routes.ts +++ b/src/Routes/participant.routes.ts @@ -1,28 +1,24 @@ import express from "express"; -import teamRouter from "./team.routes"; import { createParticipant, deleteParticipant, updateParticipant } from "../Controllers/participant.controller"; import { requireAuthentication, requireConfiguredAuthentication } from "../Middleware/auth/auth"; const router = express.Router(); -teamRouter.post<"/:teamPid/participants/", { teamPid: string }>( - "/:teamPid/participants/", - requireAuthentication, - requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), +router.post( + "/", + requireConfiguredAuthentication({ optional: false, type: { admin: true, teamleader: true } }), createParticipant ); router.patch<"/:pid/", { pid: string }>( "/:pid/", - requireAuthentication, - requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + requireConfiguredAuthentication({ optional: false, type: { admin: true, teamleader: true } }), updateParticipant ); router.delete<"/:pid/", { pid: string }>( "/:pid/", - requireAuthentication, - requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + requireConfiguredAuthentication({ optional: false, type: { admin: true, teamleader: true } }), deleteParticipant ); diff --git a/src/Routes/role.routes.ts b/src/Routes/role.routes.ts index c2bc58f..0ad57ce 100644 --- a/src/Routes/role.routes.ts +++ b/src/Routes/role.routes.ts @@ -7,15 +7,13 @@ const router = Express.Router(); //TO DO: maybe transfer getRolesForTeam to team router -> Seconded router.get<"team/:teamPid/", { teamPid: string }>( "team/:teamPid/", - requireAuthentication, - requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + requireConfiguredAuthentication({ optional: false, type: { admin: true, teamleader: true } }), getRolesForTeam ); router.put<"/:pid/participant", { pid: string }>( "/:pid/participant", - requireAuthentication, - requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + requireConfiguredAuthentication({ optional: false, type: { admin: true, teamleader: true } }), assignParticipantToRole ); diff --git a/src/Routes/team.routes.ts b/src/Routes/team.routes.ts index ff1ebac..a8ffebe 100644 --- a/src/Routes/team.routes.ts +++ b/src/Routes/team.routes.ts @@ -8,16 +8,14 @@ const router = express.Router(); router.get("/", requireConfiguredAuthentication({ type: "admin", optional: false }), getTeams); router.get( "/:id", - requireAuthentication, - requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + requireConfiguredAuthentication({ optional: false, type: { admin: true, teamleader: true } }), getTeam ); router.put("/", requireTeamleaderAuthentication, updateTeam); router.delete<"/:pid/", { pid: string }>( "/:pid/", - requireAuthentication, - requireConfiguredAuthentication({ optional: true, type: { admin: true, teamleader: true } }), + requireConfiguredAuthentication({ optional: false, type: { admin: true, teamleader: true } }), deleteTeam );