Merge remote-tracking branch 'origin/dev' into feature/own-learning-objects

# Conflicts:
#	backend/package.json
#	backend/src/config.ts
#	backend/src/controllers/learningObjects.ts
#	backend/src/controllers/learningPaths.ts
#	backend/src/data/content/attachment-repository.ts
#	backend/src/data/content/learning-object-repository.ts
#	backend/src/data/content/learning-path-repository.ts
#	backend/src/data/repositories.ts
#	backend/src/entities/content/learning-path.entity.ts
#	backend/src/exceptions.ts
#	backend/src/routes/learning-objects.ts
#	backend/src/services/learningObjects.ts
#	backend/src/services/learningPaths.ts
#	backend/src/util/apiHelper.ts
#	backend/src/util/envvars.ts
#	package-lock.json
This commit is contained in:
Gerald Schmittinger 2025-03-11 03:01:18 +01:00
commit cd0a3a8a7b
119 changed files with 8837 additions and 1697 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,14 @@
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) {
let em = this.getEntityManager();
const em = this.getEntityManager();
em.persist(entity);
await em.flush();
}
public async deleteWhere(query: FilterQuery<T>) {
let toDelete = await this.findOne(query);
let em = this.getEntityManager();
const toDelete = await this.findOne(query);
const em = this.getEntityManager();
if (toDelete) {
em.remove(toDelete);
await em.flush();

View file

@ -4,12 +4,8 @@ import { Question } from '../../entities/questions/question.entity.js';
import { Teacher } from '../../entities/users/teacher.entity.js';
export class AnswerRepository extends DwengoEntityRepository<Answer> {
public createAnswer(answer: {
toQuestion: Question;
author: Teacher;
content: string;
}): Promise<Answer> {
let answerEntity = new Answer();
public createAnswer(answer: { toQuestion: Question; author: Teacher; content: string }): Promise<Answer> {
const answerEntity = new Answer();
answerEntity.toQuestion = answer.toQuestion;
answerEntity.author = answer.author;
answerEntity.content = answer.content;
@ -21,10 +17,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,12 +4,8 @@ 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> {
let questionEntity = new Question();
public createQuestion(question: { loId: LearningObjectIdentifier; author: Student; content: string }): Promise<Question> {
const questionEntity = new Question();
questionEntity.learningObjectHruid = question.loId.hruid;
questionEntity.learningObjectLanguage = question.loId.language;
questionEntity.learningObjectVersion = question.loId.version;
@ -17,9 +13,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,
@ -31,10 +25,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';
@ -45,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) {
@ -62,49 +55,22 @@ 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
>(TeacherInvitationRepository);
export const getClassRepository = repositoryGetter<Class, ClassRepository>(Class);
export const getClassJoinRequestRepository = repositoryGetter<ClassJoinRequest, ClassJoinRequestRepository>(ClassJoinRequest);
export const getTeacherInvitationRepository = repositoryGetter<TeacherInvitation, TeacherInvitationRepository>(TeacherInvitationRepository);
/* 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<

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',