diff --git a/backend/src/controllers/auth.ts b/backend/src/controllers/auth.ts index 14b05dc8..6395715d 100644 --- a/backend/src/controllers/auth.ts +++ b/backend/src/controllers/auth.ts @@ -2,10 +2,10 @@ import { UnauthorizedException } from '../exceptions/unauthorized-exception.js'; import { getLogger } from '../logging/initalize.js'; import { AuthenticatedRequest } from '../middleware/auth/authenticated-request.js'; import { envVars, getEnvVar } from '../util/envVars.js'; -import {createOrUpdateStudent, createStudent} from "../services/students"; -import {AuthenticationInfo} from "../middleware/auth/authentication-info"; -import {Request, Response} from "express"; -import {createOrUpdateTeacher, createTeacher} from "../services/teachers"; +import { createOrUpdateStudent, createStudent } from '../services/students'; +import { AuthenticationInfo } from '../middleware/auth/authentication-info'; +import { Request, Response } from 'express'; +import { createOrUpdateTeacher, createTeacher } from '../services/teachers'; interface FrontendIdpConfig { authority: string; @@ -47,20 +47,26 @@ export function handleGetFrontendAuthConfig(_req: Request, res: Response): void export async function handleHello(req: AuthenticatedRequest): Promise { const auth: AuthenticationInfo = req.auth!; - if (auth.accountType === "teacher") { - await createTeacher({ - id: auth.username, - username: auth.username, - firstName: auth.firstName ?? "", - lastName: auth.lastName ?? "", - }, true); + if (auth.accountType === 'teacher') { + await createTeacher( + { + id: auth.username, + username: auth.username, + firstName: auth.firstName ?? '', + lastName: auth.lastName ?? '', + }, + true + ); } else { - await createStudent({ - id: auth.username, - username: auth.username, - firstName: auth.firstName ?? "", - lastName: auth.lastName ?? "", - }, true); + await createStudent( + { + id: auth.username, + username: auth.username, + firstName: auth.firstName ?? '', + lastName: auth.lastName ?? '', + }, + true + ); } } diff --git a/backend/src/controllers/teacher-invitations.ts b/backend/src/controllers/teacher-invitations.ts index 0a8b89c0..f1350660 100644 --- a/backend/src/controllers/teacher-invitations.ts +++ b/backend/src/controllers/teacher-invitations.ts @@ -2,7 +2,7 @@ import { Request, Response } from 'express'; import { requireFields } from './error-helper.js'; import { createInvitation, deleteInvitation, getAllInvitations, getInvitation, updateInvitation } from '../services/teacher-invitations.js'; import { TeacherInvitationData } from '@dwengo-1/common/interfaces/teacher-invitation'; -import {ConflictException} from "../exceptions/conflict-exception"; +import { ConflictException } from '../exceptions/conflict-exception'; export async function getAllInvitationsHandler(req: Request, res: Response): Promise { const username = req.params.username; @@ -31,8 +31,8 @@ export async function createInvitationHandler(req: Request, res: Response): Prom const classId = req.body.class; requireFields({ sender, receiver, classId }); - if (sender === receiver){ - throw new ConflictException("Cannot send an invitation to yourself"); + if (sender === receiver) { + throw new ConflictException('Cannot send an invitation to yourself'); } const data = req.body as TeacherInvitationData; diff --git a/backend/src/interfaces/user.ts b/backend/src/interfaces/user.ts index 88252a1e..3084c494 100644 --- a/backend/src/interfaces/user.ts +++ b/backend/src/interfaces/user.ts @@ -10,7 +10,7 @@ export function mapToUserDTO(user: User): UserDTO { }; } -export function mapToUsername(user: {username: string}): string { +export function mapToUsername(user: { username: string }): string { return user.username; } diff --git a/backend/src/middleware/auth/auth.ts b/backend/src/middleware/auth/auth.ts index 158e2c28..24be4825 100644 --- a/backend/src/middleware/auth/auth.ts +++ b/backend/src/middleware/auth/auth.ts @@ -1,11 +1,11 @@ -import {envVars, getEnvVar} from '../../util/envVars.js'; -import {expressjwt} from 'express-jwt'; +import { envVars, getEnvVar } from '../../util/envVars.js'; +import { expressjwt } from 'express-jwt'; import * as jwt from 'jsonwebtoken'; -import {JwtPayload} from 'jsonwebtoken'; +import { JwtPayload } from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; import * as express from 'express'; -import {AuthenticatedRequest} from './authenticated-request.js'; -import {AuthenticationInfo} from './authentication-info.js'; +import { AuthenticatedRequest } from './authenticated-request.js'; +import { AuthenticationInfo } from './authentication-info.js'; import { UnauthorizedException } from '../../exceptions/unauthorized-exception.js'; const JWKS_CACHE = true; diff --git a/backend/src/middleware/auth/authenticated-request.d.ts b/backend/src/middleware/auth/authenticated-request.d.ts index c0049dc7..af7630af 100644 --- a/backend/src/middleware/auth/authenticated-request.d.ts +++ b/backend/src/middleware/auth/authenticated-request.d.ts @@ -1,7 +1,7 @@ import { Request } from 'express'; import { JwtPayload } from 'jsonwebtoken'; import { AuthenticationInfo } from './authentication-info.js'; -import * as core from "express-serve-static-core"; +import * as core from 'express-serve-static-core'; export interface AuthenticatedRequest< P = core.ParamsDictionary, @@ -9,7 +9,7 @@ export interface AuthenticatedRequest< ReqBody = unknown, ReqQuery = core.Query, Locals extends Record = Record, -> extends Request { +> extends Request { // Properties are optional since the user is not necessarily authenticated. jwtPayload?: JwtPayload; auth?: AuthenticationInfo; diff --git a/backend/src/middleware/auth/checks/assignment-auth-checks.ts b/backend/src/middleware/auth/checks/assignment-auth-checks.ts index 070df4a0..8328dec0 100644 --- a/backend/src/middleware/auth/checks/assignment-auth-checks.ts +++ b/backend/src/middleware/auth/checks/assignment-auth-checks.ts @@ -1,7 +1,7 @@ -import {authorize} from "./auth-checks"; -import {fetchClass} from "../../../services/classes"; -import {fetchAllGroups} from "../../../services/groups"; -import {mapToUsername} from "../../../interfaces/user"; +import { authorize } from './auth-checks'; +import { fetchClass } from '../../../services/classes'; +import { fetchAllGroups } from '../../../services/groups'; +import { mapToUsername } from '../../../interfaces/user'; /** * Expects the path to contain the path parameters 'classId' and 'id' (meaning the ID of the assignment). @@ -9,15 +9,12 @@ import {mapToUsername} from "../../../interfaces/user"; * - either teachers of the class the assignment was posted in, * - or students in a group of the assignment. */ -export const onlyAllowIfHasAccessToAssignment = authorize( - async (auth, req) => { - const { classid: classId, id: assignmentId } = req.params as { classid: string, id: number }; - if (auth.accountType === "teacher") { - const clazz = await fetchClass(classId); - return clazz.teachers.map(mapToUsername).includes(auth.username); - } - const groups = await fetchAllGroups(classId, assignmentId); - return groups.some(group => group.members.map((member) => member.username).includes(auth.username) ); - +export const onlyAllowIfHasAccessToAssignment = authorize(async (auth, req) => { + const { classid: classId, id: assignmentId } = req.params as { classid: string; id: number }; + if (auth.accountType === 'teacher') { + const clazz = await fetchClass(classId); + return clazz.teachers.map(mapToUsername).includes(auth.username); } -); + const groups = await fetchAllGroups(classId, assignmentId); + return groups.some((group) => group.members.map((member) => member.username).includes(auth.username)); +}); diff --git a/backend/src/middleware/auth/checks/auth-checks.ts b/backend/src/middleware/auth/checks/auth-checks.ts index d14e8dee..a4a75db5 100644 --- a/backend/src/middleware/auth/checks/auth-checks.ts +++ b/backend/src/middleware/auth/checks/auth-checks.ts @@ -1,9 +1,9 @@ -import {AuthenticationInfo} from "../authentication-info"; -import {AuthenticatedRequest} from "../authenticated-request"; -import * as express from "express"; -import {UnauthorizedException} from "../../../exceptions/unauthorized-exception"; -import {ForbiddenException} from "../../../exceptions/forbidden-exception"; -import {RequestHandler} from "express"; +import { AuthenticationInfo } from '../authentication-info'; +import { AuthenticatedRequest } from '../authenticated-request'; +import * as express from 'express'; +import { UnauthorizedException } from '../../../exceptions/unauthorized-exception'; +import { ForbiddenException } from '../../../exceptions/forbidden-exception'; +import { RequestHandler } from 'express'; /** * Middleware which rejects unauthenticated users (with HTTP 401) and authenticated users which do not fulfill @@ -11,13 +11,17 @@ import {RequestHandler} from "express"; * @param accessCondition Predicate over the current AuthenticationInfo. Access is only granted when this evaluates * to true. */ -export function authorize>( - accessCondition: (auth: AuthenticationInfo, req: AuthenticatedRequest) => boolean | Promise -): RequestHandler { - return async (req: AuthenticatedRequest, _res: express.Response, next: express.NextFunction): Promise => { +export function authorize>( + accessCondition: (auth: AuthenticationInfo, req: AuthenticatedRequest) => boolean | Promise +): RequestHandler { + return async ( + req: AuthenticatedRequest, + _res: express.Response, + next: express.NextFunction + ): Promise => { if (!req.auth) { throw new UnauthorizedException(); - } else if (!await accessCondition(req.auth, req)) { + } else if (!(await accessCondition(req.auth, req))) { throw new ForbiddenException(); } else { next(); diff --git a/backend/src/middleware/auth/checks/class-auth-checks.ts b/backend/src/middleware/auth/checks/class-auth-checks.ts index 603142be..6aae97b3 100644 --- a/backend/src/middleware/auth/checks/class-auth-checks.ts +++ b/backend/src/middleware/auth/checks/class-auth-checks.ts @@ -1,8 +1,8 @@ -import {authorize} from "./auth-checks"; -import {AuthenticationInfo} from "../authentication-info"; -import {AuthenticatedRequest} from "../authenticated-request"; -import {fetchClass} from "../../../services/classes"; -import {mapToUsername} from "../../../interfaces/user"; +import { authorize } from './auth-checks'; +import { AuthenticationInfo } from '../authentication-info'; +import { AuthenticatedRequest } from '../authenticated-request'; +import { fetchClass } from '../../../services/classes'; +import { mapToUsername } from '../../../interfaces/user'; async function teaches(teacherUsername: string, classId: string): Promise { const clazz = await fetchClass(classId); @@ -14,53 +14,45 @@ async function teaches(teacherUsername: string, classId: string): Promise { - if (req.params.username === auth.username) { - return true; - } else if (auth.accountType === "teacher") { - return teaches(auth.username, req.params.classId); - } - return false; - +export const onlyAllowStudentHimselfAndTeachersOfClass = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { + if (req.params.username === auth.username) { + return true; + } else if (auth.accountType === 'teacher') { + return teaches(auth.username, req.params.classId); } -); + return false; +}); /** * Only let the request pass through if its path parameter "username" is the username of the currently logged-in * teacher and the path parameter "classId" refers to a class the teacher teaches. */ export const onlyAllowTeacherOfClass = authorize( - async (auth: AuthenticationInfo, req: AuthenticatedRequest) => - req.params.username === auth.username && teaches(auth.username, req.params.classId), + async (auth: AuthenticationInfo, req: AuthenticatedRequest) => req.params.username === auth.username && teaches(auth.username, req.params.classId) ); /** * Only let the request pass through if the class id in it refers to a class the current user is in (as a student * or teacher) */ -export const onlyAllowIfInClass = authorize( - async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { - const classId = req.params.classId ?? req.params.classid ?? req.params.id; - const clazz = await fetchClass(classId); - if (auth.accountType === "teacher") { - return clazz.teachers.map(mapToUsername).includes(auth.username); - } - return clazz.students.map(mapToUsername).includes(auth.username); +export const onlyAllowIfInClass = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { + const classId = req.params.classId ?? req.params.classid ?? req.params.id; + const clazz = await fetchClass(classId); + if (auth.accountType === 'teacher') { + return clazz.teachers.map(mapToUsername).includes(auth.username); } -); + return clazz.students.map(mapToUsername).includes(auth.username); +}); /** * Only allows the request to pass if the 'class' property in its body is a class the current user is a member of. */ -export const onlyAllowOwnClassInBody = authorize( - async (auth, req) => { - const classId = (req.body as {class: string})?.class; - const clazz = await fetchClass(classId); +export const onlyAllowOwnClassInBody = authorize(async (auth, req) => { + const classId = (req.body as { class: string })?.class; + const clazz = await fetchClass(classId); - if (auth.accountType === "teacher") { - return clazz.teachers.map(mapToUsername).includes(auth.username); - } - return clazz.students.map(mapToUsername).includes(auth.username); + if (auth.accountType === 'teacher') { + return clazz.teachers.map(mapToUsername).includes(auth.username); } -); + return clazz.students.map(mapToUsername).includes(auth.username); +}); diff --git a/backend/src/middleware/auth/checks/group-auth-checker.ts b/backend/src/middleware/auth/checks/group-auth-checker.ts index 643a3713..bebda954 100644 --- a/backend/src/middleware/auth/checks/group-auth-checker.ts +++ b/backend/src/middleware/auth/checks/group-auth-checker.ts @@ -1,7 +1,7 @@ -import {authorize} from "./auth-checks"; -import {fetchClass} from "../../../services/classes"; -import {fetchGroup} from "../../../services/groups"; -import {mapToUsername} from "../../../interfaces/user"; +import { authorize } from './auth-checks'; +import { fetchClass } from '../../../services/classes'; +import { fetchGroup } from '../../../services/groups'; +import { mapToUsername } from '../../../interfaces/user'; /** * Expects the path to contain the path parameters 'classid', 'assignmentid' and 'groupid'. @@ -9,17 +9,17 @@ import {mapToUsername} from "../../../interfaces/user"; * - either teachers of the class the assignment for the group was posted in, * - or students in the group */ -export const onlyAllowIfHasAccessToGroup = authorize( - async (auth, req) => { - const { classid: classId, assignmentid: assignmentId, groupid: groupId } = - req.params as { classid: string, assignmentid: number, groupid: number }; +export const onlyAllowIfHasAccessToGroup = authorize(async (auth, req) => { + const { + classid: classId, + assignmentid: assignmentId, + groupid: groupId, + } = req.params as { classid: string; assignmentid: number; groupid: number }; - if (auth.accountType === "teacher") { - const clazz = await fetchClass(classId); - return clazz.teachers.map(mapToUsername).includes(auth.username); - } // User is student - const group = await fetchGroup(classId, assignmentId, groupId); - return group.members.map(mapToUsername).includes(auth.username); - - } -); + if (auth.accountType === 'teacher') { + const clazz = await fetchClass(classId); + return clazz.teachers.map(mapToUsername).includes(auth.username); + } // User is student + const group = await fetchGroup(classId, assignmentId, groupId); + return group.members.map(mapToUsername).includes(auth.username); +}); diff --git a/backend/src/middleware/auth/checks/learning-content-auth-checks.ts b/backend/src/middleware/auth/checks/learning-content-auth-checks.ts index a13cd038..c0b34c52 100644 --- a/backend/src/middleware/auth/checks/learning-content-auth-checks.ts +++ b/backend/src/middleware/auth/checks/learning-content-auth-checks.ts @@ -1,6 +1,6 @@ -import {authorize} from "./auth-checks"; -import {AuthenticationInfo} from "../authentication-info"; -import {AuthenticatedRequest} from "../authenticated-request"; +import { authorize } from './auth-checks'; +import { AuthenticationInfo } from '../authentication-info'; +import { AuthenticatedRequest } from '../authenticated-request'; /** * Only allows requests whose learning path personalization query parameters ('forGroup' / 'assignmentNo' / 'classId') @@ -9,15 +9,12 @@ import {AuthenticatedRequest} from "../authenticated-request"; * - or set to a group the user is in, * - or set to anything if the user is a teacher. */ -export const onlyAllowPersonalizationForOwnGroup = authorize( - async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { - const {forGroup, assignmentNo, classId} = req.params; - if (auth.accountType === "student" && forGroup && assignmentNo && classId) { - // TODO: groupNumber? - // Const group = await fetchGroup(Number(classId), Number(assignmentNo), ) - return false; - } - return true; - +export const onlyAllowPersonalizationForOwnGroup = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { + const { forGroup, assignmentNo, classId } = req.params; + if (auth.accountType === 'student' && forGroup && assignmentNo && classId) { + // TODO: groupNumber? + // Const group = await fetchGroup(Number(classId), Number(assignmentNo), ) + return false; } -); + return true; +}); diff --git a/backend/src/middleware/auth/checks/question-checks.ts b/backend/src/middleware/auth/checks/question-checks.ts index 38b1f0ef..c0a4329f 100644 --- a/backend/src/middleware/auth/checks/question-checks.ts +++ b/backend/src/middleware/auth/checks/question-checks.ts @@ -1,72 +1,65 @@ -import {authorize} from "./auth-checks"; -import {AuthenticationInfo} from "../authentication-info"; -import {AuthenticatedRequest} from "../authenticated-request"; -import {requireFields} from "../../../controllers/error-helper"; -import {getLearningObjectId, getQuestionId} from "../../../controllers/questions"; -import {fetchQuestion} from "../../../services/questions"; -import {FALLBACK_SEQ_NUM} from "../../../config"; -import {fetchAnswer} from "../../../services/answers"; -import {mapToUsername} from "../../../interfaces/user"; +import { authorize } from './auth-checks'; +import { AuthenticationInfo } from '../authentication-info'; +import { AuthenticatedRequest } from '../authenticated-request'; +import { requireFields } from '../../../controllers/error-helper'; +import { getLearningObjectId, getQuestionId } from '../../../controllers/questions'; +import { fetchQuestion } from '../../../services/questions'; +import { FALLBACK_SEQ_NUM } from '../../../config'; +import { fetchAnswer } from '../../../services/answers'; +import { mapToUsername } from '../../../interfaces/user'; export const onlyAllowAuthor = authorize( (auth: AuthenticationInfo, req: AuthenticatedRequest) => (req.body as { author: string }).author === auth.username ); -export const onlyAllowAuthorRequest = authorize( - async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { - const hruid = req.params.hruid; - const version = req.params.version; - const language = req.query.lang as string; - const seq = req.params.seq; - requireFields({ hruid }); +export const onlyAllowAuthorRequest = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { + const hruid = req.params.hruid; + const version = req.params.version; + const language = req.query.lang as string; + const seq = req.params.seq; + requireFields({ hruid }); - const learningObjectId = getLearningObjectId(hruid, version, language); - const questionId = getQuestionId(learningObjectId, seq); + const learningObjectId = getLearningObjectId(hruid, version, language); + const questionId = getQuestionId(learningObjectId, seq); - const question = await fetchQuestion(questionId); + const question = await fetchQuestion(questionId); - return question.author.username === auth.username; - } -); + return question.author.username === auth.username; +}); -export const onlyAllowAuthorRequestAnswer = authorize( - async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { - const hruid = req.params.hruid; - const version = req.params.version; - const language = req.query.lang as string; - const seq = req.params.seq; - const seqAnswer = req.params.seqAnswer; - requireFields({ hruid }); +export const onlyAllowAuthorRequestAnswer = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { + const hruid = req.params.hruid; + const version = req.params.version; + const language = req.query.lang as string; + const seq = req.params.seq; + const seqAnswer = req.params.seqAnswer; + requireFields({ hruid }); - const learningObjectId = getLearningObjectId(hruid, version, language); - const questionId = getQuestionId(learningObjectId, seq); + const learningObjectId = getLearningObjectId(hruid, version, language); + const questionId = getQuestionId(learningObjectId, seq); - const sequenceNumber = Number(seqAnswer) || FALLBACK_SEQ_NUM; - const answer = await fetchAnswer(questionId, sequenceNumber); + const sequenceNumber = Number(seqAnswer) || FALLBACK_SEQ_NUM; + const answer = await fetchAnswer(questionId, sequenceNumber); - return answer.author.username === auth.username; - } -); + return answer.author.username === auth.username; +}); -export const onlyAllowIfHasAccessToQuestion = authorize( - async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { - const hruid = req.params.hruid; - const version = req.params.version; - const language = req.query.lang as string; - const seq = req.params.seq; - requireFields({ hruid }); +export const onlyAllowIfHasAccessToQuestion = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { + const hruid = req.params.hruid; + const version = req.params.version; + const language = req.query.lang as string; + const seq = req.params.seq; + requireFields({ hruid }); - const learningObjectId = getLearningObjectId(hruid, version, language); - const questionId = getQuestionId(learningObjectId, seq); + const learningObjectId = getLearningObjectId(hruid, version, language); + const questionId = getQuestionId(learningObjectId, seq); - const question = await fetchQuestion(questionId); - const group = question.inGroup; + const question = await fetchQuestion(questionId); + const group = question.inGroup; - if (auth.accountType === "teacher") { - const cls = group.assignment.within; // TODO check if contains full objects - return cls.teachers.map(mapToUsername).includes(auth.username); - } // User is student - return group.members.map(mapToUsername).includes(auth.username); - - } -); + if (auth.accountType === 'teacher') { + const cls = group.assignment.within; // TODO check if contains full objects + return cls.teachers.map(mapToUsername).includes(auth.username); + } // User is student + return group.members.map(mapToUsername).includes(auth.username); +}); diff --git a/backend/src/middleware/auth/checks/submission-checks.ts b/backend/src/middleware/auth/checks/submission-checks.ts index 78087fa9..87171584 100644 --- a/backend/src/middleware/auth/checks/submission-checks.ts +++ b/backend/src/middleware/auth/checks/submission-checks.ts @@ -1,29 +1,27 @@ -import { languageMap } from "dwengo-1-common/util/language"; -import { LearningObjectIdentifier } from "../../../entities/content/learning-object-identifier"; -import { fetchSubmission } from "../../../services/submissions"; -import { AuthenticatedRequest } from "../authenticated-request"; -import { AuthenticationInfo } from "../authentication-info"; -import { authorize } from "./auth-checks"; -import { FALLBACK_LANG } from "../../../config"; -import { mapToUsername } from "../../../interfaces/user"; +import { languageMap } from 'dwengo-1-common/util/language'; +import { LearningObjectIdentifier } from '../../../entities/content/learning-object-identifier'; +import { fetchSubmission } from '../../../services/submissions'; +import { AuthenticatedRequest } from '../authenticated-request'; +import { AuthenticationInfo } from '../authentication-info'; +import { authorize } from './auth-checks'; +import { FALLBACK_LANG } from '../../../config'; +import { mapToUsername } from '../../../interfaces/user'; export const onlyAllowSubmitter = authorize( (auth: AuthenticationInfo, req: AuthenticatedRequest) => (req.body as { submitter: string }).submitter === auth.username ); -export const onlyAllowIfHasAccessToSubmission = authorize( - async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { - const { hruid: lohruid, id: submissionNumber } = req.params; - const { language: lang, version: version } = req.query; +export const onlyAllowIfHasAccessToSubmission = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => { + const { hruid: lohruid, id: submissionNumber } = req.params; + const { language: lang, version: version } = req.query; - const loId = new LearningObjectIdentifier(lohruid, languageMap[lang as string] ?? FALLBACK_LANG, Number(version)) - const submission = await fetchSubmission(loId, Number(submissionNumber)); + const loId = new LearningObjectIdentifier(lohruid, languageMap[lang as string] ?? FALLBACK_LANG, Number(version)); + const submission = await fetchSubmission(loId, Number(submissionNumber)); - if (auth.accountType === "teacher") { - // Dit kan niet werken om dat al deze objecten niet gepopulate zijn. - return submission.onBehalfOf.assignment.within.teachers.map(mapToUsername).includes(auth.username); - } - - return submission.onBehalfOf.members.map(mapToUsername).includes(auth.username); + if (auth.accountType === 'teacher') { + // Dit kan niet werken om dat al deze objecten niet gepopulate zijn. + return submission.onBehalfOf.assignment.within.teachers.map(mapToUsername).includes(auth.username); } -) \ No newline at end of file + + return submission.onBehalfOf.members.map(mapToUsername).includes(auth.username); +}); diff --git a/backend/src/middleware/auth/checks/teacher-invitation-checks.ts b/backend/src/middleware/auth/checks/teacher-invitation-checks.ts index 27d0cab2..5f38eaf1 100644 --- a/backend/src/middleware/auth/checks/teacher-invitation-checks.ts +++ b/backend/src/middleware/auth/checks/teacher-invitation-checks.ts @@ -1,23 +1,17 @@ -import {authorize} from "./auth-checks"; -import {AuthenticationInfo} from "../authentication-info"; -import {AuthenticatedRequest} from "../authenticated-request"; +import { authorize } from './auth-checks'; +import { AuthenticationInfo } from '../authentication-info'; +import { AuthenticatedRequest } from '../authenticated-request'; export const onlyAllowSenderOrReceiver = authorize( - (auth: AuthenticationInfo, req: AuthenticatedRequest) => - req.params.sender === auth.username || req.params.receiver === auth.username + (auth: AuthenticationInfo, req: AuthenticatedRequest) => req.params.sender === auth.username || req.params.receiver === auth.username ); -export const onlyAllowSender = authorize( - (auth: AuthenticationInfo, req: AuthenticatedRequest) => - req.params.sender === auth.username -); +export const onlyAllowSender = authorize((auth: AuthenticationInfo, req: AuthenticatedRequest) => req.params.sender === auth.username); export const onlyAllowSenderBody = authorize( - (auth: AuthenticationInfo, req: AuthenticatedRequest) => - (req.body as { sender: string }).sender === auth.username + (auth: AuthenticationInfo, req: AuthenticatedRequest) => (req.body as { sender: string }).sender === auth.username ); export const onlyAllowReceiverBody = authorize( - (auth: AuthenticationInfo, req: AuthenticatedRequest) => - (req.body as { receiver: string }).receiver === auth.username + (auth: AuthenticationInfo, req: AuthenticatedRequest) => (req.body as { receiver: string }).receiver === auth.username ); diff --git a/backend/src/middleware/auth/checks/user-auth-checks.ts b/backend/src/middleware/auth/checks/user-auth-checks.ts index 10814eb8..bbe4c7f2 100644 --- a/backend/src/middleware/auth/checks/user-auth-checks.ts +++ b/backend/src/middleware/auth/checks/user-auth-checks.ts @@ -1,10 +1,8 @@ -import {authorize} from "./auth-checks"; -import {AuthenticationInfo} from "../authentication-info"; -import {AuthenticatedRequest} from "../authenticated-request"; +import { authorize } from './auth-checks'; +import { AuthenticationInfo } from '../authentication-info'; +import { AuthenticatedRequest } from '../authenticated-request'; /** * Only allow the user whose username is in the path parameter "username" to access the endpoint. */ -export const onlyAllowUserHimself = authorize( - (auth: AuthenticationInfo, req: AuthenticatedRequest) => req.params.username === auth.username -); +export const onlyAllowUserHimself = authorize((auth: AuthenticationInfo, req: AuthenticatedRequest) => req.params.username === auth.username); diff --git a/backend/src/routes/answers.ts b/backend/src/routes/answers.ts index a5ee6278..6e76a543 100644 --- a/backend/src/routes/answers.ts +++ b/backend/src/routes/answers.ts @@ -1,12 +1,7 @@ import express from 'express'; import { createAnswerHandler, deleteAnswerHandler, getAnswerHandler, getAllAnswersHandler, updateAnswerHandler } from '../controllers/answers.js'; -import {adminOnly, teachersOnly} from "../middleware/auth/checks/auth-checks"; -import { - onlyAllowAuthor, - onlyAllowAuthorRequestAnswer, - onlyAllowIfHasAccessToQuestion -} from "../middleware/auth/checks/question-checks"; - +import { adminOnly, teachersOnly } from '../middleware/auth/checks/auth-checks'; +import { onlyAllowAuthor, onlyAllowAuthorRequestAnswer, onlyAllowIfHasAccessToQuestion } from '../middleware/auth/checks/question-checks'; const router = express.Router({ mergeParams: true }); diff --git a/backend/src/routes/assignments.ts b/backend/src/routes/assignments.ts index 7b2d66fa..2a38748b 100644 --- a/backend/src/routes/assignments.ts +++ b/backend/src/routes/assignments.ts @@ -8,9 +8,9 @@ import { putAssignmentHandler, } from '../controllers/assignments.js'; import groupRouter from './groups.js'; -import {teachersOnly} from "../middleware/auth/checks/auth-checks"; -import {onlyAllowIfInClass} from "../middleware/auth/checks/class-auth-checks"; -import {onlyAllowIfHasAccessToAssignment} from "../middleware/auth/checks/assignment-auth-checks"; +import { teachersOnly } from '../middleware/auth/checks/auth-checks'; +import { onlyAllowIfInClass } from '../middleware/auth/checks/class-auth-checks'; +import { onlyAllowIfHasAccessToAssignment } from '../middleware/auth/checks/assignment-auth-checks'; const router = express.Router({ mergeParams: true }); diff --git a/backend/src/routes/classes.ts b/backend/src/routes/classes.ts index 9cf20ec0..9889151d 100644 --- a/backend/src/routes/classes.ts +++ b/backend/src/routes/classes.ts @@ -14,8 +14,8 @@ import { putClassHandler, } from '../controllers/classes.js'; import assignmentRouter from './assignments.js'; -import {adminOnly, teachersOnly} from "../middleware/auth/checks/auth-checks"; -import {onlyAllowIfInClass} from "../middleware/auth/checks/class-auth-checks"; +import { adminOnly, teachersOnly } from '../middleware/auth/checks/auth-checks'; +import { onlyAllowIfInClass } from '../middleware/auth/checks/class-auth-checks'; const router = express.Router(); diff --git a/backend/src/routes/groups.ts b/backend/src/routes/groups.ts index 5d3d8ed0..cb92e7c2 100644 --- a/backend/src/routes/groups.ts +++ b/backend/src/routes/groups.ts @@ -7,9 +7,9 @@ import { getGroupSubmissionsHandler, putGroupHandler, } from '../controllers/groups.js'; -import {onlyAllowIfHasAccessToGroup} from "../middleware/auth/checks/group-auth-checker"; -import {teachersOnly} from "../middleware/auth/checks/auth-checks"; -import {onlyAllowIfHasAccessToAssignment} from "../middleware/auth/checks/assignment-auth-checks"; +import { onlyAllowIfHasAccessToGroup } from '../middleware/auth/checks/group-auth-checker'; +import { teachersOnly } from '../middleware/auth/checks/auth-checks'; +import { onlyAllowIfHasAccessToAssignment } from '../middleware/auth/checks/assignment-auth-checks'; const router = express.Router({ mergeParams: true }); diff --git a/backend/src/routes/learning-objects.ts b/backend/src/routes/learning-objects.ts index fb65d9cd..fa438a57 100644 --- a/backend/src/routes/learning-objects.ts +++ b/backend/src/routes/learning-objects.ts @@ -3,7 +3,7 @@ import { getAllLearningObjects, getAttachment, getLearningObject, getLearningObj import submissionRoutes from './submissions.js'; import questionRoutes from './questions.js'; -import {authenticatedOnly} from "../middleware/auth/checks/auth-checks"; +import { authenticatedOnly } from '../middleware/auth/checks/auth-checks'; const router = express.Router(); diff --git a/backend/src/routes/learning-paths.ts b/backend/src/routes/learning-paths.ts index ad079551..ee3c4955 100644 --- a/backend/src/routes/learning-paths.ts +++ b/backend/src/routes/learning-paths.ts @@ -1,6 +1,6 @@ import express from 'express'; import { getLearningPaths } from '../controllers/learning-paths.js'; -import {authenticatedOnly} from "../middleware/auth/checks/auth-checks"; +import { authenticatedOnly } from '../middleware/auth/checks/auth-checks'; const router = express.Router(); diff --git a/backend/src/routes/questions.ts b/backend/src/routes/questions.ts index bffcbe9e..a15c1d0a 100644 --- a/backend/src/routes/questions.ts +++ b/backend/src/routes/questions.ts @@ -1,13 +1,9 @@ import express from 'express'; import { createQuestionHandler, deleteQuestionHandler, getAllQuestionsHandler, getQuestionHandler } from '../controllers/questions.js'; import answerRoutes from './answers.js'; -import {adminOnly, studentsOnly} from "../middleware/auth/checks/auth-checks"; -import {updateAnswerHandler} from "../controllers/answers"; -import { - onlyAllowAuthor, - onlyAllowAuthorRequest, - onlyAllowIfHasAccessToQuestion -} from "../middleware/auth/checks/question-checks"; +import { adminOnly, studentsOnly } from '../middleware/auth/checks/auth-checks'; +import { updateAnswerHandler } from '../controllers/answers'; +import { onlyAllowAuthor, onlyAllowAuthorRequest, onlyAllowIfHasAccessToQuestion } from '../middleware/auth/checks/question-checks'; const router = express.Router({ mergeParams: true }); @@ -23,7 +19,7 @@ router.get('/:seq', onlyAllowIfHasAccessToQuestion, getQuestionHandler); router.delete('/:seq', studentsOnly, onlyAllowAuthorRequest, deleteQuestionHandler); -router.put("/:seq", studentsOnly, onlyAllowAuthorRequest, updateAnswerHandler); +router.put('/:seq', studentsOnly, onlyAllowAuthorRequest, updateAnswerHandler); router.use('/:seq/answers', answerRoutes); diff --git a/backend/src/routes/student-join-requests.ts b/backend/src/routes/student-join-requests.ts index 66a6c75e..f467f346 100644 --- a/backend/src/routes/student-join-requests.ts +++ b/backend/src/routes/student-join-requests.ts @@ -5,8 +5,8 @@ import { getStudentRequestHandler, getStudentRequestsHandler, } from '../controllers/students.js'; -import {onlyAllowUserHimself} from "../middleware/auth/checks/user-auth-checks"; -import {onlyAllowStudentHimselfAndTeachersOfClass} from "../middleware/auth/checks/class-auth-checks"; +import { onlyAllowUserHimself } from '../middleware/auth/checks/user-auth-checks'; +import { onlyAllowStudentHimselfAndTeachersOfClass } from '../middleware/auth/checks/class-auth-checks'; // Under /:username/joinRequests/ diff --git a/backend/src/routes/students.ts b/backend/src/routes/students.ts index 04d260b4..e0634219 100644 --- a/backend/src/routes/students.ts +++ b/backend/src/routes/students.ts @@ -11,8 +11,8 @@ import { getStudentSubmissionsHandler, } from '../controllers/students.js'; import joinRequestRouter from './student-join-requests.js'; -import {onlyAllowUserHimself} from "../middleware/auth/checks/user-auth-checks"; -import {adminOnly} from "../middleware/auth/checks/auth-checks"; +import { onlyAllowUserHimself } from '../middleware/auth/checks/user-auth-checks'; +import { adminOnly } from '../middleware/auth/checks/auth-checks'; const router = express.Router(); diff --git a/backend/src/routes/teacher-invitations.ts b/backend/src/routes/teacher-invitations.ts index fe0b924f..d9c98e5f 100644 --- a/backend/src/routes/teacher-invitations.ts +++ b/backend/src/routes/teacher-invitations.ts @@ -6,18 +6,19 @@ import { getInvitationHandler, updateInvitationHandler, } from '../controllers/teacher-invitations'; -import {onlyAllowUserHimself} from "../middleware/auth/checks/user-auth-checks"; +import { onlyAllowUserHimself } from '../middleware/auth/checks/user-auth-checks'; import { - onlyAllowReceiverBody, onlyAllowSender, + onlyAllowReceiverBody, + onlyAllowSender, onlyAllowSenderBody, - onlyAllowSenderOrReceiver -} from "../middleware/auth/checks/teacher-invitation-checks"; + onlyAllowSenderOrReceiver, +} from '../middleware/auth/checks/teacher-invitation-checks'; const router = express.Router({ mergeParams: true }); router.get('/:username', onlyAllowUserHimself, getAllInvitationsHandler); -router.get('/:sender/:receiver/:classId', onlyAllowSenderOrReceiver ,getInvitationHandler); +router.get('/:sender/:receiver/:classId', onlyAllowSenderOrReceiver, getInvitationHandler); router.post('/', onlyAllowSenderBody, createInvitationHandler); diff --git a/backend/src/routes/teachers.ts b/backend/src/routes/teachers.ts index 776b9951..edd06118 100644 --- a/backend/src/routes/teachers.ts +++ b/backend/src/routes/teachers.ts @@ -12,9 +12,9 @@ import { } from '../controllers/teachers.js'; import invitationRouter from './teacher-invitations.js'; -import {adminOnly} from "../middleware/auth/checks/auth-checks"; -import {onlyAllowUserHimself} from "../middleware/auth/checks/user-auth-checks"; -import {onlyAllowTeacherOfClass} from "../middleware/auth/checks/class-auth-checks"; +import { adminOnly } from '../middleware/auth/checks/auth-checks'; +import { onlyAllowUserHimself } from '../middleware/auth/checks/user-auth-checks'; +import { onlyAllowTeacherOfClass } from '../middleware/auth/checks/class-auth-checks'; const router = express.Router(); // Root endpoint used to search objects diff --git a/backend/src/routes/themes.ts b/backend/src/routes/themes.ts index 089c5d46..c5882a2a 100644 --- a/backend/src/routes/themes.ts +++ b/backend/src/routes/themes.ts @@ -1,6 +1,6 @@ import express from 'express'; import { getThemesHandler, getHruidsByThemeHandler } from '../controllers/themes.js'; -import {authenticatedOnly} from "../middleware/auth/checks/auth-checks"; +import { authenticatedOnly } from '../middleware/auth/checks/auth-checks'; const router = express.Router(); diff --git a/backend/src/services/questions.ts b/backend/src/services/questions.ts index 70400226..5894ad6f 100644 --- a/backend/src/services/questions.ts +++ b/backend/src/services/questions.ts @@ -12,7 +12,7 @@ import { AssignmentDTO } from '@dwengo-1/common/interfaces/assignment'; import { fetchStudent } from './students.js'; import { NotFoundException } from '../exceptions/not-found-exception.js'; import { FALLBACK_VERSION_NUM } from '../config.js'; -import {ConflictException} from "../exceptions/conflict-exception"; +import { ConflictException } from '../exceptions/conflict-exception'; export async function getQuestionsAboutLearningObjectInAssignment( loId: LearningObjectIdentifier, @@ -91,12 +91,12 @@ export async function createQuestion(loId: LearningObjectIdentifier, questionDat const assignment = mapToAssignment(questionData.inGroup.assignment as AssignmentDTO, clazz!); const group = await getGroupRepository().findByAssignmentAndGroupNumber(assignment, questionData.inGroup.groupNumber); - if (!group){ - throw new NotFoundException("Group with id and assignment not found"); + if (!group) { + throw new NotFoundException('Group with id and assignment not found'); } - if (! group.members.contains(author)) { - throw new ConflictException("Author is not part of this group"); + if (!group.members.contains(author)) { + throw new ConflictException('Author is not part of this group'); } const question = await questionRepository.createQuestion({ diff --git a/backend/src/services/students.ts b/backend/src/services/students.ts index 09ba1643..de6a9254 100644 --- a/backend/src/services/students.ts +++ b/backend/src/services/students.ts @@ -25,7 +25,7 @@ import { QuestionDTO, QuestionId } from '@dwengo-1/common/interfaces/question'; import { ClassJoinRequestDTO } from '@dwengo-1/common/interfaces/class-join-request'; import { ConflictException } from '../exceptions/conflict-exception.js'; import { Submission } from '../entities/assignments/submission.entity'; -import {mapToUsername} from "../interfaces/user"; +import { mapToUsername } from '../interfaces/user'; export async function getAllStudents(full: boolean): Promise { const studentRepository = getStudentRepository(); diff --git a/backend/src/services/teacher-invitations.ts b/backend/src/services/teacher-invitations.ts index 6aec819b..0457496f 100644 --- a/backend/src/services/teacher-invitations.ts +++ b/backend/src/services/teacher-invitations.ts @@ -32,7 +32,7 @@ export async function createInvitation(data: TeacherInvitationData): Promise { const teacherRepository: TeacherRepository = getTeacherRepository();