Merge branch 'fix/mark-as-completed-bij-leerobjecten-werkt-niet-altijd-#253' into fix/progress-bar
Merge fix/mark-as-completed-bij-leerobjecten-werkt-niet-altijd-#253 into fix/progress-bar
This commit is contained in:
		
						commit
						779ebb28ee
					
				
					 9 changed files with 415 additions and 10 deletions
				
			
		|  | @ -62,6 +62,11 @@ export async function getAllSubmissionsHandler(req: Request, res: Response): Pro | |||
| 
 | ||||
| // TODO: gerald moet nog dingen toevoegen aan de databank voor dat dit gefinaliseerd kan worden
 | ||||
| export async function createSubmissionHandler(req: Request, res: Response): Promise<void> { | ||||
|     const submitter = req.body.submitter; | ||||
|     const usernameSubmitter = req.body.submitter.username; | ||||
|     const group = req.body.group; | ||||
|     requireFields({ group, submitter, usernameSubmitter }); | ||||
| 
 | ||||
|     const submissionDTO = req.body as SubmissionDTO; | ||||
|     const submission = await createSubmission(submissionDTO); | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ import { getLearningPathRepository } from '../../data/repositories.js'; | |||
| import learningObjectService from '../learning-objects/learning-object-service.js'; | ||||
| import { LearningPathNode } from '../../entities/content/learning-path-node.entity.js'; | ||||
| import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity.js'; | ||||
| import { getLastSubmissionForGroup, isTransitionPossible } from './learning-path-personalization-util.js'; | ||||
| import { getLastSubmissionForGroup, idFromLearningPathNode, isTransitionPossible } from './learning-path-personalization-util.js'; | ||||
| import { | ||||
|     FilteredLearningObject, | ||||
|     LearningObjectNode, | ||||
|  | @ -97,7 +97,7 @@ async function convertNode( | |||
|     personalizedFor: Group | undefined, | ||||
|     nodesToLearningObjects: Map<LearningPathNode, FilteredLearningObject> | ||||
| ): Promise<LearningObjectNode> { | ||||
|     const lastSubmission = personalizedFor ? await getLastSubmissionForGroup(node, personalizedFor) : null; | ||||
|     const lastSubmission = personalizedFor ? await getLastSubmissionForGroup(idFromLearningPathNode(node), personalizedFor) : null; | ||||
|     const transitions = node.transitions | ||||
|         .filter( | ||||
|             (trans) => | ||||
|  |  | |||
|  | @ -3,11 +3,33 @@ import { DWENGO_API_BASE } from '../../config.js'; | |||
| import { LearningPathProvider } from './learning-path-provider.js'; | ||||
| import { getLogger, Logger } from '../../logging/initalize.js'; | ||||
| import { LearningPath, LearningPathResponse } from '@dwengo-1/common/interfaces/learning-content'; | ||||
| import { Group } from '../../entities/assignments/group.entity.js'; | ||||
| import { getLastSubmissionForGroup, idFromLearningObjectNode } from './learning-path-personalization-util.js'; | ||||
| 
 | ||||
| const logger: Logger = getLogger(); | ||||
| 
 | ||||
| /** | ||||
|  * Adds progress information to the learning path. Modifies the learning path in-place. | ||||
|  * @param learningPath The learning path to add progress to. | ||||
|  * @param personalizedFor The group whose progress should be shown. | ||||
|  * @returns the modified learning path. | ||||
|  */ | ||||
| async function addProgressToLearningPath(learningPath: LearningPath, personalizedFor: Group): Promise<LearningPath> { | ||||
|     await Promise.all( | ||||
|         learningPath.nodes.map(async (node) => { | ||||
|             const lastSubmission = personalizedFor ? await getLastSubmissionForGroup(idFromLearningObjectNode(node), personalizedFor) : null; | ||||
|             node.done = Boolean(lastSubmission); | ||||
|         }) | ||||
|     ); | ||||
| 
 | ||||
|     learningPath.num_nodes = learningPath.nodes.length; | ||||
|     learningPath.num_nodes_left = learningPath.nodes.filter((it) => !it.done).length; | ||||
| 
 | ||||
|     return learningPath; | ||||
| } | ||||
| 
 | ||||
| const dwengoApiLearningPathProvider: LearningPathProvider = { | ||||
|     async fetchLearningPaths(hruids: string[], language: string, source: string): Promise<LearningPathResponse> { | ||||
|     async fetchLearningPaths(hruids: string[], language: string, source: string, personalizedFor: Group): Promise<LearningPathResponse> { | ||||
|         if (hruids.length === 0) { | ||||
|             return { | ||||
|                 success: false, | ||||
|  | @ -32,17 +54,24 @@ const dwengoApiLearningPathProvider: LearningPathProvider = { | |||
|             }; | ||||
|         } | ||||
| 
 | ||||
|         await Promise.all(learningPaths?.map(async (it) => addProgressToLearningPath(it, personalizedFor))); | ||||
| 
 | ||||
|         return { | ||||
|             success: true, | ||||
|             source, | ||||
|             data: learningPaths, | ||||
|         }; | ||||
|     }, | ||||
|     async searchLearningPaths(query: string, language: string): Promise<LearningPath[]> { | ||||
|     async searchLearningPaths(query: string, language: string, personalizedFor: Group): Promise<LearningPath[]> { | ||||
|         const apiUrl = `${DWENGO_API_BASE}/learningPath/search`; | ||||
|         const params = { all: query, language }; | ||||
| 
 | ||||
|         const searchResults = await fetchWithLogging<LearningPath[]>(apiUrl, `Search learning paths with query "${query}"`, { params }); | ||||
| 
 | ||||
|         if (searchResults) { | ||||
|             await Promise.all(searchResults?.map(async (it) => addProgressToLearningPath(it, personalizedFor))); | ||||
|         } | ||||
| 
 | ||||
|         return searchResults ?? []; | ||||
|     }, | ||||
| }; | ||||
|  |  | |||
|  | @ -5,18 +5,36 @@ import { getSubmissionRepository } from '../../data/repositories.js'; | |||
| import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier.js'; | ||||
| import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity.js'; | ||||
| import { JSONPath } from 'jsonpath-plus'; | ||||
| import { LearningObjectNode } from '@dwengo-1/common/interfaces/learning-content'; | ||||
| 
 | ||||
| /** | ||||
|  * Returns the last submission for the learning object associated with the given node and for the group | ||||
|  */ | ||||
| export async function getLastSubmissionForGroup(node: LearningPathNode, pathFor: Group): Promise<Submission | null> { | ||||
| export async function getLastSubmissionForGroup(learningObjectId: LearningObjectIdentifier, pathFor: Group): Promise<Submission | null> { | ||||
|     const submissionRepo = getSubmissionRepository(); | ||||
|     const learningObjectId: LearningObjectIdentifier = { | ||||
|     return await submissionRepo.findMostRecentSubmissionForGroup(learningObjectId, pathFor); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Creates a LearningObjectIdentifier describing the specified node. | ||||
|  */ | ||||
| export function idFromLearningObjectNode(node: LearningObjectNode): LearningObjectIdentifier { | ||||
|     return { | ||||
|         hruid: node.learningobject_hruid, | ||||
|         language: node.language, | ||||
|         version: node.version, | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Creates a LearningObjectIdentifier describing the specified node. | ||||
|  */ | ||||
| export function idFromLearningPathNode(node: LearningPathNode): LearningObjectIdentifier { | ||||
|     return { | ||||
|         hruid: node.learningObjectHruid, | ||||
|         language: node.language, | ||||
|         version: node.version, | ||||
|     }; | ||||
|     return await submissionRepo.findMostRecentSubmissionForGroup(learningObjectId, pathFor); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  |  | |||
|  | @ -42,7 +42,7 @@ export async function fetchStudent(username: string): Promise<Student> { | |||
|     const user = await studentRepository.findByUsername(username); | ||||
| 
 | ||||
|     if (!user) { | ||||
|         throw new NotFoundException('Student with username not found'); | ||||
|         throw new NotFoundException(`Student with username ${username} not found`); | ||||
|     } | ||||
| 
 | ||||
|     return user; | ||||
|  |  | |||
		Reference in a new issue
	
	 Joyelle Ndagijimana
						Joyelle Ndagijimana