Revert "merged f-endpoints and f-roles"

This reverts commit 6edaf890b1.
This commit is contained in:
Laurin
2022-06-01 14:10:08 +02:00
parent 6edaf890b1
commit eff81e32f1
10 changed files with 325 additions and 255 deletions
+1 -3
View File
@@ -37,8 +37,6 @@ model Discipline {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
pid String @unique @default(dbgenerated("gen_random_uuid()")) @db.Uuid pid String @unique @default(dbgenerated("gen_random_uuid()")) @db.Uuid
name String name String
briefDescription String
fullDescription String?
minTeamSize Int minTeamSize Int
maxTeamSize Int maxTeamSize Int
@@ -127,7 +125,7 @@ model Group {
model Media { model Media {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
pid String @unique pid String @unique
description String @default("visual") description String
events Event[] events Event[]
disciplines Discipline[] disciplines Discipline[]
+61 -83
View File
@@ -1,10 +1,10 @@
import { Prisma, Organisation, Admin, AdminLevel, Team } from "@prisma/client"; import { Prisma, Organisation, Admin, AdminLevel, Team } from "@prisma/client";
import { PrismaClientKnownRequestError, PrismaClientUnknownRequestError } from "@prisma/client/runtime"; import { PrismaClientKnownRequestError, PrismaClientUnknownRequestError } from "@prisma/client/runtime";
import { Request, Response } from "express"; import { Request, Response } from "express";
import { z } from "zod";
import prisma from "../lib/prisma"; import prisma from "../lib/prisma";
import ForwardableError from "../Middleware/error/ForwardableError"; import ForwardableError from "../Middleware/error/ForwardableError";
import NotFoundError from "../Middleware/error/NotFoundError"; import NotFoundError from "../Middleware/error/NotFoundError";
import { number, z } from "zod";
import { import {
createInsufficientPermissionsError, createInsufficientPermissionsError,
DataType, DataType,
@@ -36,8 +36,6 @@ const basicDiscipline = {
visual: { select: { pid: true } }, visual: { select: { pid: true } },
maxTeamSize: true, maxTeamSize: true,
minTeamSize: true, minTeamSize: true,
briefDescription: true,
fullDescription: true,
event: { select: { pid: true, name: true } }, event: { select: { pid: true, name: true } },
roles: { select: { pid: true, name: true } }, roles: { select: { pid: true, name: true } },
} as const; } as const;
@@ -130,90 +128,10 @@ export const getDiscipline = async (req: Request<GetDisciplineQueryParams>, 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 { interface CreateDisciplineBody {
name?: string; name?: string;
minTeamSize?: number; minTeamSize?: number;
maxTeamSize?: number; maxTeamSize?: number;
briefDescription?: string;
fullDescription?: string;
} }
// require: auth(ELEVATED) // require: auth(ELEVATED)
@@ -323,3 +241,63 @@ export const deleteDiscipline = async (req: Request<{ pid: string }>, res: Respo
throw e; throw e;
} }
}; };
interface visualParams {
disciplinePid: string;
}
interface visualBody {
mediaPid: string;
}
export const addVisual = async (req: Request<visualParams, {}, visualBody>, 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 } },
},
});
// TODO: This does not work and should be updated in all addVisual-type code segments
// Reason: update throw a PrismaClientKnownRequestError with code P2025 if the record to update could not be found
if (!discipline) {
throw new NotFoundError("discipline", disciplinePid);
}
return res.status(200).json({
type: "success",
payload: {},
});
};
export const deleteVisual = async (req: Request<visualParams & { pid: string }>, 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); // Refer: Last todo; This is a correct example
}
throw e;
}
};
+88 -47
View File
@@ -1,6 +1,6 @@
import { Prisma } from "@prisma/client"; import { Prisma } from "@prisma/client";
import { PrismaClientKnownRequestError } from "@prisma/client/runtime"; import { PrismaClientKnownRequestError } from "@prisma/client/runtime";
import e, { Request, Response } from "express"; import { Request, Response } from "express";
import { z } from "zod"; import { z } from "zod";
import prisma from "../lib/prisma"; import prisma from "../lib/prisma";
import NotFoundError from "../Middleware/error/NotFoundError"; import NotFoundError from "../Middleware/error/NotFoundError";
@@ -8,39 +8,16 @@ import { createInsufficientPermissionsError, DataType, generateError, generateIn
require("express-async-errors"); 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) => { export const getAllEvents = async (req: Request, res: Response) => {
const events = await prisma.event.findMany({ const events = await prisma.event.findMany({
select: { select: {
pid: true,
name: true, name: true,
date: true,
briefDescription: true, briefDescription: true,
fullDescription: true, fullDescription: true,
visual: { select: { pid: true, description: true } }, visual: { select: { pid: true, description: true } },
disciplines: { date: true,
select: {
pid: true, pid: true,
name: true, id: false,
}},
organisations: {
select: {
pid: true,
name: true,
}
}
}, },
}); });
@@ -69,25 +46,13 @@ export const getEvent = async (req: Request, res: Response) => {
pid: eventId, pid: eventId,
}, },
select: { select: {
pid: true,
name: true, name: true,
briefDescription: true,
fullDescription: true,
date: true, date: true,
briefDescription: true, pid: true,
fullDescription: true, id: false,
visual: { select: { pid: true, description: true } }, visual: { select: { pid: true, description: true } },
disciplines: {
select: {
pid: true,
name: true,
briefDescription: true,
fullDescription: true,
}},
organisations: {
select: {
pid: true,
name: true,
}
}
}, },
}); });
@@ -131,10 +96,12 @@ export const addEvent = async (req: Request, res: Response) => {
if (req.auth?.permission_level !== "ELEVATED") { if (req.auth?.permission_level !== "ELEVATED") {
res.status(403).json(createInsufficientPermissionsError()); res.status(403).json(createInsufficientPermissionsError());
} }
if (
const result = CreateEventBody.safeParse(req.body); typeof req.body.name !== "string" ||
typeof req.body.date !== "string" ||
if(result.success === false){ typeof req.body.briefDescription !== "string" ||
(req.body.fullDescription && typeof req.body.fullDescription !== "string")
) {
return res.status(400).json( return res.status(400).json(
generateInvalidBodyError({ generateInvalidBodyError({
name: DataType.STRING, name: DataType.STRING,
@@ -155,9 +122,10 @@ export const addEvent = async (req: Request, res: Response) => {
fullDescription: req.body.fullDescription, fullDescription: req.body.fullDescription,
}, },
select: { select: {
pid: true,
name: true, name: true,
date: true, date: true,
pid: true,
id: false,
briefDescription: true, briefDescription: true,
fullDescription: true, fullDescription: true,
}, },
@@ -171,6 +139,15 @@ 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) => { export const updateEvent = async (req: Request<{ pid: string }>, res: Response) => {
if (req.auth?.permission_level !== "ELEVATED") { if (req.auth?.permission_level !== "ELEVATED") {
res.status(403).json(createInsufficientPermissionsError()); res.status(403).json(createInsufficientPermissionsError());
@@ -273,3 +250,67 @@ export const deleteEvent = async (req: Request<DeleteEventQueryParams>, res: Res
throw e; 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<visualParams, {}, visualBody>, 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<visualParams & { pid: string }>, 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;
}
};
+1 -87
View File
@@ -1,4 +1,4 @@
import { NextFunction, Request, response, Response } from "express"; import { Request, response, Response } from "express";
import fs from "fs"; import fs from "fs";
import isSvg from "is-svg"; import isSvg from "is-svg";
import { fromBuffer as fileTypeFromBuffer } from "file-type"; import { fromBuffer as fileTypeFromBuffer } from "file-type";
@@ -12,8 +12,6 @@ import { type } from "os";
import { unlink } from "fs/promises"; import { unlink } from "fs/promises";
import ForwardableError from "../Middleware/error/ForwardableError"; import ForwardableError from "../Middleware/error/ForwardableError";
import SchemaError from "../Middleware/error/SchemaError"; import SchemaError from "../Middleware/error/SchemaError";
import { z } from "zod";
import { updateEvent } from "./event.controller";
require("express-async-errors"); require("express-async-errors");
@@ -191,87 +189,3 @@ export const deleteMedia = async (req: Request, res: Response) => {
throw e; 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 }>,
res: Response) => {
if (req.auth?.permission_level != "ELEVATED") {
res.status(403).json(createInsufficientPermissionsError());
}
const { pid } = req.params;
const { mediaPid } = req.body;
const tableToUpdate = req.originalUrl.split("/");
if(typeof mediaPid !== "string") {
return res.status(400).json(
generateInvalidBodyError({
mediaPid: DataType.UUID,
})
);
}
const updatedRec = await getPrismaUpdateFKT(tableToUpdate[2])({
where: { pid },
data: {
visual: { connect: { pid: mediaPid } },
},
});
if (!updatedRec) {
throw new NotFoundError(tableToUpdate[2], pid);
}
return res.status(200).json({
type: "success",
payload: {},
});
};
export const unlinkMedia = async (
req: Request<{ pid: string, mediaPid: string }>,
res: Response) => {
if (req.auth?.permission_level != "ELEVATED") {
res.status(403).json(createInsufficientPermissionsError());
}
const { pid, mediaPid } = req.params;
const tableToUpdate = req.originalUrl.split("/");
try {
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") {
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;
}
}
+126
View File
@@ -133,3 +133,129 @@ export const createRoleSchema = async (
throw e; 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 = UpdateRoleSchema.safeParse(req.body);
if (result.success === false) {
return res.status(400).json(
generateInvalidBodyError(
{
name: DataType.STRING,
schema: DataType.RESULT_SCHEMA,
},
result.error
)
);
}
const { name, schema } = result.data;
const validatedSchema = parseSchema(schema);
try {
const schema = await prisma.roleSchema.update({
where: { pid },
data: {
name: name,
schema: validatedSchema,
},
select: roleSchema,
});
res.status(200).json({
type: "success",
payload: schema,
});
} catch (e) {
if (e instanceof Prisma.PrismaClientKnownRequestError && e.code === "P2025") {
throw new NotFoundError("roleSchema", pid);
}
throw e;
}
};
export const deleteRoleSchema = async (req: Request<{ pid: string }>, res: Response) => {
if (req.auth?.permission_level !== "ELEVATED") {
res.status(403).json(createInsufficientPermissionsError());
}
const { pid } = req.params;
try {
await prisma.roleSchema.delete({ where: { pid } });
return res.status(204).end();
} catch (e) {
if (e instanceof PrismaClientKnownRequestError && e.code === "P2025") {
return res.status(404).json(generateError(`The RoleSchema with the ID ${pid} could not be found`));
}
throw e;
}
};
interface visualParams {
schemaPid: string;
}
interface visualBody {
mediaPid: string;
}
export const addVisual = async (req: Request<visualParams, {}, visualBody>, 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<visualParams & { pid: string }>, 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;
}
};
+14
View File
@@ -1,8 +1,10 @@
import express from "express"; import express from "express";
import eventRouter from "./event.routes"; import eventRouter from "./event.routes";
import { import {
addVisual,
createDiscipline, createDiscipline,
deleteDiscipline, deleteDiscipline,
deleteVisual,
getAllDisciplines, getAllDisciplines,
getDiscipline, getDiscipline,
updateDiscipline, updateDiscipline,
@@ -18,6 +20,18 @@ router.get("/:pid", getDiscipline);
router.patch("/:pid", requireAuthentication, updateDiscipline); router.patch("/:pid", requireAuthentication, updateDiscipline);
router.delete<"/:pid", { pid: string }>("/:pid", requireAuthentication, deleteDiscipline); 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); eventRouter.post("/:eventPid/disciplines", requireAuthentication, createDiscipline);
export default router; export default router;
+10
View File
@@ -2,7 +2,9 @@ import Express from "express";
import { string } from "zod"; import { string } from "zod";
import { import {
addEvent, addEvent,
addVisual,
deleteEvent, deleteEvent,
deleteVisual,
getAllEvents, getAllEvents,
getEvent, getEvent,
updateEvent, updateEvent,
@@ -20,4 +22,12 @@ router.patch<"/:pid/", { pid: string }>("/:pid/", requireAuthentication, updateE
router.delete<"/:pid/", { pid: string }>("/:pid/", requireAuthentication, deleteEvent); 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; export default router;
+1 -25
View File
@@ -1,7 +1,7 @@
import express from "express"; import express from "express";
import fileUpload from "express-fileupload"; import fileUpload from "express-fileupload";
import { requireAuthentication } from "../Middleware/auth/auth"; import { requireAuthentication } from "../Middleware/auth/auth";
import { deleteMedia, getAllMedia, getMediaMeta, linkMedia, unlinkMedia, uploadImage } from "../Controllers/media.controller"; import { deleteMedia, getAllMedia, getMediaMeta, uploadImage } from "../Controllers/media.controller";
import eventRouter from "./event.routes"; import eventRouter from "./event.routes";
import disciplineRouter from "./discipline.routes"; import disciplineRouter from "./discipline.routes";
import roleSchemaRouter from "./role_schema.routes"; import roleSchemaRouter from "./role_schema.routes";
@@ -19,28 +19,4 @@ router.get("/:pid/meta", getMediaMeta);
router.delete("/:pid", requireAuthentication, deleteMedia); 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; export default router;
+10
View File
@@ -1,7 +1,9 @@
import express from "express"; import express from "express";
import disciplineRouter from "./discipline.routes"; import disciplineRouter from "./discipline.routes";
import { import {
addVisual,
createRoleSchema, createRoleSchema,
deleteVisual,
getAllRoleSchemas, getAllRoleSchemas,
getAllRoleSchemasWithParam, getAllRoleSchemasWithParam,
getRoleSchema, getRoleSchema,
@@ -18,4 +20,12 @@ disciplineRouter.get("/:disciplinePid/role-schemas", getAllRoleSchemasWithParam)
disciplineRouter.post("/:disciplinePid/role-schemas", requireAuthentication, createRoleSchema); 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; export default router;
+3
View File
@@ -95,6 +95,9 @@ async function main() {
// Error handling // Error handling
app.use(defaultErrorHandler); // This has to be the LAST ROUTE app.use(defaultErrorHandler); // This has to be the LAST ROUTE
// Disable the media router for now
// app.use("/api/media", mediaRouter);
app.use(notFoundHandler); app.use(notFoundHandler);
app.listen(process.env.PORT, () => { app.listen(process.env.PORT, () => {