MERGE: dev ino feat/service-layer

This commit is contained in:
Gabriellvl 2025-03-13 17:42:04 +01:00
commit 6404335040
220 changed files with 12582 additions and 10400 deletions

View file

@ -1,7 +1,6 @@
import { Collection, Entity, ManyToMany, ManyToOne, PrimaryKey } from '@mikro-orm/core';
import { Assignment } from './assignment.entity.js';
import { Student } from '../users/student.entity.js';
import { GroupRepository } from '../../data/assignments/group-repository.js';
@Entity({
repository: () => {
@ -10,9 +9,7 @@ import { GroupRepository } from '../../data/assignments/group-repository.js';
})
export class Group {
@ManyToOne({
entity: () => {
return Assignment;
},
entity: () => Assignment,
primary: true,
})
assignment!: Assignment;
@ -20,8 +17,8 @@ export class Group {
@PrimaryKey({ type: 'integer', autoincrement: true })
groupNumber?: number;
@ManyToMany(() => {
return Student;
@ManyToMany({
entity: () => Student,
})
members!: Collection<Student>;
members!: Student[];
}

View file

@ -4,33 +4,25 @@ import { Entity, Enum, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core';
import { Language } from '../content/language.js';
import { SubmissionRepository } from '../../data/assignments/submission-repository.js';
@Entity({
repository: () => {
return SubmissionRepository;
},
})
@Entity({ repository: () => SubmissionRepository })
export class Submission {
@PrimaryKey({ type: 'string' })
learningObjectHruid!: string;
@Enum({
items: () => {
return Language;
},
items: () => Language,
primary: true,
})
learningObjectLanguage!: Language;
@PrimaryKey({ type: 'string' })
learningObjectVersion: string = '1';
@PrimaryKey({ type: 'numeric' })
learningObjectVersion: number = 1;
@PrimaryKey({ type: 'integer' })
submissionNumber!: number;
@ManyToOne({
entity: () => {
return Student;
},
entity: () => Student,
})
submitter!: Student;
@ -38,9 +30,7 @@ export class Submission {
submissionTime!: Date;
@ManyToOne({
entity: () => {
return Group;
},
entity: () => Group,
nullable: true,
})
onBehalfOf?: Group;

View file

@ -10,24 +10,18 @@ import { ClassJoinRequestRepository } from '../../data/classes/class-join-reques
})
export class ClassJoinRequest {
@ManyToOne({
entity: () => {
return Student;
},
entity: () => Student,
primary: true,
})
requester!: Student;
@ManyToOne({
entity: () => {
return Class;
},
entity: () => Class,
primary: true,
})
class!: Class;
@Enum(() => {
return ClassJoinRequestStatus;
})
@Enum(() => ClassJoinRequestStatus)
status!: ClassJoinRequestStatus;
}

View file

@ -8,7 +8,6 @@ import {
import { v4 } from 'uuid';
import { Teacher } from '../users/teacher.entity.js';
import { Student } from '../users/student.entity.js';
import { ClassRepository } from '../../data/classes/class-repository.js';
@Entity({
repository: () => {
@ -22,13 +21,9 @@ export class Class {
@Property({ type: 'string' })
displayName!: string;
@ManyToMany(() => {
return Teacher;
})
@ManyToMany(() => Teacher)
teachers!: Collection<Teacher>;
@ManyToMany(() => {
return Student;
})
@ManyToMany(() => Student)
students!: Collection<Student>;
}

View file

@ -6,32 +6,22 @@ import { TeacherInvitationRepository } from '../../data/classes/teacher-invitati
/**
* Invitation of a teacher into a class (in order to teach it).
*/
@Entity({
repository: () => {
return TeacherInvitationRepository;
},
})
@Entity({ repository: () => TeacherInvitationRepository })
export class TeacherInvitation {
@ManyToOne({
entity: () => {
return Teacher;
},
entity: () => Teacher,
primary: true,
})
sender!: Teacher;
@ManyToOne({
entity: () => {
return Teacher;
},
entity: () => Teacher,
primary: true,
})
receiver!: Teacher;
@ManyToOne({
entity: () => {
return Class;
},
entity: () => Class,
primary: true,
})
class!: Class;

View file

@ -1,6 +1,5 @@
import { Entity, ManyToOne, PrimaryKey, Property } from '@mikro-orm/core';
import { LearningObject } from './learning-object.entity.js';
import { AttachmentRepository } from '../../data/content/attachment-repository.js';
@Entity({
repository: () => {
@ -16,8 +15,8 @@ export class Attachment {
})
learningObject!: LearningObject;
@PrimaryKey({ type: 'integer' })
sequenceNumber!: number;
@PrimaryKey({ type: 'string' })
name!: string;
@Property({ type: 'string' })
mimeType!: string;

View file

@ -1,8 +1,188 @@
export enum Language {
Afar = 'aa',
Abkhazian = 'ab',
Afrikaans = 'af',
Akan = 'ak',
Albanian = 'sq',
Amharic = 'am',
Arabic = 'ar',
Aragonese = 'an',
Armenian = 'hy',
Assamese = 'as',
Avaric = 'av',
Avestan = 'ae',
Aymara = 'ay',
Azerbaijani = 'az',
Bashkir = 'ba',
Bambara = 'bm',
Basque = 'eu',
Belarusian = 'be',
Bengali = 'bn',
Bihari = 'bh',
Bislama = 'bi',
Bosnian = 'bs',
Breton = 'br',
Bulgarian = 'bg',
Burmese = 'my',
Catalan = 'ca',
Chamorro = 'ch',
Chechen = 'ce',
Chinese = 'zh',
ChurchSlavic = 'cu',
Chuvash = 'cv',
Cornish = 'kw',
Corsican = 'co',
Cree = 'cr',
Czech = 'cs',
Danish = 'da',
Divehi = 'dv',
Dutch = 'nl',
French = 'fr',
Dzongkha = 'dz',
English = 'en',
Germany = 'de',
Esperanto = 'eo',
Estonian = 'et',
Ewe = 'ee',
Faroese = 'fo',
Fijian = 'fj',
Finnish = 'fi',
French = 'fr',
Frisian = 'fy',
Fulah = 'ff',
Georgian = 'ka',
German = 'de',
Gaelic = 'gd',
Irish = 'ga',
Galician = 'gl',
Manx = 'gv',
Greek = 'el',
Guarani = 'gn',
Gujarati = 'gu',
Haitian = 'ht',
Hausa = 'ha',
Hebrew = 'he',
Herero = 'hz',
Hindi = 'hi',
HiriMotu = 'ho',
Croatian = 'hr',
Hungarian = 'hu',
Igbo = 'ig',
Icelandic = 'is',
Ido = 'io',
SichuanYi = 'ii',
Inuktitut = 'iu',
Interlingue = 'ie',
Interlingua = 'ia',
Indonesian = 'id',
Inupiaq = 'ik',
Italian = 'it',
Javanese = 'jv',
Japanese = 'ja',
Kalaallisut = 'kl',
Kannada = 'kn',
Kashmiri = 'ks',
Kanuri = 'kr',
Kazakh = 'kk',
Khmer = 'km',
Kikuyu = 'ki',
Kinyarwanda = 'rw',
Kirghiz = 'ky',
Komi = 'kv',
Kongo = 'kg',
Korean = 'ko',
Kuanyama = 'kj',
Kurdish = 'ku',
Lao = 'lo',
Latin = 'la',
Latvian = 'lv',
Limburgan = 'li',
Lingala = 'ln',
Lithuanian = 'lt',
Luxembourgish = 'lb',
LubaKatanga = 'lu',
Ganda = 'lg',
Macedonian = 'mk',
Marshallese = 'mh',
Malayalam = 'ml',
Maori = 'mi',
Marathi = 'mr',
Malay = 'ms',
Malagasy = 'mg',
Maltese = 'mt',
Mongolian = 'mn',
Nauru = 'na',
Navajo = 'nv',
SouthNdebele = 'nr',
NorthNdebele = 'nd',
Ndonga = 'ng',
Nepali = 'ne',
NorwegianNynorsk = 'nn',
NorwegianBokmal = 'nb',
Norwegian = 'no',
Chichewa = 'ny',
Occitan = 'oc',
Ojibwa = 'oj',
Oriya = 'or',
Oromo = 'om',
Ossetian = 'os',
Punjabi = 'pa',
Persian = 'fa',
Pali = 'pi',
Polish = 'pl',
Portuguese = 'pt',
Pashto = 'ps',
Quechua = 'qu',
Romansh = 'rm',
Romanian = 'ro',
Rundi = 'rn',
Russian = 'ru',
Sango = 'sg',
Sanskrit = 'sa',
Sinhala = 'si',
Slovak = 'sk',
Slovenian = 'sl',
NorthernSami = 'se',
Samoan = 'sm',
Shona = 'sn',
Sindhi = 'sd',
Somali = 'so',
Sotho = 'st',
Spanish = 'es',
Sardinian = 'sc',
Serbian = 'sr',
Swati = 'ss',
Sundanese = 'su',
Swahili = 'sw',
Swedish = 'sv',
Tahitian = 'ty',
Tamil = 'ta',
Tatar = 'tt',
Telugu = 'te',
Tajik = 'tg',
Tagalog = 'tl',
Thai = 'th',
Tibetan = 'bo',
Tigrinya = 'ti',
Tonga = 'to',
Tswana = 'tn',
Tsonga = 'ts',
Turkmen = 'tk',
Turkish = 'tr',
Twi = 'tw',
Uighur = 'ug',
Ukrainian = 'uk',
Urdu = 'ur',
Uzbek = 'uz',
Venda = 've',
Vietnamese = 'vi',
Volapuk = 'vo',
Welsh = 'cy',
Walloon = 'wa',
Wolof = 'wo',
Xhosa = 'xh',
Yiddish = 'yi',
Yoruba = 'yo',
Zhuang = 'za',
Zulu = 'zu',
}
export const languageMap: Record<string, Language> = {

View file

@ -4,6 +4,6 @@ export class LearningObjectIdentifier {
constructor(
public hruid: string,
public language: Language,
public version: string
public version: number
) {}
}

View file

@ -11,8 +11,19 @@ import {
import { Language } from './language.js';
import { Attachment } from './attachment.entity.js';
import { Teacher } from '../users/teacher.entity.js';
import { DwengoContentType } from '../../services/learning-objects/processing/content-type.js';
import { v4 } from 'uuid';
import { LearningObjectRepository } from '../../data/content/learning-object-repository.js';
@Embeddable()
export class EducationalGoal {
@Property({ type: 'string' })
source!: string;
@Property({ type: 'string' })
id!: string;
}
@Embeddable()
export class ReturnValue {
@Property({ type: 'string' })
@ -22,30 +33,25 @@ export class ReturnValue {
callbackSchema!: string;
}
@Entity({
repository: () => {
return LearningObjectRepository;
},
})
@Entity({ repository: () => LearningObjectRepository })
export class LearningObject {
@PrimaryKey({ type: 'string' })
hruid!: string;
@Enum({
items: () => {
return Language;
},
items: () => Language,
primary: true,
})
language!: Language;
@PrimaryKey({ type: 'string' })
version: string = '1';
@PrimaryKey({ type: 'number' })
version: number = 1;
@Property({ type: 'uuid', unique: true })
uuid = v4();
@ManyToMany({
entity: () => {
return Teacher;
},
entity: () => Teacher,
})
admins!: Teacher[];
@ -56,24 +62,22 @@ export class LearningObject {
description!: string;
@Property({ type: 'string' })
contentType!: string;
contentType!: DwengoContentType;
@Property({ type: 'array' })
keywords: string[] = [];
@Property({ type: 'array', nullable: true })
targetAges?: number[];
targetAges?: number[] = [];
@Property({ type: 'bool' })
teacherExclusive: boolean = false;
@Property({ type: 'array' })
skosConcepts!: string[];
skosConcepts: string[] = [];
@Embedded({
entity: () => {
return EducationalGoal;
},
entity: () => EducationalGoal,
array: true,
})
educationalGoals: EducationalGoal[] = [];
@ -87,13 +91,11 @@ export class LearningObject {
@Property({ type: 'smallint', nullable: true })
difficulty?: number;
@Property({ type: 'integer' })
estimatedTime!: number;
@Property({ type: 'integer', nullable: true })
estimatedTime?: number;
@Embedded({
entity: () => {
return ReturnValue;
},
entity: () => ReturnValue,
})
returnValue!: ReturnValue;
@ -104,9 +106,7 @@ export class LearningObject {
contentLocation?: string;
@OneToMany({
entity: () => {
return Attachment;
},
entity: () => Attachment,
mappedBy: 'learningObject',
})
attachments: Attachment[] = [];
@ -114,21 +114,3 @@ export class LearningObject {
@Property({ type: 'blob' })
content!: Buffer;
}
@Embeddable()
export class EducationalGoal {
@Property({ type: 'string' })
source!: string;
@Property({ type: 'string' })
id!: string;
}
export enum ContentType {
Markdown = 'text/markdown',
Image = 'image/image',
Mpeg = 'audio/mpeg',
Pdf = 'application/pdf',
Extern = 'extern',
Blockly = 'Blockly',
}

View file

@ -0,0 +1,37 @@
import { Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property, Rel } from '@mikro-orm/core';
import { Language } from './language.js';
import { LearningPath } from './learning-path.entity.js';
import { LearningPathTransition } from './learning-path-transition.entity.js';
@Entity()
export class LearningPathNode {
@ManyToOne({ entity: () => LearningPath, primary: true })
learningPath!: Rel<LearningPath>;
@PrimaryKey({ type: 'integer', autoincrement: true })
nodeNumber!: number;
@Property({ type: 'string' })
learningObjectHruid!: string;
@Enum({ items: () => Language })
language!: Language;
@Property({ type: 'number' })
version!: number;
@Property({ type: 'text', nullable: true })
instruction?: string;
@Property({ type: 'bool' })
startNode!: boolean;
@OneToMany({ entity: () => LearningPathTransition, mappedBy: 'node' })
transitions: LearningPathTransition[] = [];
@Property({ length: 3 })
createdAt: Date = new Date();
@Property({ length: 3, onUpdate: () => new Date() })
updatedAt: Date = new Date();
}

View file

@ -0,0 +1,17 @@
import { Entity, ManyToOne, PrimaryKey, Property, Rel } from '@mikro-orm/core';
import { LearningPathNode } from './learning-path-node.entity.js';
@Entity()
export class LearningPathTransition {
@ManyToOne({ entity: () => LearningPathNode, primary: true })
node!: Rel<LearningPathNode>;
@PrimaryKey({ type: 'numeric' })
transitionNumber!: number;
@Property({ type: 'string' })
condition!: string;
@ManyToOne({ entity: () => LearningPathNode })
next!: Rel<LearningPathNode>;
}

View file

@ -1,39 +1,18 @@
import {
Embeddable,
Embedded,
Entity,
Enum,
ManyToMany,
OneToOne,
PrimaryKey,
Property,
} from '@mikro-orm/core';
import { Entity, Enum, ManyToMany, OneToMany, PrimaryKey, Property } from '@mikro-orm/core';
import { Language } from './language.js';
import { Teacher } from '../users/teacher.entity.js';
import { LearningPathRepository } from '../../data/content/learning-path-repository.js';
import { LearningPathNode } from './learning-path-node.entity.js';
@Entity({
repository: () => {
return LearningPathRepository;
},
})
@Entity({ repository: () => LearningPathRepository })
export class LearningPath {
@PrimaryKey({ type: 'string' })
hruid!: string;
@Enum({
items: () => {
return Language;
},
primary: true,
})
@Enum({ items: () => Language, primary: true })
language!: Language;
@ManyToMany({
entity: () => {
return Teacher;
},
})
@ManyToMany({ entity: () => Teacher })
admins!: Teacher[];
@Property({ type: 'string' })
@ -42,57 +21,9 @@ export class LearningPath {
@Property({ type: 'text' })
description!: string;
@Property({ type: 'blob' })
image!: string;
@Property({ type: 'blob', nullable: true })
image: Buffer | null = null;
@Embedded({
entity: () => {
return LearningPathNode;
},
array: true,
})
@OneToMany({ entity: () => LearningPathNode, mappedBy: 'learningPath' })
nodes: LearningPathNode[] = [];
}
@Embeddable()
export class LearningPathNode {
@Property({ type: 'string' })
learningObjectHruid!: string;
@Enum({
items: () => {
return Language;
},
})
language!: Language;
@Property({ type: 'string' })
version!: string;
@Property({ type: 'longtext' })
instruction!: string;
@Property({ type: 'bool' })
startNode!: boolean;
@Embedded({
entity: () => {
return LearningPathTransition;
},
array: true,
})
transitions!: LearningPathTransition[];
}
@Embeddable()
export class LearningPathTransition {
@Property({ type: 'string' })
condition!: string;
@OneToOne({
entity: () => {
return LearningPathNode;
},
})
next!: LearningPathNode;
}

View file

@ -3,30 +3,22 @@ import { Question } from './question.entity.js';
import { Teacher } from '../users/teacher.entity.js';
import { AnswerRepository } from '../../data/questions/answer-repository.js';
@Entity({
repository: () => {
return AnswerRepository;
},
})
@Entity({ repository: () => AnswerRepository })
export class Answer {
@ManyToOne({
entity: () => {
return Teacher;
},
entity: () => Teacher,
primary: true,
})
author!: Teacher;
@ManyToOne({
entity: () => {
return Question;
},
entity: () => Question,
primary: true,
})
toQuestion!: Question;
@PrimaryKey({ type: 'integer' })
sequenceNumber!: number;
@PrimaryKey({ type: 'integer', autoincrement: true })
sequenceNumber?: number;
@Property({ type: 'datetime' })
timestamp: Date = new Date();

View file

@ -3,33 +3,25 @@ import { Language } from '../content/language.js';
import { Student } from '../users/student.entity.js';
import { QuestionRepository } from '../../data/questions/question-repository.js';
@Entity({
repository: () => {
return QuestionRepository;
},
})
@Entity({ repository: () => QuestionRepository })
export class Question {
@PrimaryKey({ type: 'string' })
learningObjectHruid!: string;
@Enum({
items: () => {
return Language;
},
items: () => Language,
primary: true,
})
learningObjectLanguage!: Language;
@PrimaryKey({ type: 'string' })
learningObjectVersion: string = '1';
@PrimaryKey({ type: 'number' })
learningObjectVersion: number = 1;
@PrimaryKey({ type: 'integer' })
sequenceNumber!: number;
@PrimaryKey({ type: 'integer', autoincrement: true })
sequenceNumber?: number;
@ManyToOne({
entity: () => {
return Student;
},
entity: () => Student,
})
author!: Student;

View file

@ -5,19 +5,13 @@ import { Group } from '../assignments/group.entity.js';
import { StudentRepository } from '../../data/users/student-repository.js';
@Entity({
repository: () => {
return StudentRepository;
},
repository: () => StudentRepository,
})
export class Student extends User {
@ManyToMany(() => {
return Class;
})
@ManyToMany(() => Class)
classes!: Collection<Class>;
@ManyToMany(() => {
return Group;
})
@ManyToMany(() => Group)
groups!: Collection<Group>;
constructor(

View file

@ -3,14 +3,16 @@ import { User } from './user.entity.js';
import { Class } from '../classes/class.entity.js';
import { TeacherRepository } from '../../data/users/teacher-repository.js';
@Entity({
repository: () => {
return TeacherRepository;
},
})
@Entity({ repository: () => TeacherRepository })
export class Teacher extends User {
@ManyToMany(() => {
return Class;
})
@ManyToMany(() => Class)
classes!: Collection<Class>;
constructor(
public username: string,
public firstName: string,
public lastName: string
) {
super();
}
}