Merge pull request #214 from SELab-2/fix/213-assignment-and-group-questions
fix: Assignments en group questions
This commit is contained in:
		
						commit
						21022efb1e
					
				
					 6 changed files with 79 additions and 42 deletions
				
			
		|  | @ -4,6 +4,7 @@ import { | ||||||
|     deleteAssignment, |     deleteAssignment, | ||||||
|     getAllAssignments, |     getAllAssignments, | ||||||
|     getAssignment, |     getAssignment, | ||||||
|  |     getAssignmentsQuestions, | ||||||
|     getAssignmentsSubmissions, |     getAssignmentsSubmissions, | ||||||
|     putAssignment, |     putAssignment, | ||||||
| } from '../services/assignments.js'; | } from '../services/assignments.js'; | ||||||
|  | @ -13,6 +14,19 @@ import { BadRequestException } from '../exceptions/bad-request-exception.js'; | ||||||
| import { Assignment } from '../entities/assignments/assignment.entity.js'; | import { Assignment } from '../entities/assignments/assignment.entity.js'; | ||||||
| import { EntityDTO } from '@mikro-orm/core'; | import { EntityDTO } from '@mikro-orm/core'; | ||||||
| 
 | 
 | ||||||
|  | function getAssignmentParams(req: Request): { classid: string; assignmentNumber: number; full: boolean } { | ||||||
|  |     const classid = req.params.classid; | ||||||
|  |     const assignmentNumber = Number(req.params.id); | ||||||
|  |     const full = req.query.full === 'true'; | ||||||
|  |     requireFields({ assignmentNumber, classid }); | ||||||
|  | 
 | ||||||
|  |     if (isNaN(assignmentNumber)) { | ||||||
|  |         throw new BadRequestException('Assignment id should be a number'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return { classid, assignmentNumber, full }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export async function getAllAssignmentsHandler(req: Request, res: Response): Promise<void> { | export async function getAllAssignmentsHandler(req: Request, res: Response): Promise<void> { | ||||||
|     const classId = req.params.classid; |     const classId = req.params.classid; | ||||||
|     const full = req.query.full === 'true'; |     const full = req.query.full === 'true'; | ||||||
|  | @ -38,58 +52,42 @@ export async function createAssignmentHandler(req: Request, res: Response): Prom | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getAssignmentHandler(req: Request, res: Response): Promise<void> { | export async function getAssignmentHandler(req: Request, res: Response): Promise<void> { | ||||||
|     const id = Number(req.params.id); |     const { classid, assignmentNumber } = getAssignmentParams(req); | ||||||
|     const classid = req.params.classid; |  | ||||||
|     requireFields({ id, classid }); |  | ||||||
| 
 | 
 | ||||||
|     if (isNaN(id)) { |     const assignment = await getAssignment(classid, assignmentNumber); | ||||||
|         throw new BadRequestException('Assignment id should be a number'); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const assignment = await getAssignment(classid, id); |  | ||||||
| 
 | 
 | ||||||
|     res.json({ assignment }); |     res.json({ assignment }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function putAssignmentHandler(req: Request, res: Response): Promise<void> { | export async function putAssignmentHandler(req: Request, res: Response): Promise<void> { | ||||||
|     const id = Number(req.params.id); |     const { classid, assignmentNumber } = getAssignmentParams(req); | ||||||
|     const classid = req.params.classid; |  | ||||||
|     requireFields({ id, classid }); |  | ||||||
| 
 |  | ||||||
|     if (isNaN(id)) { |  | ||||||
|         throw new BadRequestException('Assignment id should be a number'); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     const assignmentData = req.body as Partial<EntityDTO<Assignment>>; |     const assignmentData = req.body as Partial<EntityDTO<Assignment>>; | ||||||
|     const assignment = await putAssignment(classid, id, assignmentData); |     const assignment = await putAssignment(classid, assignmentNumber, assignmentData); | ||||||
| 
 | 
 | ||||||
|     res.json({ assignment }); |     res.json({ assignment }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function deleteAssignmentHandler(req: Request, res: Response): Promise<void> { | export async function deleteAssignmentHandler(req: Request, res: Response): Promise<void> { | ||||||
|     const id = Number(req.params.id); |     const { classid, assignmentNumber } = getAssignmentParams(req); | ||||||
|     const classid = req.params.classid; |  | ||||||
|     requireFields({ id, classid }); |  | ||||||
| 
 | 
 | ||||||
|     if (isNaN(id)) { |     const assignment = await deleteAssignment(classid, assignmentNumber); | ||||||
|         throw new BadRequestException('Assignment id should be a number'); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     const assignment = await deleteAssignment(classid, id); |  | ||||||
|     res.json({ assignment }); |     res.json({ assignment }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getAssignmentsSubmissionsHandler(req: Request, res: Response): Promise<void> { | export async function getAssignmentsSubmissionsHandler(req: Request, res: Response): Promise<void> { | ||||||
|     const classid = req.params.classid; |     const { classid, assignmentNumber, full } = getAssignmentParams(req); | ||||||
|     const assignmentNumber = Number(req.params.id); |  | ||||||
|     const full = req.query.full === 'true'; |  | ||||||
|     requireFields({ assignmentNumber, classid }); |  | ||||||
| 
 |  | ||||||
|     if (isNaN(assignmentNumber)) { |  | ||||||
|         throw new BadRequestException('Assignment id should be a number'); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     const submissions = await getAssignmentsSubmissions(classid, assignmentNumber, full); |     const submissions = await getAssignmentsSubmissions(classid, assignmentNumber, full); | ||||||
| 
 | 
 | ||||||
|     res.json({ submissions }); |     res.json({ submissions }); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export async function getAssignmentQuestionsHandler(req: Request, res: Response): Promise<void> { | ||||||
|  |     const { classid, assignmentNumber, full } = getAssignmentParams(req); | ||||||
|  | 
 | ||||||
|  |     const questions = await getAssignmentsQuestions(classid, assignmentNumber, full); | ||||||
|  | 
 | ||||||
|  |     res.json({ questions }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { Request, Response } from 'express'; | import { Request, Response } from 'express'; | ||||||
| import { createGroup, deleteGroup, getAllGroups, getGroup, getGroupSubmissions, putGroup } from '../services/groups.js'; | import { createGroup, deleteGroup, getAllGroups, getGroup, getGroupQuestions, getGroupSubmissions, putGroup } from '../services/groups.js'; | ||||||
| import { GroupDTO } from '@dwengo-1/common/interfaces/group'; | import { GroupDTO } from '@dwengo-1/common/interfaces/group'; | ||||||
| import { requireFields } from './error-helper.js'; | import { requireFields } from './error-helper.js'; | ||||||
| import { BadRequestException } from '../exceptions/bad-request-exception.js'; | import { BadRequestException } from '../exceptions/bad-request-exception.js'; | ||||||
|  | @ -84,7 +84,7 @@ export async function createGroupHandler(req: Request, res: Response): Promise<v | ||||||
|     res.status(201).json({ group }); |     res.status(201).json({ group }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function getGroupSubmissionsHandler(req: Request, res: Response): Promise<void> { | function getGroupParams(req: Request): { classId: string; assignmentId: number; groupId: number; full: boolean } { | ||||||
|     const classId = req.params.classid; |     const classId = req.params.classid; | ||||||
|     const assignmentId = Number(req.params.assignmentid); |     const assignmentId = Number(req.params.assignmentid); | ||||||
|     const groupId = Number(req.params.groupid); |     const groupId = Number(req.params.groupid); | ||||||
|  | @ -100,7 +100,21 @@ export async function getGroupSubmissionsHandler(req: Request, res: Response): P | ||||||
|         throw new BadRequestException('Group id must be a number'); |         throw new BadRequestException('Group id must be a number'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     return { classId, assignmentId, groupId, full }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export async function getGroupSubmissionsHandler(req: Request, res: Response): Promise<void> { | ||||||
|  |     const { classId, assignmentId, groupId, full } = getGroupParams(req); | ||||||
|  | 
 | ||||||
|     const submissions = await getGroupSubmissions(classId, assignmentId, groupId, full); |     const submissions = await getGroupSubmissions(classId, assignmentId, groupId, full); | ||||||
| 
 | 
 | ||||||
|     res.json({ submissions }); |     res.json({ submissions }); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export async function getGroupQuestionsHandler(req: Request, res: Response): Promise<void> { | ||||||
|  |     const { classId, assignmentId, groupId, full } = getGroupParams(req); | ||||||
|  | 
 | ||||||
|  |     const questions = await getGroupQuestions(classId, assignmentId, groupId, full); | ||||||
|  | 
 | ||||||
|  |     res.json({ questions }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -62,9 +62,7 @@ export class QuestionRepository extends DwengoEntityRepository<Question> { | ||||||
| 
 | 
 | ||||||
|     public async findAllByAssignment(assignment: Assignment): Promise<Question[]> { |     public async findAllByAssignment(assignment: Assignment): Promise<Question[]> { | ||||||
|         return this.find({ |         return this.find({ | ||||||
|             inGroup: { |             inGroup: assignment.groups.getItems(), | ||||||
|                 $contained: assignment.groups, |  | ||||||
|             }, |  | ||||||
|             learningObjectHruid: assignment.learningPathHruid, |             learningObjectHruid: assignment.learningPathHruid, | ||||||
|             learningObjectLanguage: assignment.learningPathLanguage, |             learningObjectLanguage: assignment.learningPathLanguage, | ||||||
|         }); |         }); | ||||||
|  | @ -77,6 +75,13 @@ export class QuestionRepository extends DwengoEntityRepository<Question> { | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public async findAllByGroup(inGroup: Group): Promise<Question[]> { | ||||||
|  |         return this.findAll({ | ||||||
|  |             where: { inGroup }, | ||||||
|  |             orderBy: { timestamp: 'DESC' }, | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Looks up all questions for the given learning object which were asked as part of the given assignment. |      * Looks up all questions for the given learning object which were asked as part of the given assignment. | ||||||
|      * When forStudentUsername is set, only the questions within the given user's group are shown. |      * When forStudentUsername is set, only the questions within the given user's group are shown. | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ import { | ||||||
|     deleteAssignmentHandler, |     deleteAssignmentHandler, | ||||||
|     getAllAssignmentsHandler, |     getAllAssignmentsHandler, | ||||||
|     getAssignmentHandler, |     getAssignmentHandler, | ||||||
|  |     getAssignmentQuestionsHandler, | ||||||
|     getAssignmentsSubmissionsHandler, |     getAssignmentsSubmissionsHandler, | ||||||
|     putAssignmentHandler, |     putAssignmentHandler, | ||||||
| } from '../controllers/assignments.js'; | } from '../controllers/assignments.js'; | ||||||
|  | @ -23,11 +24,7 @@ router.delete('/:id', deleteAssignmentHandler); | ||||||
| 
 | 
 | ||||||
| router.get('/:id/submissions', getAssignmentsSubmissionsHandler); | router.get('/:id/submissions', getAssignmentsSubmissionsHandler); | ||||||
| 
 | 
 | ||||||
| router.get('/:id/questions', (_req, res) => { | router.get('/:id/questions', getAssignmentQuestionsHandler); | ||||||
|     res.json({ |  | ||||||
|         questions: ['0'], |  | ||||||
|     }); |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| router.use('/:assignmentid/groups', groupRouter); | router.use('/:assignmentid/groups', groupRouter); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ import { | ||||||
|     deleteGroupHandler, |     deleteGroupHandler, | ||||||
|     getAllGroupsHandler, |     getAllGroupsHandler, | ||||||
|     getGroupHandler, |     getGroupHandler, | ||||||
|  |     getGroupQuestionsHandler, | ||||||
|     getGroupSubmissionsHandler, |     getGroupSubmissionsHandler, | ||||||
|     putGroupHandler, |     putGroupHandler, | ||||||
| } from '../controllers/groups.js'; | } from '../controllers/groups.js'; | ||||||
|  | @ -23,4 +24,6 @@ router.delete('/:groupid', deleteGroupHandler); | ||||||
| 
 | 
 | ||||||
| router.get('/:groupid/submissions', getGroupSubmissionsHandler); | router.get('/:groupid/submissions', getGroupSubmissionsHandler); | ||||||
| 
 | 
 | ||||||
|  | router.get('/:groupid/questions', getGroupQuestionsHandler); | ||||||
|  | 
 | ||||||
| export default router; | export default router; | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { EntityDTO } from '@mikro-orm/core'; | import { EntityDTO } from '@mikro-orm/core'; | ||||||
| import { getGroupRepository, getSubmissionRepository } from '../data/repositories.js'; | import { getGroupRepository, getQuestionRepository, getSubmissionRepository } from '../data/repositories.js'; | ||||||
| import { Group } from '../entities/assignments/group.entity.js'; | import { Group } from '../entities/assignments/group.entity.js'; | ||||||
| import { mapToGroupDTO, mapToGroupDTOId } from '../interfaces/group.js'; | import { mapToGroupDTO, mapToGroupDTOId } from '../interfaces/group.js'; | ||||||
| import { mapToSubmissionDTO, mapToSubmissionDTOId } from '../interfaces/submission.js'; | import { mapToSubmissionDTO, mapToSubmissionDTOId } from '../interfaces/submission.js'; | ||||||
|  | @ -12,6 +12,8 @@ import { fetchClass } from './classes.js'; | ||||||
| import { BadRequestException } from '../exceptions/bad-request-exception.js'; | import { BadRequestException } from '../exceptions/bad-request-exception.js'; | ||||||
| import { Student } from '../entities/users/student.entity.js'; | import { Student } from '../entities/users/student.entity.js'; | ||||||
| import { Class } from '../entities/classes/class.entity.js'; | import { Class } from '../entities/classes/class.entity.js'; | ||||||
|  | import { QuestionDTO, QuestionId } from '@dwengo-1/common/interfaces/question'; | ||||||
|  | import { mapToQuestionDTO, mapToQuestionDTOId } from '../interfaces/question.js'; | ||||||
| 
 | 
 | ||||||
| async function assertMembersInClass(members: Student[], cls: Class): Promise<void> { | async function assertMembersInClass(members: Student[], cls: Class): Promise<void> { | ||||||
|     if (!members.every((student) => cls.students.contains(student))) { |     if (!members.every((student) => cls.students.contains(student))) { | ||||||
|  | @ -121,3 +123,21 @@ export async function getGroupSubmissions( | ||||||
| 
 | 
 | ||||||
|     return submissions.map(mapToSubmissionDTOId); |     return submissions.map(mapToSubmissionDTOId); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export async function getGroupQuestions( | ||||||
|  |     classId: string, | ||||||
|  |     assignmentNumber: number, | ||||||
|  |     groupNumber: number, | ||||||
|  |     full: boolean | ||||||
|  | ): Promise<QuestionDTO[] | QuestionId[]> { | ||||||
|  |     const group = await fetchGroup(classId, assignmentNumber, groupNumber); | ||||||
|  | 
 | ||||||
|  |     const questionRepository = getQuestionRepository(); | ||||||
|  |     const questions = await questionRepository.findAllByGroup(group); | ||||||
|  | 
 | ||||||
|  |     if (full) { | ||||||
|  |         return questions.map(mapToQuestionDTO); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return questions.map(mapToQuestionDTOId); | ||||||
|  | } | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Adriaan J.
						Adriaan J.