This commit is contained in:
Tibo De Peuter 2025-03-13 14:54:57 +01:00
commit 79393d6552
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
161 changed files with 9836 additions and 3751 deletions

View file

@ -3,10 +3,7 @@ import { Assignment } from '../../entities/assignments/assignment.entity.js';
import { Class } from '../../entities/classes/class.entity.js';
export class AssignmentRepository extends DwengoEntityRepository<Assignment> {
public findByClassAndId(
within: Class,
id: number
): Promise<Assignment | null> {
public findByClassAndId(within: Class, id: number): Promise<Assignment | null> {
return this.findOne({ within: within, id: id });
}
public findAllAssignmentsInClass(within: Class): Promise<Assignment[]> {

View file

@ -3,24 +3,16 @@ import { Group } from '../../entities/assignments/group.entity.js';
import { Assignment } from '../../entities/assignments/assignment.entity.js';
export class GroupRepository extends DwengoEntityRepository<Group> {
public findByAssignmentAndGroupNumber(
assignment: Assignment,
groupNumber: number
): Promise<Group | null> {
public findByAssignmentAndGroupNumber(assignment: Assignment, groupNumber: number): Promise<Group | null> {
return this.findOne({
assignment: assignment,
groupNumber: groupNumber,
});
}
public findAllGroupsForAssignment(
assignment: Assignment
): Promise<Group[]> {
public findAllGroupsForAssignment(assignment: Assignment): Promise<Group[]> {
return this.findAll({ where: { assignment: assignment } });
}
public deleteByAssignmentAndGroupNumber(
assignment: Assignment,
groupNumber: number
) {
public deleteByAssignmentAndGroupNumber(assignment: Assignment, groupNumber: number) {
return this.deleteWhere({
assignment: assignment,
groupNumber: groupNumber,

View file

@ -5,10 +5,7 @@ import { LearningObjectIdentifier } from '../../entities/content/learning-object
import { Student } from '../../entities/users/student.entity.js';
export class SubmissionRepository extends DwengoEntityRepository<Submission> {
public findSubmissionByLearningObjectAndSubmissionNumber(
loId: LearningObjectIdentifier,
submissionNumber: number
): Promise<Submission | null> {
public findSubmissionByLearningObjectAndSubmissionNumber(loId: LearningObjectIdentifier, submissionNumber: number): Promise<Submission | null> {
return this.findOne({
learningObjectHruid: loId.hruid,
learningObjectLanguage: loId.language,
@ -17,10 +14,7 @@ export class SubmissionRepository extends DwengoEntityRepository<Submission> {
});
}
public findMostRecentSubmissionForStudent(
loId: LearningObjectIdentifier,
submitter: Student
): Promise<Submission | null> {
public findMostRecentSubmissionForStudent(loId: LearningObjectIdentifier, submitter: Student): Promise<Submission | null> {
return this.findOne(
{
learningObjectHruid: loId.hruid,
@ -32,10 +26,7 @@ export class SubmissionRepository extends DwengoEntityRepository<Submission> {
);
}
public findMostRecentSubmissionForGroup(
loId: LearningObjectIdentifier,
group: Group
): Promise<Submission | null> {
public findMostRecentSubmissionForGroup(loId: LearningObjectIdentifier, group: Group): Promise<Submission | null> {
return this.findOne(
{
learningObjectHruid: loId.hruid,
@ -47,10 +38,7 @@ export class SubmissionRepository extends DwengoEntityRepository<Submission> {
);
}
public deleteSubmissionByLearningObjectAndSubmissionNumber(
loId: LearningObjectIdentifier,
submissionNumber: number
): Promise<void> {
public deleteSubmissionByLearningObjectAndSubmissionNumber(loId: LearningObjectIdentifier, submissionNumber: number): Promise<void> {
return this.deleteWhere({
learningObjectHruid: loId.hruid,
learningObjectLanguage: loId.language,

View file

@ -4,24 +4,16 @@ import { TeacherInvitation } from '../../entities/classes/teacher-invitation.ent
import { Teacher } from '../../entities/users/teacher.entity.js';
export class TeacherInvitationRepository extends DwengoEntityRepository<TeacherInvitation> {
public findAllInvitationsForClass(
clazz: Class
): Promise<TeacherInvitation[]> {
public findAllInvitationsForClass(clazz: Class): Promise<TeacherInvitation[]> {
return this.findAll({ where: { class: clazz } });
}
public findAllInvitationsBy(sender: Teacher): Promise<TeacherInvitation[]> {
return this.findAll({ where: { sender: sender } });
}
public findAllInvitationsFor(
receiver: Teacher
): Promise<TeacherInvitation[]> {
public findAllInvitationsFor(receiver: Teacher): Promise<TeacherInvitation[]> {
return this.findAll({ where: { receiver: receiver } });
}
public deleteBy(
clazz: Class,
sender: Teacher,
receiver: Teacher
): Promise<void> {
public deleteBy(clazz: Class, sender: Teacher, receiver: Teacher): Promise<void> {
return this.deleteWhere({
sender: sender,
receiver: receiver,

View file

@ -1,16 +1,37 @@
import { DwengoEntityRepository } from '../dwengo-entity-repository.js';
import { Attachment } from '../../entities/content/attachment.entity.js';
import { LearningObject } from '../../entities/content/learning-object.entity.js';
import { Language } from '../../entities/content/language';
import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier';
export class AttachmentRepository extends DwengoEntityRepository<Attachment> {
public findByLearningObjectAndNumber(
learningObject: LearningObject,
sequenceNumber: number
) {
public findByLearningObjectIdAndName(learningObjectId: LearningObjectIdentifier, name: string): Promise<Attachment | null> {
return this.findOne({
learningObject: learningObject,
sequenceNumber: sequenceNumber,
learningObject: {
hruid: learningObjectId.hruid,
language: learningObjectId.language,
version: learningObjectId.version,
},
name: name,
});
}
public findByMostRecentVersionOfLearningObjectAndName(hruid: string, language: Language, attachmentName: string): Promise<Attachment | null> {
return this.findOne(
{
learningObject: {
hruid: hruid,
language: language,
},
name: attachmentName,
},
{
orderBy: {
learningObject: {
version: 'DESC',
},
},
}
);
}
// This repository is read-only for now since creating own learning object is an extension feature.
}

View file

@ -1,16 +1,34 @@
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 { Language } from '../../entities/content/language';
export class LearningObjectRepository extends DwengoEntityRepository<LearningObject> {
public findByIdentifier(
identifier: LearningObjectIdentifier
): Promise<LearningObject | null> {
return this.findOne({
hruid: identifier.hruid,
language: identifier.language,
version: identifier.version,
});
public findByIdentifier(identifier: LearningObjectIdentifier): Promise<LearningObject | null> {
return this.findOne(
{
hruid: identifier.hruid,
language: identifier.language,
version: identifier.version,
},
{
populate: ['keywords'],
}
);
}
public findLatestByHruidAndLanguage(hruid: string, language: Language) {
return this.findOne(
{
hruid: hruid,
language: language,
},
{
populate: ['keywords'],
orderBy: {
version: 'DESC',
},
}
);
}
// This repository is read-only for now since creating own learning object is an extension feature.
}

View file

@ -3,11 +3,24 @@ import { LearningPath } from '../../entities/content/learning-path.entity.js';
import { Language } from '../../entities/content/language.js';
export class LearningPathRepository extends DwengoEntityRepository<LearningPath> {
public findByHruidAndLanguage(
hruid: string,
language: Language
): Promise<LearningPath | null> {
return this.findOne({ hruid: hruid, language: language });
public findByHruidAndLanguage(hruid: string, language: Language): Promise<LearningPath | null> {
return this.findOne({ hruid: hruid, language: language }, { populate: ['nodes', 'nodes.transitions'] });
}
/**
* Returns all learning paths which have the given language and whose title OR description contains the
* query string.
*
* @param query The query string we want to seach for in the title or description.
* @param language The language of the learning paths we want to find.
*/
public async findByQueryStringAndLanguage(query: string, language: Language): Promise<LearningPath[]> {
return this.findAll({
where: {
language: language,
$or: [{ title: { $like: `%${query}%` } }, { description: { $like: `%${query}%` } }],
},
populate: ['nodes', 'nodes.transitions'],
});
}
// This repository is read-only for now since creating own learning object is an extension feature.
}

View file

@ -1,8 +1,6 @@
import { EntityRepository, FilterQuery } from '@mikro-orm/core';
export abstract class DwengoEntityRepository<
T extends object,
> extends EntityRepository<T> {
export abstract class DwengoEntityRepository<T extends object> extends EntityRepository<T> {
public async save(entity: T) {
const em = this.getEntityManager();
em.persist(entity);

View file

@ -25,10 +25,7 @@ export class AnswerRepository extends DwengoEntityRepository<Answer> {
orderBy: { sequenceNumber: 'ASC' },
});
}
public removeAnswerByQuestionAndSequenceNumber(
question: Question,
sequenceNumber: number
): Promise<void> {
public removeAnswerByQuestionAndSequenceNumber(question: Question, sequenceNumber: number): Promise<void> {
return this.deleteWhere({
toQuestion: question,
sequenceNumber: sequenceNumber,

View file

@ -4,11 +4,7 @@ import { LearningObjectIdentifier } from '../../entities/content/learning-object
import { Student } from '../../entities/users/student.entity.js';
export class QuestionRepository extends DwengoEntityRepository<Question> {
public createQuestion(question: {
loId: LearningObjectIdentifier;
author: Student;
content: string;
}): Promise<Question> {
public createQuestion(question: { loId: LearningObjectIdentifier; author: Student; content: string }): Promise<Question> {
const questionEntity = this.create({
learningObjectHruid: question.loId.hruid,
learningObjectLanguage: question.loId.language,
@ -24,9 +20,7 @@ export class QuestionRepository extends DwengoEntityRepository<Question> {
questionEntity.content = question.content;
return this.insert(questionEntity);
}
public findAllQuestionsAboutLearningObject(
loId: LearningObjectIdentifier
): Promise<Question[]> {
public findAllQuestionsAboutLearningObject(loId: LearningObjectIdentifier): Promise<Question[]> {
return this.findAll({
where: {
learningObjectHruid: loId.hruid,
@ -38,10 +32,7 @@ export class QuestionRepository extends DwengoEntityRepository<Question> {
},
});
}
public removeQuestionByLearningObjectAndSequenceNumber(
loId: LearningObjectIdentifier,
sequenceNumber: number
): Promise<void> {
public removeQuestionByLearningObjectAndSequenceNumber(loId: LearningObjectIdentifier, sequenceNumber: number): Promise<void> {
return this.deleteWhere({
learningObjectHruid: loId.hruid,
learningObjectLanguage: loId.language,

View file

@ -1,9 +1,4 @@
import {
AnyEntity,
EntityManager,
EntityName,
EntityRepository,
} from '@mikro-orm/core';
import { AnyEntity, EntityManager, EntityName, EntityRepository } from '@mikro-orm/core';
import { forkEntityManager } from '../orm.js';
import { StudentRepository } from './users/student-repository.js';
import { Student } from '../entities/users/student.entity.js';
@ -33,6 +28,8 @@ import { LearningPath } from '../entities/content/learning-path.entity.js';
import { LearningPathRepository } from './content/learning-path-repository.js';
import { AttachmentRepository } from './content/attachment-repository.js';
import { Attachment } from '../entities/content/attachment.entity.js';
import { LearningPathNode } from '../entities/content/learning-path-node.entity.js';
import { LearningPathTransition } from '../entities/content/learning-path-transition.entity.js';
let entityManager: EntityManager | undefined;
@ -43,9 +40,7 @@ export function transactional<T>(f: () => Promise<T>) {
entityManager?.transactional(f);
}
function repositoryGetter<T extends AnyEntity, R extends EntityRepository<T>>(
entity: EntityName<T>
): () => R {
function repositoryGetter<T extends AnyEntity, R extends EntityRepository<T>>(entity: EntityName<T>): () => R {
let cachedRepo: R | undefined;
return (): R => {
if (!cachedRepo) {
@ -60,60 +55,26 @@ function repositoryGetter<T extends AnyEntity, R extends EntityRepository<T>>(
/* Users */
export const getUserRepository = repositoryGetter<User, UserRepository>(User);
export const getStudentRepository = repositoryGetter<
Student,
StudentRepository
>(Student);
export const getTeacherRepository = repositoryGetter<
Teacher,
TeacherRepository
>(Teacher);
export const getStudentRepository = repositoryGetter<Student, StudentRepository>(Student);
export const getTeacherRepository = repositoryGetter<Teacher, TeacherRepository>(Teacher);
/* Classes */
export const getClassRepository = repositoryGetter<Class, ClassRepository>(
Class
);
export const getClassJoinRequestRepository = repositoryGetter<
ClassJoinRequest,
ClassJoinRequestRepository
>(ClassJoinRequest);
export const getTeacherInvitationRepository = repositoryGetter<
TeacherInvitation,
TeacherInvitationRepository
>(TeacherInvitation);
export const getClassRepository = repositoryGetter<Class, ClassRepository>(Class);
export const getClassJoinRequestRepository = repositoryGetter<ClassJoinRequest, ClassJoinRequestRepository>(ClassJoinRequest);
export const getTeacherInvitationRepository = repositoryGetter<TeacherInvitation, TeacherInvitationRepository>(TeacherInvitation);
/* Assignments */
export const getAssignmentRepository = repositoryGetter<
Assignment,
AssignmentRepository
>(Assignment);
export const getGroupRepository = repositoryGetter<Group, GroupRepository>(
Group
);
export const getSubmissionRepository = repositoryGetter<
Submission,
SubmissionRepository
>(Submission);
export const getAssignmentRepository = repositoryGetter<Assignment, AssignmentRepository>(Assignment);
export const getGroupRepository = repositoryGetter<Group, GroupRepository>(Group);
export const getSubmissionRepository = repositoryGetter<Submission, SubmissionRepository>(Submission);
/* Questions and answers */
export const getQuestionRepository = repositoryGetter<
Question,
QuestionRepository
>(Question);
export const getAnswerRepository = repositoryGetter<Answer, AnswerRepository>(
Answer
);
export const getQuestionRepository = repositoryGetter<Question, QuestionRepository>(Question);
export const getAnswerRepository = repositoryGetter<Answer, AnswerRepository>(Answer);
/* Learning content */
export const getLearningObjectRepository = repositoryGetter<
LearningObject,
LearningObjectRepository
>(LearningObject);
export const getLearningPathRepository = repositoryGetter<
LearningPath,
LearningPathRepository
>(LearningPath);
export const getAttachmentRepository = repositoryGetter<
Attachment,
AttachmentRepository
>(Attachment);
export const getLearningObjectRepository = repositoryGetter<LearningObject, LearningObjectRepository>(LearningObject);
export const getLearningPathRepository = repositoryGetter<LearningPath, LearningPathRepository>(LearningPath);
export const getLearningPathNodeRepository = repositoryGetter(LearningPathNode);
export const getLearningPathTransitionRepository = repositoryGetter(LearningPathTransition);
export const getAttachmentRepository = repositoryGetter<Attachment, AttachmentRepository>(Attachment);

View file

@ -23,13 +23,7 @@ export const themes: Theme[] = [
},
{
title: 'art',
hruids: [
'pn_werking',
'un_artificiele_intelligentie',
'art1',
'art2',
'art3',
],
hruids: ['pn_werking', 'un_artificiele_intelligentie', 'art1', 'art2', 'art3'],
},
{
title: 'socialrobot',
@ -37,12 +31,7 @@ export const themes: Theme[] = [
},
{
title: 'agriculture',
hruids: [
'pn_werking',
'un_artificiele_intelligentie',
'agri_landbouw',
'agri_lopendeband',
],
hruids: ['pn_werking', 'un_artificiele_intelligentie', 'agri_landbouw', 'agri_lopendeband'],
},
{
title: 'wegostem',
@ -83,16 +72,7 @@ export const themes: Theme[] = [
},
{
title: 'python_programming',
hruids: [
'pn_werking',
'pn_datatypes',
'pn_operatoren',
'pn_structuren',
'pn_functies',
'art2',
'stem_insectbooks',
'un_algoenprog',
],
hruids: ['pn_werking', 'pn_datatypes', 'pn_operatoren', 'pn_structuren', 'pn_functies', 'art2', 'stem_insectbooks', 'un_algoenprog'],
},
{
title: 'stem',
@ -110,15 +90,7 @@ export const themes: Theme[] = [
},
{
title: 'care',
hruids: [
'pn_werking',
'un_artificiele_intelligentie',
'aiz1_zorg',
'aiz2_grafen',
'aiz3_unplugged',
'aiz4_eindtermen',
'aiz5_triage',
],
hruids: ['pn_werking', 'un_artificiele_intelligentie', 'aiz1_zorg', 'aiz2_grafen', 'aiz3_unplugged', 'aiz4_eindtermen', 'aiz5_triage'],
},
{
title: 'chatbot',