fix: integratie user + errors gefixt zodat het runt + format
This commit is contained in:
		
							parent
							
								
									6c4ea0eefb
								
							
						
					
					
						commit
						1b096b411b
					
				
					 55 changed files with 858 additions and 594 deletions
				
			
		|  | @ -7,7 +7,7 @@ import learningPathRoutes from './routes/learning-paths.js'; | ||||||
| import learningObjectRoutes from './routes/learning-objects.js'; | import learningObjectRoutes from './routes/learning-objects.js'; | ||||||
| 
 | 
 | ||||||
| import studentRoutes from './routes/students.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 groupRoutes from './routes/groups.js'; | ||||||
| import submissionRoutes from './routes/submissions.js'; | import submissionRoutes from './routes/submissions.js'; | ||||||
| import classRoutes from './routes/classes.js'; | import classRoutes from './routes/classes.js'; | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { Request, Response } from 'express' | import { Request, Response } from 'express'; | ||||||
| import { getAllAssignments, getAssignment } from '../services/assignments.js'; | 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 { | interface AssignmentParams { | ||||||
|     classid: string; |     classid: string; | ||||||
|     id: string; |     id: string; | ||||||
|  | @ -9,7 +9,7 @@ interface AssignmentParams { | ||||||
| 
 | 
 | ||||||
| export async function getAllAssignmentsHandler( | export async function getAllAssignmentsHandler( | ||||||
|     req: Request<AssignmentParams>, |     req: Request<AssignmentParams>, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     const classid = req.params.classid; |     const classid = req.params.classid; | ||||||
|     const full = req.query.full === 'true'; |     const full = req.query.full === 'true'; | ||||||
|  | @ -23,20 +23,20 @@ export async function getAllAssignmentsHandler( | ||||||
| 
 | 
 | ||||||
| export async function getAssignmentHandler( | export async function getAssignmentHandler( | ||||||
|     req: Request<AssignmentParams>, |     req: Request<AssignmentParams>, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     const id = +req.params.id; |     const id = +req.params.id; | ||||||
|     const classid = req.params.classid; |     const classid = req.params.classid; | ||||||
| 
 | 
 | ||||||
|     if (isNaN(id)) { |     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; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const assignment = await getAssignment(classid, id); |     const assignment = await getAssignment(classid, id); | ||||||
| 
 | 
 | ||||||
|     if (!assignment) { |     if (!assignment) { | ||||||
|         res.status(404).json({ error: "Assignment not found" }); |         res.status(404).json({ error: 'Assignment not found' }); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,40 +1,44 @@ | ||||||
| import { Request, Response } from 'express'; | import { Request, Response } from 'express'; | ||||||
| import { getAllClasses, getClass, getClassStudents, getClassStudentsIds, getClassTeacherInvitations } from '../services/class.js'; | import { | ||||||
| import { ClassDTO } from '../interfaces/classes.js'; |     getAllClasses, | ||||||
|  |     getClass, | ||||||
|  |     getClassStudents, | ||||||
|  |     getClassStudentsIds, | ||||||
|  |     getClassTeacherInvitations, | ||||||
|  | } from '../services/class.js'; | ||||||
| 
 | 
 | ||||||
| export async function getAllClassesHandler( | export async function getAllClassesHandler( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     const full = req.query.full === "true"; |     const full = req.query.full === 'true'; | ||||||
|     const classes = await getAllClasses(full); |     const classes = await getAllClasses(full); | ||||||
| 
 | 
 | ||||||
|     res.json({ |     res.json({ | ||||||
|         classes: classes |         classes: classes, | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getClassHandler( | export async function getClassHandler( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const classId = req.params.id; |         const classId = req.params.id; | ||||||
|         const cls = await getClass(classId); |         const cls = await getClass(classId); | ||||||
| 
 | 
 | ||||||
|         if (!cls) { |         if (!cls) { | ||||||
|             res.status(404).json({ error: "Student not found" }); |             res.status(404).json({ error: 'Student not found' }); | ||||||
|             return; |             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) { |     } catch (error) { | ||||||
|         console.error('Error fetching learning objects:', error); |         console.error('Error fetching learning objects:', error); | ||||||
|         res.status(500).json({ error: 'Internal server error' }); |         res.status(500).json({ error: 'Internal server error' }); | ||||||
|  | @ -43,12 +47,12 @@ export async function getClassHandler( | ||||||
| 
 | 
 | ||||||
| export async function getClassStudentsHandler( | export async function getClassStudentsHandler( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     const classId = req.params.id; |     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 getClassStudents(classId) | ||||||
|         : await getClassStudentsIds(classId); |         : await getClassStudentsIds(classId); | ||||||
| 
 | 
 | ||||||
|  | @ -59,10 +63,10 @@ export async function getClassStudentsHandler( | ||||||
| 
 | 
 | ||||||
| export async function getTeacherInvitationsHandler( | export async function getTeacherInvitationsHandler( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     const classId = req.params.id; |     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); |     const invitations = await getClassTeacherInvitations(classId, full); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { Request, Response } from 'express'; | import { Request, Response } from 'express'; | ||||||
| import { getAllGroups, getGroup } from '../services/groups.js'; | 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 { | interface GroupParams { | ||||||
|     classid: string; |     classid: string; | ||||||
|     assignmentid: string; |     assignmentid: string; | ||||||
|  | @ -10,21 +10,21 @@ interface GroupParams { | ||||||
| 
 | 
 | ||||||
| export async function getGroupHandler( | export async function getGroupHandler( | ||||||
|     req: Request<GroupParams>, |     req: Request<GroupParams>, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     const classId = req.params.classid; |     const classId = req.params.classid; | ||||||
|     const full = req.query.full === "true"; |     const full = req.query.full === 'true'; | ||||||
|     const assignmentId = +req.params.assignmentid; |     const assignmentId = +req.params.assignmentid; | ||||||
| 
 | 
 | ||||||
|     if (isNaN(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; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const groupId = +req.params.groupid!; // can't be undefined
 |     const groupId = +req.params.groupid!; // Can't be undefined
 | ||||||
| 
 | 
 | ||||||
|     if (isNaN(groupId)) { |     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; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -35,15 +35,15 @@ export async function getGroupHandler( | ||||||
| 
 | 
 | ||||||
| export async function getAllGroupsHandler( | export async function getAllGroupsHandler( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     const classId = req.params.classid; |     const classId = req.params.classid; | ||||||
|     const full = req.query.full === "true"; |     const full = req.query.full === 'true'; | ||||||
| 
 | 
 | ||||||
|     const assignmentId = +req.params.assignmentid; |     const assignmentId = +req.params.assignmentid; | ||||||
| 
 | 
 | ||||||
|     if (isNaN(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; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ import { | ||||||
|     getLearningObjectsFromPath, |     getLearningObjectsFromPath, | ||||||
| } from '../services/learning-objects.js'; | } from '../services/learning-objects.js'; | ||||||
| import { FALLBACK_LANG } from '../config.js'; | import { FALLBACK_LANG } from '../config.js'; | ||||||
| import { FilteredLearningObject } from '../interfaces/learning-path'; | import { FilteredLearningObject } from '../interfaces/learning-path.js'; | ||||||
| 
 | 
 | ||||||
| export async function getAllLearningObjects( | export async function getAllLearningObjects( | ||||||
|     req: Request, |     req: Request, | ||||||
|  |  | ||||||
|  | @ -2,43 +2,62 @@ import { Request, Response } from 'express'; | ||||||
| import { | import { | ||||||
|     getStudentClasses, |     getStudentClasses, | ||||||
|     getStudentClassIds, |     getStudentClassIds, | ||||||
|     StudentService |     StudentService, | ||||||
| } from '../services/students.js'; | } from '../services/students.js'; | ||||||
| import { ClassDTO } from '../interfaces/classes.js'; | import { ClassDTO } from '../interfaces/class.js'; | ||||||
| import { getAllAssignments } from '../services/assignments.js'; | import { getAllAssignments } from '../services/assignments.js'; | ||||||
| import {createUserHandler, deleteUserHandler, getAllUsersHandler, getUserHandler} from "./users.js"; | import { | ||||||
| import { Student } from "../entities/users/student.entity.js"; |     createUserHandler, | ||||||
|  |     deleteUserHandler, | ||||||
|  |     getAllUsersHandler, | ||||||
|  |     getUserHandler, | ||||||
|  | } from './users.js'; | ||||||
|  | import { Student } from '../entities/users/student.entity.js'; | ||||||
| 
 | 
 | ||||||
| // TODO: accept arguments (full, ...)
 | // TODO: accept arguments (full, ...)
 | ||||||
| // TODO: endpoints
 | // TODO: endpoints
 | ||||||
| export async function getAllStudentsHandler (req: Request, res: Response): Promise<void> { | export async function getAllStudentsHandler( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     await getAllUsersHandler<Student>(req, res, new StudentService()); |     await getAllUsersHandler<Student>(req, res, new StudentService()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getStudentHandler(req: Request, res: Response): Promise<void> { | export async function getStudentHandler( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     await getUserHandler<Student>(req, res, new StudentService()); |     await getUserHandler<Student>(req, res, new StudentService()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function createStudentHandler(req: Request, res: Response): Promise<void> { | export async function createStudentHandler( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     await createUserHandler<Student>(req, res, new StudentService(), Student); |     await createUserHandler<Student>(req, res, new StudentService(), Student); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function deleteStudentHandler(req: Request, res: Response): Promise<void> { | export async function deleteStudentHandler( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     await deleteUserHandler<Student>(req, res, new StudentService()); |     await deleteUserHandler<Student>(req, res, new StudentService()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | export async function getStudentClassesHandler( | ||||||
| export async function getStudentClassesHandler ( |  | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const full = req.query.full === 'true'; |         const full = req.query.full === 'true'; | ||||||
|         const username = req.params.id; |         const username = req.params.id; | ||||||
| 
 | 
 | ||||||
|         let classes: ClassDTO[] | string[]; |         let classes: ClassDTO[] | string[]; | ||||||
|         if (full) classes = await getStudentClasses(username); |         if (full) { | ||||||
|         else classes = await getStudentClassIds(username); |             classes = await getStudentClasses(username); | ||||||
|  |         } else { | ||||||
|  |             classes = await getStudentClassIds(username); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         res.json({ |         res.json({ | ||||||
|             classes: classes, |             classes: classes, | ||||||
|  | @ -47,7 +66,7 @@ export async function getStudentClassesHandler ( | ||||||
|                 classes: `${req.baseUrl}/${req.params.id}/invitations`, |                 classes: `${req.baseUrl}/${req.params.id}/invitations`, | ||||||
|                 questions: `${req.baseUrl}/${req.params.id}/assignments`, |                 questions: `${req.baseUrl}/${req.params.id}/assignments`, | ||||||
|                 students: `${req.baseUrl}/${req.params.id}/students`, |                 students: `${req.baseUrl}/${req.params.id}/students`, | ||||||
|             } |             }, | ||||||
|         }); |         }); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error('Error fetching learning objects:', error); |         console.error('Error fetching learning objects:', error); | ||||||
|  | @ -57,22 +76,26 @@ export async function getStudentClassesHandler ( | ||||||
| 
 | 
 | ||||||
| // TODO
 | // TODO
 | ||||||
| // Might not be fully correct depending on if
 | // Might not be fully correct depending on if
 | ||||||
| // a class has an assignment, that all students
 | // A class has an assignment, that all students
 | ||||||
| // have this assignment.
 | // Have this assignment.
 | ||||||
| export async function getStudentAssignmentsHandler( | export async function getStudentAssignmentsHandler( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     const full = req.query.full === 'true'; |     const full = req.query.full === 'true'; | ||||||
|     const username = req.params.id; |     const username = req.params.id; | ||||||
| 
 | 
 | ||||||
|     const classes = await getStudentClasses(username); |     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({ |     res.json({ | ||||||
|         assignments: assignments |         assignments: assignments, | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -1,92 +1,53 @@ | ||||||
| import { Request, Response } from 'express'; | 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 { | import { | ||||||
|     createTeacher, |     createUserHandler, | ||||||
|     deleteTeacher, |     deleteUserHandler, | ||||||
|     getTeacherByUsername, |     getAllUsersHandler, | ||||||
|     getClassesByTeacher, |     getUserHandler, | ||||||
|     getClassIdsByTeacher, | } from './users.js'; | ||||||
|     getAllTeachers, | import { Teacher } from '../entities/users/teacher.entity.js'; | ||||||
|     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"; |  | ||||||
| 
 | 
 | ||||||
| export async function getTeacherHandler(req: Request, res: Response): Promise<void> { | export async function getAllTeachersHandler( | ||||||
|     try { |     req: Request, | ||||||
|         const full = req.query.full === 'true'; |     res: Response | ||||||
|         const username = req.query.username as string; | ): Promise<void> { | ||||||
|  |     await getAllUsersHandler<Teacher>(req, res, new TeacherUserService()); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|         if (username){ | export async function getTeacherHandler( | ||||||
|             const teacher = await getTeacherByUsername(username); |     req: Request, | ||||||
|             if (!teacher){ |     res: Response | ||||||
|                 res.status(404).json({ error: `Teacher with username '${username}' not found.` }); | ): Promise<void> { | ||||||
|                 return; |     await getUserHandler<Teacher>(req, res, new TeacherUserService()); | ||||||
|             } |  | ||||||
|             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 createTeacherHandler( | export async function createTeacherHandler( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     try { |     await createUserHandler<Teacher>( | ||||||
|         const teacherData = req.body as TeacherDTO; |         req, | ||||||
| 
 |         res, | ||||||
|         if (!teacherData.username || !teacherData.firstName || !teacherData.lastName) { |         new TeacherUserService(), | ||||||
|             res.status(400).json({ error: 'Missing required fields: username, firstName, lastName' }); |         Teacher | ||||||
|             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' }); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function deleteTeacherHandler( | export async function deleteTeacherHandler( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response |     res: Response | ||||||
| ): Promise<void> { | ): Promise<void> { | ||||||
|     try { |     await deleteUserHandler<Teacher>(req, res, new TeacherUserService()); | ||||||
|         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' }); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getTeacherClassHandler(req: Request, res: Response): Promise<void> { | export async function getTeacherClassHandler( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const username = req.params.username as string; |         const username = req.params.username as string; | ||||||
|         const full = req.query.full === 'true'; |         const full = req.query.full === 'true'; | ||||||
|  | @ -96,10 +57,11 @@ export async function getTeacherClassHandler(req: Request, res: Response): Promi | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let classes: ClassDTO[] | string[]; |         const teacherService = new TeacherService(); | ||||||
| 
 | 
 | ||||||
|         if (full) classes = await getClassesByTeacher(username); |         const classes: ClassDTO[] | string[] = full | ||||||
|         else classes = await getClassIdsByTeacher(username); |             ? await teacherService.getClassesByTeacher(username) | ||||||
|  |             : await teacherService.getClassIdsByTeacher(username); | ||||||
| 
 | 
 | ||||||
|         res.status(201).json(classes); |         res.status(201).json(classes); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|  | @ -108,7 +70,10 @@ export async function getTeacherClassHandler(req: Request, res: Response): Promi | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getTeacherStudentHandler(req: Request, res: Response): Promise<void> { | export async function getTeacherStudentHandler( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const username = req.params.username as string; |         const username = req.params.username as string; | ||||||
|         const full = req.query.full === 'true'; |         const full = req.query.full === 'true'; | ||||||
|  | @ -118,10 +83,11 @@ export async function getTeacherStudentHandler(req: Request, res: Response): Pro | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let students: StudentDTO[] | string[]; |         const teacherService = new TeacherService(); | ||||||
| 
 | 
 | ||||||
|         if (full) students = await getStudentsByTeacher(username); |         const students: StudentDTO[] | string[] = full | ||||||
|         else students = await getStudentIdsByTeacher(username); |             ? await teacherService.getStudentsByTeacher(username) | ||||||
|  |             : await teacherService.getStudentIdsByTeacher(username); | ||||||
| 
 | 
 | ||||||
|         res.status(201).json(students); |         res.status(201).json(students); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|  | @ -130,7 +96,10 @@ export async function getTeacherStudentHandler(req: Request, res: Response): Pro | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getTeacherQuestionHandler(req: Request, res: Response): Promise<void> { | export async function getTeacherQuestionHandler( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const username = req.params.username as string; |         const username = req.params.username as string; | ||||||
|         const full = req.query.full === 'true'; |         const full = req.query.full === 'true'; | ||||||
|  | @ -140,10 +109,11 @@ export async function getTeacherQuestionHandler(req: Request, res: Response): Pr | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let questions: QuestionDTO[] | QuestionId[]; |         const teacherService = new TeacherService(); | ||||||
| 
 | 
 | ||||||
|         if (full) questions = await getQuestionsByTeacher(username); |         const questions: QuestionDTO[] | QuestionId[] = full | ||||||
|         else questions = await getQuestionIdsByTeacher(username); |             ? await teacherService.getQuestionsByTeacher(username) | ||||||
|  |             : await teacherService.getQuestionIdsByTeacher(username); | ||||||
| 
 | 
 | ||||||
|         res.status(201).json(questions); |         res.status(201).json(questions); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|  | @ -151,5 +121,3 @@ export async function getTeacherQuestionHandler(req: Request, res: Response): Pr | ||||||
|         res.status(500).json({ error: 'Internal server error' }); |         res.status(500).json({ error: 'Internal server error' }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -1,7 +1,6 @@ | ||||||
| import { Request, Response } from 'express'; | import { Request, Response } from 'express'; | ||||||
| import { themes } from '../data/themes.js'; | import { themes } from '../data/themes.js'; | ||||||
| import { loadTranslations } from "../util/translation-helper.js"; | import { loadTranslations } from '../util/translation-helper.js'; | ||||||
| import { FALLBACK_LANG } from '../config.js'; |  | ||||||
| 
 | 
 | ||||||
| interface Translations { | interface Translations { | ||||||
|     curricula_page: { |     curricula_page: { | ||||||
|  |  | ||||||
|  | @ -1,30 +1,29 @@ | ||||||
| import { Request, Response } from 'express'; | import { Request, Response } from 'express'; | ||||||
| import { UserService } from "../services/users.js"; | import { UserService } from '../services/users.js'; | ||||||
| import {UserDTO} from "../interfaces/user.js"; | import { UserDTO } from '../interfaces/user.js'; | ||||||
| import {User} from "../entities/users/user.entity.js"; | import { User } from '../entities/users/user.entity.js'; | ||||||
| 
 | 
 | ||||||
| export async function getAllUsersHandler<T extends User>( | export async function getAllUsersHandler<T extends User>( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response, | ||||||
|     service: UserService<T> |     service: UserService<T> | ||||||
| ):  Promise<void> { | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const full = req.query.full === 'true'; |         const full = req.query.full === 'true'; | ||||||
| 
 | 
 | ||||||
|         let users: UserDTO[] | string[] = full |         const users: UserDTO[] | string[] = full | ||||||
|             ? await service.getAllUsers() |             ? await service.getAllUsers() | ||||||
|             : await service.getAllUserIds(); |             : await service.getAllUserIds(); | ||||||
| 
 | 
 | ||||||
|         if (!users){ |         if (!users) { | ||||||
|             res.status(404).json({ error: `Users not found.` }); |             res.status(404).json({ error: `Users not found.` }); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         res.status(201).json(users); |         res.status(201).json(users); | ||||||
| 
 |  | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error("❌ Error fetching users:", error); |         console.error('❌ Error fetching users:', error); | ||||||
|         res.status(500).json({ error: "Internal server error" }); |         res.status(500).json({ error: 'Internal server error' }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -32,7 +31,7 @@ export async function getUserHandler<T extends User>( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response, | ||||||
|     service: UserService<T> |     service: UserService<T> | ||||||
| ):  Promise<void> { | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const username = req.params.username as string; |         const username = req.params.username as string; | ||||||
| 
 | 
 | ||||||
|  | @ -43,16 +42,17 @@ export async function getUserHandler<T extends User>( | ||||||
| 
 | 
 | ||||||
|         const user = await service.getUserByUsername(username); |         const user = await service.getUserByUsername(username); | ||||||
| 
 | 
 | ||||||
|         if (!user){ |         if (!user) { | ||||||
|             res.status(404).json({ error: `User with username '${username}' not found.` }); |             res.status(404).json({ | ||||||
|  |                 error: `User with username '${username}' not found.`, | ||||||
|  |             }); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         res.status(201).json(user); |         res.status(201).json(user); | ||||||
| 
 |  | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error("❌ Error fetching users:", error); |         console.error('❌ Error fetching users:', error); | ||||||
|         res.status(500).json({ error: "Internal server error" }); |         res.status(500).json({ error: 'Internal server error' }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -63,23 +63,25 @@ export async function createUserHandler<T extends User>( | ||||||
|     UserClass: new () => T |     UserClass: new () => T | ||||||
| ) { | ) { | ||||||
|     try { |     try { | ||||||
|         console.log("req", req) |         console.log('req', req); | ||||||
|         const userData = req.body as UserDTO; |         const userData = req.body as UserDTO; | ||||||
| 
 | 
 | ||||||
|         if (!userData.username || !userData.firstName || !userData.lastName) { |         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; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const newUser = await service.createUser(userData, UserClass); |         const newUser = await service.createUser(userData, UserClass); | ||||||
|         res.status(201).json(newUser); |         res.status(201).json(newUser); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error("❌ Error creating user:", error); |         console.error('❌ Error creating user:', error); | ||||||
|         res.status(500).json({ error: "Internal server error" }); |         res.status(500).json({ error: 'Internal server error' }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function deleteUserHandler<T extends User> ( | export async function deleteUserHandler<T extends User>( | ||||||
|     req: Request, |     req: Request, | ||||||
|     res: Response, |     res: Response, | ||||||
|     service: UserService<T> |     service: UserService<T> | ||||||
|  | @ -88,19 +90,21 @@ export async function deleteUserHandler<T extends User> ( | ||||||
|         const username = req.params.username; |         const username = req.params.username; | ||||||
| 
 | 
 | ||||||
|         if (!username) { |         if (!username) { | ||||||
|             res.status(400).json({ error: "Missing required field: username" }); |             res.status(400).json({ error: 'Missing required field: username' }); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const deletedUser = await service.deleteUser(username); |         const deletedUser = await service.deleteUser(username); | ||||||
|         if (!deletedUser) { |         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; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         res.status(200).json(deletedUser); |         res.status(200).json(deletedUser); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error("❌ Error deleting user:", error); |         console.error('❌ Error deleting user:', error); | ||||||
|         res.status(500).json({ error: "Internal server error" }); |         res.status(500).json({ error: 'Internal server error' }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,21 +8,20 @@ export class GroupRepository extends DwengoEntityRepository<Group> { | ||||||
|         groupNumber: number |         groupNumber: number | ||||||
|     ): Promise<Group | null> { |     ): Promise<Group | null> { | ||||||
|         return this.findOne( |         return this.findOne( | ||||||
|         { |             { | ||||||
|             assignment: assignment, |                 assignment: assignment, | ||||||
|             groupNumber: groupNumber, |                 groupNumber: groupNumber, | ||||||
|         }, |             }, | ||||||
|         { populate: ["members"] }, |             { populate: ['members'] } | ||||||
|     ); |         ); | ||||||
|     } |     } | ||||||
|     public findAllGroupsForAssignment( |     public findAllGroupsForAssignment( | ||||||
|         assignment: Assignment |         assignment: Assignment | ||||||
|     ): Promise<Group[]> { |     ): Promise<Group[]> { | ||||||
|         return this.findAll({  |         return this.findAll({ | ||||||
|             where: { assignment: assignment },  |             where: { assignment: assignment }, | ||||||
|             populate: ["members"]  |             populate: ['members'], | ||||||
|         }, |         }); | ||||||
|         ); |  | ||||||
|     } |     } | ||||||
|     public deleteByAssignmentAndGroupNumber( |     public deleteByAssignmentAndGroupNumber( | ||||||
|         assignment: Assignment, |         assignment: Assignment, | ||||||
|  |  | ||||||
|  | @ -1,13 +1,13 @@ | ||||||
| import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; | import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; | ||||||
| import { Class } from '../../entities/classes/class.entity.js'; | import { Class } from '../../entities/classes/class.entity.js'; | ||||||
| import { Student } from '../../entities/users/student.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<Class> { | export class ClassRepository extends DwengoEntityRepository<Class> { | ||||||
|     public findById(id: string): Promise<Class | null> { |     public findById(id: string): Promise<Class | null> { | ||||||
|         return this.findOne( |         return this.findOne( | ||||||
|             { classId: id }, |             { classId: id }, | ||||||
|             { populate: ["students", "teachers"] }, |             { populate: ['students', 'teachers'] } | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|     public deleteById(id: string): Promise<void> { |     public deleteById(id: string): Promise<void> { | ||||||
|  | @ -16,14 +16,14 @@ export class ClassRepository extends DwengoEntityRepository<Class> { | ||||||
|     public findByStudent(student: Student): Promise<Class[]> { |     public findByStudent(student: Student): Promise<Class[]> { | ||||||
|         return this.find( |         return this.find( | ||||||
|             { students: student }, |             { 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<Class[]> { |     public findByTeacher(teacher: Teacher): Promise<Class[]> { | ||||||
|         return this.find( |         return this.find( | ||||||
|             { teachers: teacher }, |             { teachers: teacher }, | ||||||
|             { populate: ["students", "teachers"] } |             { populate: ['students', 'teachers'] } | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; | import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; | ||||||
| import { LearningObject } from '../../entities/content/learning-object.entity.js'; | import { LearningObject } from '../../entities/content/learning-object.entity.js'; | ||||||
| import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.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<LearningObject> { | export class LearningObjectRepository extends DwengoEntityRepository<LearningObject> { | ||||||
|     public findByIdentifier( |     public findByIdentifier( | ||||||
|  |  | ||||||
|  | @ -4,13 +4,13 @@ export abstract class DwengoEntityRepository< | ||||||
|     T extends object, |     T extends object, | ||||||
| > extends EntityRepository<T> { | > extends EntityRepository<T> { | ||||||
|     public async save(entity: T) { |     public async save(entity: T) { | ||||||
|         let em = this.getEntityManager(); |         const em = this.getEntityManager(); | ||||||
|         em.persist(entity); |         em.persist(entity); | ||||||
|         await em.flush(); |         await em.flush(); | ||||||
|     } |     } | ||||||
|     public async deleteWhere(query: FilterQuery<T>) { |     public async deleteWhere(query: FilterQuery<T>) { | ||||||
|         let toDelete = await this.findOne(query); |         const toDelete = await this.findOne(query); | ||||||
|         let em = this.getEntityManager(); |         const em = this.getEntityManager(); | ||||||
|         if (toDelete) { |         if (toDelete) { | ||||||
|             em.remove(toDelete); |             em.remove(toDelete); | ||||||
|             await em.flush(); |             await em.flush(); | ||||||
|  |  | ||||||
|  | @ -9,7 +9,7 @@ export class AnswerRepository extends DwengoEntityRepository<Answer> { | ||||||
|         author: Teacher; |         author: Teacher; | ||||||
|         content: string; |         content: string; | ||||||
|     }): Promise<Answer> { |     }): Promise<Answer> { | ||||||
|         let answerEntity = new Answer(); |         const answerEntity = new Answer(); | ||||||
|         answerEntity.toQuestion = answer.toQuestion; |         answerEntity.toQuestion = answer.toQuestion; | ||||||
|         answerEntity.author = answer.author; |         answerEntity.author = answer.author; | ||||||
|         answerEntity.content = answer.content; |         answerEntity.content = answer.content; | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ import { DwengoEntityRepository } from '../dwengo-entity-repository.js'; | ||||||
| import { Question } from '../../entities/questions/question.entity.js'; | import { Question } from '../../entities/questions/question.entity.js'; | ||||||
| import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js'; | import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js'; | ||||||
| import { Student } from '../../entities/users/student.entity.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<Question> { | export class QuestionRepository extends DwengoEntityRepository<Question> { | ||||||
|     public createQuestion(question: { |     public createQuestion(question: { | ||||||
|  | @ -10,7 +10,7 @@ export class QuestionRepository extends DwengoEntityRepository<Question> { | ||||||
|         author: Student; |         author: Student; | ||||||
|         content: string; |         content: string; | ||||||
|     }): Promise<Question> { |     }): Promise<Question> { | ||||||
|         let questionEntity = new Question(); |         const questionEntity = new Question(); | ||||||
|         questionEntity.learningObjectHruid = question.loId.hruid; |         questionEntity.learningObjectHruid = question.loId.hruid; | ||||||
|         questionEntity.learningObjectLanguage = question.loId.language; |         questionEntity.learningObjectLanguage = question.loId.language; | ||||||
|         questionEntity.learningObjectVersion = question.loId.version; |         questionEntity.learningObjectVersion = question.loId.version; | ||||||
|  | @ -44,12 +44,16 @@ export class QuestionRepository extends DwengoEntityRepository<Question> { | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public async findAllByLearningObjects(learningObjects: LearningObject[]): Promise<Question[]> { |     public async findAllByLearningObjects( | ||||||
|         const objectIdentifiers = learningObjects.map(lo => ({ |         learningObjects: LearningObject[] | ||||||
|  |     ): Promise<Question[]> { | ||||||
|  |         const objectIdentifiers = learningObjects.map((lo) => { | ||||||
|  |             return { | ||||||
|                 learningObjectHruid: lo.hruid, |                 learningObjectHruid: lo.hruid, | ||||||
|                 learningObjectLanguage: lo.language, |                 learningObjectLanguage: lo.language, | ||||||
|                 learningObjectVersion: lo.version |                 learningObjectVersion: lo.version, | ||||||
|             })); |             }; | ||||||
|  |         }); | ||||||
| 
 | 
 | ||||||
|         return this.findAll({ |         return this.findAll({ | ||||||
|             where: { $or: objectIdentifiers }, |             where: { $or: objectIdentifiers }, | ||||||
|  |  | ||||||
|  | @ -59,7 +59,9 @@ function repositoryGetter<T extends AnyEntity, R extends EntityRepository<T>>( | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Users */ | /* Users */ | ||||||
| export const getUserRepository = repositoryGetter<User, UserRepository<User>>(User); | export const getUserRepository = repositoryGetter<User, UserRepository<User>>( | ||||||
|  |     User | ||||||
|  | ); | ||||||
| export const getStudentRepository = repositoryGetter< | export const getStudentRepository = repositoryGetter< | ||||||
|     Student, |     Student, | ||||||
|     StudentRepository |     StudentRepository | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import { Student } from '../../entities/users/student.entity.js'; | 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<Student> {} | export class StudentRepository extends UserRepository<Student> {} | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import { Teacher } from '../../entities/users/teacher.entity.js'; | 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<Teacher> {} | export class TeacherRepository extends UserRepository<Teacher> {} | ||||||
|  |  | ||||||
|  | @ -11,9 +11,18 @@ import { Group } from './group.entity.js'; | ||||||
| import { Language } from '../content/language.js'; | import { Language } from '../content/language.js'; | ||||||
| import { AssignmentRepository } from '../../data/assignments/assignment-repository.js'; | import { AssignmentRepository } from '../../data/assignments/assignment-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => AssignmentRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return AssignmentRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class Assignment { | export class Assignment { | ||||||
|     @ManyToOne({ entity: () => Class, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Class; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     within!: Class; |     within!: Class; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'number' }) |     @PrimaryKey({ type: 'number' }) | ||||||
|  | @ -28,9 +37,18 @@ export class Assignment { | ||||||
|     @Property({ type: 'string' }) |     @Property({ type: 'string' }) | ||||||
|     learningPathHruid!: string; |     learningPathHruid!: string; | ||||||
| 
 | 
 | ||||||
|     @Enum({ items: () => Language }) |     @Enum({ | ||||||
|  |         items: () => { | ||||||
|  |             return Language; | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|     learningPathLanguage!: Language; |     learningPathLanguage!: Language; | ||||||
| 
 | 
 | ||||||
|     @OneToMany({ entity: () => Group, mappedBy: 'assignment' }) |     @OneToMany({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Group; | ||||||
|  |         }, | ||||||
|  |         mappedBy: 'assignment', | ||||||
|  |     }) | ||||||
|     groups!: Group[]; |     groups!: Group[]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,14 +3,27 @@ import { Assignment } from './assignment.entity.js'; | ||||||
| import { Student } from '../users/student.entity.js'; | import { Student } from '../users/student.entity.js'; | ||||||
| import { GroupRepository } from '../../data/assignments/group-repository.js'; | import { GroupRepository } from '../../data/assignments/group-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => GroupRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return GroupRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class Group { | export class Group { | ||||||
|     @ManyToOne({ entity: () => Assignment, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Assignment; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     assignment!: Assignment; |     assignment!: Assignment; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'integer' }) |     @PrimaryKey({ type: 'integer' }) | ||||||
|     groupNumber!: number; |     groupNumber!: number; | ||||||
| 
 | 
 | ||||||
|     @ManyToMany({ entity: () => Student }) |     @ManyToMany({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Student; | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|     members!: Student[]; |     members!: Student[]; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -4,12 +4,21 @@ import { Entity, Enum, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'; | ||||||
| import { Language } from '../content/language.js'; | import { Language } from '../content/language.js'; | ||||||
| import { SubmissionRepository } from '../../data/assignments/submission-repository.js'; | import { SubmissionRepository } from '../../data/assignments/submission-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => SubmissionRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return SubmissionRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class Submission { | export class Submission { | ||||||
|     @PrimaryKey({ type: 'string' }) |     @PrimaryKey({ type: 'string' }) | ||||||
|     learningObjectHruid!: string; |     learningObjectHruid!: string; | ||||||
| 
 | 
 | ||||||
|     @Enum({ items: () => Language, primary: true }) |     @Enum({ | ||||||
|  |         items: () => { | ||||||
|  |             return Language; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     learningObjectLanguage!: Language; |     learningObjectLanguage!: Language; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'string' }) |     @PrimaryKey({ type: 'string' }) | ||||||
|  | @ -18,13 +27,22 @@ export class Submission { | ||||||
|     @PrimaryKey({ type: 'integer' }) |     @PrimaryKey({ type: 'integer' }) | ||||||
|     submissionNumber!: number; |     submissionNumber!: number; | ||||||
| 
 | 
 | ||||||
|     @ManyToOne({ entity: () => Student }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Student; | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|     submitter!: Student; |     submitter!: Student; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'datetime' }) |     @Property({ type: 'datetime' }) | ||||||
|     submissionTime!: Date; |     submissionTime!: Date; | ||||||
| 
 | 
 | ||||||
|     @ManyToOne({ entity: () => Group, nullable: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Group; | ||||||
|  |         }, | ||||||
|  |         nullable: true, | ||||||
|  |     }) | ||||||
|     onBehalfOf?: Group; |     onBehalfOf?: Group; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'json' }) |     @Property({ type: 'json' }) | ||||||
|  |  | ||||||
|  | @ -3,15 +3,31 @@ import { Student } from '../users/student.entity.js'; | ||||||
| import { Class } from './class.entity.js'; | import { Class } from './class.entity.js'; | ||||||
| import { ClassJoinRequestRepository } from '../../data/classes/class-join-request-repository.js'; | import { ClassJoinRequestRepository } from '../../data/classes/class-join-request-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => ClassJoinRequestRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return ClassJoinRequestRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class ClassJoinRequest { | export class ClassJoinRequest { | ||||||
|     @ManyToOne({ entity: () => Student, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Student; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     requester!: Student; |     requester!: Student; | ||||||
| 
 | 
 | ||||||
|     @ManyToOne({ entity: () => Class, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Class; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     class!: Class; |     class!: Class; | ||||||
| 
 | 
 | ||||||
|     @Enum(() => ClassJoinRequestStatus) |     @Enum(() => { | ||||||
|  |         return ClassJoinRequestStatus; | ||||||
|  |     }) | ||||||
|     status!: ClassJoinRequestStatus; |     status!: ClassJoinRequestStatus; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,7 +10,11 @@ import { Teacher } from '../users/teacher.entity.js'; | ||||||
| import { Student } from '../users/student.entity.js'; | import { Student } from '../users/student.entity.js'; | ||||||
| import { ClassRepository } from '../../data/classes/class-repository.js'; | import { ClassRepository } from '../../data/classes/class-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => ClassRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return ClassRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class Class { | export class Class { | ||||||
|     @PrimaryKey() |     @PrimaryKey() | ||||||
|     classId = v4(); |     classId = v4(); | ||||||
|  | @ -18,9 +22,13 @@ export class Class { | ||||||
|     @Property({ type: 'string' }) |     @Property({ type: 'string' }) | ||||||
|     displayName!: string; |     displayName!: string; | ||||||
| 
 | 
 | ||||||
|     @ManyToMany(() => Teacher) |     @ManyToMany(() => { | ||||||
|  |         return Teacher; | ||||||
|  |     }) | ||||||
|     teachers!: Collection<Teacher>; |     teachers!: Collection<Teacher>; | ||||||
| 
 | 
 | ||||||
|     @ManyToMany(() => Student) |     @ManyToMany(() => { | ||||||
|  |         return Student; | ||||||
|  |     }) | ||||||
|     students!: Collection<Student>; |     students!: Collection<Student>; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -6,14 +6,33 @@ import { TeacherInvitationRepository } from '../../data/classes/teacher-invitati | ||||||
| /** | /** | ||||||
|  * Invitation of a teacher into a class (in order to teach it). |  * Invitation of a teacher into a class (in order to teach it). | ||||||
|  */ |  */ | ||||||
| @Entity({ repository: () => TeacherInvitationRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return TeacherInvitationRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class TeacherInvitation { | export class TeacherInvitation { | ||||||
|     @ManyToOne({ entity: () => Teacher, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Teacher; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     sender!: Teacher; |     sender!: Teacher; | ||||||
| 
 | 
 | ||||||
|     @ManyToOne({ entity: () => Teacher, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Teacher; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     receiver!: Teacher; |     receiver!: Teacher; | ||||||
| 
 | 
 | ||||||
|     @ManyToOne({ entity: () => Class, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Class; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     class!: Class; |     class!: Class; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,9 +2,18 @@ import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core'; | ||||||
| import { LearningObject } from './learning-object.entity.js'; | import { LearningObject } from './learning-object.entity.js'; | ||||||
| import { AttachmentRepository } from '../../data/content/attachment-repository.js'; | import { AttachmentRepository } from '../../data/content/attachment-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => AttachmentRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return AttachmentRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class Attachment { | export class Attachment { | ||||||
|     @ManyToOne({ entity: () => LearningObject, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return LearningObject; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     learningObject!: LearningObject; |     learningObject!: LearningObject; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'integer' }) |     @PrimaryKey({ type: 'integer' }) | ||||||
|  |  | ||||||
|  | @ -22,18 +22,31 @@ export class ReturnValue { | ||||||
|     callbackSchema!: string; |     callbackSchema!: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => LearningObjectRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return LearningObjectRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class LearningObject { | export class LearningObject { | ||||||
|     @PrimaryKey({ type: 'string' }) |     @PrimaryKey({ type: 'string' }) | ||||||
|     hruid!: string; |     hruid!: string; | ||||||
| 
 | 
 | ||||||
|     @Enum({ items: () => Language, primary: true }) |     @Enum({ | ||||||
|  |         items: () => { | ||||||
|  |             return Language; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     language!: Language; |     language!: Language; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'string' }) |     @PrimaryKey({ type: 'string' }) | ||||||
|     version: string = '1'; |     version: string = '1'; | ||||||
| 
 | 
 | ||||||
|     @ManyToMany({ entity: () => Teacher }) |     @ManyToMany({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Teacher; | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|     admins!: Teacher[]; |     admins!: Teacher[]; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'string' }) |     @Property({ type: 'string' }) | ||||||
|  | @ -57,7 +70,12 @@ export class LearningObject { | ||||||
|     @Property({ type: 'array' }) |     @Property({ type: 'array' }) | ||||||
|     skosConcepts!: string[]; |     skosConcepts!: string[]; | ||||||
| 
 | 
 | ||||||
|     @Embedded({ entity: () => EducationalGoal, array: true }) |     @Embedded({ | ||||||
|  |         entity: () => { | ||||||
|  |             return EducationalGoal; | ||||||
|  |         }, | ||||||
|  |         array: true, | ||||||
|  |     }) | ||||||
|     educationalGoals: EducationalGoal[] = []; |     educationalGoals: EducationalGoal[] = []; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'string' }) |     @Property({ type: 'string' }) | ||||||
|  | @ -72,7 +90,11 @@ export class LearningObject { | ||||||
|     @Property({ type: 'integer' }) |     @Property({ type: 'integer' }) | ||||||
|     estimatedTime!: number; |     estimatedTime!: number; | ||||||
| 
 | 
 | ||||||
|     @Embedded({ entity: () => ReturnValue }) |     @Embedded({ | ||||||
|  |         entity: () => { | ||||||
|  |             return ReturnValue; | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|     returnValue!: ReturnValue; |     returnValue!: ReturnValue; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'bool' }) |     @Property({ type: 'bool' }) | ||||||
|  | @ -81,7 +103,12 @@ export class LearningObject { | ||||||
|     @Property({ type: 'string', nullable: true }) |     @Property({ type: 'string', nullable: true }) | ||||||
|     contentLocation?: string; |     contentLocation?: string; | ||||||
| 
 | 
 | ||||||
|     @OneToMany({ entity: () => Attachment, mappedBy: 'learningObject' }) |     @OneToMany({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Attachment; | ||||||
|  |         }, | ||||||
|  |         mappedBy: 'learningObject', | ||||||
|  |     }) | ||||||
|     attachments: Attachment[] = []; |     attachments: Attachment[] = []; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'blob' }) |     @Property({ type: 'blob' }) | ||||||
|  |  | ||||||
|  | @ -12,15 +12,28 @@ import { Language } from './language.js'; | ||||||
| import { Teacher } from '../users/teacher.entity.js'; | import { Teacher } from '../users/teacher.entity.js'; | ||||||
| import { LearningPathRepository } from '../../data/content/learning-path-repository.js'; | import { LearningPathRepository } from '../../data/content/learning-path-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => LearningPathRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return LearningPathRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class LearningPath { | export class LearningPath { | ||||||
|     @PrimaryKey({ type: 'string' }) |     @PrimaryKey({ type: 'string' }) | ||||||
|     hruid!: string; |     hruid!: string; | ||||||
| 
 | 
 | ||||||
|     @Enum({ items: () => Language, primary: true }) |     @Enum({ | ||||||
|  |         items: () => { | ||||||
|  |             return Language; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     language!: Language; |     language!: Language; | ||||||
| 
 | 
 | ||||||
|     @ManyToMany({ entity: () => Teacher }) |     @ManyToMany({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Teacher; | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|     admins!: Teacher[]; |     admins!: Teacher[]; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'string' }) |     @Property({ type: 'string' }) | ||||||
|  | @ -32,7 +45,12 @@ export class LearningPath { | ||||||
|     @Property({ type: 'blob' }) |     @Property({ type: 'blob' }) | ||||||
|     image!: string; |     image!: string; | ||||||
| 
 | 
 | ||||||
|     @Embedded({ entity: () => LearningPathNode, array: true }) |     @Embedded({ | ||||||
|  |         entity: () => { | ||||||
|  |             return LearningPathNode; | ||||||
|  |         }, | ||||||
|  |         array: true, | ||||||
|  |     }) | ||||||
|     nodes: LearningPathNode[] = []; |     nodes: LearningPathNode[] = []; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -41,7 +59,11 @@ export class LearningPathNode { | ||||||
|     @Property({ type: 'string' }) |     @Property({ type: 'string' }) | ||||||
|     learningObjectHruid!: string; |     learningObjectHruid!: string; | ||||||
| 
 | 
 | ||||||
|     @Enum({ items: () => Language }) |     @Enum({ | ||||||
|  |         items: () => { | ||||||
|  |             return Language; | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|     language!: Language; |     language!: Language; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'string' }) |     @Property({ type: 'string' }) | ||||||
|  | @ -53,7 +75,12 @@ export class LearningPathNode { | ||||||
|     @Property({ type: 'bool' }) |     @Property({ type: 'bool' }) | ||||||
|     startNode!: boolean; |     startNode!: boolean; | ||||||
| 
 | 
 | ||||||
|     @Embedded({ entity: () => LearningPathTransition, array: true }) |     @Embedded({ | ||||||
|  |         entity: () => { | ||||||
|  |             return LearningPathTransition; | ||||||
|  |         }, | ||||||
|  |         array: true, | ||||||
|  |     }) | ||||||
|     transitions!: LearningPathTransition[]; |     transitions!: LearningPathTransition[]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -62,6 +89,10 @@ export class LearningPathTransition { | ||||||
|     @Property({ type: 'string' }) |     @Property({ type: 'string' }) | ||||||
|     condition!: string; |     condition!: string; | ||||||
| 
 | 
 | ||||||
|     @OneToOne({ entity: () => LearningPathNode }) |     @OneToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return LearningPathNode; | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|     next!: LearningPathNode; |     next!: LearningPathNode; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,12 +3,26 @@ import { Question } from './question.entity.js'; | ||||||
| import { Teacher } from '../users/teacher.entity.js'; | import { Teacher } from '../users/teacher.entity.js'; | ||||||
| import { AnswerRepository } from '../../data/questions/answer-repository.js'; | import { AnswerRepository } from '../../data/questions/answer-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => AnswerRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return AnswerRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class Answer { | export class Answer { | ||||||
|     @ManyToOne({ entity: () => Teacher, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Teacher; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     author!: Teacher; |     author!: Teacher; | ||||||
| 
 | 
 | ||||||
|     @ManyToOne({ entity: () => Question, primary: true }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Question; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     toQuestion!: Question; |     toQuestion!: Question; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'integer' }) |     @PrimaryKey({ type: 'integer' }) | ||||||
|  |  | ||||||
|  | @ -3,12 +3,21 @@ import { Language } from '../content/language.js'; | ||||||
| import { Student } from '../users/student.entity.js'; | import { Student } from '../users/student.entity.js'; | ||||||
| import { QuestionRepository } from '../../data/questions/question-repository.js'; | import { QuestionRepository } from '../../data/questions/question-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => QuestionRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return QuestionRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class Question { | export class Question { | ||||||
|     @PrimaryKey({ type: 'string' }) |     @PrimaryKey({ type: 'string' }) | ||||||
|     learningObjectHruid!: string; |     learningObjectHruid!: string; | ||||||
| 
 | 
 | ||||||
|     @Enum({ items: () => Language, primary: true }) |     @Enum({ | ||||||
|  |         items: () => { | ||||||
|  |             return Language; | ||||||
|  |         }, | ||||||
|  |         primary: true, | ||||||
|  |     }) | ||||||
|     learningObjectLanguage!: Language; |     learningObjectLanguage!: Language; | ||||||
| 
 | 
 | ||||||
|     @PrimaryKey({ type: 'string' }) |     @PrimaryKey({ type: 'string' }) | ||||||
|  | @ -17,7 +26,11 @@ export class Question { | ||||||
|     @PrimaryKey({ type: 'integer' }) |     @PrimaryKey({ type: 'integer' }) | ||||||
|     sequenceNumber!: number; |     sequenceNumber!: number; | ||||||
| 
 | 
 | ||||||
|     @ManyToOne({ entity: () => Student }) |     @ManyToOne({ | ||||||
|  |         entity: () => { | ||||||
|  |             return Student; | ||||||
|  |         }, | ||||||
|  |     }) | ||||||
|     author!: Student; |     author!: Student; | ||||||
| 
 | 
 | ||||||
|     @Property({ type: 'datetime' }) |     @Property({ type: 'datetime' }) | ||||||
|  |  | ||||||
|  | @ -4,11 +4,19 @@ import { Class } from '../classes/class.entity.js'; | ||||||
| import { Group } from '../assignments/group.entity.js'; | import { Group } from '../assignments/group.entity.js'; | ||||||
| import { StudentRepository } from '../../data/users/student-repository.js'; | import { StudentRepository } from '../../data/users/student-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => StudentRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return StudentRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class Student extends User { | export class Student extends User { | ||||||
|     @ManyToMany(() => Class) |     @ManyToMany(() => { | ||||||
|  |         return Class; | ||||||
|  |     }) | ||||||
|     classes!: Collection<Class>; |     classes!: Collection<Class>; | ||||||
| 
 | 
 | ||||||
|     @ManyToMany(() => Group) |     @ManyToMany(() => { | ||||||
|  |         return Group; | ||||||
|  |     }) | ||||||
|     groups!: Collection<Group>; |     groups!: Collection<Group>; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,8 +3,14 @@ import { User } from './user.entity.js'; | ||||||
| import { Class } from '../classes/class.entity.js'; | import { Class } from '../classes/class.entity.js'; | ||||||
| import { TeacherRepository } from '../../data/users/teacher-repository.js'; | import { TeacherRepository } from '../../data/users/teacher-repository.js'; | ||||||
| 
 | 
 | ||||||
| @Entity({ repository: () => TeacherRepository }) | @Entity({ | ||||||
|  |     repository: () => { | ||||||
|  |         return TeacherRepository; | ||||||
|  |     }, | ||||||
|  | }) | ||||||
| export class Teacher extends User { | export class Teacher extends User { | ||||||
|     @ManyToMany(() => Class) |     @ManyToMany(() => { | ||||||
|  |         return Class; | ||||||
|  |     }) | ||||||
|     classes!: Collection<Class>; |     classes!: Collection<Class>; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,14 +1,14 @@ | ||||||
| import { Assignment } from "../entities/assignments/assignment.entity.js"; | import { Assignment } from '../entities/assignments/assignment.entity.js'; | ||||||
| import { GroupDTO, mapToGroupDTO } from "./groups.js"; | import { GroupDTO, mapToGroupDTO } from './group.js'; | ||||||
| 
 | 
 | ||||||
| export interface AssignmentDTO { | export interface AssignmentDTO { | ||||||
|     id: number, |     id: number; | ||||||
|     class: string, // id of class 'within'
 |     class: string; // Id of class 'within'
 | ||||||
|     title: string, |     title: string; | ||||||
|     description: string, |     description: string; | ||||||
|     learningPath: string, |     learningPath: string; | ||||||
|     language: string, |     language: string; | ||||||
|     groups?: GroupDTO[] | string[], // TODO
 |     groups?: GroupDTO[] | string[]; // TODO
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function mapToAssignmentDTOId(assignment: Assignment): AssignmentDTO { | export function mapToAssignmentDTOId(assignment: Assignment): AssignmentDTO { | ||||||
|  | @ -19,8 +19,8 @@ export function mapToAssignmentDTOId(assignment: Assignment): AssignmentDTO { | ||||||
|         description: assignment.description, |         description: assignment.description, | ||||||
|         learningPath: assignment.learningPathHruid, |         learningPath: assignment.learningPathHruid, | ||||||
|         language: assignment.learningPathLanguage, |         language: assignment.learningPathLanguage, | ||||||
|         // groups: assignment.groups.map(group => group.groupNumber),
 |         // Groups: assignment.groups.map(group => group.groupNumber),
 | ||||||
|     } |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function mapToAssignmentDTO(assignment: Assignment): AssignmentDTO { | export function mapToAssignmentDTO(assignment: Assignment): AssignmentDTO { | ||||||
|  | @ -31,6 +31,6 @@ export function mapToAssignmentDTO(assignment: Assignment): AssignmentDTO { | ||||||
|         description: assignment.description, |         description: assignment.description, | ||||||
|         learningPath: assignment.learningPathHruid, |         learningPath: assignment.learningPathHruid, | ||||||
|         language: assignment.learningPathLanguage, |         language: assignment.learningPathLanguage, | ||||||
|         // groups: assignment.groups.map(mapToGroupDTO),
 |         // Groups: assignment.groups.map(mapToGroupDTO),
 | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import { Class } from "../entities/classes/class.entity.js"; | import { Class } from '../entities/classes/class.entity.js'; | ||||||
| 
 | 
 | ||||||
| export interface ClassDTO { | export interface ClassDTO { | ||||||
|     id: string; |     id: string; | ||||||
|  | @ -18,8 +18,12 @@ export function mapToClassDTO(cls: Class): ClassDTO { | ||||||
|     return { |     return { | ||||||
|         id: cls.classId, |         id: cls.classId, | ||||||
|         displayName: cls.displayName, |         displayName: cls.displayName, | ||||||
|         teachers: cls.teachers.map(teacher => teacher.username), |         teachers: cls.teachers.map((teacher) => { | ||||||
|         students: cls.students.map(student => student.username), |             return teacher.username; | ||||||
|  |         }), | ||||||
|  |         students: cls.students.map((student) => { | ||||||
|  |             return student.username; | ||||||
|  |         }), | ||||||
|         joinRequests: [], // TODO
 |         joinRequests: [], // TODO
 | ||||||
|     } |     }; | ||||||
| }; | } | ||||||
|  |  | ||||||
|  | @ -1,25 +1,27 @@ | ||||||
| import { Group } from "../entities/assignments/group.entity.js"; | import { Group } from '../entities/assignments/group.entity.js'; | ||||||
| import { AssignmentDTO, mapToAssignmentDTO } from "./assignments.js"; | import { AssignmentDTO, mapToAssignmentDTO } from './assignment.js'; | ||||||
| import { mapToStudentDTO, StudentDTO } from "./students.js"; | import { mapToStudentDTO, StudentDTO } from './student.js'; | ||||||
| 
 | 
 | ||||||
| export interface GroupDTO { | export interface GroupDTO { | ||||||
|     assignment: number | AssignmentDTO, |     assignment: number | AssignmentDTO; | ||||||
|     groupNumber: number, |     groupNumber: number; | ||||||
|     members: string[] | StudentDTO[], |     members: string[] | StudentDTO[]; | ||||||
| }; | } | ||||||
| 
 | 
 | ||||||
| export function mapToGroupDTO(group: Group): GroupDTO { | export function mapToGroupDTO(group: Group): GroupDTO { | ||||||
|     return { |     return { | ||||||
|         assignment: mapToAssignmentDTO(group.assignment), // ERROR: , group.assignment.within),
 |         assignment: mapToAssignmentDTO(group.assignment), // ERROR: , group.assignment.within),
 | ||||||
|         groupNumber: group.groupNumber, |         groupNumber: group.groupNumber, | ||||||
|         members: group.members.map(mapToStudentDTO), |         members: group.members.map(mapToStudentDTO), | ||||||
|     } |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function mapToGroupDTOId(group: Group): GroupDTO { | export function mapToGroupDTOId(group: Group): GroupDTO { | ||||||
|     return { |     return { | ||||||
|         assignment: group.assignment.id, |         assignment: group.assignment.id, | ||||||
|         groupNumber: group.groupNumber, |         groupNumber: group.groupNumber, | ||||||
|         members: group.members.map(member => member.username), |         members: group.members.map((member) => { | ||||||
|     } |             return member.username; | ||||||
|  |         }), | ||||||
|  |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| // TODO: implement something like this but with named endpoints
 | // TODO: implement something like this but with named endpoints
 | ||||||
| export interface List<T> { | export interface List<T> { | ||||||
|     items: T[], |     items: T[]; | ||||||
|     endpoints?: string[], |     endpoints?: string[]; | ||||||
| }; | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,4 @@ | ||||||
| import {Question} from "../entities/questions/question.entity"; | import { Question } from '../entities/questions/question.entity.js'; | ||||||
| import {Enum, PrimaryKey} from "@mikro-orm/core"; |  | ||||||
| import {Language} from "../entities/content/language"; |  | ||||||
| 
 | 
 | ||||||
| export interface QuestionDTO { | export interface QuestionDTO { | ||||||
|     learningObjectHruid: string; |     learningObjectHruid: string; | ||||||
|  | @ -34,8 +32,17 @@ export function mapToQuestionDTO(question: Question): QuestionDTO { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface QuestionId { | export interface QuestionId { | ||||||
|     learningObjectHruid: string, |     learningObjectHruid: string; | ||||||
|     learningObjectLanguage: Language, |     learningObjectLanguage: string; | ||||||
|     learningObjectVersion: string, |     learningObjectVersion: string; | ||||||
|     sequenceNumber: number |     sequenceNumber: number; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export function mapToQuestionId(question: QuestionDTO): QuestionId { | ||||||
|  |     return { | ||||||
|  |         learningObjectHruid: question.learningObjectHruid, | ||||||
|  |         learningObjectLanguage: question.learningObjectLanguage, | ||||||
|  |         learningObjectVersion: question.learningObjectVersion, | ||||||
|  |         sequenceNumber: question.sequenceNumber, | ||||||
|  |     }; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import { Student } from "../entities/users/student.entity.js"; | import { Student } from '../entities/users/student.entity.js'; | ||||||
| 
 | 
 | ||||||
| export interface StudentDTO { | export interface StudentDTO { | ||||||
|     id: string; |     id: string; | ||||||
|  |  | ||||||
|  | @ -1,22 +1,26 @@ | ||||||
| import { TeacherInvitation } from "../entities/classes/teacher-invitation.entity.js"; | import { TeacherInvitation } from '../entities/classes/teacher-invitation.entity.js'; | ||||||
| import { ClassDTO, mapToClassDTO } from "./classes.js"; | import { ClassDTO, mapToClassDTO } from './class.js'; | ||||||
| import { mapToTeacherDTO, TeacherDTO } from "./teacher.js"; | import { mapToUserDTO, UserDTO } from './user.js'; | ||||||
| 
 | 
 | ||||||
| export interface TeacherInvitationDTO { | export interface TeacherInvitationDTO { | ||||||
|     sender: string | TeacherDTO, |     sender: string | UserDTO; | ||||||
|     receiver: string | TeacherDTO, |     receiver: string | UserDTO; | ||||||
|     class: string | ClassDTO, |     class: string | ClassDTO; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function mapToTeacherInvitationDTO(invitation: TeacherInvitation): TeacherInvitationDTO { | export function mapToTeacherInvitationDTO( | ||||||
|  |     invitation: TeacherInvitation | ||||||
|  | ): TeacherInvitationDTO { | ||||||
|     return { |     return { | ||||||
|         sender: mapToTeacherDTO(invitation.sender), |         sender: mapToUserDTO(invitation.sender), | ||||||
|         receiver: mapToTeacherDTO(invitation.receiver), |         receiver: mapToUserDTO(invitation.receiver), | ||||||
|         class: mapToClassDTO(invitation.class), |         class: mapToClassDTO(invitation.class), | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function mapToTeacherInvitationDTOIds(invitation: TeacherInvitation): TeacherInvitationDTO { | export function mapToTeacherInvitationDTOIds( | ||||||
|  |     invitation: TeacherInvitation | ||||||
|  | ): TeacherInvitationDTO { | ||||||
|     return { |     return { | ||||||
|         sender: invitation.sender.username, |         sender: invitation.sender.username, | ||||||
|         receiver: invitation.receiver.username, |         receiver: invitation.receiver.username, | ||||||
|  |  | ||||||
|  | @ -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; |  | ||||||
| } |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import { User } from "../entities/users/user.entity.js"; | import { User } from '../entities/users/user.entity.js'; | ||||||
| 
 | 
 | ||||||
| export interface UserDTO { | export interface UserDTO { | ||||||
|     id?: string, |     id?: string; | ||||||
|     username: string; |     username: string; | ||||||
|     firstName: string; |     firstName: string; | ||||||
|     lastName: string; |     lastName: string; | ||||||
|  | @ -22,7 +22,10 @@ export function mapToUserDTO(user: User): UserDTO { | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function mapToUser<T extends User>(userData: UserDTO, userInstance: T): T { | export function mapToUser<T extends User>( | ||||||
|  |     userData: UserDTO, | ||||||
|  |     userInstance: T | ||||||
|  | ): T { | ||||||
|     userInstance.username = userData.username; |     userInstance.username = userData.username; | ||||||
|     userInstance.firstName = userData.firstName; |     userInstance.firstName = userData.firstName; | ||||||
|     userInstance.lastName = userData.lastName; |     userInstance.lastName = userData.lastName; | ||||||
|  |  | ||||||
|  | @ -24,11 +24,20 @@ import { Answer } from './entities/questions/answer.entity.js'; | ||||||
| import { Question } from './entities/questions/question.entity.js'; | import { Question } from './entities/questions/question.entity.js'; | ||||||
| 
 | 
 | ||||||
| const entities = [ | const entities = [ | ||||||
|     User, Student, Teacher, |     User, | ||||||
|     Assignment, Group, Submission, |     Student, | ||||||
|     Class, ClassJoinRequest, TeacherInvitation, |     Teacher, | ||||||
|     Attachment, LearningObject, LearningPath, |     Assignment, | ||||||
|     Answer, Question |     Group, | ||||||
|  |     Submission, | ||||||
|  |     Class, | ||||||
|  |     ClassJoinRequest, | ||||||
|  |     TeacherInvitation, | ||||||
|  |     Attachment, | ||||||
|  |     LearningObject, | ||||||
|  |     LearningPath, | ||||||
|  |     Answer, | ||||||
|  |     Question, | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| function config(testingMode: boolean = false): Options { | function config(testingMode: boolean = false): Options { | ||||||
|  | @ -37,25 +46,26 @@ function config(testingMode: boolean = false): Options { | ||||||
|             driver: SqliteDriver, |             driver: SqliteDriver, | ||||||
|             dbName: getEnvVar(EnvVars.DbName), |             dbName: getEnvVar(EnvVars.DbName), | ||||||
|             entities: entities, |             entities: entities, | ||||||
|             // entitiesTs: entitiesTs,
 |             // EntitiesTs: entitiesTs,
 | ||||||
| 
 | 
 | ||||||
|             // Workaround: vitest: `TypeError: Unknown file extension ".ts"` (ERR_UNKNOWN_FILE_EXTENSION)
 |             // Workaround: vitest: `TypeError: Unknown file extension ".ts"` (ERR_UNKNOWN_FILE_EXTENSION)
 | ||||||
|             // (see https://mikro-orm.io/docs/guide/project-setup#testing-the-endpoint)
 |             // (see https://mikro-orm.io/docs/guide/project-setup#testing-the-endpoint)
 | ||||||
|             dynamicImportProvider: (id) => import(id), |             dynamicImportProvider: (id) => { | ||||||
|         }; |                 return 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, |  | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |     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; | export default config; | ||||||
|  |  | ||||||
|  | @ -1,31 +1,30 @@ | ||||||
| import express from 'express' | import express from 'express'; | ||||||
| import { getAllAssignmentsHandler, getAssignmentHandler } from '../controllers/assignments.js'; | import { | ||||||
| import groupRouter from './group.js'; |     getAllAssignmentsHandler, | ||||||
|  |     getAssignmentHandler, | ||||||
|  | } from '../controllers/assignments.js'; | ||||||
|  | import groupRouter from './groups.js'; | ||||||
| 
 | 
 | ||||||
| const router = express.Router({ mergeParams: true }); | const router = express.Router({ mergeParams: true }); | ||||||
| 
 | 
 | ||||||
| // root endpoint used to search objects
 | // Root endpoint used to search objects
 | ||||||
| router.get('/', getAllAssignmentsHandler); | router.get('/', getAllAssignmentsHandler); | ||||||
| 
 | 
 | ||||||
| // information about an assignment with id 'id'
 | // Information about an assignment with id 'id'
 | ||||||
| router.get('/:id', getAssignmentHandler); | router.get('/:id', getAssignmentHandler); | ||||||
| 
 | 
 | ||||||
| router.get('/:id/submissions', (req, res) => { | router.get('/:id/submissions', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         submissions: [ |         submissions: ['0'], | ||||||
|             '0' |  | ||||||
|         ], |  | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| router.get('/:id/questions', (req, res) => { | router.get('/:id/questions', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         questions: [ |         questions: ['0'], | ||||||
|             '0' |  | ||||||
|         ], |  | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| router.use('/:assignmentid/groups', groupRouter); | router.use('/:assignmentid/groups', groupRouter); | ||||||
| 
 | 
 | ||||||
| export default router | export default router; | ||||||
|  |  | ||||||
|  | @ -1,13 +1,18 @@ | ||||||
| import express from 'express' | import express from 'express'; | ||||||
| import { getAllClassesHandler, getClassHandler, getClassStudentsHandler, getTeacherInvitationsHandler } from '../controllers/classes.js'; | import { | ||||||
| import assignmentRouter from './assignment.js'; |     getAllClassesHandler, | ||||||
|  |     getClassHandler, | ||||||
|  |     getClassStudentsHandler, | ||||||
|  |     getTeacherInvitationsHandler, | ||||||
|  | } from '../controllers/classes.js'; | ||||||
|  | import assignmentRouter from './assignments.js'; | ||||||
| 
 | 
 | ||||||
| const router = express.Router(); | const router = express.Router(); | ||||||
| 
 | 
 | ||||||
| // root endpoint used to search objects
 | // Root endpoint used to search objects
 | ||||||
| router.get('/', getAllClassesHandler); | router.get('/', getAllClassesHandler); | ||||||
| 
 | 
 | ||||||
| // information about an class with id 'id'
 | // Information about an class with id 'id'
 | ||||||
| router.get('/:id', getClassHandler); | router.get('/:id', getClassHandler); | ||||||
| 
 | 
 | ||||||
| router.get('/:id/teacher-invitations', getTeacherInvitationsHandler); | router.get('/:id/teacher-invitations', getTeacherInvitationsHandler); | ||||||
|  | @ -16,4 +21,4 @@ router.get('/:id/students', getClassStudentsHandler); | ||||||
| 
 | 
 | ||||||
| router.use('/:classid/assignments', assignmentRouter); | router.use('/:classid/assignments', assignmentRouter); | ||||||
| 
 | 
 | ||||||
| export default router | export default router; | ||||||
|  |  | ||||||
|  | @ -1,18 +1,19 @@ | ||||||
| import express from 'express' | import express from 'express'; | ||||||
| import { getAllGroupsHandler, getGroupHandler } from '../controllers/groups.js'; | import { getAllGroupsHandler, getGroupHandler } from '../controllers/groups.js'; | ||||||
|  | 
 | ||||||
| const router = express.Router({ mergeParams: true }); | const router = express.Router({ mergeParams: true }); | ||||||
| 
 | 
 | ||||||
| // root endpoint used to search objects
 | // Root endpoint used to search objects
 | ||||||
| router.get('/', getAllGroupsHandler); | router.get('/', getAllGroupsHandler); | ||||||
| 
 | 
 | ||||||
| // information about a group (members, ... [TODO DOC])
 | // Information about a group (members, ... [TODO DOC])
 | ||||||
| router.get('/:groupid', getGroupHandler); | 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) => { | router.get('/:id/question', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         questions: [ '0' ], |         questions: ['0'], | ||||||
|     }); |     }); | ||||||
| }) | }); | ||||||
| 
 | 
 | ||||||
| export default router | export default router; | ||||||
|  |  | ||||||
|  | @ -1,38 +1,34 @@ | ||||||
| import express from 'express' | import express from 'express'; | ||||||
| const router = express.Router(); | const router = express.Router(); | ||||||
| 
 | 
 | ||||||
| // root endpoint used to search objects
 | // Root endpoint used to search objects
 | ||||||
| router.get('/', (req, res) => { | router.get('/', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         questions: [ |         questions: ['0', '1'], | ||||||
|             '0', |  | ||||||
|             '1', |  | ||||||
|         ] |  | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| // information about an question with id 'id'
 | // Information about an question with id 'id'
 | ||||||
| router.get('/:id', (req, res) => { | router.get('/:id', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         id: req.params.id, |         id: req.params.id, | ||||||
|         student: '0', |         student: '0', | ||||||
|         group: '0', |         group: '0', | ||||||
|         time: new Date(2025, 1, 1), |         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', |         learningObject: '0', | ||||||
|         links: { |         links: { | ||||||
|             self: `${req.baseUrl}/${req.params.id}`, |             self: `${req.baseUrl}/${req.params.id}`, | ||||||
|             answers: `${req.baseUrl}/${req.params.id}/answers`, |             answers: `${req.baseUrl}/${req.params.id}/answers`, | ||||||
|         } |         }, | ||||||
|     }); |     }); | ||||||
| }) | }); | ||||||
| 
 | 
 | ||||||
| router.get('/:id/answers', (req, res) => { | router.get('/:id/answers', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         answers: [ |         answers: ['0'], | ||||||
|             '0' |     }); | ||||||
|         ], | }); | ||||||
|     }) |  | ||||||
| }) |  | ||||||
| 
 | 
 | ||||||
| export default router | export default router; | ||||||
|  |  | ||||||
|  | @ -1,51 +1,49 @@ | ||||||
| import express from 'express' | import express from 'express'; | ||||||
| import { | import { | ||||||
|     createStudentHandler, deleteStudentHandler, |     createStudentHandler, | ||||||
|  |     deleteStudentHandler, | ||||||
|     getAllStudentsHandler, |     getAllStudentsHandler, | ||||||
|     getStudentAssignmentsHandler, |     getStudentAssignmentsHandler, | ||||||
|     getStudentClassesHandler, |     getStudentClassesHandler, | ||||||
|     getStudentHandler |     getStudentHandler, | ||||||
| } from '../controllers/students.js'; | } from '../controllers/students.js'; | ||||||
| const router = express.Router(); | const router = express.Router(); | ||||||
| 
 | 
 | ||||||
| // root endpoint used to search objects
 | // Root endpoint used to search objects
 | ||||||
| router.get('/', getAllStudentsHandler); | router.get('/', getAllStudentsHandler); | ||||||
| 
 | 
 | ||||||
| router.post('/', createStudentHandler); | router.post('/', createStudentHandler); | ||||||
| 
 | 
 | ||||||
| router.delete('/:username', deleteStudentHandler); | router.delete('/:username', deleteStudentHandler); | ||||||
| 
 | 
 | ||||||
| // information about a student's profile
 | // Information about a student's profile
 | ||||||
| router.get('/:username', getStudentHandler); | 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); | 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) => { | router.get('/:id/submissions', (req, res) => { | ||||||
|     res.json({ |     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); | 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) => { | router.get('/:id/groups', (req, res) => { | ||||||
|     res.json({ |     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) => { | router.get('/:id/questions', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         questions: [ '0' ], |         questions: ['0'], | ||||||
|     }); |     }); | ||||||
| }) | }); | ||||||
| 
 | 
 | ||||||
| export default router | export default router; | ||||||
|  |  | ||||||
|  | @ -1,17 +1,14 @@ | ||||||
| import express from 'express' | import express from 'express'; | ||||||
| const router = express.Router(); | const router = express.Router(); | ||||||
| 
 | 
 | ||||||
| // root endpoint used to search objects
 | // Root endpoint used to search objects
 | ||||||
| router.get('/', (req, res) => { | router.get('/', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         submissions: [ |         submissions: ['0', '1'], | ||||||
|             '0', |  | ||||||
|             '1', |  | ||||||
|         ] |  | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| // information about an submission with id 'id'
 | // Information about an submission with id 'id'
 | ||||||
| router.get('/:id', (req, res) => { | router.get('/:id', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         id: req.params.id, |         id: req.params.id, | ||||||
|  | @ -21,6 +18,6 @@ router.get('/:id', (req, res) => { | ||||||
|         content: 'Wortel 2 is rationeel', |         content: 'Wortel 2 is rationeel', | ||||||
|         learningObject: '0', |         learningObject: '0', | ||||||
|     }); |     }); | ||||||
| }) | }); | ||||||
| 
 | 
 | ||||||
| export default router | export default router; | ||||||
|  |  | ||||||
|  | @ -1,17 +1,22 @@ | ||||||
| import express from 'express' | import express from 'express'; | ||||||
| import { | import { | ||||||
|     createTeacherHandler, |     createTeacherHandler, | ||||||
|     deleteTeacherHandler, |     deleteTeacherHandler, | ||||||
|  |     getAllTeachersHandler, | ||||||
|     getTeacherClassHandler, |     getTeacherClassHandler, | ||||||
|     getTeacherHandler, getTeacherQuestionHandler, getTeacherStudentHandler |     getTeacherHandler, | ||||||
| } from "../controllers/teachers.js"; |     getTeacherQuestionHandler, | ||||||
|  |     getTeacherStudentHandler, | ||||||
|  | } from '../controllers/teachers.js'; | ||||||
| const router = express.Router(); | const router = express.Router(); | ||||||
| 
 | 
 | ||||||
| // root endpoint used to search objects
 | // Root endpoint used to search objects
 | ||||||
| router.get('/', getTeacherHandler); | router.get('/', getAllTeachersHandler); | ||||||
| 
 | 
 | ||||||
| router.post('/', createTeacherHandler); | router.post('/', createTeacherHandler); | ||||||
| 
 | 
 | ||||||
|  | router.get('/:username', getTeacherHandler); | ||||||
|  | 
 | ||||||
| router.delete('/:username', deleteTeacherHandler); | router.delete('/:username', deleteTeacherHandler); | ||||||
| 
 | 
 | ||||||
| router.get('/:username/classes', getTeacherClassHandler); | router.get('/:username/classes', getTeacherClassHandler); | ||||||
|  | @ -20,15 +25,11 @@ router.get('/:username/students', getTeacherStudentHandler); | ||||||
| 
 | 
 | ||||||
| router.get('/:username/questions', getTeacherQuestionHandler); | 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) => { | router.get('/:id/invitations', (req, res) => { | ||||||
|     res.json({ |     res.json({ | ||||||
|         invitations: [ |         invitations: ['0'], | ||||||
|             '0' |  | ||||||
|         ], |  | ||||||
|     }); |     }); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| 
 | export default router; | ||||||
| 
 |  | ||||||
| export default router |  | ||||||
|  |  | ||||||
|  | @ -1,7 +1,17 @@ | ||||||
| import { getAssignmentRepository, getClassRepository } from "../data/repositories.js"; | import { | ||||||
| import { AssignmentDTO, mapToAssignmentDTO, mapToAssignmentDTOId } from "../interfaces/assignments.js"; |     getAssignmentRepository, | ||||||
|  |     getClassRepository, | ||||||
|  | } from '../data/repositories.js'; | ||||||
|  | import { | ||||||
|  |     AssignmentDTO, | ||||||
|  |     mapToAssignmentDTO, | ||||||
|  |     mapToAssignmentDTOId, | ||||||
|  | } from '../interfaces/assignment.js'; | ||||||
| 
 | 
 | ||||||
| export async function getAllAssignments(classid: string, full: boolean): Promise<AssignmentDTO[]> { | export async function getAllAssignments( | ||||||
|  |     classid: string, | ||||||
|  |     full: boolean | ||||||
|  | ): Promise<AssignmentDTO[]> { | ||||||
|     const classRepository = getClassRepository(); |     const classRepository = getClassRepository(); | ||||||
|     const cls = await classRepository.findById(classid); |     const cls = await classRepository.findById(classid); | ||||||
| 
 | 
 | ||||||
|  | @ -10,7 +20,8 @@ export async function getAllAssignments(classid: string, full: boolean): Promise | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const assignmentRepository = getAssignmentRepository(); |     const assignmentRepository = getAssignmentRepository(); | ||||||
|     const assignments = await assignmentRepository.findAllAssignmentsInClass(cls); |     const assignments = | ||||||
|  |         await assignmentRepository.findAllAssignmentsInClass(cls); | ||||||
| 
 | 
 | ||||||
|     if (full) { |     if (full) { | ||||||
|         return assignments.map(mapToAssignmentDTO); |         return assignments.map(mapToAssignmentDTO); | ||||||
|  | @ -19,7 +30,10 @@ export async function getAllAssignments(classid: string, full: boolean): Promise | ||||||
|     return assignments.map(mapToAssignmentDTOId); |     return assignments.map(mapToAssignmentDTOId); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getAssignment(classid: string, id: number): Promise<AssignmentDTO | null> { | export async function getAssignment( | ||||||
|  |     classid: string, | ||||||
|  |     id: number | ||||||
|  | ): Promise<AssignmentDTO | null> { | ||||||
|     const classRepository = getClassRepository(); |     const classRepository = getClassRepository(); | ||||||
|     const cls = await classRepository.findById(classid); |     const cls = await classRepository.findById(classid); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,11 +1,23 @@ | ||||||
| import { getClassRepository } from "../data/repositories"; | import { | ||||||
| import { Class } from "../entities/classes/class.entity"; |     getClassRepository, | ||||||
| import { ClassDTO, mapToClassDTO } from "../interfaces/class"; |     getTeacherInvitationRepository, | ||||||
| import { mapToStudentDTO, StudentDTO } from "../interfaces/student"; | } 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<ClassDTO[] | string[]> { | export async function getAllClasses( | ||||||
|  |     full: boolean | ||||||
|  | ): Promise<ClassDTO[] | string[]> { | ||||||
|     const classRepository = getClassRepository(); |     const classRepository = getClassRepository(); | ||||||
|     const classes = await classRepository.find({}, { populate: ["students", "teachers"] }); |     const classes = await classRepository.find( | ||||||
|  |         {}, | ||||||
|  |         { populate: ['students', 'teachers'] } | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     if (!classes) { |     if (!classes) { | ||||||
|         return []; |         return []; | ||||||
|  | @ -13,27 +25,30 @@ export async function getAllClasses(full: boolean): Promise<ClassDTO[] | string[ | ||||||
| 
 | 
 | ||||||
|     if (full) { |     if (full) { | ||||||
|         return classes.map(mapToClassDTO); |         return classes.map(mapToClassDTO); | ||||||
|     } else { |  | ||||||
|         return classes.map((cls) => cls.classId); |  | ||||||
|     } |     } | ||||||
|  |     return classes.map((cls) => { | ||||||
|  |         return cls.classId; | ||||||
|  |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getClass(classId: string): Promise<ClassDTO | null> { | export async function getClass(classId: string): Promise<ClassDTO | null> { | ||||||
|     const classRepository = getClassRepository(); |     const classRepository = getClassRepository(); | ||||||
|     const cls = await classRepository.findById(classId); |     const cls = await classRepository.findById(classId); | ||||||
| 
 | 
 | ||||||
|     if (!cls) return null; |     if (!cls) { | ||||||
|     else { |         return null; | ||||||
|         return mapToClassDTO(cls); |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     return mapToClassDTO(cls); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function fetchClassStudents(classId: string, full: boolean): Promise<StudentDTO[] | string[]> { | async function fetchClassStudents(classId: string): Promise<StudentDTO[]> { | ||||||
|     const classRepository = getClassRepository(); |     const classRepository = getClassRepository(); | ||||||
|     const cls = await classRepository.findById(classId); |     const cls = await classRepository.findById(classId); | ||||||
| 
 | 
 | ||||||
|     if (!cls) |     if (!cls) { | ||||||
|         return []; |         return []; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     return cls.students.map(mapToStudentDTO); |     return cls.students.map(mapToStudentDTO); | ||||||
| } | } | ||||||
|  | @ -43,6 +58,36 @@ export async function getClassStudents(classId: string): Promise<StudentDTO[]> { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getClassStudentsIds(classId: string): Promise<string[]> { | export async function getClassStudentsIds(classId: string): Promise<string[]> { | ||||||
|     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<TeacherInvitationDTO[]> { | ||||||
|  |     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); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,11 +1,19 @@ | ||||||
| import { getAssignmentRepository, getClassRepository, getGroupRepository } from "../data/repositories.js"; | import { | ||||||
| import { GroupDTO, mapToGroupDTO, mapToGroupDTOId } from "../interfaces/groups.js"; |     getAssignmentRepository, | ||||||
|  |     getClassRepository, | ||||||
|  |     getGroupRepository, | ||||||
|  | } from '../data/repositories.js'; | ||||||
|  | import { | ||||||
|  |     GroupDTO, | ||||||
|  |     mapToGroupDTO, | ||||||
|  |     mapToGroupDTOId, | ||||||
|  | } from '../interfaces/group.js'; | ||||||
| 
 | 
 | ||||||
| export async function getGroup( | export async function getGroup( | ||||||
|     classId: string, |     classId: string, | ||||||
|     assignmentNumber: number, |     assignmentNumber: number, | ||||||
|     groupNumber: number, |     groupNumber: number, | ||||||
|     full: boolean, |     full: boolean | ||||||
| ): Promise<GroupDTO | null> { | ): Promise<GroupDTO | null> { | ||||||
|     const classRepository = getClassRepository(); |     const classRepository = getClassRepository(); | ||||||
|     const cls = await classRepository.findById(classId); |     const cls = await classRepository.findById(classId); | ||||||
|  | @ -15,14 +23,20 @@ export async function getGroup( | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const assignmentRepository = getAssignmentRepository(); |     const assignmentRepository = getAssignmentRepository(); | ||||||
|     const assignment = await assignmentRepository.findByClassAndId(cls, assignmentNumber); |     const assignment = await assignmentRepository.findByClassAndId( | ||||||
|  |         cls, | ||||||
|  |         assignmentNumber | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     if (!assignment) { |     if (!assignment) { | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const groupRepository = getGroupRepository(); |     const groupRepository = getGroupRepository(); | ||||||
|     const group = await groupRepository.findByAssignmentAndGroupNumber(assignment, groupNumber); |     const group = await groupRepository.findByAssignmentAndGroupNumber( | ||||||
|  |         assignment, | ||||||
|  |         groupNumber | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     if (!group) { |     if (!group) { | ||||||
|         return null; |         return null; | ||||||
|  | @ -38,7 +52,7 @@ export async function getGroup( | ||||||
| export async function getAllGroups( | export async function getAllGroups( | ||||||
|     classId: string, |     classId: string, | ||||||
|     assignmentNumber: number, |     assignmentNumber: number, | ||||||
|     full: boolean, |     full: boolean | ||||||
| ): Promise<GroupDTO[]> { | ): Promise<GroupDTO[]> { | ||||||
|     const classRepository = getClassRepository(); |     const classRepository = getClassRepository(); | ||||||
|     const cls = await classRepository.findById(classId); |     const cls = await classRepository.findById(classId); | ||||||
|  | @ -48,7 +62,10 @@ export async function getAllGroups( | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const assignmentRepository = getAssignmentRepository(); |     const assignmentRepository = getAssignmentRepository(); | ||||||
|     const assignment = await assignmentRepository.findByClassAndId(cls, assignmentNumber); |     const assignment = await assignmentRepository.findByClassAndId( | ||||||
|  |         cls, | ||||||
|  |         assignmentNumber | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     if (!assignment) { |     if (!assignment) { | ||||||
|         return []; |         return []; | ||||||
|  |  | ||||||
|  | @ -1,8 +1,11 @@ | ||||||
| import { getClassRepository, getStudentRepository } from "../data/repositories.js"; | import { | ||||||
| import { Class } from "../entities/classes/class.entity.js"; |     getClassRepository, | ||||||
| import { Student } from "../entities/users/student.entity.js"; |     getStudentRepository, | ||||||
| import { ClassDTO, mapToClassDTO } from "../interfaces/classes.js"; | } from '../data/repositories.js'; | ||||||
| import {UserService} from "./users.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<Student> { | export class StudentService extends UserService<Student> { | ||||||
|     constructor() { |     constructor() { | ||||||
|  | @ -14,12 +17,16 @@ async function fetchStudentClasses(username: string): Promise<Class[]> { | ||||||
|     const studentRepository = getStudentRepository(); |     const studentRepository = getStudentRepository(); | ||||||
|     const student = await studentRepository.findByUsername(username); |     const student = await studentRepository.findByUsername(username); | ||||||
| 
 | 
 | ||||||
|     if (!student) return []; |     if (!student) { | ||||||
|  |         return []; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     const classRepository = getClassRepository(); |     const classRepository = getClassRepository(); | ||||||
|     const classes = await classRepository.findByStudent(student); |     const classes = await classRepository.findByStudent(student); | ||||||
| 
 | 
 | ||||||
|     if (!classes) return []; |     if (!classes) { | ||||||
|  |         return []; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     return classes; |     return classes; | ||||||
| } | } | ||||||
|  | @ -31,6 +38,7 @@ export async function getStudentClasses(username: string): Promise<ClassDTO[]> { | ||||||
| 
 | 
 | ||||||
| export async function getStudentClassIds(username: string): Promise<string[]> { | export async function getStudentClassIds(username: string): Promise<string[]> { | ||||||
|     const classes = await fetchStudentClasses(username); |     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
 | ||||||
| } | } | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -2,130 +2,108 @@ import { | ||||||
|     getClassRepository, |     getClassRepository, | ||||||
|     getLearningObjectRepository, |     getLearningObjectRepository, | ||||||
|     getQuestionRepository, |     getQuestionRepository, | ||||||
|     getTeacherRepository |     getStudentRepository, | ||||||
| } from "../data/repositories.js"; |     getTeacherRepository, | ||||||
| import {mapToTeacher, mapToTeacherDTO, TeacherDTO} from "../interfaces/teacher.js"; | } from '../data/repositories.js'; | ||||||
| import { Teacher } from "../entities/users/teacher.entity"; | import { Teacher } from '../entities/users/teacher.entity.js'; | ||||||
| import {ClassDTO, mapToClassDTO} from "../interfaces/class"; | import { ClassDTO, mapToClassDTO } from '../interfaces/class.js'; | ||||||
| import {getClassStudents, getClassStudentsIds} from "./class"; | import { getClassStudents } from './class.js'; | ||||||
| import {StudentDTO} from "../interfaces/student"; | import { StudentDTO } from '../interfaces/student.js'; | ||||||
| import {mapToQuestionDTO, QuestionDTO, QuestionId} from "../interfaces/question"; | import { | ||||||
|  |     mapToQuestionDTO, | ||||||
|  |     mapToQuestionId, | ||||||
|  |     QuestionDTO, | ||||||
|  |     QuestionId, | ||||||
|  | } from '../interfaces/question.js'; | ||||||
|  | import { UserService } from './users.js'; | ||||||
|  | import { mapToUser } from '../interfaces/user.js'; | ||||||
| 
 | 
 | ||||||
| 
 | export class TeacherUserService extends UserService<Teacher> { | ||||||
| async function fetchAllTeachers(): Promise<TeacherDTO[]> { |     constructor() { | ||||||
|     const teacherRepository = getTeacherRepository(); |         super(getTeacherRepository()); | ||||||
|     const teachers = await teacherRepository.find({}); |     } | ||||||
| 
 |  | ||||||
|     return teachers.map(mapToTeacherDTO); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getAllTeachers(): Promise<TeacherDTO[]> { | export class TeacherService { | ||||||
|     return await fetchAllTeachers(); |     protected teacherService = new TeacherUserService(); | ||||||
| } |     protected teacherRepository = getTeacherRepository(); | ||||||
|  |     protected classRepository = getClassRepository(); | ||||||
|  |     protected learningObjectRepository = getLearningObjectRepository(); | ||||||
|  |     protected questionRepository = getQuestionRepository(); | ||||||
| 
 | 
 | ||||||
| export async function getAllTeachersIds(): Promise<string[]> { |     async fetchClassesByTeacher(username: string): Promise<ClassDTO[]> { | ||||||
|     return await fetchAllTeachers().map((teacher) => teacher.username) |         const teacher = await this.teacherRepository.findByUsername(username); | ||||||
| } |         if (!teacher) { | ||||||
|  |             return []; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
| export async function createTeacher(teacherData: TeacherDTO): Promise<Teacher> { |         const classes = await this.classRepository.findByTeacher(teacher); | ||||||
|     const teacherRepository = getTeacherRepository(); |         return classes.map(mapToClassDTO); | ||||||
|     const newTeacher = mapToTeacher(teacherData); |  | ||||||
| 
 |  | ||||||
|     await teacherRepository.addTeacher(newTeacher); |  | ||||||
|     return newTeacher; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export async function getTeacherByUsername(username: string): Promise<TeacherDTO | null> { |  | ||||||
|     const teacherRepository = getTeacherRepository(); |  | ||||||
|     const teacher = await teacherRepository.findByUsername(username); |  | ||||||
| 
 |  | ||||||
|     return teacher ? mapToTeacherDTO(teacher) : null; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export async function deleteTeacher(username: string): Promise<TeacherDTO | null> { |  | ||||||
|     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<ClassDTO[]> { |  | ||||||
|     const teacherRepository = getTeacherRepository(); |  | ||||||
|     const classRepository = getClassRepository(); |  | ||||||
| 
 |  | ||||||
|     const teacher = await teacherRepository.findByUsername(username); |  | ||||||
|     if (!teacher) { |  | ||||||
|         return []; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const classes = await classRepository.findByTeacher(teacher); |     async getClassesByTeacher(username: string): Promise<ClassDTO[]> { | ||||||
|     return classes.map(mapToClassDTO); |         return await this.fetchClassesByTeacher(username); | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export async function getClassesByTeacher(username: string): Promise<ClassDTO[]> { |  | ||||||
|     return await fetchClassesByTeacher(username) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export async function getClassIdsByTeacher(): Promise<string[]> { |  | ||||||
|     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<StudentDTO[]> { |  | ||||||
|     return await fetchStudentsByTeacher(username); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export async function getStudentIdsByTeacher(): Promise<string[]> { |  | ||||||
|     return await fetchStudentsByTeacher(username).map((student) => student.username); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| async function fetchTeacherQuestions(username: string): Promise<QuestionDTO[]> { |  | ||||||
|     const learningObjectRepository = getLearningObjectRepository(); |  | ||||||
|     const questionRepository = getQuestionRepository(); |  | ||||||
| 
 |  | ||||||
|     const teacher = getTeacherByUsername(username); |  | ||||||
|     if (!teacher) { |  | ||||||
|         throw new Error(`Teacher with username '${username}' not found.`); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Find all learning objects that this teacher manages
 |     async getClassIdsByTeacher(username: string): Promise<string[]> { | ||||||
|     const learningObjects = await learningObjectRepository.findAllByTeacher(teacher); |         const classes = await this.fetchClassesByTeacher(username); | ||||||
|  |         return classes.map((cls) => { | ||||||
|  |             return cls.id; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     // Fetch all questions related to these learning objects
 |     async fetchStudentsByTeacher(username: string) { | ||||||
|     const questions = await questionRepository.findAllByLearningObjects(learningObjects); |         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<StudentDTO[]> { | ||||||
|  |         return await this.fetchStudentsByTeacher(username); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async getStudentIdsByTeacher(username: string): Promise<string[]> { | ||||||
|  |         const students = await this.fetchStudentsByTeacher(username); | ||||||
|  |         return students.map((student) => { | ||||||
|  |             return student.username; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fetchTeacherQuestions(username: string): Promise<QuestionDTO[]> { | ||||||
|  |         const teacherDTO = | ||||||
|  |             await this.teacherService.getUserByUsername(username); | ||||||
|  |         if (!teacherDTO) { | ||||||
|  |             throw new Error(`Teacher with username '${username}' not found.`); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const teacher = mapToUser<Teacher>(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<QuestionDTO[]> { | ||||||
|  |         return await this.fetchTeacherQuestions(username); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async getQuestionIdsByTeacher(username: string): Promise<QuestionId[]> { | ||||||
|  |         const questions = await this.fetchTeacherQuestions(username); | ||||||
|  | 
 | ||||||
|  |         return questions.map(mapToQuestionId); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| export async function getQuestionsByTeacher(username: string): Promise<QuestionDTO[]> { |  | ||||||
|     return await fetchTeacherQuestions(username); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export async function getQuestionIdsByTeacher(username: string): Promise<QuestionId[]> { |  | ||||||
|     const questions = await fetchTeacherQuestions(username); |  | ||||||
| 
 |  | ||||||
|     return questions.map((question) => ({ |  | ||||||
|         learningObjectHruid: question.learningObjectHruid, |  | ||||||
|         learningObjectLanguage: question.learningObjectLanguage, |  | ||||||
|         learningObjectVersion: question.learningObjectVersion, |  | ||||||
|         sequenceNumber: question.sequenceNumber |  | ||||||
|     })); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { UserRepository } from "../data/users/user-repository.js"; | import { UserRepository } from '../data/users/user-repository.js'; | ||||||
| import { UserDTO, mapToUser, mapToUserDTO } from "../interfaces/user.js"; | import { UserDTO, mapToUser, mapToUserDTO } from '../interfaces/user.js'; | ||||||
| import {User} from "../entities/users/user.entity.js"; | import { User } from '../entities/users/user.entity.js'; | ||||||
| 
 | 
 | ||||||
| export class UserService<T extends User> { | export class UserService<T extends User> { | ||||||
|     protected repository: UserRepository<T>; |     protected repository: UserRepository<T>; | ||||||
|  | @ -16,11 +16,13 @@ export class UserService<T extends User> { | ||||||
| 
 | 
 | ||||||
|     async getAllUserIds(): Promise<string[]> { |     async getAllUserIds(): Promise<string[]> { | ||||||
|         const users = await this.getAllUsers(); |         const users = await this.getAllUsers(); | ||||||
|         return users.map((user) => user.username); |         return users.map((user) => { | ||||||
|  |             return user.username; | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async getUserByUsername(username: string): Promise<UserDTO | null> { |     async getUserByUsername(username: string): Promise<UserDTO | null> { | ||||||
|         const user = await this.repository.findByUsername(username) |         const user = await this.repository.findByUsername(username); | ||||||
|         return user ? mapToUserDTO(user) : null; |         return user ? mapToUserDTO(user) : null; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -32,8 +34,10 @@ export class UserService<T extends User> { | ||||||
| 
 | 
 | ||||||
|     async deleteUser(username: string): Promise<UserDTO | null> { |     async deleteUser(username: string): Promise<UserDTO | null> { | ||||||
|         const user = await this.getUserByUsername(username); |         const user = await this.getUserByUsername(username); | ||||||
|         if (!user) return null; |         if (!user) { | ||||||
|         await this.repository.deleteByUsername(username) |             return null; | ||||||
|  |         } | ||||||
|  |         await this.repository.deleteByUsername(username); | ||||||
|         return mapToUserDTO(user); |         return mapToUserDTO(user); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| import fs from 'fs'; | import fs from 'fs'; | ||||||
| import path from 'path'; | import path from 'path'; | ||||||
| import yaml from 'js-yaml'; | import yaml from 'js-yaml'; | ||||||
| import { FALLBACK_LANG } from "../config.js"; | import { FALLBACK_LANG } from '../config.js'; | ||||||
| 
 | 
 | ||||||
| export function loadTranslations<T>(language: string): T { | export function loadTranslations<T>(language: string): T { | ||||||
|     try { |     try { | ||||||
|  | @ -13,7 +13,11 @@ export function loadTranslations<T>(language: string): T { | ||||||
|             `Cannot load translation for ${language}, fallen back to dutch` |             `Cannot load translation for ${language}, fallen back to dutch` | ||||||
|         ); |         ); | ||||||
|         console.error(error); |         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; |         return yaml.load(fs.readFileSync(fallbackPath, 'utf8')) as T; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Gabriellvl
						Gabriellvl