fix(backend): Formatting + .env.development.example

npm run format uitgevoerd, .env.development.example toegevoegd.
This commit is contained in:
Gerald Schmittinger 2025-02-26 22:03:53 +01:00
parent 4e883a1a18
commit 48c8ce7c57
36 changed files with 499 additions and 331 deletions

View file

@ -0,0 +1,6 @@
PORT=3000
DWENGO_DB_HOST=localhost
DWENGO_DB_PORT=5431
DWENGO_DB_USERNAME=postgres
DWENGO_DB_PASSWORD=postgres
DWENGO_DB_UPDATE=true

View file

@ -1,15 +1,18 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {Assignment} from "../../entities/assignments/assignment.entity";
import {Class} from "../../entities/classes/class.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { Assignment } from '../../entities/assignments/assignment.entity';
import { Class } from '../../entities/classes/class.entity';
export class AssignmentRepository extends DwengoEntityRepository<Assignment> {
public findByClassAndId(within: Class, id: number): Promise<Assignment | null> {
return this.findOne({within: within, id: id});
public findByClassAndId(
within: Class,
id: number
): Promise<Assignment | null> {
return this.findOne({ within: within, id: id });
}
public findAllAssignmentsInClass(within: Class): Promise<Assignment[]> {
return this.findAll({where: {within: within}});
return this.findAll({ where: { within: within } });
}
public deleteByClassAndId(within: Class, id: number): Promise<void> {
return this.deleteWhere({within: within, id: id});
return this.deleteWhere({ within: within, id: id });
}
}

View file

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

View file

@ -1,43 +1,61 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {Group} from "../../entities/assignments/group.entity";
import {Submission} from "../../entities/assignments/submission.entity";
import {LearningObjectIdentifier} from "../../entities/content/learning-object-identifier";
import {Student} from "../../entities/users/student.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { Group } from '../../entities/assignments/group.entity';
import { Submission } from '../../entities/assignments/submission.entity';
import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier';
import { Student } from '../../entities/users/student.entity';
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,
learningObjectVersion: loId.version,
submissionNumber: submissionNumber
submissionNumber: submissionNumber,
});
}
public findMostRecentSubmissionForStudent(loId: LearningObjectIdentifier, submitter: Student): Promise<Submission | null> {
return this.findOne({
learningObjectHruid: loId.hruid,
learningObjectLanguage: loId.language,
learningObjectVersion: loId.version,
submitter: submitter,
}, {orderBy: {submissionNumber: "DESC"}})
public findMostRecentSubmissionForStudent(
loId: LearningObjectIdentifier,
submitter: Student
): Promise<Submission | null> {
return this.findOne(
{
learningObjectHruid: loId.hruid,
learningObjectLanguage: loId.language,
learningObjectVersion: loId.version,
submitter: submitter,
},
{ orderBy: { submissionNumber: 'DESC' } }
);
}
public findMostRecentSubmissionForGroup(loId: LearningObjectIdentifier, group: Group): Promise<Submission | null> {
return this.findOne({
learningObjectHruid: loId.hruid,
learningObjectLanguage: loId.language,
learningObjectVersion: loId.version,
onBehalfOf: group,
}, {orderBy: {submissionNumber: "DESC"}})
public findMostRecentSubmissionForGroup(
loId: LearningObjectIdentifier,
group: Group
): Promise<Submission | null> {
return this.findOne(
{
learningObjectHruid: loId.hruid,
learningObjectLanguage: loId.language,
learningObjectVersion: loId.version,
onBehalfOf: group,
},
{ orderBy: { submissionNumber: 'DESC' } }
);
}
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,
learningObjectVersion: loId.version,
submissionNumber: submissionNumber
})
submissionNumber: submissionNumber,
});
}
}

View file

@ -1,16 +1,16 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {Class} from "../../entities/classes/class.entity";
import {ClassJoinRequest} from "../../entities/classes/class-join-request.entity";
import {Student} from "../../entities/users/student.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { Class } from '../../entities/classes/class.entity';
import { ClassJoinRequest } from '../../entities/classes/class-join-request.entity';
import { Student } from '../../entities/users/student.entity';
export class ClassJoinRequestRepository extends DwengoEntityRepository<ClassJoinRequest> {
public findAllRequestsBy(requester: Student): Promise<ClassJoinRequest[]> {
return this.findAll({where: {requester: requester}});
return this.findAll({ where: { requester: requester } });
}
public findAllOpenRequestsTo(clazz: Class): Promise<ClassJoinRequest[]> {
return this.findAll({where: {class: clazz}});
return this.findAll({ where: { class: clazz } });
}
public deleteBy(requester: Student, clazz: Class): Promise<void> {
return this.deleteWhere({requester: requester, class: clazz});
return this.deleteWhere({ requester: requester, class: clazz });
}
}

View file

@ -1,11 +1,11 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {Class} from "../../entities/classes/class.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { Class } from '../../entities/classes/class.entity';
export class ClassRepository extends DwengoEntityRepository<Class> {
public findById(id: string): Promise<Class | null> {
return this.findOne({classId: id});
return this.findOne({ classId: id });
}
public deleteById(id: string): Promise<void> {
return this.deleteWhere({classId: id});
return this.deleteWhere({ classId: id });
}
}

View file

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

View file

@ -1,10 +1,16 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {Attachment} from "../../entities/content/attachment.entity";
import {LearningObject} from "../../entities/content/learning-object.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { Attachment } from '../../entities/content/attachment.entity';
import { LearningObject } from '../../entities/content/learning-object.entity';
export class AttachmentRepository extends DwengoEntityRepository<Attachment> {
public findByLearningObjectAndNumber(learningObject: LearningObject, sequenceNumber: number) {
return this.findOne({learningObject: learningObject, sequenceNumber: sequenceNumber});
public findByLearningObjectAndNumber(
learningObject: LearningObject,
sequenceNumber: number
) {
return this.findOne({
learningObject: learningObject,
sequenceNumber: sequenceNumber,
});
}
// This repository is read-only for now since creating own learning object is an extension feature.
}

View file

@ -1,13 +1,15 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {LearningObject} from "../../entities/content/learning-object.entity";
import {LearningObjectIdentifier} from "../../entities/content/learning-object-identifier";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { LearningObject } from '../../entities/content/learning-object.entity';
import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier';
export class LearningObjectRepository extends DwengoEntityRepository<LearningObject> {
public findByIdentifier(identifier: LearningObjectIdentifier): Promise<LearningObject | null> {
public findByIdentifier(
identifier: LearningObjectIdentifier
): Promise<LearningObject | null> {
return this.findOne({
hruid: identifier.hruid,
language: identifier.language,
version: identifier.version
version: identifier.version,
});
}
// This repository is read-only for now since creating own learning object is an extension feature.

View file

@ -1,10 +1,13 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {LearningPath} from "../../entities/content/learning-path.entity";
import {Language} from "../../entities/content/language";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { LearningPath } from '../../entities/content/learning-path.entity';
import { Language } from '../../entities/content/language';
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 });
}
// This repository is read-only for now since creating own learning object is an extension feature.
}

View file

@ -1,6 +1,8 @@
import {EntityRepository, FilterQuery} from "@mikro-orm/core";
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();
em.persist(entity);

View file

@ -1,10 +1,14 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {Answer} from "../../entities/questions/answer.entity";
import {Question} from "../../entities/questions/question.entity";
import {Teacher} from "../../entities/users/teacher.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { Answer } from '../../entities/questions/answer.entity';
import { Question } from '../../entities/questions/question.entity';
import { Teacher } from '../../entities/users/teacher.entity';
export class AnswerRepository extends DwengoEntityRepository<Answer> {
public createAnswer(answer: {toQuestion: Question, author: Teacher, content: string}): Promise<Answer> {
public createAnswer(answer: {
toQuestion: Question;
author: Teacher;
content: string;
}): Promise<Answer> {
let answerEntity = new Answer();
answerEntity.toQuestion = answer.toQuestion;
answerEntity.author = answer.author;
@ -14,13 +18,16 @@ export class AnswerRepository extends DwengoEntityRepository<Answer> {
public findAllAnswersToQuestion(question: Question): Promise<Answer[]> {
return this.findAll({
where: { toQuestion: question },
orderBy: { sequenceNumber: "ASC" }
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
sequenceNumber: sequenceNumber,
});
}
}

View file

@ -1,10 +1,14 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {Question} from "../../entities/questions/question.entity";
import {LearningObjectIdentifier} from "../../entities/content/learning-object-identifier";
import {Student} from "../../entities/users/student.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { Question } from '../../entities/questions/question.entity';
import { LearningObjectIdentifier } from '../../entities/content/learning-object-identifier';
import { Student } from '../../entities/users/student.entity';
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> {
let questionEntity = new Question();
questionEntity.learningObjectHruid = question.loId.hruid;
questionEntity.learningObjectLanguage = question.loId.language;
@ -13,24 +17,29 @@ 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,
learningObjectLanguage: loId.language,
learningObjectVersion: loId.version
learningObjectVersion: loId.version,
},
orderBy: {
sequenceNumber: "ASC"
}
sequenceNumber: 'ASC',
},
});
}
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,
learningObjectVersion: loId.version,
sequenceNumber: sequenceNumber
})
sequenceNumber: sequenceNumber,
});
}
}

View file

@ -1,33 +1,38 @@
import {AnyEntity, EntityManager, EntityName, EntityRepository} from "@mikro-orm/core";
import {forkEntityManager} from "../orm";
import {StudentRepository} from "./users/student-repository";
import {Student} from "../entities/users/student.entity";
import {User} from "../entities/users/user.entity";
import {UserRepository} from "./users/user-repository";
import {Teacher} from "../entities/users/teacher.entity";
import {TeacherRepository} from "./users/teacher-repository";
import {Class} from "../entities/classes/class.entity";
import {ClassRepository} from "./classes/class-repository";
import {ClassJoinRequest} from "../entities/classes/class-join-request.entity";
import {ClassJoinRequestRepository} from "./classes/class-join-request-repository";
import {TeacherInvitationRepository} from "./classes/teacher-invitation-repository";
import {TeacherInvitation} from "../entities/classes/teacher-invitation.entity";
import {Assignment} from "../entities/assignments/assignment.entity";
import {AssignmentRepository} from "./assignments/assignment-repository";
import {GroupRepository} from "./assignments/group-repository";
import {Group} from "../entities/assignments/group.entity";
import {Submission} from "../entities/assignments/submission.entity";
import {SubmissionRepository} from "./assignments/submission-repository";
import {Question} from "../entities/questions/question.entity";
import {QuestionRepository} from "./questions/question-repository";
import {Answer} from "../entities/questions/answer.entity";
import {AnswerRepository} from "./questions/answer-repository";
import {LearningObject} from "../entities/content/learning-object.entity";
import {LearningObjectRepository} from "./content/learning-object-repository";
import {LearningPath} from "../entities/content/learning-path.entity";
import {LearningPathRepository} from "./content/learning-path-repository";
import {AttachmentRepository} from "./content/attachment-repository";
import {Attachment} from "../entities/content/attachment.entity";
import {
AnyEntity,
EntityManager,
EntityName,
EntityRepository,
} from '@mikro-orm/core';
import { forkEntityManager } from '../orm';
import { StudentRepository } from './users/student-repository';
import { Student } from '../entities/users/student.entity';
import { User } from '../entities/users/user.entity';
import { UserRepository } from './users/user-repository';
import { Teacher } from '../entities/users/teacher.entity';
import { TeacherRepository } from './users/teacher-repository';
import { Class } from '../entities/classes/class.entity';
import { ClassRepository } from './classes/class-repository';
import { ClassJoinRequest } from '../entities/classes/class-join-request.entity';
import { ClassJoinRequestRepository } from './classes/class-join-request-repository';
import { TeacherInvitationRepository } from './classes/teacher-invitation-repository';
import { TeacherInvitation } from '../entities/classes/teacher-invitation.entity';
import { Assignment } from '../entities/assignments/assignment.entity';
import { AssignmentRepository } from './assignments/assignment-repository';
import { GroupRepository } from './assignments/group-repository';
import { Group } from '../entities/assignments/group.entity';
import { Submission } from '../entities/assignments/submission.entity';
import { SubmissionRepository } from './assignments/submission-repository';
import { Question } from '../entities/questions/question.entity';
import { QuestionRepository } from './questions/question-repository';
import { Answer } from '../entities/questions/answer.entity';
import { AnswerRepository } from './questions/answer-repository';
import { LearningObject } from '../entities/content/learning-object.entity';
import { LearningObjectRepository } from './content/learning-object-repository';
import { LearningPath } from '../entities/content/learning-path.entity';
import { LearningPathRepository } from './content/learning-path-repository';
import { AttachmentRepository } from './content/attachment-repository';
import { Attachment } from '../entities/content/attachment.entity';
let entityManager: EntityManager | undefined;
@ -38,7 +43,9 @@ 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) {
@ -48,29 +55,65 @@ function repositoryGetter<T extends AnyEntity, R extends EntityRepository<T>>(en
cachedRepo = entityManager.getRepository(entity) as R;
}
return cachedRepo;
}
};
}
/* Users */
export const getUserRepository = repositoryGetter<User, UserRepository>(User)
export const getStudentRepository = repositoryGetter<Student, StudentRepository>(Student);
export const getTeacherRepository = repositoryGetter<Teacher, TeacherRepository>(Teacher);
export const getUserRepository = repositoryGetter<User, UserRepository>(User);
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<LearningObject, LearningObjectRepository>(LearningObject);
export const getLearningPathRepository = repositoryGetter<LearningPath, LearningPathRepository>(LearningPath);
export const getAttachmentRepository = repositoryGetter<Attachment, AttachmentRepository>(Assignment);
export const getLearningObjectRepository = repositoryGetter<
LearningObject,
LearningObjectRepository
>(LearningObject);
export const getLearningPathRepository = repositoryGetter<
LearningPath,
LearningPathRepository
>(LearningPath);
export const getAttachmentRepository = repositoryGetter<
Attachment,
AttachmentRepository
>(Assignment);

View file

@ -1,11 +1,11 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {Student} from "../../entities/users/student.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { Student } from '../../entities/users/student.entity';
export class StudentRepository extends DwengoEntityRepository<Student> {
public findByUsername(username: string): Promise<Student | null> {
return this.findOne({username: username});
return this.findOne({ username: username });
}
public deleteByUsername(username: string): Promise<void> {
return this.deleteWhere({username: username});
return this.deleteWhere({ username: username });
}
}

View file

@ -1,11 +1,11 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {Teacher} from "../../entities/users/teacher.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { Teacher } from '../../entities/users/teacher.entity';
export class TeacherRepository extends DwengoEntityRepository<Teacher> {
public findByUsername(username: string): Promise<Teacher | null> {
return this.findOne({username: username});
return this.findOne({ username: username });
}
public deleteByUsername(username: string): Promise<void> {
return this.deleteWhere({username: username});
return this.deleteWhere({ username: username });
}
}

View file

@ -1,11 +1,11 @@
import {DwengoEntityRepository} from "../dwengo-entity-repository";
import {User} from "../../entities/users/user.entity";
import { DwengoEntityRepository } from '../dwengo-entity-repository';
import { User } from '../../entities/users/user.entity';
export class UserRepository extends DwengoEntityRepository<User> {
public findByUsername(username: string): Promise<User | null> {
return this.findOne({username: username});
return this.findOne({ username: username });
}
public deleteByUsername(username: string): Promise<void> {
return this.deleteWhere({username: username});
return this.deleteWhere({ username: username });
}
}

View file

@ -1,28 +1,35 @@
import {Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property} from "@mikro-orm/core";
import {Class} from "../classes/class.entity";
import {Group} from "./group.entity"
import {Language} from "../content/language";
import {
Entity,
Enum,
ManyToOne,
OneToMany,
PrimaryKey,
Property,
} from '@mikro-orm/core';
import { Class } from '../classes/class.entity';
import { Group } from './group.entity';
import { Language } from '../content/language';
@Entity()
export class Assignment {
@ManyToOne({entity: () => Class, primary: true})
@ManyToOne({ entity: () => Class, primary: true })
within!: Class;
@PrimaryKey({type: "number"})
@PrimaryKey({ type: 'number' })
id!: number;
@Property({type: "string"})
@Property({ type: 'string' })
title!: string;
@Property({type: "text"})
@Property({ type: 'text' })
description!: string;
@Property({type: "string"})
@Property({ type: 'string' })
learningPathHruid!: string;
@Enum({items: () => Language})
@Enum({ items: () => Language })
learningPathLanguage!: Language;
@OneToMany({entity: () => Group, mappedBy: "assignment"})
@OneToMany({ entity: () => Group, mappedBy: 'assignment' })
groups!: Group[];
}

View file

@ -1,15 +1,15 @@
import {Entity, ManyToMany, ManyToOne, PrimaryKey} from "@mikro-orm/core";
import {Assignment} from "./assignment.entity";
import {Student} from "../users/student.entity";
import { Entity, ManyToMany, ManyToOne, PrimaryKey } from '@mikro-orm/core';
import { Assignment } from './assignment.entity';
import { Student } from '../users/student.entity';
@Entity()
export class Group {
@ManyToOne({entity: () => Assignment, primary: true})
@ManyToOne({ entity: () => Assignment, primary: true })
assignment!: Assignment;
@PrimaryKey({type: "integer"})
@PrimaryKey({ type: 'integer' })
groupNumber!: number;
@ManyToMany({entity: () => Student})
@ManyToMany({ entity: () => Student })
members!: Student[];
}

View file

@ -1,31 +1,31 @@
import {Student} from "../users/student.entity";
import {Group} from "./group.entity";
import {Entity, Enum, ManyToOne, PrimaryKey, Property} from "@mikro-orm/core";
import {Language} from "../content/language";
import { Student } from '../users/student.entity';
import { Group } from './group.entity';
import { Entity, Enum, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core';
import { Language } from '../content/language';
@Entity()
export class Submission {
@PrimaryKey({type: "string"})
@PrimaryKey({ type: 'string' })
learningObjectHruid!: string;
@Enum({items: () => Language, primary: true})
@Enum({ items: () => Language, primary: true })
learningObjectLanguage!: Language;
@PrimaryKey({type: "string"})
learningObjectVersion: string = "1";
@PrimaryKey({ type: 'string' })
learningObjectVersion: string = '1';
@PrimaryKey({type: "integer"})
@PrimaryKey({ type: 'integer' })
submissionNumber!: number;
@ManyToOne({entity: () => Student})
@ManyToOne({ entity: () => Student })
submitter!: Student;
@Property({type: "datetime"})
@Property({ type: 'datetime' })
submissionTime!: Date;
@ManyToOne({entity: () => Group, nullable: true})
@ManyToOne({ entity: () => Group, nullable: true })
onBehalfOf?: Group;
@Property({type: "json"})
@Property({ type: 'json' })
content!: string;
}

View file

@ -1,13 +1,13 @@
import {Entity, Enum, ManyToOne} from "@mikro-orm/core";
import {Student} from "../users/student.entity";
import {Class} from "./class.entity";
import { Entity, Enum, ManyToOne } from '@mikro-orm/core';
import { Student } from '../users/student.entity';
import { Class } from './class.entity';
@Entity()
export class ClassJoinRequest {
@ManyToOne({entity: () => Student, primary: true})
@ManyToOne({ entity: () => Student, primary: true })
requester!: Student;
@ManyToOne({entity: () => Class, primary: true})
@ManyToOne({ entity: () => Class, primary: true })
class!: Class;
@Enum(() => ClassJoinRequestStatus)
@ -15,7 +15,7 @@ export class ClassJoinRequest {
}
export enum ClassJoinRequestStatus {
Open = "open",
Accepted = "accepted",
Declined = "declined"
Open = 'open',
Accepted = 'accepted',
Declined = 'declined',
}

View file

@ -1,14 +1,20 @@
import {Collection, Entity, ManyToMany, PrimaryKey, Property} from "@mikro-orm/core";
import {
Collection,
Entity,
ManyToMany,
PrimaryKey,
Property,
} from '@mikro-orm/core';
import { v4 } from 'uuid';
import {Teacher} from "../users/teacher.entity";
import {Student} from "../users/student.entity";
import { Teacher } from '../users/teacher.entity';
import { Student } from '../users/student.entity';
@Entity()
export class Class {
@PrimaryKey()
classId = v4();
@Property({type: "string"})
@Property({ type: 'string' })
displayName!: string;
@ManyToMany(() => Teacher)

View file

@ -1,18 +1,18 @@
import {Entity, ManyToOne} from "@mikro-orm/core";
import {Teacher} from "../users/teacher.entity";
import {Class} from "./class.entity";
import { Entity, ManyToOne } from '@mikro-orm/core';
import { Teacher } from '../users/teacher.entity';
import { Class } from './class.entity';
/**
* Invitation of a teacher into a class (in order to teach it).
*/
@Entity()
export class TeacherInvitation {
@ManyToOne({entity: () => Teacher, primary: true})
@ManyToOne({ entity: () => Teacher, primary: true })
sender!: Teacher;
@ManyToOne({entity: () => Teacher, primary: true})
@ManyToOne({ entity: () => Teacher, primary: true })
receiver!: Teacher;
@ManyToOne({entity: () => Class, primary: true})
@ManyToOne({ entity: () => Class, primary: true })
class!: Class;
}

View file

@ -1,17 +1,17 @@
import {Entity, ManyToOne, PrimaryKey, Property} from "@mikro-orm/core";
import {LearningObject} from "./learning-object.entity";
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core';
import { LearningObject } from './learning-object.entity';
@Entity()
export class Attachment {
@ManyToOne({entity: () => LearningObject, primary: true})
@ManyToOne({ entity: () => LearningObject, primary: true })
learningObject!: LearningObject;
@PrimaryKey({type: "integer"})
@PrimaryKey({ type: 'integer' })
sequenceNumber!: number;
@Property({type: "string"})
@Property({ type: 'string' })
mimeType!: string;
@Property({type: "blob"})
@Property({ type: 'blob' })
content!: Buffer;
}

View file

@ -1,6 +1,6 @@
export enum Language {
Dutch = "nl",
French = "fr",
English = "en",
Germany = "de"
Dutch = 'nl',
French = 'fr',
English = 'en',
Germany = 'de',
}

View file

@ -1,7 +1,9 @@
import {Language} from "./language";
import { Language } from './language';
export class LearningObjectIdentifier {
constructor(public hruid: string, public language: Language, public version: string) {
}
constructor(
public hruid: string,
public language: Language,
public version: string
) {}
}

View file

@ -1,97 +1,106 @@
import {Embeddable, Embedded, Entity, Enum, ManyToMany, OneToMany, PrimaryKey, Property} from "@mikro-orm/core";
import {Language} from "./language";
import {Attachment} from "./attachment.entity";
import {Teacher} from "../users/teacher.entity";
import {
Embeddable,
Embedded,
Entity,
Enum,
ManyToMany,
OneToMany,
PrimaryKey,
Property,
} from '@mikro-orm/core';
import { Language } from './language';
import { Attachment } from './attachment.entity';
import { Teacher } from '../users/teacher.entity';
@Entity()
export class LearningObject {
@PrimaryKey({type: "string"})
@PrimaryKey({ type: 'string' })
hruid!: string;
@Enum({items: () => Language, primary: true})
@Enum({ items: () => Language, primary: true })
language!: Language;
@PrimaryKey({type: "string"})
version: string = "1";
@PrimaryKey({ type: 'string' })
version: string = '1';
@ManyToMany({entity: () => Teacher})
@ManyToMany({ entity: () => Teacher })
admins!: Teacher[];
@Property({type: "string"})
@Property({ type: 'string' })
title!: string;
@Property({type: "text"})
@Property({ type: 'text' })
description!: string;
@Property({type: "string"})
@Property({ type: 'string' })
contentType!: string;
@Property({type: "array"})
@Property({ type: 'array' })
keywords: string[] = [];
@Property({type: "array", nullable: true})
@Property({ type: 'array', nullable: true })
targetAges?: number[];
@Property({type: "bool"})
@Property({ type: 'bool' })
teacherExclusive: boolean = false;
@Property({type: "array"})
@Property({ type: 'array' })
skosConcepts!: string[];
@Embedded({entity: () => EducationalGoal, array: true})
@Embedded({ entity: () => EducationalGoal, array: true })
educationalGoals: EducationalGoal[] = [];
@Property({type: "string"})
copyright: string = ""
@Property({ type: 'string' })
copyright: string = '';
@Property({type: "string"})
license: string = ""
@Property({ type: 'string' })
license: string = '';
@Property({type: "smallint", nullable: true})
@Property({ type: 'smallint', nullable: true })
difficulty?: number;
@Property({type: "integer"})
@Property({ type: 'integer' })
estimatedTime!: number;
@Embedded({entity: () => ReturnValue})
@Embedded({ entity: () => ReturnValue })
returnValue!: ReturnValue;
@Property({type: "bool"})
@Property({ type: 'bool' })
available: boolean = true;
@Property({type: "string", nullable: true})
@Property({ type: 'string', nullable: true })
contentLocation?: string;
@OneToMany({entity: () => Attachment, mappedBy: "learningObject"})
@OneToMany({ entity: () => Attachment, mappedBy: 'learningObject' })
attachments: Attachment[] = [];
@Property({type: "blob"})
@Property({ type: 'blob' })
content!: Buffer;
}
@Embeddable()
export class EducationalGoal {
@Property({type: "string"})
@Property({ type: 'string' })
source!: string;
@Property({type: "string"})
@Property({ type: 'string' })
id!: string;
}
@Embeddable()
export class ReturnValue {
@Property({type: "string"})
@Property({ type: 'string' })
callbackUrl!: string;
@Property({type: "json"})
@Property({ type: 'json' })
callbackSchema!: string;
}
export enum ContentType {
Markdown = "text/markdown",
Image = "image/image",
Mpeg = "audio/mpeg",
Pdf = "application/pdf",
Extern = "extern",
Blockly = "Blockly"
Markdown = 'text/markdown',
Image = 'image/image',
Mpeg = 'audio/mpeg',
Pdf = 'application/pdf',
Extern = 'extern',
Blockly = 'Blockly',
}

View file

@ -1,57 +1,66 @@
import {Embeddable, Embedded, Entity, Enum, ManyToMany, OneToOne, PrimaryKey, Property} from "@mikro-orm/core";
import {Language} from "./language";
import {Teacher} from "../users/teacher.entity";
import {
Embeddable,
Embedded,
Entity,
Enum,
ManyToMany,
OneToOne,
PrimaryKey,
Property,
} from '@mikro-orm/core';
import { Language } from './language';
import { Teacher } from '../users/teacher.entity';
@Entity()
export class LearningPath {
@PrimaryKey({type: "string"})
@PrimaryKey({ type: 'string' })
hruid!: string;
@Enum({items: () => Language, primary: true})
@Enum({ items: () => Language, primary: true })
language!: Language;
@ManyToMany({entity: () => Teacher})
@ManyToMany({ entity: () => Teacher })
admins!: Teacher[];
@Property({type: "string"})
@Property({ type: 'string' })
title!: string;
@Property({type: "text"})
@Property({ type: 'text' })
description!: string;
@Property({type: "blob"})
@Property({ type: 'blob' })
image!: string;
@Embedded({entity: () => LearningPathNode, array: true})
@Embedded({ entity: () => LearningPathNode, array: true })
nodes: LearningPathNode[] = [];
}
@Embeddable()
export class LearningPathNode {
@Property({type: "string"})
@Property({ type: 'string' })
learningObjectHruid!: string;
@Enum({items: () => Language})
@Enum({ items: () => Language })
language!: Language;
@Property({type: "string"})
@Property({ type: 'string' })
version!: string;
@Property({type: "longtext"})
@Property({ type: 'longtext' })
instruction!: string;
@Property({type: "bool"})
@Property({ type: 'bool' })
startNode!: boolean;
@Embedded({entity: () => LearningPathTransition, array: true})
@Embedded({ entity: () => LearningPathTransition, array: true })
transitions!: LearningPathTransition[];
}
@Embeddable()
export class LearningPathTransition {
@Property({type: "string"})
@Property({ type: 'string' })
condition!: string;
@OneToOne({entity: () => LearningPathNode})
@OneToOne({ entity: () => LearningPathNode })
next!: LearningPathNode;
}

View file

@ -1,22 +1,21 @@
import {Entity, ManyToOne, PrimaryKey, Property} from "@mikro-orm/core";
import {Question} from "./question.entity";
import {Teacher} from "../users/teacher.entity";
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core';
import { Question } from './question.entity';
import { Teacher } from '../users/teacher.entity';
@Entity()
export class Answer {
@ManyToOne({entity: () => Teacher, primary: true})
@ManyToOne({ entity: () => Teacher, primary: true })
author!: Teacher;
@ManyToOne({entity: () => Question, primary: true})
@ManyToOne({ entity: () => Question, primary: true })
toQuestion!: Question;
@PrimaryKey({type: "integer"})
@PrimaryKey({ type: 'integer' })
sequenceNumber!: number;
@Property({type: "datetime"})
@Property({ type: 'datetime' })
timestamp: Date = new Date();
@Property({type: "text"})
@Property({ type: 'text' })
content!: string;
}

View file

@ -1,27 +1,27 @@
import {Entity, Enum, ManyToOne, PrimaryKey, Property} from "@mikro-orm/core";
import {Language} from "../content/language";
import {Student} from "../users/student.entity";
import { Entity, Enum, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core';
import { Language } from '../content/language';
import { Student } from '../users/student.entity';
@Entity()
export class Question {
@PrimaryKey({type: "string"})
@PrimaryKey({ type: 'string' })
learningObjectHruid!: string;
@Enum({items: () => Language, primary: true})
@Enum({ items: () => Language, primary: true })
learningObjectLanguage!: Language;
@PrimaryKey({type: "string"})
learningObjectVersion: string = "1";
@PrimaryKey({ type: 'string' })
learningObjectVersion: string = '1';
@PrimaryKey({type: "integer"})
@PrimaryKey({ type: 'integer' })
sequenceNumber!: number;
@ManyToOne({entity: () => Student})
@ManyToOne({ entity: () => Student })
author!: Student;
@Property({type: "datetime"})
@Property({ type: 'datetime' })
timestamp: Date = new Date();
@Property({type: "text"})
@Property({ type: 'text' })
content!: string;
}

View file

@ -1,10 +1,10 @@
import {User} from "./user.entity";
import {Collection, Entity, ManyToMany} from '@mikro-orm/core';
import {Class} from "../classes/class.entity";
import {Group} from "../assignments/group.entity";
import {StudentRepository} from "../../data/users/student-repository";
import { User } from './user.entity';
import { Collection, Entity, ManyToMany } from '@mikro-orm/core';
import { Class } from '../classes/class.entity';
import { Group } from '../assignments/group.entity';
import { StudentRepository } from '../../data/users/student-repository';
@Entity({repository: () => StudentRepository})
@Entity({ repository: () => StudentRepository })
export class Student extends User {
@ManyToMany(() => Class)
classes!: Collection<Class>;
@ -12,7 +12,11 @@ export class Student extends User {
@ManyToMany(() => Group)
groups!: Collection<Group>;
constructor(public username: string, public firstName: string, public lastName: string) {
constructor(
public username: string,
public firstName: string,
public lastName: string
) {
super();
}
}

View file

@ -1,6 +1,6 @@
import {Collection, Entity, ManyToMany} from '@mikro-orm/core';
import {User} from "./user.entity";
import {Class} from "../classes/class.entity";
import { Collection, Entity, ManyToMany } from '@mikro-orm/core';
import { User } from './user.entity';
import { Class } from '../classes/class.entity';
@Entity()
export class Teacher extends User {

View file

@ -1,8 +1,8 @@
import { Entity, PrimaryKey, Property } from '@mikro-orm/core';
@Entity({abstract: true})
@Entity({ abstract: true })
export abstract class User {
@PrimaryKey({type: "string"})
@PrimaryKey({ type: 'string' })
username!: string;
@Property()

View file

@ -1,7 +1,7 @@
import {Options} from '@mikro-orm/core';
import {PostgreSqlDriver} from "@mikro-orm/postgresql";
import {EnvVars, getEnvVar, getNumericEnvVar} from "./util/envvars";
import {SqliteDriver} from "@mikro-orm/sqlite";
import { Options } from '@mikro-orm/core';
import { PostgreSqlDriver } from '@mikro-orm/postgresql';
import { EnvVars, getEnvVar, getNumericEnvVar } from './util/envvars';
import { SqliteDriver } from '@mikro-orm/sqlite';
const entities = ['dist/**/*.entity.js'];
const entitiesTs = ['src/**/*.entity.ts'];
@ -15,7 +15,7 @@ function config(testingMode: boolean = false): Options {
// Workaround: vitest: `TypeError: Unknown file extension ".ts"` (ERR_UNKNOWN_FILE_EXTENSION)
// (see https://mikro-orm.io/docs/guide/project-setup#testing-the-endpoint)
dynamicImportProvider: id => import(id)
dynamicImportProvider: (id) => import(id),
};
} else {
return {
@ -27,7 +27,7 @@ function config(testingMode: boolean = false): Options {
password: getEnvVar(EnvVars.DbPassword),
entities: entities,
entitiesTs: entitiesTs,
debug: true
debug: true,
};
}
}

View file

@ -1,6 +1,6 @@
import { EntityManager, MikroORM} from '@mikro-orm/core';
import { EntityManager, MikroORM } from '@mikro-orm/core';
import config from './mikro-orm.config.js';
import {EnvVars, getEnvVar} from "./util/envvars";
import { EnvVars, getEnvVar } from './util/envvars';
let orm: MikroORM | undefined;
export async function initORM(testingMode: boolean = false) {
@ -11,15 +11,20 @@ export async function initORM(testingMode: boolean = false) {
} else {
const diff = await orm.schema.getUpdateSchemaSQL();
if (diff) {
throw Error("The database structure needs to be updated in order to fit the new database structure " +
"of the app. In order to do so automatically, set the environment variable DWENGO_DB_UPDATE to true. " +
"The following queries will then be executed:\n" + diff)
throw Error(
'The database structure needs to be updated in order to fit the new database structure ' +
'of the app. In order to do so automatically, set the environment variable DWENGO_DB_UPDATE to true. ' +
'The following queries will then be executed:\n' +
diff
);
}
}
}
export function forkEntityManager(): EntityManager {
if (!orm) {
throw Error("Accessing the Entity Manager before the ORM is fully initialized.")
throw Error(
'Accessing the Entity Manager before the ORM is fully initialized.'
);
}
return orm.em.fork();
}

View file

@ -1,15 +1,15 @@
const PREFIX = "DWENGO_";
const DB_PREFIX = PREFIX + "DB_";
const PREFIX = 'DWENGO_';
const DB_PREFIX = PREFIX + 'DB_';
type EnvVar = {key: string, required?: boolean, defaultValue?: any}
type EnvVar = { key: string; required?: boolean; defaultValue?: any };
export const EnvVars: {[key: string]: EnvVar} = {
"DbHost": {key: DB_PREFIX + "HOST", required: true},
"DbPort": {key: DB_PREFIX + "PORT", defaultValue: 5432},
"DbName": {key: DB_PREFIX + "NAME", defaultValue: "dwengo"},
"DbUsername": {key: DB_PREFIX + "USERNAME", required: true},
"DbPassword": {key: DB_PREFIX + "PASSWORD", required: true},
"DbUpdate": {key: DB_PREFIX + "UPDATE", defaultValue: false},
export const EnvVars: { [key: string]: EnvVar } = {
DbHost: { key: DB_PREFIX + 'HOST', required: true },
DbPort: { key: DB_PREFIX + 'PORT', defaultValue: 5432 },
DbName: { key: DB_PREFIX + 'NAME', defaultValue: 'dwengo' },
DbUsername: { key: DB_PREFIX + 'USERNAME', required: true },
DbPassword: { key: DB_PREFIX + 'PASSWORD', required: true },
DbUpdate: { key: DB_PREFIX + 'UPDATE', defaultValue: false },
} as const;
/**
@ -27,7 +27,7 @@ export function getEnvVar(envVar: EnvVar): string {
} else if (envVar.required) {
throw new Error(`Missing environment variable: ${envVar.key}`);
} else {
return envVar.defaultValue || "";
return envVar.defaultValue || '';
}
}
@ -35,7 +35,9 @@ export function getNumericEnvVar(envVar: EnvVar): number {
const valueString = getEnvVar(envVar);
const value = parseInt(valueString);
if (isNaN(value)) {
throw new Error(`Invalid value for environment variable ${envVar.key}: ${valueString}. Expected a number.`)
throw new Error(
`Invalid value for environment variable ${envVar.key}: ${valueString}. Expected a number.`
);
} else {
return value;
}