Merge remote-tracking branch 'origin/dev' into feat/pagina-om-leerpaden-te-bekijken-#41

# Conflicts:
#	backend/src/controllers/learning-objects.ts
#	frontend/src/controllers/base-controller.ts
This commit is contained in:
Gerald Schmittinger 2025-04-01 09:00:28 +02:00
commit 99dc346dc1
155 changed files with 3463 additions and 2931 deletions

View file

@ -2,7 +2,7 @@ import { Request, Response } from 'express';
import { createAssignment, getAllAssignments, getAssignment, getAssignmentsSubmissions } from '../services/assignments.js';
import { AssignmentDTO } from '../interfaces/assignment.js';
// Typescript is annoy with with parameter forwarding from class.ts
// Typescript is annoying with parameter forwarding from class.ts
interface AssignmentParams {
classid: string;
id: string;
@ -41,7 +41,7 @@ export async function createAssignmentHandler(req: Request<AssignmentParams>, re
}
export async function getAssignmentHandler(req: Request<AssignmentParams>, res: Response): Promise<void> {
const id = +req.params.id;
const id = Number(req.params.id);
const classid = req.params.classid;
if (isNaN(id)) {
@ -61,7 +61,7 @@ export async function getAssignmentHandler(req: Request<AssignmentParams>, res:
export async function getAssignmentsSubmissionsHandler(req: Request<AssignmentParams>, res: Response): Promise<void> {
const classid = req.params.classid;
const assignmentNumber = +req.params.id;
const assignmentNumber = Number(req.params.id);
const full = req.query.full === 'true';
if (isNaN(assignmentNumber)) {

View file

@ -1,16 +1,16 @@
import { EnvVars, getEnvVar } from '../util/envvars.js';
import { envVars, getEnvVar } from '../util/envVars.js';
type FrontendIdpConfig = {
interface FrontendIdpConfig {
authority: string;
clientId: string;
scope: string;
responseType: string;
};
}
type FrontendAuthConfig = {
interface FrontendAuthConfig {
student: FrontendIdpConfig;
teacher: FrontendIdpConfig;
};
}
const SCOPE = 'openid profile email';
const RESPONSE_TYPE = 'code';
@ -18,14 +18,14 @@ const RESPONSE_TYPE = 'code';
export function getFrontendAuthConfig(): FrontendAuthConfig {
return {
student: {
authority: getEnvVar(EnvVars.IdpStudentUrl),
clientId: getEnvVar(EnvVars.IdpStudentClientId),
authority: getEnvVar(envVars.IdpStudentUrl),
clientId: getEnvVar(envVars.IdpStudentClientId),
scope: SCOPE,
responseType: RESPONSE_TYPE,
},
teacher: {
authority: getEnvVar(EnvVars.IdpTeacherUrl),
clientId: getEnvVar(EnvVars.IdpTeacherClientId),
authority: getEnvVar(envVars.IdpTeacherUrl),
clientId: getEnvVar(envVars.IdpTeacherClientId),
scope: SCOPE,
responseType: RESPONSE_TYPE,
},

View file

@ -12,14 +12,14 @@ interface GroupParams {
export async function getGroupHandler(req: Request<GroupParams>, res: Response): Promise<void> {
const classId = req.params.classid;
const full = req.query.full === 'true';
const assignmentId = +req.params.assignmentid;
const assignmentId = Number(req.params.assignmentid);
if (isNaN(assignmentId)) {
res.status(400).json({ error: 'Assignment id must be a number' });
return;
}
const groupId = +req.params.groupid!; // Can't be undefined
const groupId = Number(req.params.groupid!); // Can't be undefined
if (isNaN(groupId)) {
res.status(400).json({ error: 'Group id must be a number' });
@ -40,7 +40,7 @@ export async function getAllGroupsHandler(req: Request, res: Response): Promise<
const classId = req.params.classid;
const full = req.query.full === 'true';
const assignmentId = +req.params.assignmentid;
const assignmentId = Number(req.params.assignmentid);
if (isNaN(assignmentId)) {
res.status(400).json({ error: 'Assignment id must be a number' });
@ -56,7 +56,7 @@ export async function getAllGroupsHandler(req: Request, res: Response): Promise<
export async function createGroupHandler(req: Request, res: Response): Promise<void> {
const classid = req.params.classid;
const assignmentId = +req.params.assignmentid;
const assignmentId = Number(req.params.assignmentid);
if (isNaN(assignmentId)) {
res.status(400).json({ error: 'Assignment id must be a number' });
@ -78,14 +78,14 @@ export async function getGroupSubmissionsHandler(req: Request, res: Response): P
const classId = req.params.classid;
const full = req.query.full === 'true';
const assignmentId = +req.params.assignmentid;
const assignmentId = Number(req.params.assignmentid);
if (isNaN(assignmentId)) {
res.status(400).json({ error: 'Assignment id must be a number' });
return;
}
const groupId = +req.params.groupid!; // Can't be undefined
const groupId = Number(req.params.groupid); // Can't be undefined
if (isNaN(groupId)) {
res.status(400).json({ error: 'Group id must be a number' });

View file

@ -2,18 +2,19 @@ import { Request, Response } from 'express';
import { FALLBACK_LANG } from '../config.js';
import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../interfaces/learning-content.js';
import learningObjectService from '../services/learning-objects/learning-object-service.js';
import { EnvVars, getEnvVar } from '../util/envvars.js';
import { Language } from '../entities/content/language.js';
import {BadRequestException, NotFoundException} from '../exceptions.js';
import attachmentService from '../services/learning-objects/attachment-service.js';
import { BadRequestException } from '../exceptions/bad-request-exception.js';
import { NotFoundException } from '../exceptions/not-found-exception.js';
import { envVars, getEnvVar } from '../util/envVars.js';
function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIdentifier {
if (!req.params.hruid) {
throw new BadRequestException('HRUID is required.');
}
return {
hruid: req.params.hruid as string,
language: (req.query.language || getEnvVar(EnvVars.FallbackLanguage)) as Language,
hruid: req.params.hruid,
language: (req.query.language || getEnvVar(envVars.FallbackLanguage)) as Language,
version: parseInt(req.query.version as string),
};
}
@ -23,7 +24,7 @@ function getLearningPathIdentifierFromRequest(req: Request): LearningPathIdentif
throw new BadRequestException('HRUID is required.');
}
return {
hruid: req.params.hruid as string,
hruid: req.params.hruid,
language: (req.query.language as Language) || FALLBACK_LANG,
};
}

View file

@ -2,13 +2,14 @@ import { Request, Response } from 'express';
import { themes } from '../data/themes.js';
import { FALLBACK_LANG } from '../config.js';
import learningPathService from '../services/learning-paths/learning-path-service.js';
import { BadRequestException, NotFoundException } from '../exceptions.js';
import { Language } from '../entities/content/language.js';
import {
PersonalizationTarget,
personalizedForGroup,
personalizedForStudent,
} from '../services/learning-paths/learning-path-personalization-util.js';
import { BadRequestException } from '../exceptions/bad-request-exception.js';
import { NotFoundException } from '../exceptions/not-found-exception.js';
/**
* Fetch learning paths based on query parameters.

View file

@ -17,7 +17,7 @@ function getObjectId(req: Request, res: Response): LearningObjectIdentifier | nu
return {
hruid,
language: (lang as Language) || FALLBACK_LANG,
version: +version,
version: Number(version),
};
}

View file

@ -46,7 +46,7 @@ export async function getStudentHandler(req: Request, res: Response): Promise<vo
res.json(user);
}
export async function createStudentHandler(req: Request, res: Response) {
export async function createStudentHandler(req: Request, res: Response): Promise<void> {
const userData = req.body as StudentDTO;
if (!userData.username || !userData.firstName || !userData.lastName) {
@ -68,7 +68,7 @@ export async function createStudentHandler(req: Request, res: Response) {
res.status(201).json(newUser);
}
export async function deleteStudentHandler(req: Request, res: Response) {
export async function deleteStudentHandler(req: Request, res: Response): Promise<void> {
const username = req.params.username;
if (!username) {
@ -93,9 +93,7 @@ export async function getStudentClassesHandler(req: Request, res: Response): Pro
const classes = await getStudentClasses(username, full);
res.json({
classes: classes,
});
res.json({ classes: classes });
}
// TODO

View file

@ -10,7 +10,7 @@ interface SubmissionParams {
export async function getSubmissionHandler(req: Request<SubmissionParams>, res: Response): Promise<void> {
const lohruid = req.params.hruid;
const submissionNumber = +req.params.id;
const submissionNumber = Number(req.params.id);
if (isNaN(submissionNumber)) {
res.status(400).json({ error: 'Submission number is not a number' });
@ -30,7 +30,7 @@ export async function getSubmissionHandler(req: Request<SubmissionParams>, res:
res.json(submission);
}
export async function createSubmissionHandler(req: Request, res: Response) {
export async function createSubmissionHandler(req: Request, res: Response): Promise<void> {
const submissionDTO = req.body as SubmissionDTO;
const submission = await createSubmission(submissionDTO);
@ -43,9 +43,9 @@ export async function createSubmissionHandler(req: Request, res: Response) {
res.json(submission);
}
export async function deleteSubmissionHandler(req: Request, res: Response) {
export async function deleteSubmissionHandler(req: Request, res: Response): Promise<void> {
const hruid = req.params.hruid;
const submissionNumber = +req.params.id;
const submissionNumber = Number(req.params.id);
const lang = languageMap[req.query.language as string] || Language.Dutch;
const version = (req.query.version || 1) as number;

View file

@ -43,7 +43,7 @@ export async function getTeacherHandler(req: Request, res: Response): Promise<vo
res.json(user);
}
export async function createTeacherHandler(req: Request, res: Response) {
export async function createTeacherHandler(req: Request, res: Response): Promise<void> {
const userData = req.body as TeacherDTO;
if (!userData.username || !userData.firstName || !userData.lastName) {
@ -63,7 +63,7 @@ export async function createTeacherHandler(req: Request, res: Response) {
res.status(201).json(newUser);
}
export async function deleteTeacherHandler(req: Request, res: Response) {
export async function deleteTeacherHandler(req: Request, res: Response): Promise<void> {
const username = req.params.username;
if (!username) {
@ -83,7 +83,7 @@ export async function deleteTeacherHandler(req: Request, res: Response) {
}
export async function getTeacherClassHandler(req: Request, res: Response): Promise<void> {
const username = req.params.username as string;
const username = req.params.username;
const full = req.query.full === 'true';
if (!username) {
@ -102,7 +102,7 @@ export async function getTeacherClassHandler(req: Request, res: Response): Promi
}
export async function getTeacherStudentHandler(req: Request, res: Response): Promise<void> {
const username = req.params.username as string;
const username = req.params.username;
const full = req.query.full === 'true';
if (!username) {
@ -121,7 +121,7 @@ export async function getTeacherStudentHandler(req: Request, res: Response): Pro
}
export async function getTeacherQuestionHandler(req: Request, res: Response): Promise<void> {
const username = req.params.username as string;
const username = req.params.username;
const full = req.query.full === 'true';
if (!username) {

View file

@ -3,25 +3,23 @@ import { themes } from '../data/themes.js';
import { loadTranslations } from '../util/translation-helper.js';
interface Translations {
curricula_page: {
[key: string]: { title: string; description?: string };
};
curricula_page: Record<string, { title: string; description?: string }>;
}
export function getThemesHandler(req: Request, res: Response) {
const language = (req.query.language as string)?.toLowerCase() || 'nl';
export function getThemesHandler(req: Request, res: Response): void {
const language = ((req.query.language as string) || 'nl').toLowerCase();
const translations = loadTranslations<Translations>(language);
const themeList = themes.map((theme) => ({
key: theme.title,
title: translations.curricula_page[theme.title]?.title || theme.title,
description: translations.curricula_page[theme.title]?.description,
title: translations.curricula_page[theme.title].title || theme.title,
description: translations.curricula_page[theme.title].description,
image: `https://dwengo.org/images/curricula/logo_${theme.title}.png`,
}));
res.json(themeList);
}
export function getHruidsByThemeHandler(req: Request, res: Response) {
export function getHruidsByThemeHandler(req: Request, res: Response): void {
const themeKey = req.params.theme;
if (!themeKey) {