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