fix: Problemen met PUT op leerpaden en verschillende kleinere problemen
This commit is contained in:
parent
2db5d77296
commit
96821c40ab
21 changed files with 205 additions and 103 deletions
|
@ -68,13 +68,14 @@ export async function getLearningPaths(req: Request, res: Response): Promise<voi
|
|||
function postOrPutLearningPath(isPut: boolean): (req: AuthenticatedRequest, res: Response) => Promise<void> {
|
||||
return async (req, res) => {
|
||||
const path: LearningPath = req.body;
|
||||
const teacher = await getTeacher(req.auth!.username);
|
||||
if (isPut) {
|
||||
if (req.params.hruid !== path.hruid || req.params.language !== path.language) {
|
||||
throw new BadRequestException("id_not_matching_query_params");
|
||||
}
|
||||
await learningPathService.deleteLearningPath({hruid: path.hruid, language: path.language as Language});
|
||||
}
|
||||
const teacher = await getTeacher(req.auth!.username);
|
||||
res.json(await learningPathService.createNewLearningPath(path, [teacher], isPut));
|
||||
res.json(await learningPathService.createNewLearningPath(path, [teacher]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,10 @@ import { EntityAlreadyExistsException } from '../../exceptions/entity-already-ex
|
|||
|
||||
export class LearningPathRepository extends DwengoEntityRepository<LearningPath> {
|
||||
public async findByHruidAndLanguage(hruid: string, language: Language): Promise<LearningPath | null> {
|
||||
return this.findOne({ hruid: hruid, language: language }, { populate: ['nodes', 'nodes.transitions'] });
|
||||
return this.findOne(
|
||||
{ hruid: hruid, language: language },
|
||||
{ populate: ['nodes', 'nodes.transitions', 'admins'] }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,7 +27,7 @@ export class LearningPathRepository extends DwengoEntityRepository<LearningPath>
|
|||
language: language,
|
||||
$or: [{ title: { $like: `%${query}%` } }, { description: { $like: `%${query}%` } }],
|
||||
},
|
||||
populate: ['nodes', 'nodes.transitions'],
|
||||
populate: ['nodes', 'nodes.transitions', 'admins'],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -37,7 +40,8 @@ export class LearningPathRepository extends DwengoEntityRepository<LearningPath>
|
|||
admins: {
|
||||
username: adminUsername
|
||||
}
|
||||
}
|
||||
},
|
||||
populate: ['nodes', 'nodes.transitions', 'admins']
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property, Rel } from '@mikro-orm/core';
|
||||
import { Cascade, Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property, Rel } from '@mikro-orm/core';
|
||||
import { LearningPath } from './learning-path.entity.js';
|
||||
import { LearningPathTransition } from './learning-path-transition.entity.js';
|
||||
import { Language } from '@dwengo-1/common/util/language';
|
||||
|
@ -26,7 +26,7 @@ export class LearningPathNode {
|
|||
@Property({ type: 'bool' })
|
||||
startNode!: boolean;
|
||||
|
||||
@OneToMany({ entity: () => LearningPathTransition, mappedBy: 'node' })
|
||||
@OneToMany({ entity: () => LearningPathTransition, mappedBy: 'node', cascade: [Cascade.ALL] })
|
||||
transitions!: Collection<LearningPathTransition>;
|
||||
|
||||
@Property({ length: 3 })
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Collection, Entity, Enum, ManyToMany, OneToMany, PrimaryKey, Property } from '@mikro-orm/core';
|
||||
import { Cascade, Collection, Entity, Enum, ManyToMany, OneToMany, PrimaryKey, Property } from '@mikro-orm/core';
|
||||
import { Teacher } from '../users/teacher.entity.js';
|
||||
import { LearningPathRepository } from '../../data/content/learning-path-repository.js';
|
||||
import { LearningPathNode } from './learning-path-node.entity.js';
|
||||
|
@ -24,6 +24,6 @@ export class LearningPath {
|
|||
@Property({ type: 'blob', nullable: true })
|
||||
image: Buffer | null = null;
|
||||
|
||||
@OneToMany({ entity: () => LearningPathNode, mappedBy: 'learningPath' })
|
||||
@OneToMany({ entity: () => LearningPathNode, mappedBy: 'learningPath', cascade: [Cascade.ALL] })
|
||||
nodes: Collection<LearningPathNode> = new Collection<LearningPathNode>(this);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Language } from "@dwengo-1/common/util/language";
|
||||
import learningPathService from "../../../services/learning-paths/learning-path-service";
|
||||
import { authorize } from "../auth";
|
||||
import { AuthenticatedRequest } from "../authenticated-request";
|
||||
|
@ -5,8 +6,8 @@ import { AuthenticationInfo } from "../authentication-info";
|
|||
|
||||
export const onlyAdminsForLearningPath = authorize(async (auth: AuthenticationInfo, req: AuthenticatedRequest) => {
|
||||
const adminsForLearningPath = await learningPathService.getAdmins({
|
||||
hruid: req.body.hruid,
|
||||
language: req.body.language
|
||||
hruid: req.params.hruid,
|
||||
language: req.params.language as Language
|
||||
});
|
||||
return adminsForLearningPath && adminsForLearningPath.includes(auth.username);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import express from 'express';
|
||||
import { deleteLearningPath, getLearningPaths, postLearningPath, putLearningPath } from '../controllers/learning-paths.js';
|
||||
import { teachersOnly } from '../middleware/auth/auth.js';
|
||||
import { onlyAdminsForLearningObject } from '../middleware/auth/checks/learning-object-auth-checks.js';
|
||||
import { onlyAdminsForLearningPath } from '../middleware/auth/checks/learning-path-auth-checks.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
@ -27,7 +27,7 @@ const router = express.Router();
|
|||
router.get('/', getLearningPaths);
|
||||
router.post('/', teachersOnly, postLearningPath)
|
||||
|
||||
router.put('/:hruid/:language', onlyAdminsForLearningObject, putLearningPath);
|
||||
router.delete('/:hruid/:language', onlyAdminsForLearningObject, deleteLearningPath);
|
||||
router.put('/:hruid/:language', onlyAdminsForLearningPath, putLearningPath);
|
||||
router.delete('/:hruid/:language', onlyAdminsForLearningPath, deleteLearningPath);
|
||||
|
||||
export default router;
|
||||
|
|
|
@ -72,6 +72,8 @@ const learningObjectService = {
|
|||
learningObject.hruid = getEnvVar(envVars.UserContentPrefix) + learningObject.hruid;
|
||||
}
|
||||
|
||||
await learningObjectRepository.getEntityManager().flush();
|
||||
|
||||
// Lookup the admin teachers based on their usernames and add them to the admins of the learning object.
|
||||
const teacherRepo = getTeacherRepository();
|
||||
const adminTeachers = await Promise.all(
|
||||
|
|
|
@ -16,6 +16,9 @@ import { Language } from '@dwengo-1/common/util/language';
|
|||
import { Group } from '../../entities/assignments/group.entity';
|
||||
import { Collection } from '@mikro-orm/core';
|
||||
import { v4 } from 'uuid';
|
||||
import { getLogger } from '../../logging/initalize.js';
|
||||
|
||||
const logger = getLogger();
|
||||
|
||||
/**
|
||||
* Fetches the corresponding learning object for each of the nodes and creates a map that maps each node to its
|
||||
|
@ -38,8 +41,13 @@ async function getLearningObjectsForNodes(nodes: Collection<LearningPathNode>):
|
|||
)
|
||||
)
|
||||
);
|
||||
if (Array.from(nullableNodesToLearningObjects.values()).some((it) => it === null)) {
|
||||
throw new Error('At least one of the learning objects on this path could not be found.');
|
||||
|
||||
// Ignore all learning objects that cannot be found such that the rest of the learning path keeps working.
|
||||
for (const [key, value] of nullableNodesToLearningObjects) {
|
||||
if (value === null) {
|
||||
logger.warn(`Learning object ${key.learningObjectHruid}/${key.language}/${key.version} not found!`);
|
||||
nullableNodesToLearningObjects.delete(key);
|
||||
}
|
||||
}
|
||||
return nullableNodesToLearningObjects as Map<LearningPathNode, FilteredLearningObject>;
|
||||
}
|
||||
|
@ -102,7 +110,14 @@ async function convertNode(
|
|||
!personalizedFor || // If we do not want a personalized learning path, keep all transitions
|
||||
isTransitionPossible(trans, optionalJsonStringToObject(lastSubmission?.content)) // Otherwise remove all transitions that aren't possible.
|
||||
)
|
||||
.map((trans, i) => convertTransition(trans, i, nodesToLearningObjects));
|
||||
.map((trans, i) => {
|
||||
try {
|
||||
return convertTransition(trans, i, nodesToLearningObjects)
|
||||
} catch (_: unknown) {
|
||||
logger.error(`Transition could not be resolved: ${JSON.stringify(trans)}`);
|
||||
return undefined; // Do not crash on invalid transitions, just ignore them so the rest of the learning path keeps working.
|
||||
}
|
||||
}).filter(it => it);
|
||||
return {
|
||||
_id: learningObject.uuid,
|
||||
language: learningObject.language,
|
||||
|
|
|
@ -130,13 +130,12 @@ const learningPathService = {
|
|||
* Add a new learning path to the database.
|
||||
* @param dto Learning path DTO from which the learning path will be created.
|
||||
* @param admins Teachers who should become an admin of the learning path.
|
||||
* @param allowReplace If this is set to true and there is already a learning path with the same identifier, it is replaced.
|
||||
* @returns the created learning path.
|
||||
*/
|
||||
async createNewLearningPath(dto: LearningPath, admins: TeacherDTO[], allowReplace = false): Promise<LearningPathEntity> {
|
||||
async createNewLearningPath(dto: LearningPath, admins: TeacherDTO[]): Promise<LearningPathEntity> {
|
||||
const repo = getLearningPathRepository();
|
||||
const path = mapToLearningPath(dto, admins);
|
||||
await repo.save(path, { preventOverwrite: allowReplace });
|
||||
await repo.save(path, { preventOverwrite: true });
|
||||
return path;
|
||||
},
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue