refactor(backend): Functions
This commit is contained in:
parent
5ec62554e3
commit
65c1a5e6b6
57 changed files with 172 additions and 117 deletions
|
|
@ -79,7 +79,7 @@ export async function getAssignmentsSubmissions(classid: string, assignmentNumbe
|
|||
const groups = await groupRepository.findAllGroupsForAssignment(assignment);
|
||||
|
||||
const submissionRepository = getSubmissionRepository();
|
||||
const submissions = (await Promise.all(groups.map((group) => submissionRepository.findAllSubmissionsForGroup(group)))).flat();
|
||||
const submissions = (await Promise.all(groups.map(async (group) => submissionRepository.findAllSubmissionsForGroup(group)))).flat();
|
||||
|
||||
return submissions.map(mapToSubmissionDTO);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,15 @@ export async function getAllClasses(full: boolean): Promise<ClassDTO[] | string[
|
|||
export async function createClass(classData: ClassDTO): Promise<Class | null> {
|
||||
const teacherRepository = getTeacherRepository();
|
||||
const teacherUsernames = classData.teachers || [];
|
||||
const teachers = (await Promise.all(teacherUsernames.map((id) => teacherRepository.findByUsername(id)))).filter((teacher) => teacher != null);
|
||||
const teachers = (await Promise.all(teacherUsernames.map(async (id) => teacherRepository.findByUsername(id)))).filter(
|
||||
(teacher) => teacher != null
|
||||
);
|
||||
|
||||
const studentRepository = getStudentRepository();
|
||||
const studentUsernames = classData.students || [];
|
||||
const students = (await Promise.all(studentUsernames.map((id) => studentRepository.findByUsername(id)))).filter((student) => student != null);
|
||||
const students = (await Promise.all(studentUsernames.map(async (id) => studentRepository.findByUsername(id)))).filter(
|
||||
(student) => student != null
|
||||
);
|
||||
|
||||
//Const cls = mapToClass(classData, teachers, students);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,9 @@ export async function createGroup(groupData: GroupDTO, classid: string, assignme
|
|||
const studentRepository = getStudentRepository();
|
||||
|
||||
const memberUsernames = (groupData.members as string[]) || []; // TODO check if groupdata.members is a list
|
||||
const members = (await Promise.all([...memberUsernames].map((id) => studentRepository.findByUsername(id)))).filter((student) => student != null);
|
||||
const members = (await Promise.all([...memberUsernames].map(async (id) => studentRepository.findByUsername(id)))).filter(
|
||||
(student) => student != null
|
||||
);
|
||||
|
||||
getLogger().debug(members);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Attachment } from '../../entities/content/attachment.entity.js';
|
|||
import { LearningObjectIdentifier } from '../../interfaces/learning-content.js';
|
||||
|
||||
const attachmentService = {
|
||||
getAttachment(learningObjectId: LearningObjectIdentifier, attachmentName: string): Promise<Attachment | null> {
|
||||
async getAttachment(learningObjectId: LearningObjectIdentifier, attachmentName: string): Promise<Attachment | null> {
|
||||
const attachmentRepo = getAttachmentRepository();
|
||||
|
||||
if (learningObjectId.version) {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ function convertLearningObject(learningObject: LearningObject | null): FilteredL
|
|||
};
|
||||
}
|
||||
|
||||
function findLearningObjectEntityById(id: LearningObjectIdentifier): Promise<LearningObject | null> {
|
||||
async function findLearningObjectEntityById(id: LearningObjectIdentifier): Promise<LearningObject | null> {
|
||||
const learningObjectRepo = getLearningObjectRepository();
|
||||
|
||||
return learningObjectRepo.findLatestByHruidAndLanguage(id.hruid, id.language as Language);
|
||||
|
|
@ -69,7 +69,7 @@ const databaseLearningObjectProvider: LearningObjectProvider = {
|
|||
if (!learningObject) {
|
||||
return null;
|
||||
}
|
||||
return await processingService.render(learningObject, (id) => findLearningObjectEntityById(id));
|
||||
return await processingService.render(learningObject, async (id) => findLearningObjectEntityById(id));
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -96,7 +96,7 @@ const databaseLearningObjectProvider: LearningObjectProvider = {
|
|||
throw new NotFoundError('The learning path with the given ID could not be found.');
|
||||
}
|
||||
const learningObjects = await Promise.all(
|
||||
learningPath.nodes.map((it) => {
|
||||
learningPath.nodes.map(async (it) => {
|
||||
const learningObject = learningObjectService.getLearningObjectById({
|
||||
hruid: it.learningObjectHruid,
|
||||
language: it.language,
|
||||
|
|
|
|||
|
|
@ -18,28 +18,28 @@ const learningObjectService = {
|
|||
/**
|
||||
* Fetches a single learning object by its HRUID
|
||||
*/
|
||||
getLearningObjectById(id: LearningObjectIdentifier): Promise<FilteredLearningObject | null> {
|
||||
async getLearningObjectById(id: LearningObjectIdentifier): Promise<FilteredLearningObject | null> {
|
||||
return getProvider(id).getLearningObjectById(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch full learning object data (metadata)
|
||||
*/
|
||||
getLearningObjectsFromPath(id: LearningPathIdentifier): Promise<FilteredLearningObject[]> {
|
||||
async getLearningObjectsFromPath(id: LearningPathIdentifier): Promise<FilteredLearningObject[]> {
|
||||
return getProvider(id).getLearningObjectsFromPath(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch only learning object HRUIDs
|
||||
*/
|
||||
getLearningObjectIdsFromPath(id: LearningPathIdentifier): Promise<string[]> {
|
||||
async getLearningObjectIdsFromPath(id: LearningPathIdentifier): Promise<string[]> {
|
||||
return getProvider(id).getLearningObjectIdsFromPath(id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Obtain a HTML-rendering of the learning object with the given identifier (as a string).
|
||||
*/
|
||||
getLearningObjectHTML(id: LearningObjectIdentifier): Promise<string | null> {
|
||||
async getLearningObjectHTML(id: LearningObjectIdentifier): Promise<string | null> {
|
||||
return getProvider(id).getLearningObjectHTML(id);
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class ExternProcessor extends StringProcessor {
|
|||
super(DwengoContentType.EXTERN);
|
||||
}
|
||||
|
||||
override renderFn(externURL: string) {
|
||||
override renderFn(externURL: string): string {
|
||||
if (!isValidHttpUrl(externURL)) {
|
||||
throw new ProcessingError('The url is not valid: ' + externURL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class GiftProcessor extends StringProcessor {
|
|||
super(DwengoContentType.GIFT);
|
||||
}
|
||||
|
||||
override renderFn(giftString: string) {
|
||||
override renderFn(giftString: string): string {
|
||||
const quizQuestions: GIFTQuestion[] = parse(giftString);
|
||||
|
||||
let html = "<div class='learning-object-gift'>\n";
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ class BlockImageProcessor extends InlineImageProcessor {
|
|||
super();
|
||||
}
|
||||
|
||||
override renderFn(imageUrl: string) {
|
||||
override renderFn(imageUrl: string): string {
|
||||
const inlineHtml = super.render(imageUrl);
|
||||
return DOMPurify.sanitize(`<div>${inlineHtml}</div>`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class InlineImageProcessor extends StringProcessor {
|
|||
super(contentType);
|
||||
}
|
||||
|
||||
override renderFn(imageUrl: string) {
|
||||
override renderFn(imageUrl: string): string {
|
||||
if (!isValidHttpUrl(imageUrl)) {
|
||||
throw new ProcessingError(`Image URL is invalid: ${imageUrl}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class MarkdownProcessor extends StringProcessor {
|
|||
super(DwengoContentType.TEXT_MARKDOWN);
|
||||
}
|
||||
|
||||
override renderFn(mdText: string) {
|
||||
override renderFn(mdText: string): string {
|
||||
try {
|
||||
marked.use({ renderer: dwengoMarkedRenderer });
|
||||
const html = marked(mdText, { async: false });
|
||||
|
|
@ -24,7 +24,7 @@ class MarkdownProcessor extends StringProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
replaceLinks(html: string) {
|
||||
replaceLinks(html: string): string {
|
||||
const proc = new InlineImageProcessor();
|
||||
html = html.replace(
|
||||
/<img.*?src="(.*?)".*?(alt="(.*?)")?.*?(title="(.*?)")?.*?>/g,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class PdfProcessor extends StringProcessor {
|
|||
super(DwengoContentType.APPLICATION_PDF);
|
||||
}
|
||||
|
||||
override renderFn(pdfUrl: string) {
|
||||
override renderFn(pdfUrl: string): string {
|
||||
if (!isValidHttpUrl(pdfUrl)) {
|
||||
throw new ProcessingError(`PDF URL is invalid: ${pdfUrl}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ import { DwengoContentType } from './content-type.js';
|
|||
* Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/processor.js
|
||||
*/
|
||||
abstract class Processor<T> {
|
||||
protected constructor(public contentType: DwengoContentType) {}
|
||||
protected constructor(public contentType: DwengoContentType) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the given object.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class TextProcessor extends StringProcessor {
|
|||
super(DwengoContentType.TEXT_PLAIN);
|
||||
}
|
||||
|
||||
override renderFn(text: string) {
|
||||
override renderFn(text: string): string {
|
||||
// Sanitize plain text to prevent xss.
|
||||
return DOMPurify.sanitize(text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ async function getLearningObjectsForNodes(nodes: LearningPathNode[]): Promise<Ma
|
|||
// Its corresponding learning object.
|
||||
const nullableNodesToLearningObjects = new Map<LearningPathNode, FilteredLearningObject | null>(
|
||||
await Promise.all(
|
||||
nodes.map((node) =>
|
||||
nodes.map(async (node) =>
|
||||
learningObjectService
|
||||
.getLearningObjectById({
|
||||
hruid: node.learningObjectHruid,
|
||||
|
|
@ -117,7 +117,7 @@ async function convertNodes(
|
|||
nodesToLearningObjects: Map<LearningPathNode, FilteredLearningObject>,
|
||||
personalizedFor?: PersonalizationTarget
|
||||
): Promise<LearningObjectNode[]> {
|
||||
const nodesPromise = Array.from(nodesToLearningObjects.entries()).map((entry) =>
|
||||
const nodesPromise = Array.from(nodesToLearningObjects.entries()).map(async (entry) =>
|
||||
convertNode(entry[0], entry[1], personalizedFor, nodesToLearningObjects)
|
||||
);
|
||||
return await Promise.all(nodesPromise);
|
||||
|
|
@ -179,11 +179,11 @@ const databaseLearningPathProvider: LearningPathProvider = {
|
|||
): Promise<LearningPathResponse> {
|
||||
const learningPathRepo = getLearningPathRepository();
|
||||
|
||||
const learningPaths = (await Promise.all(hruids.map((hruid) => learningPathRepo.findByHruidAndLanguage(hruid, language)))).filter(
|
||||
const learningPaths = (await Promise.all(hruids.map(async (hruid) => learningPathRepo.findByHruidAndLanguage(hruid, language)))).filter(
|
||||
(learningPath) => learningPath !== null
|
||||
);
|
||||
const filteredLearningPaths = await Promise.all(
|
||||
learningPaths.map((learningPath, index) => convertLearningPath(learningPath, index, personalizedFor))
|
||||
learningPaths.map(async (learningPath, index) => convertLearningPath(learningPath, index, personalizedFor))
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
@ -200,7 +200,7 @@ const databaseLearningPathProvider: LearningPathProvider = {
|
|||
const learningPathRepo = getLearningPathRepository();
|
||||
|
||||
const searchResults = await learningPathRepo.findByQueryStringAndLanguage(query, language);
|
||||
return await Promise.all(searchResults.map((result, index) => convertLearningPath(result, index, personalizedFor)));
|
||||
return await Promise.all(searchResults.map(async (result, index) => convertLearningPath(result, index, personalizedFor)));
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,9 @@ const learningPathService = {
|
|||
* Search learning paths in the data source using the given search string.
|
||||
*/
|
||||
async searchLearningPaths(query: string, language: Language, personalizedFor?: PersonalizationTarget): Promise<LearningPath[]> {
|
||||
const providerResponses = await Promise.all(allProviders.map((provider) => provider.searchLearningPaths(query, language, personalizedFor)));
|
||||
const providerResponses = await Promise.all(
|
||||
allProviders.map(async (provider) => provider.searchLearningPaths(query, language, personalizedFor))
|
||||
);
|
||||
return providerResponses.flat();
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { getAnswerRepository, getQuestionRepository } from '../data/repositories
|
|||
import { mapToQuestionDTO, mapToQuestionId, QuestionDTO, QuestionId } from '../interfaces/question.js';
|
||||
import { Question } from '../entities/questions/question.entity.js';
|
||||
import { Answer } from '../entities/questions/answer.entity.js';
|
||||
import { mapToAnswerDTO, mapToAnswerId } from '../interfaces/answer.js';
|
||||
import { AnswerDTO, AnswerId, mapToAnswerDTO, mapToAnswerId } from '../interfaces/answer.js';
|
||||
import { QuestionRepository } from '../data/questions/question-repository.js';
|
||||
import { LearningObjectIdentifier } from '../entities/content/learning-object-identifier.js';
|
||||
import { mapToStudent } from '../interfaces/student.js';
|
||||
|
|
@ -45,7 +45,7 @@ export async function getQuestion(questionId: QuestionId): Promise<QuestionDTO |
|
|||
return mapToQuestionDTO(question);
|
||||
}
|
||||
|
||||
export async function getAnswersByQuestion(questionId: QuestionId, full: boolean) {
|
||||
export async function getAnswersByQuestion(questionId: QuestionId, full: boolean): Promise<AnswerDTO[] | AnswerId[]> {
|
||||
const answerRepository = getAnswerRepository();
|
||||
const question = await fetchQuestion(questionId);
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ export async function getAnswersByQuestion(questionId: QuestionId, full: boolean
|
|||
return answersDTO.map(mapToAnswerId);
|
||||
}
|
||||
|
||||
export async function createQuestion(questionDTO: QuestionDTO) {
|
||||
export async function createQuestion(questionDTO: QuestionDTO): Promise<QuestionDTO | null> {
|
||||
const questionRepository = getQuestionRepository();
|
||||
|
||||
const author = mapToStudent(questionDTO.author);
|
||||
|
|
@ -86,7 +86,7 @@ export async function createQuestion(questionDTO: QuestionDTO) {
|
|||
return questionDTO;
|
||||
}
|
||||
|
||||
export async function deleteQuestion(questionId: QuestionId) {
|
||||
export async function deleteQuestion(questionId: QuestionId): Promise<Question | null> {
|
||||
const questionRepository = getQuestionRepository();
|
||||
|
||||
const question = await fetchQuestion(questionId);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { getSubmissionRepository } from '../data/repositories.js';
|
|||
import { Language } from '../entities/content/language.js';
|
||||
import { LearningObjectIdentifier } from '../entities/content/learning-object-identifier.js';
|
||||
import { mapToSubmission, mapToSubmissionDTO, SubmissionDTO } from '../interfaces/submission.js';
|
||||
import { Submission } from '../entities/assignments/submission.entity.js';
|
||||
|
||||
export async function getSubmission(
|
||||
learningObjectHruid: string,
|
||||
|
|
@ -21,7 +22,7 @@ export async function getSubmission(
|
|||
return mapToSubmissionDTO(submission);
|
||||
}
|
||||
|
||||
export async function createSubmission(submissionDTO: SubmissionDTO) {
|
||||
export async function createSubmission(submissionDTO: SubmissionDTO): Promise<Submission | null> {
|
||||
const submissionRepository = getSubmissionRepository();
|
||||
const submission = mapToSubmission(submissionDTO);
|
||||
|
||||
|
|
@ -35,7 +36,12 @@ export async function createSubmission(submissionDTO: SubmissionDTO) {
|
|||
return submission;
|
||||
}
|
||||
|
||||
export async function deleteSubmission(learningObjectHruid: string, language: Language, version: number, submissionNumber: number) {
|
||||
export async function deleteSubmission(
|
||||
learningObjectHruid: string,
|
||||
language: Language,
|
||||
version: number,
|
||||
submissionNumber: number
|
||||
): Promise<SubmissionDTO | null> {
|
||||
const submissionRepository = getSubmissionRepository();
|
||||
|
||||
const submission = getSubmission(learningObjectHruid, language, version, submissionNumber);
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export async function getClassIdsByTeacher(username: string): Promise<string[]>
|
|||
return classes.map((cls) => cls.id);
|
||||
}
|
||||
|
||||
export async function fetchStudentsByTeacher(username: string) {
|
||||
export async function fetchStudentsByTeacher(username: string): Promise<StudentDTO[]> {
|
||||
const classes = await getClassIdsByTeacher(username);
|
||||
|
||||
return (await Promise.all(classes.map(async (id) => getClassStudents(id)))).flat();
|
||||
|
|
|
|||
Reference in a new issue