style(backend): Format

This commit is contained in:
Tibo De Peuter 2025-03-02 15:21:27 +01:00
parent c37d4d8e04
commit ddee299b4a
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
25 changed files with 265 additions and 150 deletions

View file

@ -22,7 +22,6 @@ const logger: Logger = getLogger();
const app: Express = express(); const app: Express = express();
const port: string | number = getNumericEnvVar(EnvVars.Port); const port: string | number = getNumericEnvVar(EnvVars.Port);
app.use(express.json()); app.use(express.json());
app.use(responseTime(responseTimeLogger)); app.use(responseTime(responseTimeLogger));

View file

@ -57,7 +57,10 @@ export async function getLearningPaths(
); );
res.json(learningPaths.data); res.json(learningPaths.data);
} catch (error) { } catch (error) {
getLogger().error('❌ Unexpected error fetching learning paths:', error); getLogger().error(
'❌ Unexpected error fetching learning paths:',
error
);
res.status(500).json({ error: 'Internal server error' }); res.status(500).json({ error: 'Internal server error' });
} }
} }

View file

@ -12,7 +12,12 @@ import { Language } from '../content/language.js';
@Entity() @Entity()
export class Assignment { export class Assignment {
@ManyToOne({ entity: () => {return Class}, primary: true }) @ManyToOne({
entity: () => {
return Class;
},
primary: true,
})
within!: Class; within!: Class;
@PrimaryKey({ type: 'number' }) @PrimaryKey({ type: 'number' })
@ -27,9 +32,18 @@ export class Assignment {
@Property({ type: 'string' }) @Property({ type: 'string' })
learningPathHruid!: string; learningPathHruid!: string;
@Enum({ items: () => {return Language} }) @Enum({
items: () => {
return Language;
},
})
learningPathLanguage!: Language; learningPathLanguage!: Language;
@OneToMany({ entity: () => {return Group}, mappedBy: 'assignment' }) @OneToMany({
entity: () => {
return Group;
},
mappedBy: 'assignment',
})
groups!: Group[]; groups!: Group[];
} }

View file

@ -4,12 +4,21 @@ import { Student } from '../users/student.entity.js';
@Entity() @Entity()
export class Group { export class Group {
@ManyToOne({ entity: () => {return Assignment}, primary: true }) @ManyToOne({
entity: () => {
return Assignment;
},
primary: true,
})
assignment!: Assignment; assignment!: Assignment;
@PrimaryKey({ type: 'integer' }) @PrimaryKey({ type: 'integer' })
groupNumber!: number; groupNumber!: number;
@ManyToMany({ entity: () => {return Student} }) @ManyToMany({
entity: () => {
return Student;
},
})
members!: Student[]; members!: Student[];
} }

View file

@ -8,7 +8,12 @@ export class Submission {
@PrimaryKey({ type: 'string' }) @PrimaryKey({ type: 'string' })
learningObjectHruid!: string; learningObjectHruid!: string;
@Enum({ items: () => {return Language}, primary: true }) @Enum({
items: () => {
return Language;
},
primary: true,
})
learningObjectLanguage!: Language; learningObjectLanguage!: Language;
@PrimaryKey({ type: 'string' }) @PrimaryKey({ type: 'string' })
@ -17,13 +22,22 @@ export class Submission {
@PrimaryKey({ type: 'integer' }) @PrimaryKey({ type: 'integer' })
submissionNumber!: number; submissionNumber!: number;
@ManyToOne({ entity: () => {return Student} }) @ManyToOne({
entity: () => {
return Student;
},
})
submitter!: Student; submitter!: Student;
@Property({ type: 'datetime' }) @Property({ type: 'datetime' })
submissionTime!: Date; submissionTime!: Date;
@ManyToOne({ entity: () => {return Group}, nullable: true }) @ManyToOne({
entity: () => {
return Group;
},
nullable: true,
})
onBehalfOf?: Group; onBehalfOf?: Group;
@Property({ type: 'json' }) @Property({ type: 'json' })

View file

@ -4,13 +4,25 @@ import { Class } from './class.entity.js';
@Entity() @Entity()
export class ClassJoinRequest { export class ClassJoinRequest {
@ManyToOne({ entity: () => {return Student}, primary: true }) @ManyToOne({
entity: () => {
return Student;
},
primary: true,
})
requester!: Student; requester!: Student;
@ManyToOne({ entity: () => {return Class}, primary: true }) @ManyToOne({
entity: () => {
return Class;
},
primary: true,
})
class!: Class; class!: Class;
@Enum(() => {return ClassJoinRequestStatus}) @Enum(() => {
return ClassJoinRequestStatus;
})
status!: ClassJoinRequestStatus; status!: ClassJoinRequestStatus;
} }

View file

@ -17,9 +17,13 @@ export class Class {
@Property({ type: 'string' }) @Property({ type: 'string' })
displayName!: string; displayName!: string;
@ManyToMany(() => {return Teacher}) @ManyToMany(() => {
return Teacher;
})
teachers!: Collection<Teacher>; teachers!: Collection<Teacher>;
@ManyToMany(() => {return Student}) @ManyToMany(() => {
return Student;
})
students!: Collection<Student>; students!: Collection<Student>;
} }

View file

@ -7,12 +7,27 @@ import { Class } from './class.entity.js';
*/ */
@Entity() @Entity()
export class TeacherInvitation { export class TeacherInvitation {
@ManyToOne({ entity: () => {return Teacher}, primary: true }) @ManyToOne({
entity: () => {
return Teacher;
},
primary: true,
})
sender!: Teacher; sender!: Teacher;
@ManyToOne({ entity: () => {return Teacher}, primary: true }) @ManyToOne({
entity: () => {
return Teacher;
},
primary: true,
})
receiver!: Teacher; receiver!: Teacher;
@ManyToOne({ entity: () => {return Class}, primary: true }) @ManyToOne({
entity: () => {
return Class;
},
primary: true,
})
class!: Class; class!: Class;
} }

View file

@ -3,7 +3,12 @@ import { LearningObject } from './learning-object.entity.js';
@Entity() @Entity()
export class Attachment { export class Attachment {
@ManyToOne({ entity: () => {return LearningObject}, primary: true }) @ManyToOne({
entity: () => {
return LearningObject;
},
primary: true,
})
learningObject!: LearningObject; learningObject!: LearningObject;
@PrimaryKey({ type: 'integer' }) @PrimaryKey({ type: 'integer' })

View file

@ -17,13 +17,22 @@ export class LearningObject {
@PrimaryKey({ type: 'string' }) @PrimaryKey({ type: 'string' })
hruid!: string; hruid!: string;
@Enum({ items: () => {return Language}, primary: true }) @Enum({
items: () => {
return Language;
},
primary: true,
})
language!: Language; language!: Language;
@PrimaryKey({ type: 'string' }) @PrimaryKey({ type: 'string' })
version: string = '1'; version: string = '1';
@ManyToMany({ entity: () => {return Teacher} }) @ManyToMany({
entity: () => {
return Teacher;
},
})
admins!: Teacher[]; admins!: Teacher[];
@Property({ type: 'string' }) @Property({ type: 'string' })
@ -47,7 +56,12 @@ export class LearningObject {
@Property({ type: 'array' }) @Property({ type: 'array' })
skosConcepts!: string[]; skosConcepts!: string[];
@Embedded({ entity: () => {return EducationalGoal}, array: true }) @Embedded({
entity: () => {
return EducationalGoal;
},
array: true,
})
educationalGoals: EducationalGoal[] = []; educationalGoals: EducationalGoal[] = [];
@Property({ type: 'string' }) @Property({ type: 'string' })
@ -62,7 +76,11 @@ export class LearningObject {
@Property({ type: 'integer' }) @Property({ type: 'integer' })
estimatedTime!: number; estimatedTime!: number;
@Embedded({ entity: () => {return ReturnValue} }) @Embedded({
entity: () => {
return ReturnValue;
},
})
returnValue!: ReturnValue; returnValue!: ReturnValue;
@Property({ type: 'bool' }) @Property({ type: 'bool' })
@ -71,7 +89,12 @@ export class LearningObject {
@Property({ type: 'string', nullable: true }) @Property({ type: 'string', nullable: true })
contentLocation?: string; contentLocation?: string;
@OneToMany({ entity: () => {return Attachment}, mappedBy: 'learningObject' }) @OneToMany({
entity: () => {
return Attachment;
},
mappedBy: 'learningObject',
})
attachments: Attachment[] = []; attachments: Attachment[] = [];
@Property({ type: 'blob' }) @Property({ type: 'blob' })

View file

@ -16,10 +16,19 @@ export class LearningPath {
@PrimaryKey({ type: 'string' }) @PrimaryKey({ type: 'string' })
hruid!: string; hruid!: string;
@Enum({ items: () => {return Language}, primary: true }) @Enum({
items: () => {
return Language;
},
primary: true,
})
language!: Language; language!: Language;
@ManyToMany({ entity: () => {return Teacher} }) @ManyToMany({
entity: () => {
return Teacher;
},
})
admins!: Teacher[]; admins!: Teacher[];
@Property({ type: 'string' }) @Property({ type: 'string' })
@ -31,7 +40,12 @@ export class LearningPath {
@Property({ type: 'blob' }) @Property({ type: 'blob' })
image!: string; image!: string;
@Embedded({ entity: () => {return LearningPathNode}, array: true }) @Embedded({
entity: () => {
return LearningPathNode;
},
array: true,
})
nodes: LearningPathNode[] = []; nodes: LearningPathNode[] = [];
} }
@ -40,7 +54,11 @@ export class LearningPathNode {
@Property({ type: 'string' }) @Property({ type: 'string' })
learningObjectHruid!: string; learningObjectHruid!: string;
@Enum({ items: () => {return Language} }) @Enum({
items: () => {
return Language;
},
})
language!: Language; language!: Language;
@Property({ type: 'string' }) @Property({ type: 'string' })
@ -52,7 +70,12 @@ export class LearningPathNode {
@Property({ type: 'bool' }) @Property({ type: 'bool' })
startNode!: boolean; startNode!: boolean;
@Embedded({ entity: () => {return LearningPathTransition}, array: true }) @Embedded({
entity: () => {
return LearningPathTransition;
},
array: true,
})
transitions!: LearningPathTransition[]; transitions!: LearningPathTransition[];
} }
@ -61,6 +84,10 @@ export class LearningPathTransition {
@Property({ type: 'string' }) @Property({ type: 'string' })
condition!: string; condition!: string;
@OneToOne({ entity: () => {return LearningPathNode} }) @OneToOne({
entity: () => {
return LearningPathNode;
},
})
next!: LearningPathNode; next!: LearningPathNode;
} }

View file

@ -4,10 +4,20 @@ import { Teacher } from '../users/teacher.entity';
@Entity() @Entity()
export class Answer { export class Answer {
@ManyToOne({ entity: () => {return Teacher}, primary: true }) @ManyToOne({
entity: () => {
return Teacher;
},
primary: true,
})
author!: Teacher; author!: Teacher;
@ManyToOne({ entity: () => {return Question}, primary: true }) @ManyToOne({
entity: () => {
return Question;
},
primary: true,
})
toQuestion!: Question; toQuestion!: Question;
@PrimaryKey({ type: 'integer' }) @PrimaryKey({ type: 'integer' })

View file

@ -7,7 +7,12 @@ export class Question {
@PrimaryKey({ type: 'string' }) @PrimaryKey({ type: 'string' })
learningObjectHruid!: string; learningObjectHruid!: string;
@Enum({ items: () => {return Language}, primary: true }) @Enum({
items: () => {
return Language;
},
primary: true,
})
learningObjectLanguage!: Language; learningObjectLanguage!: Language;
@PrimaryKey({ type: 'string' }) @PrimaryKey({ type: 'string' })
@ -16,7 +21,11 @@ export class Question {
@PrimaryKey({ type: 'integer' }) @PrimaryKey({ type: 'integer' })
sequenceNumber!: number; sequenceNumber!: number;
@ManyToOne({ entity: () => {return Student} }) @ManyToOne({
entity: () => {
return Student;
},
})
author!: Student; author!: Student;
@Property({ type: 'datetime' }) @Property({ type: 'datetime' })

View file

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

View file

@ -4,6 +4,8 @@ import { Class } from '../classes/class.entity.js';
@Entity() @Entity()
export class Teacher extends User { export class Teacher extends User {
@ManyToMany(() => {return Class}) @ManyToMany(() => {
return Class;
})
classes!: Collection<Class>; classes!: Collection<Class>;
} }

View file

@ -1,13 +1,10 @@
import express from 'express' import express from 'express';
const router = express.Router(); const router = express.Router();
// Root endpoint used to search objects // Root endpoint used to search objects
router.get('/', (req, res) => { router.get('/', (req, res) => {
res.json({ res.json({
assignments: [ assignments: ['0', '1'],
'0',
'1',
]
}); });
}); });
@ -25,30 +22,24 @@ router.get('/:id', (req, res) => {
submissions: `${req.baseUrl}/${req.params.id}`, submissions: `${req.baseUrl}/${req.params.id}`,
}, },
}); });
}) });
router.get('/:id/submissions', (req, res) => { router.get('/:id/submissions', (req, res) => {
res.json({ res.json({
submissions: [ submissions: ['0'],
'0'
],
}); });
}); });
router.get('/:id/groups', (req, res) => { router.get('/:id/groups', (req, res) => {
res.json({ res.json({
groups: [ groups: ['0'],
'0'
],
}); });
}); });
router.get('/:id/questions', (req, res) => { router.get('/:id/questions', (req, res) => {
res.json({ res.json({
questions: [ questions: ['0'],
'0'
],
}); });
}); });
export default router export default router;

View file

@ -1,13 +1,10 @@
import express from 'express' import express from 'express';
const router = express.Router(); const router = express.Router();
// Root endpoint used to search objects // Root endpoint used to search objects
router.get('/', (req, res) => { router.get('/', (req, res) => {
res.json({ res.json({
classes: [ classes: ['0', '1'],
'0',
'1',
]
}); });
}); });
@ -24,32 +21,26 @@ router.get('/:id', (req, res) => {
classes: `${req.baseUrl}/${req.params.id}/invitations`, classes: `${req.baseUrl}/${req.params.id}/invitations`,
questions: `${req.baseUrl}/${req.params.id}/assignments`, questions: `${req.baseUrl}/${req.params.id}/assignments`,
students: `${req.baseUrl}/${req.params.id}/students`, students: `${req.baseUrl}/${req.params.id}/students`,
} },
});
}); });
})
router.get('/:id/invitations', (req, res) => { router.get('/:id/invitations', (req, res) => {
res.json({ res.json({
invitations: [ invitations: ['0'],
'0' });
],
}); });
})
router.get('/:id/assignments', (req, res) => { router.get('/:id/assignments', (req, res) => {
res.json({ res.json({
assignments: [ assignments: ['0'],
'0' });
],
}); });
})
router.get('/:id/students', (req, res) => { router.get('/:id/students', (req, res) => {
res.json({ res.json({
students: [ students: ['0'],
'0' });
],
}); });
})
export default router export default router;

View file

@ -1,13 +1,10 @@
import express from 'express' import express from 'express';
const router = express.Router(); const router = express.Router();
// Root endpoint used to search objects // Root endpoint used to search objects
router.get('/', (req, res) => { router.get('/', (req, res) => {
res.json({ res.json({
groups: [ groups: ['0', '1'],
'0',
'1',
]
}); });
}); });
@ -22,13 +19,13 @@ router.get('/:id', (req, res) => {
// Should be less hardcoded // Should be less hardcoded
questions: `/group/${req.params.id}/question`, questions: `/group/${req.params.id}/question`,
}); });
}) });
// The list of questions a group has made // The list of questions a group has made
router.get('/:id/question', (req, res) => { router.get('/:id/question', (req, res) => {
res.json({ res.json({
questions: ['0'], questions: ['0'],
}); });
}) });
export default router export default router;

View file

@ -1,4 +1,4 @@
import express from 'express' import express from 'express';
const router = express.Router(); const router = express.Router();
// Returns login paths for IDP // Returns login paths for IDP
@ -9,6 +9,6 @@ router.get('/', (req, res) => {
leerkracht: '/login-leerkracht', leerkracht: '/login-leerkracht',
leerling: '/login-leerling', leerling: '/login-leerling',
}); });
}) });
export default router export default router;

View file

@ -1,13 +1,10 @@
import express from 'express' import express from 'express';
const router = express.Router(); const router = express.Router();
// Root endpoint used to search objects // Root endpoint used to search objects
router.get('/', (req, res) => { router.get('/', (req, res) => {
res.json({ res.json({
questions: [ questions: ['0', '1'],
'0',
'1',
]
}); });
}); });
@ -18,21 +15,20 @@ router.get('/:id', (req, res) => {
student: '0', student: '0',
group: '0', group: '0',
time: new Date(2025, 1, 1), time: new Date(2025, 1, 1),
content: 'Zijn alle gehele getallen groter dan 2 gelijk aan de som van 2 priemgetallen????', content:
'Zijn alle gehele getallen groter dan 2 gelijk aan de som van 2 priemgetallen????',
learningObject: '0', learningObject: '0',
links: { links: {
self: `${req.baseUrl}/${req.params.id}`, self: `${req.baseUrl}/${req.params.id}`,
answers: `${req.baseUrl}/${req.params.id}/answers`, answers: `${req.baseUrl}/${req.params.id}/answers`,
} },
});
}); });
})
router.get('/:id/answers', (req, res) => { router.get('/:id/answers', (req, res) => {
res.json({ res.json({
answers: [ answers: ['0'],
'0' });
], });
})
})
export default router export default router;

View file

@ -1,13 +1,10 @@
import express from 'express' import express from 'express';
const router = express.Router(); const router = express.Router();
// Root endpoint used to search objects // Root endpoint used to search objects
router.get('/', (req, res) => { router.get('/', (req, res) => {
res.json({ res.json({
students: [ students: ['0', '1'],
'0',
'1',
]
}); });
}); });
@ -32,28 +29,27 @@ router.get('/:id/classes', (req, res) => {
res.json({ res.json({
classes: ['0'], classes: ['0'],
}); });
}) });
// The list of submissions a student has made // The list of submissions a student has made
router.get('/:id/submissions', (req, res) => { router.get('/:id/submissions', (req, res) => {
res.json({ res.json({
submissions: ['0'], submissions: ['0'],
}); });
}) });
// The list of assignments a student has // The list of assignments a student has
router.get('/:id/assignments', (req, res) => { router.get('/:id/assignments', (req, res) => {
res.json({ res.json({
assignments: ['0'], assignments: ['0'],
}); });
}) });
// The list of groups a student is in // The list of groups a student is in
router.get('/:id/groups', (req, res) => { router.get('/:id/groups', (req, res) => {
res.json({ res.json({
groups: ['0'], groups: ['0'],
}); });
}) });
export default router export default router;

View file

@ -1,13 +1,10 @@
import express from 'express' import express from 'express';
const router = express.Router(); const router = express.Router();
// Root endpoint used to search objects // Root endpoint used to search objects
router.get('/', (req, res) => { router.get('/', (req, res) => {
res.json({ res.json({
submissions: [ submissions: ['0', '1'],
'0',
'1',
]
}); });
}); });
@ -21,6 +18,6 @@ router.get('/:id', (req, res) => {
content: 'Wortel 2 is rationeel', content: 'Wortel 2 is rationeel',
learningObject: '0', learningObject: '0',
}); });
}) });
export default router export default router;

View file

@ -1,13 +1,10 @@
import express from 'express' import express from 'express';
const router = express.Router(); const router = express.Router();
// Root endpoint used to search objects // Root endpoint used to search objects
router.get('/', (req, res) => { router.get('/', (req, res) => {
res.json({ res.json({
teachers: [ teachers: ['0', '1'],
'0',
'1',
]
}); });
}); });
@ -25,34 +22,27 @@ router.get('/:id', (req, res) => {
invitations: `${req.baseUrl}/${req.params.id}/invitations`, invitations: `${req.baseUrl}/${req.params.id}/invitations`,
}, },
}); });
}) });
// The questions students asked a teacher // The questions students asked a teacher
router.get('/:id/questions', (req, res) => { router.get('/:id/questions', (req, res) => {
res.json({ res.json({
questions: [ questions: ['0'],
'0'
],
}); });
}); });
// Invitations to other classes a teacher received // Invitations to other classes a teacher received
router.get('/:id/invitations', (req, res) => { router.get('/:id/invitations', (req, res) => {
res.json({ res.json({
invitations: [ invitations: ['0'],
'0'
],
}); });
}); });
// A list with ids of classes a teacher is in // A list with ids of classes a teacher is in
router.get('/:id/classes', (req, res) => { router.get('/:id/classes', (req, res) => {
res.json({ res.json({
classes: [ classes: ['0'],
'0'
],
}); });
}); });
export default router;
export default router

View file

@ -1,6 +1,9 @@
import { fetchWithLogging } from '../util/apiHelper.js'; import { fetchWithLogging } from '../util/apiHelper.js';
import { DWENGO_API_BASE } from '../config.js'; import { DWENGO_API_BASE } from '../config.js';
import { LearningPath, LearningPathResponse } from '../interfaces/learningPath.js'; import {
LearningPath,
LearningPathResponse,
} from '../interfaces/learningPath.js';
import { getLogger, Logger } from '../logging/initalize.js'; import { getLogger, Logger } from '../logging/initalize.js';
const logger: Logger = getLogger(); const logger: Logger = getLogger();