From 1b096b411b5c24230b4d64658832c4d283eeb553 Mon Sep 17 00:00:00 2001 From: Gabriellvl Date: Sun, 9 Mar 2025 23:59:31 +0100 Subject: [PATCH] fix: integratie user + errors gefixt zodat het runt + format --- backend/src/app.ts | 2 +- backend/src/controllers/assignments.ts | 12 +- backend/src/controllers/classes.ts | 46 ++-- backend/src/controllers/groups.ts | 18 +- backend/src/controllers/learning-objects.ts | 2 +- backend/src/controllers/students.ts | 65 ++++-- backend/src/controllers/teachers.ts | 136 +++++------- backend/src/controllers/themes.ts | 3 +- backend/src/controllers/users.ts | 52 +++-- .../src/data/assignments/group-repository.ts | 21 +- backend/src/data/classes/class-repository.ts | 10 +- .../content/learning-object-repository.ts | 2 +- backend/src/data/dwengo-entity-repository.ts | 6 +- .../src/data/questions/answer-repository.ts | 2 +- .../src/data/questions/question-repository.ts | 16 +- backend/src/data/repositories.ts | 4 +- backend/src/data/users/student-repository.ts | 2 +- backend/src/data/users/teacher-repository.ts | 2 +- .../entities/assignments/assignment.entity.ts | 26 ++- .../src/entities/assignments/group.entity.ts | 19 +- .../entities/assignments/submission.entity.ts | 26 ++- .../classes/class-join-request.entity.ts | 24 +- backend/src/entities/classes/class.entity.ts | 14 +- .../classes/teacher-invitation.entity.ts | 27 ++- .../src/entities/content/attachment.entity.ts | 13 +- .../content/learning-object.entity.ts | 39 +++- .../entities/content/learning-path.entity.ts | 45 +++- .../src/entities/questions/answer.entity.ts | 20 +- .../src/entities/questions/question.entity.ts | 19 +- backend/src/entities/users/student.entity.ts | 14 +- backend/src/entities/users/teacher.entity.ts | 10 +- backend/src/interfaces/assignment.ts | 24 +- backend/src/interfaces/class.ts | 14 +- backend/src/interfaces/group.ts | 22 +- backend/src/interfaces/list.ts | 6 +- backend/src/interfaces/question.ts | 21 +- backend/src/interfaces/student.ts | 2 +- backend/src/interfaces/teacher-invitation.ts | 24 +- backend/src/interfaces/teacher.ts | 36 --- backend/src/interfaces/user.ts | 9 +- backend/src/mikro-orm.config.ts | 48 ++-- backend/src/routes/assignments.ts | 23 +- backend/src/routes/classes.ts | 17 +- backend/src/routes/groups.ts | 15 +- backend/src/routes/questions.ts | 28 +-- backend/src/routes/students.ts | 38 ++-- backend/src/routes/submissions.ts | 15 +- backend/src/routes/teachers.ts | 25 ++- backend/src/services/assignments.ts | 24 +- backend/src/services/class.ts | 73 ++++-- backend/src/services/groups.ts | 31 ++- backend/src/services/students.ts | 26 ++- backend/src/services/teachers.ts | 208 ++++++++---------- backend/src/services/users.ts | 18 +- backend/src/util/translation-helper.ts | 8 +- 55 files changed, 858 insertions(+), 594 deletions(-) delete mode 100644 backend/src/interfaces/teacher.ts diff --git a/backend/src/app.ts b/backend/src/app.ts index 37cfec67..20581e35 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -7,7 +7,7 @@ import learningPathRoutes from './routes/learning-paths.js'; import learningObjectRoutes from './routes/learning-objects.js'; import studentRoutes from './routes/students.js'; -import teacherRoutes from './routes/teachers.js' +import teacherRoutes from './routes/teachers.js'; import groupRoutes from './routes/groups.js'; import submissionRoutes from './routes/submissions.js'; import classRoutes from './routes/classes.js'; diff --git a/backend/src/controllers/assignments.ts b/backend/src/controllers/assignments.ts index ab0f951f..b1be1302 100644 --- a/backend/src/controllers/assignments.ts +++ b/backend/src/controllers/assignments.ts @@ -1,7 +1,7 @@ -import { Request, Response } from 'express' +import { Request, Response } from 'express'; import { getAllAssignments, getAssignment } from '../services/assignments.js'; -// typescript is annoy with with parameter forwarding from class.ts +// Typescript is annoy with with parameter forwarding from class.ts interface AssignmentParams { classid: string; id: string; @@ -9,7 +9,7 @@ interface AssignmentParams { export async function getAllAssignmentsHandler( req: Request, - res: Response, + res: Response ): Promise { const classid = req.params.classid; const full = req.query.full === 'true'; @@ -23,20 +23,20 @@ export async function getAllAssignmentsHandler( export async function getAssignmentHandler( req: Request, - res: Response, + res: Response ): Promise { const id = +req.params.id; const classid = req.params.classid; if (isNaN(id)) { - res.status(400).json({ error: "Assignment id must be a number" }); + res.status(400).json({ error: 'Assignment id must be a number' }); return; } const assignment = await getAssignment(classid, id); if (!assignment) { - res.status(404).json({ error: "Assignment not found" }); + res.status(404).json({ error: 'Assignment not found' }); return; } diff --git a/backend/src/controllers/classes.ts b/backend/src/controllers/classes.ts index 6fb9d7f4..b8061b5a 100644 --- a/backend/src/controllers/classes.ts +++ b/backend/src/controllers/classes.ts @@ -1,40 +1,44 @@ import { Request, Response } from 'express'; -import { getAllClasses, getClass, getClassStudents, getClassStudentsIds, getClassTeacherInvitations } from '../services/class.js'; -import { ClassDTO } from '../interfaces/classes.js'; +import { + getAllClasses, + getClass, + getClassStudents, + getClassStudentsIds, + getClassTeacherInvitations, +} from '../services/class.js'; export async function getAllClassesHandler( req: Request, - res: Response, + res: Response ): Promise { - const full = req.query.full === "true"; + const full = req.query.full === 'true'; const classes = await getAllClasses(full); res.json({ - classes: classes + classes: classes, }); } export async function getClassHandler( req: Request, - res: Response, + res: Response ): Promise { try { const classId = req.params.id; const cls = await getClass(classId); if (!cls) { - res.status(404).json({ error: "Student not found" }); + res.status(404).json({ error: 'Student not found' }); return; - } else { - cls.endpoints = { - self: `${req.baseUrl}/${req.params.id}`, - invitations: `${req.baseUrl}/${req.params.id}/invitations`, - assignments: `${req.baseUrl}/${req.params.id}/assignments`, - students: `${req.baseUrl}/${req.params.id}/students`, - } - - res.json(cls); } + cls.endpoints = { + self: `${req.baseUrl}/${req.params.id}`, + invitations: `${req.baseUrl}/${req.params.id}/invitations`, + assignments: `${req.baseUrl}/${req.params.id}/assignments`, + students: `${req.baseUrl}/${req.params.id}/students`, + }; + + res.json(cls); } catch (error) { console.error('Error fetching learning objects:', error); res.status(500).json({ error: 'Internal server error' }); @@ -43,12 +47,12 @@ export async function getClassHandler( export async function getClassStudentsHandler( req: Request, - res: Response, + res: Response ): Promise { const classId = req.params.id; - const full = req.query.full === "true"; + const full = req.query.full === 'true'; - let students = full + const students = full ? await getClassStudents(classId) : await getClassStudentsIds(classId); @@ -59,10 +63,10 @@ export async function getClassStudentsHandler( export async function getTeacherInvitationsHandler( req: Request, - res: Response, + res: Response ): Promise { const classId = req.params.id; - const full = req.query.full === "true"; // TODO: not implemented yet + const full = req.query.full === 'true'; // TODO: not implemented yet const invitations = await getClassTeacherInvitations(classId, full); diff --git a/backend/src/controllers/groups.ts b/backend/src/controllers/groups.ts index d301c98d..e484c409 100644 --- a/backend/src/controllers/groups.ts +++ b/backend/src/controllers/groups.ts @@ -1,7 +1,7 @@ import { Request, Response } from 'express'; import { getAllGroups, getGroup } from '../services/groups.js'; -// typescript is annoywith with parameter forwarding from class.ts +// Typescript is annoywith with parameter forwarding from class.ts interface GroupParams { classid: string; assignmentid: string; @@ -10,21 +10,21 @@ interface GroupParams { export async function getGroupHandler( req: Request, - res: Response, + res: Response ): Promise { const classId = req.params.classid; - const full = req.query.full === "true"; + const full = req.query.full === 'true'; const assignmentId = +req.params.assignmentid; if (isNaN(assignmentId)) { - res.status(400).json({ error: "Assignment id must be a number" }); + res.status(400).json({ error: 'Assignment id must be a number' }); return; } - const groupId = +req.params.groupid!; // can't be undefined + const groupId = +req.params.groupid!; // Can't be undefined if (isNaN(groupId)) { - res.status(400).json({ error: "Group id must be a number" }); + res.status(400).json({ error: 'Group id must be a number' }); return; } @@ -35,15 +35,15 @@ export async function getGroupHandler( export async function getAllGroupsHandler( req: Request, - res: Response, + res: Response ): Promise { const classId = req.params.classid; - const full = req.query.full === "true"; + const full = req.query.full === 'true'; const assignmentId = +req.params.assignmentid; if (isNaN(assignmentId)) { - res.status(400).json({ error: "Assignment id must be a number" }); + res.status(400).json({ error: 'Assignment id must be a number' }); return; } diff --git a/backend/src/controllers/learning-objects.ts b/backend/src/controllers/learning-objects.ts index c8a51734..12c0201f 100644 --- a/backend/src/controllers/learning-objects.ts +++ b/backend/src/controllers/learning-objects.ts @@ -5,7 +5,7 @@ import { getLearningObjectsFromPath, } from '../services/learning-objects.js'; import { FALLBACK_LANG } from '../config.js'; -import { FilteredLearningObject } from '../interfaces/learning-path'; +import { FilteredLearningObject } from '../interfaces/learning-path.js'; export async function getAllLearningObjects( req: Request, diff --git a/backend/src/controllers/students.ts b/backend/src/controllers/students.ts index b4fe7b47..2134a9f2 100644 --- a/backend/src/controllers/students.ts +++ b/backend/src/controllers/students.ts @@ -2,43 +2,62 @@ import { Request, Response } from 'express'; import { getStudentClasses, getStudentClassIds, - StudentService + StudentService, } from '../services/students.js'; -import { ClassDTO } from '../interfaces/classes.js'; +import { ClassDTO } from '../interfaces/class.js'; import { getAllAssignments } from '../services/assignments.js'; -import {createUserHandler, deleteUserHandler, getAllUsersHandler, getUserHandler} from "./users.js"; -import { Student } from "../entities/users/student.entity.js"; +import { + createUserHandler, + deleteUserHandler, + getAllUsersHandler, + getUserHandler, +} from './users.js'; +import { Student } from '../entities/users/student.entity.js'; // TODO: accept arguments (full, ...) // TODO: endpoints -export async function getAllStudentsHandler (req: Request, res: Response): Promise { +export async function getAllStudentsHandler( + req: Request, + res: Response +): Promise { await getAllUsersHandler(req, res, new StudentService()); } -export async function getStudentHandler(req: Request, res: Response): Promise { +export async function getStudentHandler( + req: Request, + res: Response +): Promise { await getUserHandler(req, res, new StudentService()); } -export async function createStudentHandler(req: Request, res: Response): Promise { +export async function createStudentHandler( + req: Request, + res: Response +): Promise { await createUserHandler(req, res, new StudentService(), Student); } -export async function deleteStudentHandler(req: Request, res: Response): Promise { +export async function deleteStudentHandler( + req: Request, + res: Response +): Promise { await deleteUserHandler(req, res, new StudentService()); } - -export async function getStudentClassesHandler ( +export async function getStudentClassesHandler( req: Request, - res: Response, + res: Response ): Promise { try { const full = req.query.full === 'true'; const username = req.params.id; let classes: ClassDTO[] | string[]; - if (full) classes = await getStudentClasses(username); - else classes = await getStudentClassIds(username); + if (full) { + classes = await getStudentClasses(username); + } else { + classes = await getStudentClassIds(username); + } res.json({ classes: classes, @@ -47,7 +66,7 @@ export async function getStudentClassesHandler ( classes: `${req.baseUrl}/${req.params.id}/invitations`, questions: `${req.baseUrl}/${req.params.id}/assignments`, students: `${req.baseUrl}/${req.params.id}/students`, - } + }, }); } catch (error) { console.error('Error fetching learning objects:', error); @@ -57,22 +76,26 @@ export async function getStudentClassesHandler ( // TODO // Might not be fully correct depending on if -// a class has an assignment, that all students -// have this assignment. +// A class has an assignment, that all students +// Have this assignment. export async function getStudentAssignmentsHandler( req: Request, - res: Response, + res: Response ): Promise { const full = req.query.full === 'true'; const username = req.params.id; const classes = await getStudentClasses(username); - const assignments = (await Promise.all(classes.map(async cls => await getAllAssignments(cls.id, full)))).flat(); + const assignments = ( + await Promise.all( + classes.map(async (cls) => { + return await getAllAssignments(cls.id, full); + }) + ) + ).flat(); res.json({ - assignments: assignments + assignments: assignments, }); } - - diff --git a/backend/src/controllers/teachers.ts b/backend/src/controllers/teachers.ts index d3b6a4db..c083710d 100644 --- a/backend/src/controllers/teachers.ts +++ b/backend/src/controllers/teachers.ts @@ -1,92 +1,53 @@ import { Request, Response } from 'express'; +import { TeacherUserService, TeacherService } from '../services/teachers.js'; +import { ClassDTO } from '../interfaces/class.js'; +import { StudentDTO } from '../interfaces/student.js'; +import { QuestionDTO, QuestionId } from '../interfaces/question.js'; import { - createTeacher, - deleteTeacher, - getTeacherByUsername, - getClassesByTeacher, - getClassIdsByTeacher, - getAllTeachers, - getAllTeachersIds, getStudentsByTeacher, getStudentIdsByTeacher, getQuestionsByTeacher, getQuestionIdsByTeacher -} from '../services/teachers.js'; -import {TeacherDTO} from "../interfaces/teacher"; -import {ClassDTO} from "../interfaces/class"; -import {StudentDTO} from "../interfaces/student"; -import {QuestionDTO, QuestionId} from "../interfaces/question"; + createUserHandler, + deleteUserHandler, + getAllUsersHandler, + getUserHandler, +} from './users.js'; +import { Teacher } from '../entities/users/teacher.entity.js'; -export async function getTeacherHandler(req: Request, res: Response): Promise { - try { - const full = req.query.full === 'true'; - const username = req.query.username as string; +export async function getAllTeachersHandler( + req: Request, + res: Response +): Promise { + await getAllUsersHandler(req, res, new TeacherUserService()); +} - if (username){ - const teacher = await getTeacherByUsername(username); - if (!teacher){ - res.status(404).json({ error: `Teacher with username '${username}' not found.` }); - return; - } - res.json(teacher); - return; - } - - let teachers: TeacherDTO[] | string[]; - - if (full) teachers = await getAllTeachers(); - else teachers = await getAllTeachersIds(); - - res.json(teachers); - } catch (error) { - console.error("❌ Error fetching teachers:", error); - res.status(500).json({ error: "Internal server error" }); - } +export async function getTeacherHandler( + req: Request, + res: Response +): Promise { + await getUserHandler(req, res, new TeacherUserService()); } export async function createTeacherHandler( req: Request, res: Response ): Promise { - try { - const teacherData = req.body as TeacherDTO; - - if (!teacherData.username || !teacherData.firstName || !teacherData.lastName) { - res.status(400).json({ error: 'Missing required fields: username, firstName, lastName' }); - return; - } - - const newTeacher = await createTeacher(teacherData); - res.status(201).json(newTeacher); - } catch (error) { - console.error('Error creating teacher:', error); - res.status(500).json({ error: 'Internal server error' }); - } + await createUserHandler( + req, + res, + new TeacherUserService(), + Teacher + ); } export async function deleteTeacherHandler( req: Request, res: Response ): Promise { - try { - const username = req.params.username as string; - - if (!username) { - res.status(400).json({ error: 'Missing required field: username' }); - return; - } - - const deletedTeacher = await deleteTeacher(username); - - if (!deletedTeacher) { - res.status(400).json({ error: `Did not find teacher with username ${username}` }); - return; - } - - res.status(201).json(deletedTeacher); - } catch (error) { - console.error('Error deleting teacher:', error); - res.status(500).json({ error: 'Internal server error' }); - } + await deleteUserHandler(req, res, new TeacherUserService()); } -export async function getTeacherClassHandler(req: Request, res: Response): Promise { +export async function getTeacherClassHandler( + req: Request, + res: Response +): Promise { try { const username = req.params.username as string; const full = req.query.full === 'true'; @@ -96,10 +57,11 @@ export async function getTeacherClassHandler(req: Request, res: Response): Promi return; } - let classes: ClassDTO[] | string[]; + const teacherService = new TeacherService(); - if (full) classes = await getClassesByTeacher(username); - else classes = await getClassIdsByTeacher(username); + const classes: ClassDTO[] | string[] = full + ? await teacherService.getClassesByTeacher(username) + : await teacherService.getClassIdsByTeacher(username); res.status(201).json(classes); } catch (error) { @@ -108,7 +70,10 @@ export async function getTeacherClassHandler(req: Request, res: Response): Promi } } -export async function getTeacherStudentHandler(req: Request, res: Response): Promise { +export async function getTeacherStudentHandler( + req: Request, + res: Response +): Promise { try { const username = req.params.username as string; const full = req.query.full === 'true'; @@ -118,10 +83,11 @@ export async function getTeacherStudentHandler(req: Request, res: Response): Pro return; } - let students: StudentDTO[] | string[]; + const teacherService = new TeacherService(); - if (full) students = await getStudentsByTeacher(username); - else students = await getStudentIdsByTeacher(username); + const students: StudentDTO[] | string[] = full + ? await teacherService.getStudentsByTeacher(username) + : await teacherService.getStudentIdsByTeacher(username); res.status(201).json(students); } catch (error) { @@ -130,7 +96,10 @@ export async function getTeacherStudentHandler(req: Request, res: Response): Pro } } -export async function getTeacherQuestionHandler(req: Request, res: Response): Promise { +export async function getTeacherQuestionHandler( + req: Request, + res: Response +): Promise { try { const username = req.params.username as string; const full = req.query.full === 'true'; @@ -140,10 +109,11 @@ export async function getTeacherQuestionHandler(req: Request, res: Response): Pr return; } - let questions: QuestionDTO[] | QuestionId[]; + const teacherService = new TeacherService(); - if (full) questions = await getQuestionsByTeacher(username); - else questions = await getQuestionIdsByTeacher(username); + const questions: QuestionDTO[] | QuestionId[] = full + ? await teacherService.getQuestionsByTeacher(username) + : await teacherService.getQuestionIdsByTeacher(username); res.status(201).json(questions); } catch (error) { @@ -151,5 +121,3 @@ export async function getTeacherQuestionHandler(req: Request, res: Response): Pr res.status(500).json({ error: 'Internal server error' }); } } - - diff --git a/backend/src/controllers/themes.ts b/backend/src/controllers/themes.ts index 208b27d1..30cb2b13 100644 --- a/backend/src/controllers/themes.ts +++ b/backend/src/controllers/themes.ts @@ -1,7 +1,6 @@ import { Request, Response } from 'express'; import { themes } from '../data/themes.js'; -import { loadTranslations } from "../util/translation-helper.js"; -import { FALLBACK_LANG } from '../config.js'; +import { loadTranslations } from '../util/translation-helper.js'; interface Translations { curricula_page: { diff --git a/backend/src/controllers/users.ts b/backend/src/controllers/users.ts index 4b29617e..8b256a0e 100644 --- a/backend/src/controllers/users.ts +++ b/backend/src/controllers/users.ts @@ -1,30 +1,29 @@ import { Request, Response } from 'express'; -import { UserService } from "../services/users.js"; -import {UserDTO} from "../interfaces/user.js"; -import {User} from "../entities/users/user.entity.js"; +import { UserService } from '../services/users.js'; +import { UserDTO } from '../interfaces/user.js'; +import { User } from '../entities/users/user.entity.js'; export async function getAllUsersHandler( req: Request, res: Response, service: UserService -): Promise { +): Promise { try { const full = req.query.full === 'true'; - let users: UserDTO[] | string[] = full + const users: UserDTO[] | string[] = full ? await service.getAllUsers() : await service.getAllUserIds(); - if (!users){ + if (!users) { res.status(404).json({ error: `Users not found.` }); return; } res.status(201).json(users); - } catch (error) { - console.error("❌ Error fetching users:", error); - res.status(500).json({ error: "Internal server error" }); + console.error('❌ Error fetching users:', error); + res.status(500).json({ error: 'Internal server error' }); } } @@ -32,7 +31,7 @@ export async function getUserHandler( req: Request, res: Response, service: UserService -): Promise { +): Promise { try { const username = req.params.username as string; @@ -43,16 +42,17 @@ export async function getUserHandler( const user = await service.getUserByUsername(username); - if (!user){ - res.status(404).json({ error: `User with username '${username}' not found.` }); + if (!user) { + res.status(404).json({ + error: `User with username '${username}' not found.`, + }); return; } res.status(201).json(user); - } catch (error) { - console.error("❌ Error fetching users:", error); - res.status(500).json({ error: "Internal server error" }); + console.error('❌ Error fetching users:', error); + res.status(500).json({ error: 'Internal server error' }); } } @@ -63,23 +63,25 @@ export async function createUserHandler( UserClass: new () => T ) { try { - console.log("req", req) + console.log('req', req); const userData = req.body as UserDTO; if (!userData.username || !userData.firstName || !userData.lastName) { - res.status(400).json({ error: "Missing required fields: username, firstName, lastName" }); + res.status(400).json({ + error: 'Missing required fields: username, firstName, lastName', + }); return; } const newUser = await service.createUser(userData, UserClass); res.status(201).json(newUser); } catch (error) { - console.error("❌ Error creating user:", error); - res.status(500).json({ error: "Internal server error" }); + console.error('❌ Error creating user:', error); + res.status(500).json({ error: 'Internal server error' }); } } -export async function deleteUserHandler ( +export async function deleteUserHandler( req: Request, res: Response, service: UserService @@ -88,19 +90,21 @@ export async function deleteUserHandler ( const username = req.params.username; if (!username) { - res.status(400).json({ error: "Missing required field: username" }); + res.status(400).json({ error: 'Missing required field: username' }); return; } const deletedUser = await service.deleteUser(username); if (!deletedUser) { - res.status(404).json({ error: `User with username '${username}' not found.` }); + res.status(404).json({ + error: `User with username '${username}' not found.`, + }); return; } res.status(200).json(deletedUser); } catch (error) { - console.error("❌ Error deleting user:", error); - res.status(500).json({ error: "Internal server error" }); + console.error('❌ Error deleting user:', error); + res.status(500).json({ error: 'Internal server error' }); } } diff --git a/backend/src/data/assignments/group-repository.ts b/backend/src/data/assignments/group-repository.ts index c8770eb5..e9b668b9 100644 --- a/backend/src/data/assignments/group-repository.ts +++ b/backend/src/data/assignments/group-repository.ts @@ -8,21 +8,20 @@ export class GroupRepository extends DwengoEntityRepository { groupNumber: number ): Promise { return this.findOne( - { - assignment: assignment, - groupNumber: groupNumber, - }, - { populate: ["members"] }, - ); + { + assignment: assignment, + groupNumber: groupNumber, + }, + { populate: ['members'] } + ); } public findAllGroupsForAssignment( assignment: Assignment ): Promise { - return this.findAll({ - where: { assignment: assignment }, - populate: ["members"] - }, - ); + return this.findAll({ + where: { assignment: assignment }, + populate: ['members'], + }); } public deleteByAssignmentAndGroupNumber( assignment: Assignment, diff --git a/backend/src/data/classes/class-repository.ts b/backend/src/data/classes/class-repository.ts index 9fd50d75..4f2f5b0e 100644 --- a/backend/src/data/classes/class-repository.ts +++ b/backend/src/data/classes/class-repository.ts @@ -1,13 +1,13 @@ import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; import { Class } from '../../entities/classes/class.entity.js'; import { Student } from '../../entities/users/student.entity.js'; -import {Teacher} from "../../entities/users/teacher.entity"; +import { Teacher } from '../../entities/users/teacher.entity'; export class ClassRepository extends DwengoEntityRepository { public findById(id: string): Promise { return this.findOne( { classId: id }, - { populate: ["students", "teachers"] }, + { populate: ['students', 'teachers'] } ); } public deleteById(id: string): Promise { @@ -16,14 +16,14 @@ export class ClassRepository extends DwengoEntityRepository { public findByStudent(student: Student): Promise { return this.find( { students: student }, - { populate: ["students", "teachers"] } // voegt student en teacher objecten toe - ) + { populate: ['students', 'teachers'] } // Voegt student en teacher objecten toe + ); } public findByTeacher(teacher: Teacher): Promise { return this.find( { teachers: teacher }, - { populate: ["students", "teachers"] } + { populate: ['students', 'teachers'] } ); } } diff --git a/backend/src/data/content/learning-object-repository.ts b/backend/src/data/content/learning-object-repository.ts index d8b07943..4de31076 100644 --- a/backend/src/data/content/learning-object-repository.ts +++ b/backend/src/data/content/learning-object-repository.ts @@ -1,7 +1,7 @@ import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; import { LearningObject } from '../../entities/content/learning-object.entity.js'; import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js'; -import {Teacher} from "../../entities/users/teacher.entity"; +import { Teacher } from '../../entities/users/teacher.entity'; export class LearningObjectRepository extends DwengoEntityRepository { public findByIdentifier( diff --git a/backend/src/data/dwengo-entity-repository.ts b/backend/src/data/dwengo-entity-repository.ts index 368f3a2c..e29d9ede 100644 --- a/backend/src/data/dwengo-entity-repository.ts +++ b/backend/src/data/dwengo-entity-repository.ts @@ -4,13 +4,13 @@ export abstract class DwengoEntityRepository< T extends object, > extends EntityRepository { public async save(entity: T) { - let em = this.getEntityManager(); + const em = this.getEntityManager(); em.persist(entity); await em.flush(); } public async deleteWhere(query: FilterQuery) { - let toDelete = await this.findOne(query); - let em = this.getEntityManager(); + const toDelete = await this.findOne(query); + const em = this.getEntityManager(); if (toDelete) { em.remove(toDelete); await em.flush(); diff --git a/backend/src/data/questions/answer-repository.ts b/backend/src/data/questions/answer-repository.ts index 6a2629f4..6c45211c 100644 --- a/backend/src/data/questions/answer-repository.ts +++ b/backend/src/data/questions/answer-repository.ts @@ -9,7 +9,7 @@ export class AnswerRepository extends DwengoEntityRepository { author: Teacher; content: string; }): Promise { - let answerEntity = new Answer(); + const answerEntity = new Answer(); answerEntity.toQuestion = answer.toQuestion; answerEntity.author = answer.author; answerEntity.content = answer.content; diff --git a/backend/src/data/questions/question-repository.ts b/backend/src/data/questions/question-repository.ts index 05430ddd..7dee3b96 100644 --- a/backend/src/data/questions/question-repository.ts +++ b/backend/src/data/questions/question-repository.ts @@ -2,7 +2,7 @@ import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; import { Question } from '../../entities/questions/question.entity.js'; import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js'; import { Student } from '../../entities/users/student.entity.js'; -import {LearningObject} from "../../entities/content/learning-object.entity"; +import { LearningObject } from '../../entities/content/learning-object.entity'; export class QuestionRepository extends DwengoEntityRepository { public createQuestion(question: { @@ -10,7 +10,7 @@ export class QuestionRepository extends DwengoEntityRepository { author: Student; content: string; }): Promise { - let questionEntity = new Question(); + const questionEntity = new Question(); questionEntity.learningObjectHruid = question.loId.hruid; questionEntity.learningObjectLanguage = question.loId.language; questionEntity.learningObjectVersion = question.loId.version; @@ -44,12 +44,16 @@ export class QuestionRepository extends DwengoEntityRepository { }); } - public async findAllByLearningObjects(learningObjects: LearningObject[]): Promise { - const objectIdentifiers = learningObjects.map(lo => ({ + public async findAllByLearningObjects( + learningObjects: LearningObject[] + ): Promise { + const objectIdentifiers = learningObjects.map((lo) => { + return { learningObjectHruid: lo.hruid, learningObjectLanguage: lo.language, - learningObjectVersion: lo.version - })); + learningObjectVersion: lo.version, + }; + }); return this.findAll({ where: { $or: objectIdentifiers }, diff --git a/backend/src/data/repositories.ts b/backend/src/data/repositories.ts index e65bb882..74e9a07e 100644 --- a/backend/src/data/repositories.ts +++ b/backend/src/data/repositories.ts @@ -59,7 +59,9 @@ function repositoryGetter>( } /* Users */ -export const getUserRepository = repositoryGetter>(User); +export const getUserRepository = repositoryGetter>( + User +); export const getStudentRepository = repositoryGetter< Student, StudentRepository diff --git a/backend/src/data/users/student-repository.ts b/backend/src/data/users/student-repository.ts index c553aab8..6835e430 100644 --- a/backend/src/data/users/student-repository.ts +++ b/backend/src/data/users/student-repository.ts @@ -1,4 +1,4 @@ import { Student } from '../../entities/users/student.entity.js'; -import {UserRepository} from "./user-repository.js"; +import { UserRepository } from './user-repository.js'; export class StudentRepository extends UserRepository {} diff --git a/backend/src/data/users/teacher-repository.ts b/backend/src/data/users/teacher-repository.ts index 9940b4bd..4c4f7687 100644 --- a/backend/src/data/users/teacher-repository.ts +++ b/backend/src/data/users/teacher-repository.ts @@ -1,4 +1,4 @@ import { Teacher } from '../../entities/users/teacher.entity.js'; -import {UserRepository} from "./user-repository.js"; +import { UserRepository } from './user-repository.js'; export class TeacherRepository extends UserRepository {} diff --git a/backend/src/entities/assignments/assignment.entity.ts b/backend/src/entities/assignments/assignment.entity.ts index 785a8b9c..f6e3c3eb 100644 --- a/backend/src/entities/assignments/assignment.entity.ts +++ b/backend/src/entities/assignments/assignment.entity.ts @@ -11,9 +11,18 @@ import { Group } from './group.entity.js'; import { Language } from '../content/language.js'; import { AssignmentRepository } from '../../data/assignments/assignment-repository.js'; -@Entity({ repository: () => AssignmentRepository }) +@Entity({ + repository: () => { + return AssignmentRepository; + }, +}) export class Assignment { - @ManyToOne({ entity: () => Class, primary: true }) + @ManyToOne({ + entity: () => { + return Class; + }, + primary: true, + }) within!: Class; @PrimaryKey({ type: 'number' }) @@ -28,9 +37,18 @@ export class Assignment { @Property({ type: 'string' }) learningPathHruid!: string; - @Enum({ items: () => Language }) + @Enum({ + items: () => { + return Language; + }, + }) learningPathLanguage!: Language; - @OneToMany({ entity: () => Group, mappedBy: 'assignment' }) + @OneToMany({ + entity: () => { + return Group; + }, + mappedBy: 'assignment', + }) groups!: Group[]; } diff --git a/backend/src/entities/assignments/group.entity.ts b/backend/src/entities/assignments/group.entity.ts index cb4cd6e6..9c2ed2cf 100644 --- a/backend/src/entities/assignments/group.entity.ts +++ b/backend/src/entities/assignments/group.entity.ts @@ -3,14 +3,27 @@ import { Assignment } from './assignment.entity.js'; import { Student } from '../users/student.entity.js'; import { GroupRepository } from '../../data/assignments/group-repository.js'; -@Entity({ repository: () => GroupRepository }) +@Entity({ + repository: () => { + return GroupRepository; + }, +}) export class Group { - @ManyToOne({ entity: () => Assignment, primary: true }) + @ManyToOne({ + entity: () => { + return Assignment; + }, + primary: true, + }) assignment!: Assignment; @PrimaryKey({ type: 'integer' }) groupNumber!: number; - @ManyToMany({ entity: () => Student }) + @ManyToMany({ + entity: () => { + return Student; + }, + }) members!: Student[]; } diff --git a/backend/src/entities/assignments/submission.entity.ts b/backend/src/entities/assignments/submission.entity.ts index 26269020..2836c8dc 100644 --- a/backend/src/entities/assignments/submission.entity.ts +++ b/backend/src/entities/assignments/submission.entity.ts @@ -4,12 +4,21 @@ import { Entity, Enum, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'; import { Language } from '../content/language.js'; import { SubmissionRepository } from '../../data/assignments/submission-repository.js'; -@Entity({ repository: () => SubmissionRepository }) +@Entity({ + repository: () => { + return SubmissionRepository; + }, +}) export class Submission { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => Language, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) learningObjectLanguage!: Language; @PrimaryKey({ type: 'string' }) @@ -18,13 +27,22 @@ export class Submission { @PrimaryKey({ type: 'integer' }) submissionNumber!: number; - @ManyToOne({ entity: () => Student }) + @ManyToOne({ + entity: () => { + return Student; + }, + }) submitter!: Student; @Property({ type: 'datetime' }) submissionTime!: Date; - @ManyToOne({ entity: () => Group, nullable: true }) + @ManyToOne({ + entity: () => { + return Group; + }, + nullable: true, + }) onBehalfOf?: Group; @Property({ type: 'json' }) diff --git a/backend/src/entities/classes/class-join-request.entity.ts b/backend/src/entities/classes/class-join-request.entity.ts index 0636e044..6055454b 100644 --- a/backend/src/entities/classes/class-join-request.entity.ts +++ b/backend/src/entities/classes/class-join-request.entity.ts @@ -3,15 +3,31 @@ import { Student } from '../users/student.entity.js'; import { Class } from './class.entity.js'; import { ClassJoinRequestRepository } from '../../data/classes/class-join-request-repository.js'; -@Entity({ repository: () => ClassJoinRequestRepository }) +@Entity({ + repository: () => { + return ClassJoinRequestRepository; + }, +}) export class ClassJoinRequest { - @ManyToOne({ entity: () => Student, primary: true }) + @ManyToOne({ + entity: () => { + return Student; + }, + primary: true, + }) requester!: Student; - @ManyToOne({ entity: () => Class, primary: true }) + @ManyToOne({ + entity: () => { + return Class; + }, + primary: true, + }) class!: Class; - @Enum(() => ClassJoinRequestStatus) + @Enum(() => { + return ClassJoinRequestStatus; + }) status!: ClassJoinRequestStatus; } diff --git a/backend/src/entities/classes/class.entity.ts b/backend/src/entities/classes/class.entity.ts index 06d31479..b40b5baf 100644 --- a/backend/src/entities/classes/class.entity.ts +++ b/backend/src/entities/classes/class.entity.ts @@ -10,7 +10,11 @@ import { Teacher } from '../users/teacher.entity.js'; import { Student } from '../users/student.entity.js'; import { ClassRepository } from '../../data/classes/class-repository.js'; -@Entity({ repository: () => ClassRepository }) +@Entity({ + repository: () => { + return ClassRepository; + }, +}) export class Class { @PrimaryKey() classId = v4(); @@ -18,9 +22,13 @@ export class Class { @Property({ type: 'string' }) displayName!: string; - @ManyToMany(() => Teacher) + @ManyToMany(() => { + return Teacher; + }) teachers!: Collection; - @ManyToMany(() => Student) + @ManyToMany(() => { + return Student; + }) students!: Collection; } diff --git a/backend/src/entities/classes/teacher-invitation.entity.ts b/backend/src/entities/classes/teacher-invitation.entity.ts index 42700d3a..877a183b 100644 --- a/backend/src/entities/classes/teacher-invitation.entity.ts +++ b/backend/src/entities/classes/teacher-invitation.entity.ts @@ -6,14 +6,33 @@ import { TeacherInvitationRepository } from '../../data/classes/teacher-invitati /** * Invitation of a teacher into a class (in order to teach it). */ -@Entity({ repository: () => TeacherInvitationRepository }) +@Entity({ + repository: () => { + return TeacherInvitationRepository; + }, +}) export class TeacherInvitation { - @ManyToOne({ entity: () => Teacher, primary: true }) + @ManyToOne({ + entity: () => { + return Teacher; + }, + primary: true, + }) sender!: Teacher; - @ManyToOne({ entity: () => Teacher, primary: true }) + @ManyToOne({ + entity: () => { + return Teacher; + }, + primary: true, + }) receiver!: Teacher; - @ManyToOne({ entity: () => Class, primary: true }) + @ManyToOne({ + entity: () => { + return Class; + }, + primary: true, + }) class!: Class; } diff --git a/backend/src/entities/content/attachment.entity.ts b/backend/src/entities/content/attachment.entity.ts index 7f14d178..8225ebf2 100644 --- a/backend/src/entities/content/attachment.entity.ts +++ b/backend/src/entities/content/attachment.entity.ts @@ -2,9 +2,18 @@ import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'; import { LearningObject } from './learning-object.entity.js'; import { AttachmentRepository } from '../../data/content/attachment-repository.js'; -@Entity({ repository: () => AttachmentRepository }) +@Entity({ + repository: () => { + return AttachmentRepository; + }, +}) export class Attachment { - @ManyToOne({ entity: () => LearningObject, primary: true }) + @ManyToOne({ + entity: () => { + return LearningObject; + }, + primary: true, + }) learningObject!: LearningObject; @PrimaryKey({ type: 'integer' }) diff --git a/backend/src/entities/content/learning-object.entity.ts b/backend/src/entities/content/learning-object.entity.ts index 78d4aa00..888de5e3 100644 --- a/backend/src/entities/content/learning-object.entity.ts +++ b/backend/src/entities/content/learning-object.entity.ts @@ -22,18 +22,31 @@ export class ReturnValue { callbackSchema!: string; } -@Entity({ repository: () => LearningObjectRepository }) +@Entity({ + repository: () => { + return LearningObjectRepository; + }, +}) export class LearningObject { @PrimaryKey({ type: 'string' }) hruid!: string; - @Enum({ items: () => Language, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) language!: Language; @PrimaryKey({ type: 'string' }) version: string = '1'; - @ManyToMany({ entity: () => Teacher }) + @ManyToMany({ + entity: () => { + return Teacher; + }, + }) admins!: Teacher[]; @Property({ type: 'string' }) @@ -57,7 +70,12 @@ export class LearningObject { @Property({ type: 'array' }) skosConcepts!: string[]; - @Embedded({ entity: () => EducationalGoal, array: true }) + @Embedded({ + entity: () => { + return EducationalGoal; + }, + array: true, + }) educationalGoals: EducationalGoal[] = []; @Property({ type: 'string' }) @@ -72,7 +90,11 @@ export class LearningObject { @Property({ type: 'integer' }) estimatedTime!: number; - @Embedded({ entity: () => ReturnValue }) + @Embedded({ + entity: () => { + return ReturnValue; + }, + }) returnValue!: ReturnValue; @Property({ type: 'bool' }) @@ -81,7 +103,12 @@ export class LearningObject { @Property({ type: 'string', nullable: true }) contentLocation?: string; - @OneToMany({ entity: () => Attachment, mappedBy: 'learningObject' }) + @OneToMany({ + entity: () => { + return Attachment; + }, + mappedBy: 'learningObject', + }) attachments: Attachment[] = []; @Property({ type: 'blob' }) diff --git a/backend/src/entities/content/learning-path.entity.ts b/backend/src/entities/content/learning-path.entity.ts index de62aa15..34026461 100644 --- a/backend/src/entities/content/learning-path.entity.ts +++ b/backend/src/entities/content/learning-path.entity.ts @@ -12,15 +12,28 @@ import { Language } from './language.js'; import { Teacher } from '../users/teacher.entity.js'; import { LearningPathRepository } from '../../data/content/learning-path-repository.js'; -@Entity({ repository: () => LearningPathRepository }) +@Entity({ + repository: () => { + return LearningPathRepository; + }, +}) export class LearningPath { @PrimaryKey({ type: 'string' }) hruid!: string; - @Enum({ items: () => Language, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) language!: Language; - @ManyToMany({ entity: () => Teacher }) + @ManyToMany({ + entity: () => { + return Teacher; + }, + }) admins!: Teacher[]; @Property({ type: 'string' }) @@ -32,7 +45,12 @@ export class LearningPath { @Property({ type: 'blob' }) image!: string; - @Embedded({ entity: () => LearningPathNode, array: true }) + @Embedded({ + entity: () => { + return LearningPathNode; + }, + array: true, + }) nodes: LearningPathNode[] = []; } @@ -41,7 +59,11 @@ export class LearningPathNode { @Property({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => Language }) + @Enum({ + items: () => { + return Language; + }, + }) language!: Language; @Property({ type: 'string' }) @@ -53,7 +75,12 @@ export class LearningPathNode { @Property({ type: 'bool' }) startNode!: boolean; - @Embedded({ entity: () => LearningPathTransition, array: true }) + @Embedded({ + entity: () => { + return LearningPathTransition; + }, + array: true, + }) transitions!: LearningPathTransition[]; } @@ -62,6 +89,10 @@ export class LearningPathTransition { @Property({ type: 'string' }) condition!: string; - @OneToOne({ entity: () => LearningPathNode }) + @OneToOne({ + entity: () => { + return LearningPathNode; + }, + }) next!: LearningPathNode; } diff --git a/backend/src/entities/questions/answer.entity.ts b/backend/src/entities/questions/answer.entity.ts index 7fb64575..b73c7014 100644 --- a/backend/src/entities/questions/answer.entity.ts +++ b/backend/src/entities/questions/answer.entity.ts @@ -3,12 +3,26 @@ import { Question } from './question.entity.js'; import { Teacher } from '../users/teacher.entity.js'; import { AnswerRepository } from '../../data/questions/answer-repository.js'; -@Entity({ repository: () => AnswerRepository }) +@Entity({ + repository: () => { + return AnswerRepository; + }, +}) export class Answer { - @ManyToOne({ entity: () => Teacher, primary: true }) + @ManyToOne({ + entity: () => { + return Teacher; + }, + primary: true, + }) author!: Teacher; - @ManyToOne({ entity: () => Question, primary: true }) + @ManyToOne({ + entity: () => { + return Question; + }, + primary: true, + }) toQuestion!: Question; @PrimaryKey({ type: 'integer' }) diff --git a/backend/src/entities/questions/question.entity.ts b/backend/src/entities/questions/question.entity.ts index 67efdfe7..689b6ca1 100644 --- a/backend/src/entities/questions/question.entity.ts +++ b/backend/src/entities/questions/question.entity.ts @@ -3,12 +3,21 @@ import { Language } from '../content/language.js'; import { Student } from '../users/student.entity.js'; import { QuestionRepository } from '../../data/questions/question-repository.js'; -@Entity({ repository: () => QuestionRepository }) +@Entity({ + repository: () => { + return QuestionRepository; + }, +}) export class Question { @PrimaryKey({ type: 'string' }) learningObjectHruid!: string; - @Enum({ items: () => Language, primary: true }) + @Enum({ + items: () => { + return Language; + }, + primary: true, + }) learningObjectLanguage!: Language; @PrimaryKey({ type: 'string' }) @@ -17,7 +26,11 @@ export class Question { @PrimaryKey({ type: 'integer' }) sequenceNumber!: number; - @ManyToOne({ entity: () => Student }) + @ManyToOne({ + entity: () => { + return Student; + }, + }) author!: Student; @Property({ type: 'datetime' }) diff --git a/backend/src/entities/users/student.entity.ts b/backend/src/entities/users/student.entity.ts index 401b1ed2..7ad8c9b3 100644 --- a/backend/src/entities/users/student.entity.ts +++ b/backend/src/entities/users/student.entity.ts @@ -4,11 +4,19 @@ import { Class } from '../classes/class.entity.js'; import { Group } from '../assignments/group.entity.js'; import { StudentRepository } from '../../data/users/student-repository.js'; -@Entity({ repository: () => StudentRepository }) +@Entity({ + repository: () => { + return StudentRepository; + }, +}) export class Student extends User { - @ManyToMany(() => Class) + @ManyToMany(() => { + return Class; + }) classes!: Collection; - @ManyToMany(() => Group) + @ManyToMany(() => { + return Group; + }) groups!: Collection; } diff --git a/backend/src/entities/users/teacher.entity.ts b/backend/src/entities/users/teacher.entity.ts index d53ca603..52cc9f7b 100644 --- a/backend/src/entities/users/teacher.entity.ts +++ b/backend/src/entities/users/teacher.entity.ts @@ -3,8 +3,14 @@ import { User } from './user.entity.js'; import { Class } from '../classes/class.entity.js'; import { TeacherRepository } from '../../data/users/teacher-repository.js'; -@Entity({ repository: () => TeacherRepository }) +@Entity({ + repository: () => { + return TeacherRepository; + }, +}) export class Teacher extends User { - @ManyToMany(() => Class) + @ManyToMany(() => { + return Class; + }) classes!: Collection; } diff --git a/backend/src/interfaces/assignment.ts b/backend/src/interfaces/assignment.ts index 146a0517..ad6d8330 100644 --- a/backend/src/interfaces/assignment.ts +++ b/backend/src/interfaces/assignment.ts @@ -1,14 +1,14 @@ -import { Assignment } from "../entities/assignments/assignment.entity.js"; -import { GroupDTO, mapToGroupDTO } from "./groups.js"; +import { Assignment } from '../entities/assignments/assignment.entity.js'; +import { GroupDTO, mapToGroupDTO } from './group.js'; export interface AssignmentDTO { - id: number, - class: string, // id of class 'within' - title: string, - description: string, - learningPath: string, - language: string, - groups?: GroupDTO[] | string[], // TODO + id: number; + class: string; // Id of class 'within' + title: string; + description: string; + learningPath: string; + language: string; + groups?: GroupDTO[] | string[]; // TODO } export function mapToAssignmentDTOId(assignment: Assignment): AssignmentDTO { @@ -19,8 +19,8 @@ export function mapToAssignmentDTOId(assignment: Assignment): AssignmentDTO { description: assignment.description, learningPath: assignment.learningPathHruid, language: assignment.learningPathLanguage, - // groups: assignment.groups.map(group => group.groupNumber), - } + // Groups: assignment.groups.map(group => group.groupNumber), + }; } export function mapToAssignmentDTO(assignment: Assignment): AssignmentDTO { @@ -31,6 +31,6 @@ export function mapToAssignmentDTO(assignment: Assignment): AssignmentDTO { description: assignment.description, learningPath: assignment.learningPathHruid, language: assignment.learningPathLanguage, - // groups: assignment.groups.map(mapToGroupDTO), + // Groups: assignment.groups.map(mapToGroupDTO), }; } diff --git a/backend/src/interfaces/class.ts b/backend/src/interfaces/class.ts index 0274d90c..c18ee842 100644 --- a/backend/src/interfaces/class.ts +++ b/backend/src/interfaces/class.ts @@ -1,4 +1,4 @@ -import { Class } from "../entities/classes/class.entity.js"; +import { Class } from '../entities/classes/class.entity.js'; export interface ClassDTO { id: string; @@ -18,8 +18,12 @@ export function mapToClassDTO(cls: Class): ClassDTO { return { id: cls.classId, displayName: cls.displayName, - teachers: cls.teachers.map(teacher => teacher.username), - students: cls.students.map(student => student.username), + teachers: cls.teachers.map((teacher) => { + return teacher.username; + }), + students: cls.students.map((student) => { + return student.username; + }), joinRequests: [], // TODO - } -}; + }; +} diff --git a/backend/src/interfaces/group.ts b/backend/src/interfaces/group.ts index c4c95baf..9c4cecdc 100644 --- a/backend/src/interfaces/group.ts +++ b/backend/src/interfaces/group.ts @@ -1,25 +1,27 @@ -import { Group } from "../entities/assignments/group.entity.js"; -import { AssignmentDTO, mapToAssignmentDTO } from "./assignments.js"; -import { mapToStudentDTO, StudentDTO } from "./students.js"; +import { Group } from '../entities/assignments/group.entity.js'; +import { AssignmentDTO, mapToAssignmentDTO } from './assignment.js'; +import { mapToStudentDTO, StudentDTO } from './student.js'; export interface GroupDTO { - assignment: number | AssignmentDTO, - groupNumber: number, - members: string[] | StudentDTO[], -}; + assignment: number | AssignmentDTO; + groupNumber: number; + members: string[] | StudentDTO[]; +} export function mapToGroupDTO(group: Group): GroupDTO { return { assignment: mapToAssignmentDTO(group.assignment), // ERROR: , group.assignment.within), groupNumber: group.groupNumber, members: group.members.map(mapToStudentDTO), - } + }; } export function mapToGroupDTOId(group: Group): GroupDTO { return { assignment: group.assignment.id, groupNumber: group.groupNumber, - members: group.members.map(member => member.username), - } + members: group.members.map((member) => { + return member.username; + }), + }; } diff --git a/backend/src/interfaces/list.ts b/backend/src/interfaces/list.ts index 0037403d..6892fb9d 100644 --- a/backend/src/interfaces/list.ts +++ b/backend/src/interfaces/list.ts @@ -1,5 +1,5 @@ // TODO: implement something like this but with named endpoints export interface List { - items: T[], - endpoints?: string[], -}; \ No newline at end of file + items: T[]; + endpoints?: string[]; +} diff --git a/backend/src/interfaces/question.ts b/backend/src/interfaces/question.ts index 1a8c914a..90de4999 100644 --- a/backend/src/interfaces/question.ts +++ b/backend/src/interfaces/question.ts @@ -1,6 +1,4 @@ -import {Question} from "../entities/questions/question.entity"; -import {Enum, PrimaryKey} from "@mikro-orm/core"; -import {Language} from "../entities/content/language"; +import { Question } from '../entities/questions/question.entity.js'; export interface QuestionDTO { learningObjectHruid: string; @@ -34,8 +32,17 @@ export function mapToQuestionDTO(question: Question): QuestionDTO { } export interface QuestionId { - learningObjectHruid: string, - learningObjectLanguage: Language, - learningObjectVersion: string, - sequenceNumber: number + learningObjectHruid: string; + learningObjectLanguage: string; + learningObjectVersion: string; + sequenceNumber: number; +} + +export function mapToQuestionId(question: QuestionDTO): QuestionId { + return { + learningObjectHruid: question.learningObjectHruid, + learningObjectLanguage: question.learningObjectLanguage, + learningObjectVersion: question.learningObjectVersion, + sequenceNumber: question.sequenceNumber, + }; } diff --git a/backend/src/interfaces/student.ts b/backend/src/interfaces/student.ts index c18461e8..529c6ead 100644 --- a/backend/src/interfaces/student.ts +++ b/backend/src/interfaces/student.ts @@ -1,4 +1,4 @@ -import { Student } from "../entities/users/student.entity.js"; +import { Student } from '../entities/users/student.entity.js'; export interface StudentDTO { id: string; diff --git a/backend/src/interfaces/teacher-invitation.ts b/backend/src/interfaces/teacher-invitation.ts index 489e5565..badbbbd7 100644 --- a/backend/src/interfaces/teacher-invitation.ts +++ b/backend/src/interfaces/teacher-invitation.ts @@ -1,22 +1,26 @@ -import { TeacherInvitation } from "../entities/classes/teacher-invitation.entity.js"; -import { ClassDTO, mapToClassDTO } from "./classes.js"; -import { mapToTeacherDTO, TeacherDTO } from "./teacher.js"; +import { TeacherInvitation } from '../entities/classes/teacher-invitation.entity.js'; +import { ClassDTO, mapToClassDTO } from './class.js'; +import { mapToUserDTO, UserDTO } from './user.js'; export interface TeacherInvitationDTO { - sender: string | TeacherDTO, - receiver: string | TeacherDTO, - class: string | ClassDTO, + sender: string | UserDTO; + receiver: string | UserDTO; + class: string | ClassDTO; } -export function mapToTeacherInvitationDTO(invitation: TeacherInvitation): TeacherInvitationDTO { +export function mapToTeacherInvitationDTO( + invitation: TeacherInvitation +): TeacherInvitationDTO { return { - sender: mapToTeacherDTO(invitation.sender), - receiver: mapToTeacherDTO(invitation.receiver), + sender: mapToUserDTO(invitation.sender), + receiver: mapToUserDTO(invitation.receiver), class: mapToClassDTO(invitation.class), }; } -export function mapToTeacherInvitationDTOIds(invitation: TeacherInvitation): TeacherInvitationDTO { +export function mapToTeacherInvitationDTOIds( + invitation: TeacherInvitation +): TeacherInvitationDTO { return { sender: invitation.sender.username, receiver: invitation.receiver.username, diff --git a/backend/src/interfaces/teacher.ts b/backend/src/interfaces/teacher.ts deleted file mode 100644 index 15c89520..00000000 --- a/backend/src/interfaces/teacher.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Teacher } from "../entities/users/teacher.entity.js"; - -/** - * Teacher Data Transfer Object - */ -export interface TeacherDTO { - username: string; - firstName: string; - lastName: string; - endpoints?: { - self: string; - classes: string; - questions: string; - invitations: string; - }; -} - -/** - * Maps a Teacher entity to a TeacherDTO - */ -export function mapToTeacherDTO(teacher: Teacher): TeacherDTO { - return { - username: teacher.username, - firstName: teacher.firstName, - lastName: teacher.lastName, - }; -} - -export function mapToTeacher(teacherData: TeacherDTO): Teacher { - const teacher = new Teacher(); - teacher.username = teacherData.username; - teacher.firstName = teacherData.firstName; - teacher.lastName = teacherData.lastName; - - return teacher; -} diff --git a/backend/src/interfaces/user.ts b/backend/src/interfaces/user.ts index 02e27d83..64081d48 100644 --- a/backend/src/interfaces/user.ts +++ b/backend/src/interfaces/user.ts @@ -1,7 +1,7 @@ -import { User } from "../entities/users/user.entity.js"; +import { User } from '../entities/users/user.entity.js'; export interface UserDTO { - id?: string, + id?: string; username: string; firstName: string; lastName: string; @@ -22,7 +22,10 @@ export function mapToUserDTO(user: User): UserDTO { }; } -export function mapToUser(userData: UserDTO, userInstance: T): T { +export function mapToUser( + userData: UserDTO, + userInstance: T +): T { userInstance.username = userData.username; userInstance.firstName = userData.firstName; userInstance.lastName = userData.lastName; diff --git a/backend/src/mikro-orm.config.ts b/backend/src/mikro-orm.config.ts index 6af867e9..05b68fef 100644 --- a/backend/src/mikro-orm.config.ts +++ b/backend/src/mikro-orm.config.ts @@ -24,11 +24,20 @@ import { Answer } from './entities/questions/answer.entity.js'; import { Question } from './entities/questions/question.entity.js'; const entities = [ - User, Student, Teacher, - Assignment, Group, Submission, - Class, ClassJoinRequest, TeacherInvitation, - Attachment, LearningObject, LearningPath, - Answer, Question + User, + Student, + Teacher, + Assignment, + Group, + Submission, + Class, + ClassJoinRequest, + TeacherInvitation, + Attachment, + LearningObject, + LearningPath, + Answer, + Question, ]; function config(testingMode: boolean = false): Options { @@ -37,25 +46,26 @@ function config(testingMode: boolean = false): Options { driver: SqliteDriver, dbName: getEnvVar(EnvVars.DbName), entities: entities, - // entitiesTs: entitiesTs, + // EntitiesTs: entitiesTs, // Workaround: vitest: `TypeError: Unknown file extension ".ts"` (ERR_UNKNOWN_FILE_EXTENSION) // (see https://mikro-orm.io/docs/guide/project-setup#testing-the-endpoint) - dynamicImportProvider: (id) => import(id), - }; - } else { - return { - driver: PostgreSqlDriver, - host: getEnvVar(EnvVars.DbHost), - port: getNumericEnvVar(EnvVars.DbPort), - dbName: getEnvVar(EnvVars.DbName), - user: getEnvVar(EnvVars.DbUsername), - password: getEnvVar(EnvVars.DbPassword), - entities: entities, - //entitiesTs: entitiesTs, - debug: true, + dynamicImportProvider: (id) => { + return import(id); + }, }; } + return { + driver: PostgreSqlDriver, + host: getEnvVar(EnvVars.DbHost), + port: getNumericEnvVar(EnvVars.DbPort), + dbName: getEnvVar(EnvVars.DbName), + user: getEnvVar(EnvVars.DbUsername), + password: getEnvVar(EnvVars.DbPassword), + entities: entities, + //EntitiesTs: entitiesTs, + debug: true, + }; } export default config; diff --git a/backend/src/routes/assignments.ts b/backend/src/routes/assignments.ts index 9d83e755..85f3bc82 100644 --- a/backend/src/routes/assignments.ts +++ b/backend/src/routes/assignments.ts @@ -1,31 +1,30 @@ -import express from 'express' -import { getAllAssignmentsHandler, getAssignmentHandler } from '../controllers/assignments.js'; -import groupRouter from './group.js'; +import express from 'express'; +import { + getAllAssignmentsHandler, + getAssignmentHandler, +} from '../controllers/assignments.js'; +import groupRouter from './groups.js'; const router = express.Router({ mergeParams: true }); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', getAllAssignmentsHandler); -// information about an assignment with id 'id' +// Information about an assignment with id 'id' router.get('/:id', getAssignmentHandler); router.get('/:id/submissions', (req, res) => { res.json({ - submissions: [ - '0' - ], + submissions: ['0'], }); }); router.get('/:id/questions', (req, res) => { res.json({ - questions: [ - '0' - ], + questions: ['0'], }); }); router.use('/:assignmentid/groups', groupRouter); -export default router +export default router; diff --git a/backend/src/routes/classes.ts b/backend/src/routes/classes.ts index 06154e60..c67b573b 100644 --- a/backend/src/routes/classes.ts +++ b/backend/src/routes/classes.ts @@ -1,13 +1,18 @@ -import express from 'express' -import { getAllClassesHandler, getClassHandler, getClassStudentsHandler, getTeacherInvitationsHandler } from '../controllers/classes.js'; -import assignmentRouter from './assignment.js'; +import express from 'express'; +import { + getAllClassesHandler, + getClassHandler, + getClassStudentsHandler, + getTeacherInvitationsHandler, +} from '../controllers/classes.js'; +import assignmentRouter from './assignments.js'; const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', getAllClassesHandler); -// information about an class with id 'id' +// Information about an class with id 'id' router.get('/:id', getClassHandler); router.get('/:id/teacher-invitations', getTeacherInvitationsHandler); @@ -16,4 +21,4 @@ router.get('/:id/students', getClassStudentsHandler); router.use('/:classid/assignments', assignmentRouter); -export default router +export default router; diff --git a/backend/src/routes/groups.ts b/backend/src/routes/groups.ts index 76cdc61f..d604c088 100644 --- a/backend/src/routes/groups.ts +++ b/backend/src/routes/groups.ts @@ -1,18 +1,19 @@ -import express from 'express' +import express from 'express'; import { getAllGroupsHandler, getGroupHandler } from '../controllers/groups.js'; + const router = express.Router({ mergeParams: true }); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', getAllGroupsHandler); -// information about a group (members, ... [TODO DOC]) +// Information about a group (members, ... [TODO DOC]) router.get('/:groupid', getGroupHandler); -// the list of questions a group has made +// The list of questions a group has made router.get('/:id/question', (req, res) => { res.json({ - questions: [ '0' ], + questions: ['0'], }); -}) +}); -export default router +export default router; diff --git a/backend/src/routes/questions.ts b/backend/src/routes/questions.ts index 25d168b7..f683d998 100644 --- a/backend/src/routes/questions.ts +++ b/backend/src/routes/questions.ts @@ -1,38 +1,34 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - questions: [ - '0', - '1', - ] + questions: ['0', '1'], }); }); -// information about an question with id 'id' +// Information about an question with id 'id' router.get('/:id', (req, res) => { res.json({ id: req.params.id, student: '0', group: '0', time: new Date(2025, 1, 1), - content: 'Zijn alle gehele getallen groter dan 2 gelijk aan de som van 2 priemgetallen????', + content: + 'Zijn alle gehele getallen groter dan 2 gelijk aan de som van 2 priemgetallen????', learningObject: '0', links: { self: `${req.baseUrl}/${req.params.id}`, answers: `${req.baseUrl}/${req.params.id}/answers`, - } + }, }); -}) +}); router.get('/:id/answers', (req, res) => { res.json({ - answers: [ - '0' - ], - }) -}) + answers: ['0'], + }); +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/students.ts b/backend/src/routes/students.ts index a5355c48..da1c4308 100644 --- a/backend/src/routes/students.ts +++ b/backend/src/routes/students.ts @@ -1,51 +1,49 @@ -import express from 'express' +import express from 'express'; import { - createStudentHandler, deleteStudentHandler, + createStudentHandler, + deleteStudentHandler, getAllStudentsHandler, getStudentAssignmentsHandler, getStudentClassesHandler, - getStudentHandler + getStudentHandler, } from '../controllers/students.js'; const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', getAllStudentsHandler); router.post('/', createStudentHandler); router.delete('/:username', deleteStudentHandler); -// information about a student's profile +// Information about a student's profile router.get('/:username', getStudentHandler); - - -// the list of classes a student is in +// The list of classes a student is in router.get('/:id/classes', getStudentClassesHandler); -// the list of submissions a student has made +// The list of submissions a student has made router.get('/:id/submissions', (req, res) => { res.json({ - submissions: [ '0' ], + submissions: ['0'], }); -}) +}); - -// the list of assignments a student has +// The list of assignments a student has router.get('/:id/assignments', getStudentAssignmentsHandler); -// the list of groups a student is in +// The list of groups a student is in router.get('/:id/groups', (req, res) => { res.json({ - groups: [ '0' ], + groups: ['0'], }); -}) +}); -// a list of questions a user has created +// A list of questions a user has created router.get('/:id/questions', (req, res) => { res.json({ - questions: [ '0' ], + questions: ['0'], }); -}) +}); -export default router +export default router; diff --git a/backend/src/routes/submissions.ts b/backend/src/routes/submissions.ts index 8d09cf8e..cb4d3e85 100644 --- a/backend/src/routes/submissions.ts +++ b/backend/src/routes/submissions.ts @@ -1,17 +1,14 @@ -import express from 'express' +import express from 'express'; const router = express.Router(); -// root endpoint used to search objects +// Root endpoint used to search objects router.get('/', (req, res) => { res.json({ - submissions: [ - '0', - '1', - ] + submissions: ['0', '1'], }); }); -// information about an submission with id 'id' +// Information about an submission with id 'id' router.get('/:id', (req, res) => { res.json({ id: req.params.id, @@ -21,6 +18,6 @@ router.get('/:id', (req, res) => { content: 'Wortel 2 is rationeel', learningObject: '0', }); -}) +}); -export default router \ No newline at end of file +export default router; diff --git a/backend/src/routes/teachers.ts b/backend/src/routes/teachers.ts index 2a29897b..8e7f709d 100644 --- a/backend/src/routes/teachers.ts +++ b/backend/src/routes/teachers.ts @@ -1,17 +1,22 @@ -import express from 'express' +import express from 'express'; import { createTeacherHandler, deleteTeacherHandler, + getAllTeachersHandler, getTeacherClassHandler, - getTeacherHandler, getTeacherQuestionHandler, getTeacherStudentHandler -} from "../controllers/teachers.js"; + getTeacherHandler, + getTeacherQuestionHandler, + getTeacherStudentHandler, +} from '../controllers/teachers.js'; const router = express.Router(); -// root endpoint used to search objects -router.get('/', getTeacherHandler); +// Root endpoint used to search objects +router.get('/', getAllTeachersHandler); router.post('/', createTeacherHandler); +router.get('/:username', getTeacherHandler); + router.delete('/:username', deleteTeacherHandler); router.get('/:username/classes', getTeacherClassHandler); @@ -20,15 +25,11 @@ router.get('/:username/students', getTeacherStudentHandler); router.get('/:username/questions', getTeacherQuestionHandler); -// invitations to other classes a teacher received +// Invitations to other classes a teacher received router.get('/:id/invitations', (req, res) => { res.json({ - invitations: [ - '0' - ], + invitations: ['0'], }); }); - - -export default router +export default router; diff --git a/backend/src/services/assignments.ts b/backend/src/services/assignments.ts index aaa51c10..1ecfb4d4 100644 --- a/backend/src/services/assignments.ts +++ b/backend/src/services/assignments.ts @@ -1,7 +1,17 @@ -import { getAssignmentRepository, getClassRepository } from "../data/repositories.js"; -import { AssignmentDTO, mapToAssignmentDTO, mapToAssignmentDTOId } from "../interfaces/assignments.js"; +import { + getAssignmentRepository, + getClassRepository, +} from '../data/repositories.js'; +import { + AssignmentDTO, + mapToAssignmentDTO, + mapToAssignmentDTOId, +} from '../interfaces/assignment.js'; -export async function getAllAssignments(classid: string, full: boolean): Promise { +export async function getAllAssignments( + classid: string, + full: boolean +): Promise { const classRepository = getClassRepository(); const cls = await classRepository.findById(classid); @@ -10,7 +20,8 @@ export async function getAllAssignments(classid: string, full: boolean): Promise } const assignmentRepository = getAssignmentRepository(); - const assignments = await assignmentRepository.findAllAssignmentsInClass(cls); + const assignments = + await assignmentRepository.findAllAssignmentsInClass(cls); if (full) { return assignments.map(mapToAssignmentDTO); @@ -19,7 +30,10 @@ export async function getAllAssignments(classid: string, full: boolean): Promise return assignments.map(mapToAssignmentDTOId); } -export async function getAssignment(classid: string, id: number): Promise { +export async function getAssignment( + classid: string, + id: number +): Promise { const classRepository = getClassRepository(); const cls = await classRepository.findById(classid); diff --git a/backend/src/services/class.ts b/backend/src/services/class.ts index 3867d910..a26aa7c2 100644 --- a/backend/src/services/class.ts +++ b/backend/src/services/class.ts @@ -1,11 +1,23 @@ -import { getClassRepository } from "../data/repositories"; -import { Class } from "../entities/classes/class.entity"; -import { ClassDTO, mapToClassDTO } from "../interfaces/class"; -import { mapToStudentDTO, StudentDTO } from "../interfaces/student"; +import { + getClassRepository, + getTeacherInvitationRepository, +} from '../data/repositories.js'; +import { ClassDTO, mapToClassDTO } from '../interfaces/class.js'; +import { mapToStudentDTO, StudentDTO } from '../interfaces/student.js'; +import { + mapToTeacherInvitationDTO, + mapToTeacherInvitationDTOIds, + TeacherInvitationDTO, +} from '../interfaces/teacher-invitation.js'; -export async function getAllClasses(full: boolean): Promise { +export async function getAllClasses( + full: boolean +): Promise { const classRepository = getClassRepository(); - const classes = await classRepository.find({}, { populate: ["students", "teachers"] }); + const classes = await classRepository.find( + {}, + { populate: ['students', 'teachers'] } + ); if (!classes) { return []; @@ -13,27 +25,30 @@ export async function getAllClasses(full: boolean): Promise cls.classId); } + return classes.map((cls) => { + return cls.classId; + }); } export async function getClass(classId: string): Promise { const classRepository = getClassRepository(); const cls = await classRepository.findById(classId); - if (!cls) return null; - else { - return mapToClassDTO(cls); + if (!cls) { + return null; } + + return mapToClassDTO(cls); } -async function fetchClassStudents(classId: string, full: boolean): Promise { +async function fetchClassStudents(classId: string): Promise { const classRepository = getClassRepository(); const cls = await classRepository.findById(classId); - if (!cls) + if (!cls) { return []; + } return cls.students.map(mapToStudentDTO); } @@ -43,6 +58,36 @@ export async function getClassStudents(classId: string): Promise { } export async function getClassStudentsIds(classId: string): Promise { - return await fetchClassStudents(classId).map((student) => student.username); + const students: StudentDTO[] = await fetchClassStudents(classId); + return students.map((student) => { + return student.username; + }); } +export async function getClassTeacherInvitations( + classId: string, + full: boolean +): Promise { + const classRepository = getClassRepository(); + const cls = await classRepository.findById(classId); + + if (!cls) { + return []; + } + + const teacherInvitationRepository = getTeacherInvitationRepository(); + const invitations = + await teacherInvitationRepository.findAllInvitationsForClass(cls); + + console.log(invitations); + + if (!invitations) { + return []; + } + + if (full) { + return invitations.map(mapToTeacherInvitationDTO); + } + + return invitations.map(mapToTeacherInvitationDTOIds); +} diff --git a/backend/src/services/groups.ts b/backend/src/services/groups.ts index b37c7c5c..467f90a3 100644 --- a/backend/src/services/groups.ts +++ b/backend/src/services/groups.ts @@ -1,11 +1,19 @@ -import { getAssignmentRepository, getClassRepository, getGroupRepository } from "../data/repositories.js"; -import { GroupDTO, mapToGroupDTO, mapToGroupDTOId } from "../interfaces/groups.js"; +import { + getAssignmentRepository, + getClassRepository, + getGroupRepository, +} from '../data/repositories.js'; +import { + GroupDTO, + mapToGroupDTO, + mapToGroupDTOId, +} from '../interfaces/group.js'; export async function getGroup( classId: string, assignmentNumber: number, groupNumber: number, - full: boolean, + full: boolean ): Promise { const classRepository = getClassRepository(); const cls = await classRepository.findById(classId); @@ -15,14 +23,20 @@ export async function getGroup( } const assignmentRepository = getAssignmentRepository(); - const assignment = await assignmentRepository.findByClassAndId(cls, assignmentNumber); + const assignment = await assignmentRepository.findByClassAndId( + cls, + assignmentNumber + ); if (!assignment) { return null; } const groupRepository = getGroupRepository(); - const group = await groupRepository.findByAssignmentAndGroupNumber(assignment, groupNumber); + const group = await groupRepository.findByAssignmentAndGroupNumber( + assignment, + groupNumber + ); if (!group) { return null; @@ -38,7 +52,7 @@ export async function getGroup( export async function getAllGroups( classId: string, assignmentNumber: number, - full: boolean, + full: boolean ): Promise { const classRepository = getClassRepository(); const cls = await classRepository.findById(classId); @@ -48,7 +62,10 @@ export async function getAllGroups( } const assignmentRepository = getAssignmentRepository(); - const assignment = await assignmentRepository.findByClassAndId(cls, assignmentNumber); + const assignment = await assignmentRepository.findByClassAndId( + cls, + assignmentNumber + ); if (!assignment) { return []; diff --git a/backend/src/services/students.ts b/backend/src/services/students.ts index 24c9029b..952c3cf1 100644 --- a/backend/src/services/students.ts +++ b/backend/src/services/students.ts @@ -1,8 +1,11 @@ -import { getClassRepository, getStudentRepository } from "../data/repositories.js"; -import { Class } from "../entities/classes/class.entity.js"; -import { Student } from "../entities/users/student.entity.js"; -import { ClassDTO, mapToClassDTO } from "../interfaces/classes.js"; -import {UserService} from "./users.js"; +import { + getClassRepository, + getStudentRepository, +} from '../data/repositories.js'; +import { Class } from '../entities/classes/class.entity.js'; +import { Student } from '../entities/users/student.entity.js'; +import { ClassDTO, mapToClassDTO } from '../interfaces/class.js'; +import { UserService } from './users.js'; export class StudentService extends UserService { constructor() { @@ -14,12 +17,16 @@ async function fetchStudentClasses(username: string): Promise { const studentRepository = getStudentRepository(); const student = await studentRepository.findByUsername(username); - if (!student) return []; + if (!student) { + return []; + } const classRepository = getClassRepository(); const classes = await classRepository.findByStudent(student); - if (!classes) return []; + if (!classes) { + return []; + } return classes; } @@ -31,6 +38,7 @@ export async function getStudentClasses(username: string): Promise { export async function getStudentClassIds(username: string): Promise { const classes = await fetchStudentClasses(username); - return classes.map(cls => cls.classId); // 'class' is a native keyword + return classes.map((cls) => { + return cls.classId; + }); // 'class' is a native keyword } - diff --git a/backend/src/services/teachers.ts b/backend/src/services/teachers.ts index 4b8affc5..b87c3b92 100644 --- a/backend/src/services/teachers.ts +++ b/backend/src/services/teachers.ts @@ -2,130 +2,108 @@ import { getClassRepository, getLearningObjectRepository, getQuestionRepository, - getTeacherRepository -} from "../data/repositories.js"; -import {mapToTeacher, mapToTeacherDTO, TeacherDTO} from "../interfaces/teacher.js"; -import { Teacher } from "../entities/users/teacher.entity"; -import {ClassDTO, mapToClassDTO} from "../interfaces/class"; -import {getClassStudents, getClassStudentsIds} from "./class"; -import {StudentDTO} from "../interfaces/student"; -import {mapToQuestionDTO, QuestionDTO, QuestionId} from "../interfaces/question"; + getStudentRepository, + getTeacherRepository, +} from '../data/repositories.js'; +import { Teacher } from '../entities/users/teacher.entity.js'; +import { ClassDTO, mapToClassDTO } from '../interfaces/class.js'; +import { getClassStudents } from './class.js'; +import { StudentDTO } from '../interfaces/student.js'; +import { + mapToQuestionDTO, + mapToQuestionId, + QuestionDTO, + QuestionId, +} from '../interfaces/question.js'; +import { UserService } from './users.js'; +import { mapToUser } from '../interfaces/user.js'; - -async function fetchAllTeachers(): Promise { - const teacherRepository = getTeacherRepository(); - const teachers = await teacherRepository.find({}); - - return teachers.map(mapToTeacherDTO); +export class TeacherUserService extends UserService { + constructor() { + super(getTeacherRepository()); + } } -export async function getAllTeachers(): Promise { - return await fetchAllTeachers(); -} +export class TeacherService { + protected teacherService = new TeacherUserService(); + protected teacherRepository = getTeacherRepository(); + protected classRepository = getClassRepository(); + protected learningObjectRepository = getLearningObjectRepository(); + protected questionRepository = getQuestionRepository(); -export async function getAllTeachersIds(): Promise { - return await fetchAllTeachers().map((teacher) => teacher.username) -} + async fetchClassesByTeacher(username: string): Promise { + const teacher = await this.teacherRepository.findByUsername(username); + if (!teacher) { + return []; + } -export async function createTeacher(teacherData: TeacherDTO): Promise { - const teacherRepository = getTeacherRepository(); - const newTeacher = mapToTeacher(teacherData); - - await teacherRepository.addTeacher(newTeacher); - return newTeacher; -} - -export async function getTeacherByUsername(username: string): Promise { - const teacherRepository = getTeacherRepository(); - const teacher = await teacherRepository.findByUsername(username); - - return teacher ? mapToTeacherDTO(teacher) : null; -} - -export async function deleteTeacher(username: string): Promise { - const teacherRepository = getTeacherRepository(); - const teacher = await teacherRepository.findByUsername(username); - - if (!teacher) - return null; - - await teacherRepository.deleteByUsername(username); - return teacher; -} - -async function fetchClassesByTeacher(username: string): Promise { - const teacherRepository = getTeacherRepository(); - const classRepository = getClassRepository(); - - const teacher = await teacherRepository.findByUsername(username); - if (!teacher) { - return []; + const classes = await this.classRepository.findByTeacher(teacher); + return classes.map(mapToClassDTO); } - const classes = await classRepository.findByTeacher(teacher); - return classes.map(mapToClassDTO); -} - -export async function getClassesByTeacher(username: string): Promise { - return await fetchClassesByTeacher(username) -} - -export async function getClassIdsByTeacher(): Promise { - return await fetchClassesByTeacher(username).map((cls) => cls.id); -} - -async function fetchStudentsByTeacher(username: string) { - const classes = await getClassIdsByTeacher(); - - return Promise.all( - classes.map( async (id) => getClassStudents(id)) - ); -} - -export async function getStudentsByTeacher(username: string): Promise { - return await fetchStudentsByTeacher(username); -} - -export async function getStudentIdsByTeacher(): Promise { - return await fetchStudentsByTeacher(username).map((student) => student.username); -} - -async function fetchTeacherQuestions(username: string): Promise { - const learningObjectRepository = getLearningObjectRepository(); - const questionRepository = getQuestionRepository(); - - const teacher = getTeacherByUsername(username); - if (!teacher) { - throw new Error(`Teacher with username '${username}' not found.`); + async getClassesByTeacher(username: string): Promise { + return await this.fetchClassesByTeacher(username); } - // Find all learning objects that this teacher manages - const learningObjects = await learningObjectRepository.findAllByTeacher(teacher); + async getClassIdsByTeacher(username: string): Promise { + const classes = await this.fetchClassesByTeacher(username); + return classes.map((cls) => { + return cls.id; + }); + } - // Fetch all questions related to these learning objects - const questions = await questionRepository.findAllByLearningObjects(learningObjects); + async fetchStudentsByTeacher(username: string) { + const classes = await this.getClassIdsByTeacher(username); - return questions.map(mapToQuestionDTO); + return ( + await Promise.all( + classes.map(async (id) => { + return getClassStudents(id); + }) + ) + ).flat(); + } + + async getStudentsByTeacher(username: string): Promise { + return await this.fetchStudentsByTeacher(username); + } + + async getStudentIdsByTeacher(username: string): Promise { + const students = await this.fetchStudentsByTeacher(username); + return students.map((student) => { + return student.username; + }); + } + + async fetchTeacherQuestions(username: string): Promise { + const teacherDTO = + await this.teacherService.getUserByUsername(username); + if (!teacherDTO) { + throw new Error(`Teacher with username '${username}' not found.`); + } + + const teacher = mapToUser(teacherDTO, new Teacher()); + + // Find all learning objects that this teacher manages + const learningObjects = + await this.learningObjectRepository.findAllByTeacher(teacher); + + // Fetch all questions related to these learning objects + const questions = + await this.questionRepository.findAllByLearningObjects( + learningObjects + ); + + return questions.map(mapToQuestionDTO); + } + + async getQuestionsByTeacher(username: string): Promise { + return await this.fetchTeacherQuestions(username); + } + + async getQuestionIdsByTeacher(username: string): Promise { + const questions = await this.fetchTeacherQuestions(username); + + return questions.map(mapToQuestionId); + } } - -export async function getQuestionsByTeacher(username: string): Promise { - return await fetchTeacherQuestions(username); -} - -export async function getQuestionIdsByTeacher(username: string): Promise { - const questions = await fetchTeacherQuestions(username); - - return questions.map((question) => ({ - learningObjectHruid: question.learningObjectHruid, - learningObjectLanguage: question.learningObjectLanguage, - learningObjectVersion: question.learningObjectVersion, - sequenceNumber: question.sequenceNumber - })); -} - - - - - - - diff --git a/backend/src/services/users.ts b/backend/src/services/users.ts index bf88e916..fc1ea599 100644 --- a/backend/src/services/users.ts +++ b/backend/src/services/users.ts @@ -1,6 +1,6 @@ -import { UserRepository } from "../data/users/user-repository.js"; -import { UserDTO, mapToUser, mapToUserDTO } from "../interfaces/user.js"; -import {User} from "../entities/users/user.entity.js"; +import { UserRepository } from '../data/users/user-repository.js'; +import { UserDTO, mapToUser, mapToUserDTO } from '../interfaces/user.js'; +import { User } from '../entities/users/user.entity.js'; export class UserService { protected repository: UserRepository; @@ -16,11 +16,13 @@ export class UserService { async getAllUserIds(): Promise { const users = await this.getAllUsers(); - return users.map((user) => user.username); + return users.map((user) => { + return user.username; + }); } async getUserByUsername(username: string): Promise { - const user = await this.repository.findByUsername(username) + const user = await this.repository.findByUsername(username); return user ? mapToUserDTO(user) : null; } @@ -32,8 +34,10 @@ export class UserService { async deleteUser(username: string): Promise { const user = await this.getUserByUsername(username); - if (!user) return null; - await this.repository.deleteByUsername(username) + if (!user) { + return null; + } + await this.repository.deleteByUsername(username); return mapToUserDTO(user); } } diff --git a/backend/src/util/translation-helper.ts b/backend/src/util/translation-helper.ts index d6d842ff..f02a3a1b 100644 --- a/backend/src/util/translation-helper.ts +++ b/backend/src/util/translation-helper.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import path from 'path'; import yaml from 'js-yaml'; -import { FALLBACK_LANG } from "../config.js"; +import { FALLBACK_LANG } from '../config.js'; export function loadTranslations(language: string): T { try { @@ -13,7 +13,11 @@ export function loadTranslations(language: string): T { `Cannot load translation for ${language}, fallen back to dutch` ); console.error(error); - const fallbackPath = path.join(process.cwd(), '_i18n', `${FALLBACK_LANG}.yml`); + const fallbackPath = path.join( + process.cwd(), + '_i18n', + `${FALLBACK_LANG}.yml` + ); return yaml.load(fs.readFileSync(fallbackPath, 'utf8')) as T; } }