diff --git a/backend/src/controllers/assignments.ts b/backend/src/controllers/assignments.ts index c66e8799..c8dd1ec8 100644 --- a/backend/src/controllers/assignments.ts +++ b/backend/src/controllers/assignments.ts @@ -37,7 +37,7 @@ export async function createAssignmentHandler(req: Request, re return; } - res.status(201).json({ assignment: assignment }); + res.status(201).json(assignment); } export async function getAssignmentHandler(req: Request, res: Response): Promise { @@ -62,13 +62,14 @@ export async function getAssignmentHandler(req: Request, res: export async function getAssignmentsSubmissionsHandler(req: Request, res: Response): Promise { const classid = req.params.classid; const assignmentNumber = Number(req.params.id); + const full = req.query.full === 'true'; if (isNaN(assignmentNumber)) { res.status(400).json({ error: 'Assignment id must be a number' }); return; } - const submissions = await getAssignmentsSubmissions(classid, assignmentNumber); + const submissions = await getAssignmentsSubmissions(classid, assignmentNumber, full); res.json({ submissions: submissions, diff --git a/backend/src/controllers/classes.ts b/backend/src/controllers/classes.ts index fbbd6737..7526f7c4 100644 --- a/backend/src/controllers/classes.ts +++ b/backend/src/controllers/classes.ts @@ -1,7 +1,6 @@ import { Request, Response } from 'express'; -import { createClass, getAllClasses, getClass, getClassStudents, getClassStudentsIds, getClassTeacherInvitations } from '../services/class.js'; +import { createClass, getAllClasses, getClass, getClassStudents, getClassStudentsIds, getClassTeacherInvitations } from '../services/classes.js'; import { ClassDTO } from '../interfaces/class.js'; -import { getLogger } from '../logging/initalize.js'; export async function getAllClassesHandler(req: Request, res: Response): Promise { const full = req.query.full === 'true'; @@ -29,30 +28,19 @@ export async function createClassHandler(req: Request, res: Response): Promise { - try { - const classId = req.params.id; - const cls = await getClass(classId); + const classId = req.params.id; + const cls = await getClass(classId); - if (!cls) { - res.status(404).json({ error: 'Class not found' }); - return; - } - 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) { - getLogger().error('Error fetching learning objects:', error); - res.status(500).json({ error: 'Internal server error' }); + if (!cls) { + res.status(404).json({ error: 'Class not found' }); + return; } + + res.json(cls); } export async function getClassStudentsHandler(req: Request, res: Response): Promise { @@ -68,7 +56,7 @@ export async function getClassStudentsHandler(req: Request, res: Response): Prom export async function getTeacherInvitationsHandler(req: Request, res: Response): Promise { const classId = req.params.id; - const full = req.query.full === 'true'; // TODO: not implemented yet + const full = req.query.full === 'true'; const invitations = await getClassTeacherInvitations(classId, full); diff --git a/backend/src/controllers/groups.ts b/backend/src/controllers/groups.ts index 7b1f5a1e..7de3e114 100644 --- a/backend/src/controllers/groups.ts +++ b/backend/src/controllers/groups.ts @@ -28,6 +28,11 @@ export async function getGroupHandler(req: Request, res: Response): const group = await getGroup(classId, assignmentId, groupId, full); + if (!group) { + res.status(404).json({ error: 'Group not found' }); + return; + } + res.json(group); } @@ -66,12 +71,12 @@ export async function createGroupHandler(req: Request, res: Response): Promise { const classId = req.params.classid; - // Const full = req.query.full === 'true'; + const full = req.query.full === 'true'; const assignmentId = Number(req.params.assignmentid); @@ -87,7 +92,7 @@ export async function getGroupSubmissionsHandler(req: Request, res: Response): P return; } - const submissions = await getGroupSubmissions(classId, assignmentId, groupId); + const submissions = await getGroupSubmissions(classId, assignmentId, groupId, full); res.json({ submissions: submissions, diff --git a/backend/src/controllers/learning-objects.ts b/backend/src/controllers/learning-objects.ts index ab850d6a..6117cc75 100644 --- a/backend/src/controllers/learning-objects.ts +++ b/backend/src/controllers/learning-objects.ts @@ -40,7 +40,7 @@ export async function getAllLearningObjects(req: Request, res: Response): Promis learningObjects = await learningObjectService.getLearningObjectIdsFromPath(learningPathId); } - res.json(learningObjects); + res.json({ learningObjects: learningObjects }); } export async function getLearningObject(req: Request, res: Response): Promise { diff --git a/backend/src/controllers/questions.ts b/backend/src/controllers/questions.ts index 1b3dc850..6735c305 100644 --- a/backend/src/controllers/questions.ts +++ b/backend/src/controllers/questions.ts @@ -48,7 +48,7 @@ export async function getAllQuestionsHandler(req: Request, res: Response): Promi if (!questions) { res.status(404).json({ error: `Questions not found.` }); } else { - res.json(questions); + res.json({ questions: questions }); } } @@ -76,12 +76,12 @@ export async function getQuestionAnswersHandler(req: Request, res: Response): Pr return; } - const answers = getAnswersByQuestion(questionId, full); + const answers = await getAnswersByQuestion(questionId, full); if (!answers) { - res.status(404).json({ error: `Questions not found.` }); + res.status(404).json({ error: `Questions not found` }); } else { - res.json(answers); + res.json({ answers: answers }); } } @@ -96,7 +96,7 @@ export async function createQuestionHandler(req: Request, res: Response): Promis const question = await createQuestion(questionDTO); if (!question) { - res.status(400).json({ error: 'Could not add question' }); + res.status(400).json({ error: 'Could not create question' }); } else { res.json(question); } diff --git a/backend/src/controllers/students.ts b/backend/src/controllers/students.ts index d71571e5..f3fbed5e 100644 --- a/backend/src/controllers/students.ts +++ b/backend/src/controllers/students.ts @@ -10,21 +10,20 @@ import { getStudentSubmissions, } from '../services/students.js'; import { StudentDTO } from '../interfaces/student.js'; -import { getLogger } from '../logging/initalize.js'; // TODO: accept arguments (full, ...) // TODO: endpoints export async function getAllStudentsHandler(req: Request, res: Response): Promise { const full = req.query.full === 'true'; - const students: StudentDTO[] | string[] = full ? await getAllStudents() : await getAllStudents(); + const students = await getAllStudents(full); if (!students) { res.status(404).json({ error: `Student not found.` }); return; } - res.status(201).json(students); + res.json({ students: students }); } export async function getStudentHandler(req: Request, res: Response): Promise { @@ -44,7 +43,7 @@ export async function getStudentHandler(req: Request, res: Response): Promise { @@ -58,6 +57,14 @@ export async function createStudentHandler(req: Request, res: Response): Promise } const newUser = await createStudent(userData); + + if (!newUser) { + res.status(500).json({ + error: 'Something went wrong while creating student' + }); + return; + } + res.status(201).json(newUser); } @@ -81,25 +88,12 @@ export async function deleteStudentHandler(req: Request, res: Response): Promise } export async function getStudentClassesHandler(req: Request, res: Response): Promise { - try { - const full = req.query.full === 'true'; - const username = req.params.id; + const full = req.query.full === 'true'; + const username = req.params.id; - const classes = await getStudentClasses(username, full); + const classes = await getStudentClasses(username, full); - res.json({ - classes: classes, - endpoints: { - self: `${req.baseUrl}/${req.params.id}`, - classes: `${req.baseUrl}/${req.params.id}/invitations`, - questions: `${req.baseUrl}/${req.params.id}/assignments`, - students: `${req.baseUrl}/${req.params.id}/students`, - }, - }); - } catch (error) { - getLogger().error('Error fetching learning objects:', error); - res.status(500).json({ error: 'Internal server error' }); - } + res.json({ classes: classes }); } // TODO @@ -130,8 +124,9 @@ export async function getStudentGroupsHandler(req: Request, res: Response): Prom export async function getStudentSubmissionsHandler(req: Request, res: Response): Promise { const username = req.params.id; + const full = req.query.full === 'true'; - const submissions = await getStudentSubmissions(username); + const submissions = await getStudentSubmissions(username, full); res.json({ submissions: submissions, diff --git a/backend/src/controllers/submissions.ts b/backend/src/controllers/submissions.ts index 16836a34..67c1d3a9 100644 --- a/backend/src/controllers/submissions.ts +++ b/backend/src/controllers/submissions.ts @@ -36,10 +36,11 @@ export async function createSubmissionHandler(req: Request, res: Response): Prom const submission = await createSubmission(submissionDTO); if (!submission) { - res.status(404).json({ error: 'Submission not added' }); - } else { - res.json(submission); + res.status(400).json({ error: 'Failed to create submission' }); + return; } + + res.json(submission); } export async function deleteSubmissionHandler(req: Request, res: Response): Promise { @@ -53,7 +54,8 @@ export async function deleteSubmissionHandler(req: Request, res: Response): Prom if (!submission) { res.status(404).json({ error: 'Submission not found' }); - } else { - res.json(submission); + return; } + + res.json(submission); } diff --git a/backend/src/controllers/teachers.ts b/backend/src/controllers/teachers.ts index 4bf7eb53..06316681 100644 --- a/backend/src/controllers/teachers.ts +++ b/backend/src/controllers/teachers.ts @@ -4,30 +4,23 @@ import { deleteTeacher, getAllTeachers, getClassesByTeacher, - getClassIdsByTeacher, - getQuestionIdsByTeacher, getQuestionsByTeacher, - getStudentIdsByTeacher, getStudentsByTeacher, getTeacher, } from '../services/teachers.js'; -import { ClassDTO } from '../interfaces/class.js'; -import { StudentDTO } from '../interfaces/student.js'; -import { QuestionDTO, QuestionId } from '../interfaces/question.js'; import { TeacherDTO } from '../interfaces/teacher.js'; -import { getLogger } from '../logging/initalize.js'; export async function getAllTeachersHandler(req: Request, res: Response): Promise { const full = req.query.full === 'true'; - const teachers: TeacherDTO[] | string[] = full ? await getAllTeachers() : await getAllTeachers(); + const teachers = await getAllTeachers(full); if (!teachers) { res.status(404).json({ error: `Teacher not found.` }); return; } - res.status(201).json(teachers); + res.json({ teachers: teachers }); } export async function getTeacherHandler(req: Request, res: Response): Promise { @@ -42,12 +35,12 @@ export async function getTeacherHandler(req: Request, res: Response): Promise { @@ -61,6 +54,12 @@ export async function createTeacherHandler(req: Request, res: Response): Promise } const newUser = await createTeacher(userData); + + if (!newUser) { + res.status(400).json({ error: 'Failed to create teacher' }); + return; + } + res.status(201).json(newUser); } @@ -75,7 +74,7 @@ export async function deleteTeacherHandler(req: Request, res: Response): Promise const deletedUser = await deleteTeacher(username); if (!deletedUser) { res.status(404).json({ - error: `User with username '${username}' not found.`, + error: `User '${username}' not found.`, }); return; } @@ -84,58 +83,58 @@ export async function deleteTeacherHandler(req: Request, res: Response): Promise } export async function getTeacherClassHandler(req: Request, res: Response): Promise { - try { - const username = req.params.username; - const full = req.query.full === 'true'; + const username = req.params.username; + const full = req.query.full === 'true'; - if (!username) { - res.status(400).json({ error: 'Missing required field: username' }); - return; - } - - const classes: ClassDTO[] | string[] = full ? await getClassesByTeacher(username) : await getClassIdsByTeacher(username); - - res.status(201).json(classes); - } catch (error) { - getLogger().error('Error fetching classes by teacher:', error); - res.status(500).json({ error: 'Internal server error' }); + if (!username) { + res.status(400).json({ error: 'Missing required field: username' }); + return; } + + const classes = await getClassesByTeacher(username, full); + + if (!classes) { + res.status(404).json({ error: 'Teacher not found' }); + return; + } + + res.json({ classes: classes }); } export async function getTeacherStudentHandler(req: Request, res: Response): Promise { - try { - const username = req.params.username; - const full = req.query.full === 'true'; + const username = req.params.username; + const full = req.query.full === 'true'; - if (!username) { - res.status(400).json({ error: 'Missing required field: username' }); - return; - } - - const students: StudentDTO[] | string[] = full ? await getStudentsByTeacher(username) : await getStudentIdsByTeacher(username); - - res.status(201).json(students); - } catch (error) { - getLogger().error('Error fetching students by teacher:', error); - res.status(500).json({ error: 'Internal server error' }); + if (!username) { + res.status(400).json({ error: 'Missing required field: username' }); + return; } + + const students = await getStudentsByTeacher(username, full); + + if (!students) { + res.status(404).json({ error: 'Teacher not found' }); + return; + } + + res.json({ students: students }); } export async function getTeacherQuestionHandler(req: Request, res: Response): Promise { - try { - const username = req.params.username; - const full = req.query.full === 'true'; + const username = req.params.username; + const full = req.query.full === 'true'; - if (!username) { - res.status(400).json({ error: 'Missing required field: username' }); - return; - } - - const questions: QuestionDTO[] | QuestionId[] = full ? await getQuestionsByTeacher(username) : await getQuestionIdsByTeacher(username); - - res.status(201).json(questions); - } catch (error) { - getLogger().error('Error fetching questions by teacher:', error); - res.status(500).json({ error: 'Internal server error' }); + if (!username) { + res.status(400).json({ error: 'Missing required field: username' }); + return; } + + const questions = await getQuestionsByTeacher(username, full); + + if (!questions) { + res.status(404).json({ error: 'Teacher not found' }); + return; + } + + res.json({ questions: questions }); } diff --git a/backend/src/controllers/users.ts b/backend/src/controllers/users.ts deleted file mode 100644 index 255db93a..00000000 --- a/backend/src/controllers/users.ts +++ /dev/null @@ -1,92 +0,0 @@ -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 { getLogger } from '../logging/initalize.js'; - -export async function getAllUsersHandler(req: Request, res: Response, service: UserService): Promise { - try { - const full = req.query.full === 'true'; - - const users: UserDTO[] | string[] = full ? await service.getAllUsers() : await service.getAllUserIds(); - - if (!users) { - res.status(404).json({ error: `Users not found.` }); - return; - } - - res.status(201).json(users); - } catch (error) { - getLogger().error('❌ Error fetching users:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} - -export async function getUserHandler(req: Request, res: Response, service: UserService): Promise { - try { - const username = req.params.username; - - if (!username) { - res.status(400).json({ error: 'Missing required field: username' }); - return; - } - - const user = await service.getUserByUsername(username); - - if (!user) { - res.status(404).json({ - error: `User with username '${username}' not found.`, - }); - return; - } - - res.status(201).json(user); - } catch (error) { - getLogger().error('❌ Error fetching users:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} - -export async function createUserHandler(req: Request, res: Response, service: UserService, userClass: new () => T): Promise { - try { - getLogger().debug({ 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', - }); - return; - } - - const newUser = await service.createUser(userData, userClass); - res.status(201).json(newUser); - } catch (error) { - getLogger().error('❌ Error creating user:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} - -export async function deleteUserHandler(req: Request, res: Response, service: UserService): Promise { - try { - const username = req.params.username; - - if (!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.`, - }); - return; - } - - res.status(200).json(deletedUser); - } catch (error) { - getLogger().error('❌ Error deleting user:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} diff --git a/backend/src/entities/classes/class-join-request.entity.ts b/backend/src/entities/classes/class-join-request.entity.ts index bdef1f52..64a597bb 100644 --- a/backend/src/entities/classes/class-join-request.entity.ts +++ b/backend/src/entities/classes/class-join-request.entity.ts @@ -3,6 +3,12 @@ import { Student } from '../users/student.entity.js'; import { Class } from './class.entity.js'; import { ClassJoinRequestRepository } from '../../data/classes/class-join-request-repository.js'; +export enum ClassJoinRequestStatus { + Open = 'open', + Accepted = 'accepted', + Declined = 'declined', +} + @Entity({ repository: () => ClassJoinRequestRepository, }) @@ -21,10 +27,4 @@ export class ClassJoinRequest { @Enum(() => ClassJoinRequestStatus) status!: ClassJoinRequestStatus; -} - -export enum ClassJoinRequestStatus { - Open = 'open', - Accepted = 'accepted', - Declined = 'declined', -} +} \ No newline at end of file diff --git a/backend/src/interfaces/class.ts b/backend/src/interfaces/class.ts index 371e3cae..ea1d4901 100644 --- a/backend/src/interfaces/class.ts +++ b/backend/src/interfaces/class.ts @@ -9,12 +9,6 @@ export interface ClassDTO { teachers: string[]; students: string[]; joinRequests: string[]; - endpoints?: { - self: string; - invitations: string; - assignments: string; - students: string; - }; } export function mapToClassDTO(cls: Class): ClassDTO { diff --git a/backend/src/interfaces/submission.ts b/backend/src/interfaces/submission.ts index 522d48cf..98cc4f22 100644 --- a/backend/src/interfaces/submission.ts +++ b/backend/src/interfaces/submission.ts @@ -2,11 +2,10 @@ import { Submission } from '../entities/assignments/submission.entity.js'; import { Language } from '../entities/content/language.js'; import { GroupDTO, mapToGroupDTO } from './group.js'; import { mapToStudent, mapToStudentDTO, StudentDTO } from './student.js'; +import { LearningObjectIdentifier } from './learning-content.js'; export interface SubmissionDTO { - learningObjectHruid: string; - learningObjectLanguage: Language; - learningObjectVersion: number; + learningObjectIdentifier: LearningObjectIdentifier; submissionNumber?: number; submitter: StudentDTO; @@ -15,11 +14,21 @@ export interface SubmissionDTO { content: string; } +export interface SubmissionDTOId { + learningObjectHruid: string; + learningObjectLanguage: Language; + learningObjectVersion: number; + + submissionNumber?: number; +} + export function mapToSubmissionDTO(submission: Submission): SubmissionDTO { return { - learningObjectHruid: submission.learningObjectHruid, - learningObjectLanguage: submission.learningObjectLanguage, - learningObjectVersion: submission.learningObjectVersion, + learningObjectIdentifier: { + hruid: submission.learningObjectHruid, + language: submission.learningObjectLanguage, + version: submission.learningObjectVersion, + }, submissionNumber: submission.submissionNumber, submitter: mapToStudentDTO(submission.submitter), @@ -29,11 +38,21 @@ export function mapToSubmissionDTO(submission: Submission): SubmissionDTO { }; } +export function mapToSubmissionDTOId(submission: Submission): SubmissionDTOId { + return { + learningObjectHruid: submission.learningObjectHruid, + learningObjectLanguage: submission.learningObjectLanguage, + learningObjectVersion: submission.learningObjectVersion, + + submissionNumber: submission.submissionNumber, + }; +} + export function mapToSubmission(submissionDTO: SubmissionDTO): Submission { const submission = new Submission(); - submission.learningObjectHruid = submissionDTO.learningObjectHruid; - submission.learningObjectLanguage = submissionDTO.learningObjectLanguage; - submission.learningObjectVersion = submissionDTO.learningObjectVersion; + submission.learningObjectHruid = submissionDTO.learningObjectIdentifier.hruid; + submission.learningObjectLanguage = submissionDTO.learningObjectIdentifier.language; + submission.learningObjectVersion = submissionDTO.learningObjectIdentifier.version!; // Submission.submissionNumber = submissionDTO.submissionNumber; submission.submitter = mapToStudent(submissionDTO.submitter); // Submission.submissionTime = submissionDTO.time; diff --git a/backend/src/routes/router.ts b/backend/src/routes/router.ts index 639857a7..99d4312c 100644 --- a/backend/src/routes/router.ts +++ b/backend/src/routes/router.ts @@ -1,10 +1,7 @@ import { Response, Router } from 'express'; import studentRouter from './students.js'; -import groupRouter from './groups.js'; -import assignmentRouter from './assignments.js'; -import submissionRouter from './submissions.js'; +import teacherRouter from './teachers.js'; import classRouter from './classes.js'; -import questionRouter from './questions.js'; import authRouter from './auth.js'; import themeRoutes from './themes.js'; import learningPathRoutes from './learning-paths.js'; @@ -22,11 +19,8 @@ router.get('/', (_, res: Response) => { }); router.use('/student', studentRouter /* #swagger.tags = ['Student'] */); -router.use('/group', groupRouter /* #swagger.tags = ['Group'] */); -router.use('/assignment', assignmentRouter /* #swagger.tags = ['Assignment'] */); -router.use('/submission', submissionRouter /* #swagger.tags = ['Submission'] */); +router.use('/teacher', teacherRouter /* #swagger.tags = ['Teacher'] */); router.use('/class', classRouter /* #swagger.tags = ['Class'] */); -router.use('/question', questionRouter /* #swagger.tags = ['Question'] */); router.use('/auth', authRouter /* #swagger.tags = ['Auth'] */); router.use('/theme', themeRoutes /* #swagger.tags = ['Theme'] */); router.use('/learningPath', learningPathRoutes /* #swagger.tags = ['Learning Path'] */); diff --git a/backend/src/services/assignments.ts b/backend/src/services/assignments.ts index 7ac52844..22c5ce9e 100644 --- a/backend/src/services/assignments.ts +++ b/backend/src/services/assignments.ts @@ -1,7 +1,7 @@ import { getAssignmentRepository, getClassRepository, getGroupRepository, getSubmissionRepository } from '../data/repositories.js'; -import { Assignment } from '../entities/assignments/assignment.entity.js'; import { AssignmentDTO, mapToAssignment, mapToAssignmentDTO, mapToAssignmentDTOId } from '../interfaces/assignment.js'; -import { mapToSubmissionDTO, SubmissionDTO } from '../interfaces/submission.js'; +import { mapToSubmissionDTO, mapToSubmissionDTOId, SubmissionDTO, SubmissionDTOId } from '../interfaces/submission.js'; +import { getLogger } from '../logging/initalize.js'; export async function getAllAssignments(classid: string, full: boolean): Promise { const classRepository = getClassRepository(); @@ -21,7 +21,7 @@ export async function getAllAssignments(classid: string, full: boolean): Promise return assignments.map(mapToAssignmentDTOId); } -export async function createAssignment(classid: string, assignmentData: AssignmentDTO): Promise { +export async function createAssignment(classid: string, assignmentData: AssignmentDTO): Promise { const classRepository = getClassRepository(); const cls = await classRepository.findById(classid); @@ -36,8 +36,9 @@ export async function createAssignment(classid: string, assignmentData: Assignme const newAssignment = assignmentRepository.create(assignment); await assignmentRepository.save(newAssignment); - return newAssignment; - } catch (_) { + return mapToAssignmentDTO(newAssignment); + } catch (e) { + getLogger().error(e); return null; } } @@ -60,7 +61,11 @@ export async function getAssignment(classid: string, id: number): Promise { +export async function getAssignmentsSubmissions( + classid: string, + assignmentNumber: number, + full: boolean +): Promise { const classRepository = getClassRepository(); const cls = await classRepository.findById(classid); @@ -81,5 +86,9 @@ export async function getAssignmentsSubmissions(classid: string, assignmentNumbe const submissionRepository = getSubmissionRepository(); const submissions = (await Promise.all(groups.map(async (group) => submissionRepository.findAllSubmissionsForGroup(group)))).flat(); - return submissions.map(mapToSubmissionDTO); + if (full) { + return submissions.map(mapToSubmissionDTO); + } + + return submissions.map(mapToSubmissionDTOId); } diff --git a/backend/src/services/class.ts b/backend/src/services/classes.ts similarity index 95% rename from backend/src/services/class.ts rename to backend/src/services/classes.ts index 52d841f4..dc3ac8a0 100644 --- a/backend/src/services/class.ts +++ b/backend/src/services/classes.ts @@ -1,5 +1,4 @@ import { getClassRepository, getStudentRepository, getTeacherInvitationRepository, getTeacherRepository } from '../data/repositories.js'; -import { Class } from '../entities/classes/class.entity.js'; import { ClassDTO, mapToClassDTO } from '../interfaces/class.js'; import { mapToStudentDTO, StudentDTO } from '../interfaces/student.js'; import { mapToTeacherInvitationDTO, mapToTeacherInvitationDTOIds, TeacherInvitationDTO } from '../interfaces/teacher-invitation.js'; @@ -21,7 +20,7 @@ export async function getAllClasses(full: boolean): Promise cls.classId!); } -export async function createClass(classData: ClassDTO): Promise { +export async function createClass(classData: ClassDTO): Promise { const teacherRepository = getTeacherRepository(); const teacherUsernames = classData.teachers || []; const teachers = (await Promise.all(teacherUsernames.map(async (id) => teacherRepository.findByUsername(id)))).filter( @@ -34,8 +33,6 @@ export async function createClass(classData: ClassDTO): Promise { (student) => student !== null ); - //Const cls = mapToClass(classData, teachers, students); - const classRepository = getClassRepository(); try { @@ -46,7 +43,7 @@ export async function createClass(classData: ClassDTO): Promise { }); await classRepository.save(newClass); - return newClass; + return mapToClassDTO(newClass); } catch (e) { logger.error(e); return null; diff --git a/backend/src/services/groups.ts b/backend/src/services/groups.ts index 30be8b86..16895e0a 100644 --- a/backend/src/services/groups.ts +++ b/backend/src/services/groups.ts @@ -7,7 +7,7 @@ import { } from '../data/repositories.js'; import { Group } from '../entities/assignments/group.entity.js'; import { GroupDTO, mapToGroupDTO, mapToGroupDTOId } from '../interfaces/group.js'; -import { mapToSubmissionDTO, SubmissionDTO } from '../interfaces/submission.js'; +import { mapToSubmissionDTO, mapToSubmissionDTOId, SubmissionDTO, SubmissionDTOId } from '../interfaces/submission.js'; import { getLogger } from '../logging/initalize.js'; export async function getGroup(classId: string, assignmentNumber: number, groupNumber: number, full: boolean): Promise { @@ -104,7 +104,12 @@ export async function getAllGroups(classId: string, assignmentNumber: number, fu return groups.map(mapToGroupDTOId); } -export async function getGroupSubmissions(classId: string, assignmentNumber: number, groupNumber: number): Promise { +export async function getGroupSubmissions( + classId: string, + assignmentNumber: number, + groupNumber: number, + full: boolean +): Promise { const classRepository = getClassRepository(); const cls = await classRepository.findById(classId); @@ -129,5 +134,9 @@ export async function getGroupSubmissions(classId: string, assignmentNumber: num const submissionRepository = getSubmissionRepository(); const submissions = await submissionRepository.findAllSubmissionsForGroup(group); - return submissions.map(mapToSubmissionDTO); + if (full) { + return submissions.map(mapToSubmissionDTO); + } + + return submissions.map(mapToSubmissionDTOId); } diff --git a/backend/src/services/learning-objects.ts b/backend/src/services/learning-objects.ts index 5298e5b3..43af1aca 100644 --- a/backend/src/services/learning-objects.ts +++ b/backend/src/services/learning-objects.ts @@ -46,6 +46,13 @@ export async function getLearningObjectById(hruid: string, language: string): Pr return filterData(metadata, htmlUrl); } +/** + * Generic function to fetch learning paths + */ +function fetchLearningPaths(_arg0: string[], _language: string, _arg2: string): LearningPathResponse | PromiseLike { + throw new Error('Function not implemented.'); +} + /** * Generic function to fetch learning objects (full data or just HRUIDs) */ @@ -86,6 +93,3 @@ export async function getLearningObjectsFromPath(hruid: string, language: string export async function getLearningObjectIdsFromPath(hruid: string, language: string): Promise { return (await fetchLearningObjects(hruid, false, language)) as string[]; } -function fetchLearningPaths(_arg0: string[], _language: string, _arg2: string): LearningPathResponse | PromiseLike { - throw new Error('Function not implemented.'); -} diff --git a/backend/src/services/questions.ts b/backend/src/services/questions.ts index bb42aabd..ac1095bf 100644 --- a/backend/src/services/questions.ts +++ b/backend/src/services/questions.ts @@ -86,7 +86,7 @@ export async function createQuestion(questionDTO: QuestionDTO): Promise { +export async function deleteQuestion(questionId: QuestionId): Promise { const questionRepository = getQuestionRepository(); const question = await fetchQuestion(questionId); @@ -101,5 +101,5 @@ export async function deleteQuestion(questionId: QuestionId): Promise { +export async function getAllStudents(full: boolean): Promise { const studentRepository = getStudentRepository(); - const users = await studentRepository.findAll(); - return users.map(mapToStudentDTO); -} + const students = await studentRepository.findAll(); -export async function getAllStudentIds(): Promise { - const users = await getAllStudents(); - return users.map((user) => user.username); + if (full) { + return students.map(mapToStudentDTO); + } + + return students.map((student) => student.username); } export async function getStudent(username: string): Promise { @@ -86,9 +91,7 @@ export async function getStudentAssignments(username: string, full: boolean): Pr const classRepository = getClassRepository(); const classes = await classRepository.findByStudent(student); - const assignments = (await Promise.all(classes.map(async (cls) => await getAllAssignments(cls.classId!, full)))).flat(); - - return assignments; + return (await Promise.all(classes.map(async (cls) => await getAllAssignments(cls.classId!, full)))).flat(); } export async function getStudentGroups(username: string, full: boolean): Promise { @@ -109,7 +112,7 @@ export async function getStudentGroups(username: string, full: boolean): Promise return groups.map(mapToGroupDTOId); } -export async function getStudentSubmissions(username: string): Promise { +export async function getStudentSubmissions(username: string, full: boolean): Promise { const studentRepository = getStudentRepository(); const student = await studentRepository.findByUsername(username); @@ -120,5 +123,9 @@ export async function getStudentSubmissions(username: string): Promise { +export async function createSubmission(submissionDTO: SubmissionDTO): Promise { const submissionRepository = getSubmissionRepository(); const submission = mapToSubmission(submissionDTO); @@ -33,7 +32,7 @@ export async function createSubmission(submissionDTO: SubmissionDTO): Promise { +export async function getAllTeachers(full: boolean): Promise { const teacherRepository = getTeacherRepository(); - const users = await teacherRepository.findAll(); - return users.map(mapToTeacherDTO); -} + const teachers = await teacherRepository.findAll(); -export async function getAllTeacherIds(): Promise { - const users = await getAllTeachers(); - return users.map((user) => user.username); + if (full) { + return teachers.map(mapToTeacherDTO); + } + + return teachers.map((teacher) => teacher.username); } export async function getTeacher(username: string): Promise { @@ -56,11 +61,11 @@ export async function deleteTeacher(username: string): Promise { +export async function fetchClassesByTeacher(username: string): Promise { const teacherRepository = getTeacherRepository(); const teacher = await teacherRepository.findByUsername(username); if (!teacher) { - return []; + return null; } const classRepository = getClassRepository(); @@ -68,35 +73,49 @@ export async function fetchClassesByTeacher(username: string): Promise { - return await fetchClassesByTeacher(username); -} - -export async function getClassIdsByTeacher(username: string): Promise { +export async function getClassesByTeacher(username: string, full: boolean): Promise { const classes = await fetchClassesByTeacher(username); + + if (!classes) { + return null; + } + + if (full) { + return classes; + } + return classes.map((cls) => cls.id); } -export async function fetchStudentsByTeacher(username: string): Promise { - const classes = await getClassIdsByTeacher(username); +export async function fetchStudentsByTeacher(username: string): Promise { + const classes = (await getClassesByTeacher(username, false)) as string[]; + + if (!classes) { + return null; + } return (await Promise.all(classes.map(async (id) => getClassStudents(id)))).flat(); } -export async function getStudentsByTeacher(username: string): Promise { - return await fetchStudentsByTeacher(username); -} - -export async function getStudentIdsByTeacher(username: string): Promise { +export async function getStudentsByTeacher(username: string, full: boolean): Promise { const students = await fetchStudentsByTeacher(username); + + if (!students) { + return null; + } + + if (full) { + return students; + } + return students.map((student) => student.username); } -export async function fetchTeacherQuestions(username: string): Promise { +export async function fetchTeacherQuestions(username: string): Promise { const teacherRepository = getTeacherRepository(); const teacher = await teacherRepository.findByUsername(username); if (!teacher) { - throw new Error(`Teacher with username '${username}' not found.`); + return null; } // Find all learning objects that this teacher manages @@ -110,12 +129,16 @@ export async function fetchTeacherQuestions(username: string): Promise { - return await fetchTeacherQuestions(username); -} - -export async function getQuestionIdsByTeacher(username: string): Promise { +export async function getQuestionsByTeacher(username: string, full: boolean): Promise { const questions = await fetchTeacherQuestions(username); + if (!questions) { + return null; + } + + if (full) { + return questions; + } + return questions.map(mapToQuestionId); } diff --git a/backend/src/services/users.ts b/backend/src/services/users.ts deleted file mode 100644 index dd5a733b..00000000 --- a/backend/src/services/users.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { UserRepository } from '../data/users/user-repository.js'; -import { UserDTO, mapToUser, mapToUserDTO } from '../interfaces/user.js'; -import { User } from '../entities/users/user.entity.js'; - -export class UserService { - protected repository: UserRepository; - - constructor(repository: UserRepository) { - this.repository = repository; - } - - async getAllUsers(): Promise { - const users = await this.repository.findAll(); - return users.map(mapToUserDTO); - } - - async getAllUserIds(): Promise { - const users = await this.getAllUsers(); - return users.map((user) => user.username); - } - - async getUserByUsername(username: string): Promise { - const user = await this.repository.findByUsername(username); - return user ? mapToUserDTO(user) : null; - } - - async createUser(userData: UserDTO, userClass: new () => T): Promise { - const newUser = mapToUser(userData, new userClass()); - await this.repository.save(newUser); - return newUser; - } - - async deleteUser(username: string): Promise { - const user = await this.getUserByUsername(username); - if (!user) { - return null; - } - await this.repository.deleteByUsername(username); - return mapToUserDTO(user); - } -}