diff --git a/backend/package.json b/backend/package.json index 40d49982..275bad7d 100644 --- a/backend/package.json +++ b/backend/package.json @@ -16,11 +16,11 @@ "test:unit": "vitest --run" }, "dependencies": { - "@mikro-orm/core": "6.4.9", - "@mikro-orm/knex": "6.4.9", - "@mikro-orm/postgresql": "6.4.9", - "@mikro-orm/reflection": "6.4.9", - "@mikro-orm/sqlite": "6.4.9", + "@mikro-orm/core": "6.4.12", + "@mikro-orm/knex": "6.4.12", + "@mikro-orm/postgresql": "6.4.12", + "@mikro-orm/reflection": "6.4.12", + "@mikro-orm/sqlite": "6.4.12", "axios": "^1.8.2", "cors": "^2.8.5", "cross": "^1.0.0", @@ -43,7 +43,7 @@ "winston-loki": "^6.1.3" }, "devDependencies": { - "@mikro-orm/cli": "6.4.9", + "@mikro-orm/cli": "6.4.12", "@types/cors": "^2.8.17", "@types/express": "^5.0.0", "@types/js-yaml": "^4.0.9", diff --git a/backend/src/controllers/groups.ts b/backend/src/controllers/groups.ts index ec177dcc..53bc96ec 100644 --- a/backend/src/controllers/groups.ts +++ b/backend/src/controllers/groups.ts @@ -69,8 +69,8 @@ export async function getAllGroupsHandler(req: Request, res: Response): Promise< export async function createGroupHandler(req: Request, res: Response): Promise { const classid = req.params.classid; const assignmentId = Number(req.params.assignmentid); - - requireFields({ classid, assignmentId }); + const members = req.body.members; + requireFields({ classid, assignmentId, members }); if (isNaN(assignmentId)) { throw new BadRequestException('Assignment id must be a number'); diff --git a/backend/src/data/assignments/assignment-repository.ts b/backend/src/data/assignments/assignment-repository.ts index db12a74f..1c8bb504 100644 --- a/backend/src/data/assignments/assignment-repository.ts +++ b/backend/src/data/assignments/assignment-repository.ts @@ -4,7 +4,7 @@ import { Class } from '../../entities/classes/class.entity.js'; export class AssignmentRepository extends DwengoEntityRepository { public async findByClassAndId(within: Class, id: number): Promise { - return this.findOne({ within: within, id: id }); + return this.findOne({ within: within, id: id }, { populate: ['groups', 'groups.members'] }); } public async findByClassIdAndAssignmentId(withinClass: string, id: number): Promise { return this.findOne({ within: { classId: withinClass }, id: id }); @@ -23,7 +23,7 @@ export class AssignmentRepository extends DwengoEntityRepository { }); } public async findAllAssignmentsInClass(within: Class): Promise { - return this.findAll({ where: { within: within } }); + return this.findAll({ where: { within: within }, populate: ['groups', 'groups.members'] }); } public async deleteByClassAndId(within: Class, id: number): Promise { return this.deleteWhere({ within: within, id: id }); diff --git a/backend/src/entities/assignments/assignment.entity.ts b/backend/src/entities/assignments/assignment.entity.ts index e3f75489..ed8745f6 100644 --- a/backend/src/entities/assignments/assignment.entity.ts +++ b/backend/src/entities/assignments/assignment.entity.ts @@ -14,7 +14,7 @@ export class Assignment { }) within!: Class; - @PrimaryKey({ type: 'number', autoincrement: true }) + @PrimaryKey({ type: 'integer', autoincrement: true }) id?: number; @Property({ type: 'string' }) @@ -35,5 +35,5 @@ export class Assignment { entity: () => Group, mappedBy: 'assignment', }) - groups!: Collection; + groups: Collection = new Collection(this); } diff --git a/backend/src/entities/assignments/group.entity.ts b/backend/src/entities/assignments/group.entity.ts index 55770b7f..62d5fee9 100644 --- a/backend/src/entities/assignments/group.entity.ts +++ b/backend/src/entities/assignments/group.entity.ts @@ -7,17 +7,23 @@ import { GroupRepository } from '../../data/assignments/group-repository.js'; repository: () => GroupRepository, }) export class Group { + /* + WARNING: Don't move the definition of groupNumber! If it does not come before the definition of assignment, + creating groups fails because of a MikroORM bug! + */ + @PrimaryKey({ type: 'integer', autoincrement: true }) + groupNumber?: number; + @ManyToOne({ entity: () => Assignment, primary: true, }) assignment!: Assignment; - @PrimaryKey({ type: 'integer', autoincrement: true }) - groupNumber?: number; - @ManyToMany({ entity: () => Student, + owner: true, + inversedBy: 'groups', }) - members!: Collection; + members: Collection = new Collection(this); } diff --git a/backend/src/entities/classes/class.entity.ts b/backend/src/entities/classes/class.entity.ts index 63315304..b2c59ade 100644 --- a/backend/src/entities/classes/class.entity.ts +++ b/backend/src/entities/classes/class.entity.ts @@ -14,9 +14,9 @@ export class Class { @Property({ type: 'string' }) displayName!: string; - @ManyToMany(() => Teacher) + @ManyToMany({ entity: () => Teacher, owner: true, inversedBy: 'classes' }) teachers!: Collection; - @ManyToMany(() => Student) + @ManyToMany({ entity: () => Student, owner: true, inversedBy: 'classes' }) students!: Collection; } diff --git a/backend/src/entities/users/student.entity.ts b/backend/src/entities/users/student.entity.ts index 58e82765..9f294d3c 100644 --- a/backend/src/entities/users/student.entity.ts +++ b/backend/src/entities/users/student.entity.ts @@ -8,9 +8,9 @@ import { StudentRepository } from '../../data/users/student-repository.js'; repository: () => StudentRepository, }) export class Student extends User { - @ManyToMany(() => Class) + @ManyToMany({ entity: () => Class, mappedBy: 'students' }) classes!: Collection; - @ManyToMany(() => Group) - groups!: Collection; + @ManyToMany({ entity: () => Group, mappedBy: 'members' }) + groups: Collection = new Collection(this); } diff --git a/backend/src/entities/users/teacher.entity.ts b/backend/src/entities/users/teacher.entity.ts index d53ca603..8fbe5e51 100644 --- a/backend/src/entities/users/teacher.entity.ts +++ b/backend/src/entities/users/teacher.entity.ts @@ -5,6 +5,6 @@ import { TeacherRepository } from '../../data/users/teacher-repository.js'; @Entity({ repository: () => TeacherRepository }) export class Teacher extends User { - @ManyToMany(() => Class) + @ManyToMany({ entity: () => Class, mappedBy: 'teachers' }) classes!: Collection; } diff --git a/backend/src/exceptions/server-error-exception.ts b/backend/src/exceptions/server-error-exception.ts new file mode 100644 index 00000000..49251bdf --- /dev/null +++ b/backend/src/exceptions/server-error-exception.ts @@ -0,0 +1,12 @@ +import { ExceptionWithHttpState } from './exception-with-http-state.js'; + +/** + * Exception for HTTP 500 Internal Server Error + */ +export class ServerErrorException extends ExceptionWithHttpState { + status = 500; + + constructor(message = 'Internal server error, something went wrong') { + super(500, message); + } +} diff --git a/backend/src/interfaces/assignment.ts b/backend/src/interfaces/assignment.ts index 7abb3d3c..7c5a0909 100644 --- a/backend/src/interfaces/assignment.ts +++ b/backend/src/interfaces/assignment.ts @@ -1,18 +1,14 @@ import { languageMap } from '@dwengo-1/common/util/language'; -import { FALLBACK_LANG } from '../config.js'; import { Assignment } from '../entities/assignments/assignment.entity.js'; import { Class } from '../entities/classes/class.entity.js'; -import { getLogger } from '../logging/initalize.js'; -import { AssignmentDTO } from '@dwengo-1/common/interfaces/assignment'; +import { AssignmentDTO, AssignmentDTOId } from '@dwengo-1/common/interfaces/assignment'; +import { mapToGroupDTO } from './group.js'; +import { getAssignmentRepository } from '../data/repositories.js'; -export function mapToAssignmentDTOId(assignment: Assignment): AssignmentDTO { +export function mapToAssignmentDTOId(assignment: Assignment): AssignmentDTOId { return { id: assignment.id!, within: assignment.within.classId!, - title: assignment.title, - description: assignment.description, - learningPath: assignment.learningPathHruid, - language: assignment.learningPathLanguage, }; } @@ -24,19 +20,17 @@ export function mapToAssignmentDTO(assignment: Assignment): AssignmentDTO { description: assignment.description, learningPath: assignment.learningPathHruid, language: assignment.learningPathLanguage, - // Groups: assignment.groups.map(mapToGroupDTO), + groups: assignment.groups.map((group) => mapToGroupDTO(group, assignment.within)), }; } export function mapToAssignment(assignmentData: AssignmentDTO, cls: Class): Assignment { - const assignment = new Assignment(); - assignment.title = assignmentData.title; - assignment.description = assignmentData.description; - assignment.learningPathHruid = assignmentData.learningPath; - assignment.learningPathLanguage = languageMap[assignmentData.language] || FALLBACK_LANG; - assignment.within = cls; - - getLogger().debug(assignment); - - return assignment; + return getAssignmentRepository().create({ + within: cls, + title: assignmentData.title, + description: assignmentData.description, + learningPathHruid: assignmentData.learningPath, + learningPathLanguage: languageMap[assignmentData.language], + groups: [], + }); } diff --git a/backend/src/interfaces/group.ts b/backend/src/interfaces/group.ts index 792086d4..3cebb9eb 100644 --- a/backend/src/interfaces/group.ts +++ b/backend/src/interfaces/group.ts @@ -1,14 +1,12 @@ import { Group } from '../entities/assignments/group.entity.js'; import { mapToAssignment } from './assignment.js'; import { mapToStudent } from './student.js'; -import { mapToAssignmentDTO } from './assignment.js'; import { mapToStudentDTO } from './student.js'; -import { GroupDTO } from '@dwengo-1/common/interfaces/group'; +import { GroupDTO, GroupDTOId } from '@dwengo-1/common/interfaces/group'; import { getGroupRepository } from '../data/repositories.js'; import { AssignmentDTO } from '@dwengo-1/common/interfaces/assignment'; import { Class } from '../entities/classes/class.entity.js'; import { StudentDTO } from '@dwengo-1/common/interfaces/student'; -import { mapToClassDTO } from './class.js'; export function mapToGroup(groupDto: GroupDTO, clazz: Class): Group { const assignmentDto = groupDto.assignment as AssignmentDTO; @@ -20,18 +18,18 @@ export function mapToGroup(groupDto: GroupDTO, clazz: Class): Group { }); } -export function mapToGroupDTO(group: Group): GroupDTO { +export function mapToGroupDTO(group: Group, cls: Class): GroupDTO { return { - class: mapToClassDTO(group.assignment.within), - assignment: mapToAssignmentDTO(group.assignment), + class: cls.classId!, + assignment: group.assignment.id!, groupNumber: group.groupNumber!, members: group.members.map(mapToStudentDTO), }; } -export function mapToGroupDTOId(group: Group): GroupDTO { +export function mapToGroupDTOId(group: Group, cls: Class): GroupDTOId { return { - class: group.assignment.within.classId!, + class: cls.classId!, assignment: group.assignment.id!, groupNumber: group.groupNumber!, }; diff --git a/backend/src/interfaces/question.ts b/backend/src/interfaces/question.ts index 50a61301..98e6f33c 100644 --- a/backend/src/interfaces/question.ts +++ b/backend/src/interfaces/question.ts @@ -31,7 +31,7 @@ export function mapToQuestionDTO(question: Question): QuestionDTO { learningObjectIdentifier, sequenceNumber: question.sequenceNumber!, author: mapToStudentDTO(question.author), - inGroup: mapToGroupDTOId(question.inGroup), + inGroup: mapToGroupDTOId(question.inGroup, question.inGroup.assignment?.within), timestamp: question.timestamp.toISOString(), content: question.content, }; diff --git a/backend/src/interfaces/submission.ts b/backend/src/interfaces/submission.ts index bb30d400..e3b60311 100644 --- a/backend/src/interfaces/submission.ts +++ b/backend/src/interfaces/submission.ts @@ -16,7 +16,7 @@ export function mapToSubmissionDTO(submission: Submission): SubmissionDTO { submissionNumber: submission.submissionNumber, submitter: mapToStudentDTO(submission.submitter), time: submission.submissionTime, - group: mapToGroupDTOId(submission.onBehalfOf), + group: submission.onBehalfOf ? mapToGroupDTOId(submission.onBehalfOf, submission.onBehalfOf.assignment.within) : undefined, content: submission.content, }; } diff --git a/backend/src/services/assignments.ts b/backend/src/services/assignments.ts index 5fd8f67f..2379ecfb 100644 --- a/backend/src/services/assignments.ts +++ b/backend/src/services/assignments.ts @@ -1,4 +1,4 @@ -import { AssignmentDTO } from '@dwengo-1/common/interfaces/assignment'; +import { AssignmentDTO, AssignmentDTOId } from '@dwengo-1/common/interfaces/assignment'; import { getAssignmentRepository, getClassRepository, @@ -16,6 +16,8 @@ import { QuestionDTO, QuestionId } from '@dwengo-1/common/interfaces/question'; import { SubmissionDTO, SubmissionDTOId } from '@dwengo-1/common/interfaces/submission'; import { EntityDTO } from '@mikro-orm/core'; import { putObject } from './service-helper.js'; +import { fetchStudents } from './students.js'; +import { ServerErrorException } from '../exceptions/server-error-exception.js'; export async function fetchAssignment(classid: string, assignmentNumber: number): Promise { const classRepository = getClassRepository(); @@ -35,7 +37,7 @@ export async function fetchAssignment(classid: string, assignmentNumber: number) return assignment; } -export async function getAllAssignments(classid: string, full: boolean): Promise { +export async function getAllAssignments(classid: string, full: boolean): Promise { const cls = await fetchClass(classid); const assignmentRepository = getAssignmentRepository(); @@ -51,13 +53,39 @@ export async function getAllAssignments(classid: string, full: boolean): Promise export async function createAssignment(classid: string, assignmentData: AssignmentDTO): Promise { const cls = await fetchClass(classid); - const assignment = mapToAssignment(assignmentData, cls); - const assignmentRepository = getAssignmentRepository(); - const newAssignment = assignmentRepository.create(assignment); - await assignmentRepository.save(newAssignment, { preventOverwrite: true }); + const assignment = mapToAssignment(assignmentData, cls); + await assignmentRepository.save(assignment); - return mapToAssignmentDTO(newAssignment); + if (assignmentData.groups) { + /* + For some reason when trying to add groups, it does not work when using the original assignment variable. + The assignment needs to be refetched in order for it to work. + */ + + const assignmentCopy = await assignmentRepository.findByClassAndId(cls, assignment.id!); + + if (assignmentCopy === null) { + throw new ServerErrorException('Something has gone horribly wrong. Could not find newly added assignment which is needed to add groups.'); + } + + const groupRepository = getGroupRepository(); + + (assignmentData.groups as string[][]).forEach(async (memberUsernames) => { + const members = await fetchStudents(memberUsernames); + + const newGroup = groupRepository.create({ + assignment: assignmentCopy, + members: members, + }); + await groupRepository.save(newGroup); + }); + } + + /* Need to refetch the assignment here again such that the groups are added. */ + const assignmentWithGroups = await fetchAssignment(classid, assignment.id!); + + return mapToAssignmentDTO(assignmentWithGroups); } export async function getAssignment(classid: string, id: number): Promise { diff --git a/backend/src/services/groups.ts b/backend/src/services/groups.ts index 3c6f2919..0c73c8c5 100644 --- a/backend/src/services/groups.ts +++ b/backend/src/services/groups.ts @@ -1,13 +1,14 @@ import { EntityDTO } from '@mikro-orm/core'; -import { getGroupRepository, getStudentRepository, getSubmissionRepository } from '../data/repositories.js'; +import { getGroupRepository, getSubmissionRepository } from '../data/repositories.js'; import { Group } from '../entities/assignments/group.entity.js'; -import { mapToGroupDTO, mapToShallowGroupDTO } from '../interfaces/group.js'; +import { mapToGroupDTO, mapToGroupDTOId } from '../interfaces/group.js'; import { mapToSubmissionDTO, mapToSubmissionDTOId } from '../interfaces/submission.js'; -import { GroupDTO } from '@dwengo-1/common/interfaces/group'; +import { GroupDTO, GroupDTOId } from '@dwengo-1/common/interfaces/group'; import { SubmissionDTO, SubmissionDTOId } from '@dwengo-1/common/interfaces/submission'; import { fetchAssignment } from './assignments.js'; import { NotFoundException } from '../exceptions/not-found-exception.js'; import { putObject } from './service-helper.js'; +import { fetchStudents } from './students.js'; export async function fetchGroup(classId: string, assignmentNumber: number, groupNumber: number): Promise { const assignment = await fetchAssignment(classId, assignmentNumber); @@ -24,7 +25,7 @@ export async function fetchGroup(classId: string, assignmentNumber: number, grou export async function getGroup(classId: string, assignmentNumber: number, groupNumber: number): Promise { const group = await fetchGroup(classId, assignmentNumber, groupNumber); - return mapToGroupDTO(group); + return mapToGroupDTO(group, group.assignment.within); } export async function putGroup( @@ -37,7 +38,7 @@ export async function putGroup( await putObject(group, groupData, getGroupRepository()); - return mapToGroupDTO(group); + return mapToGroupDTO(group, group.assignment.within); } export async function deleteGroup(classId: string, assignmentNumber: number, groupNumber: number): Promise { @@ -47,7 +48,7 @@ export async function deleteGroup(classId: string, assignmentNumber: number, gro const groupRepository = getGroupRepository(); await groupRepository.deleteByAssignmentAndGroupNumber(assignment, groupNumber); - return mapToGroupDTO(group); + return mapToGroupDTO(group, assignment.within); } export async function getExistingGroupFromGroupDTO(groupData: GroupDTO): Promise { @@ -59,12 +60,8 @@ export async function getExistingGroupFromGroupDTO(groupData: GroupDTO): Promise } export async function createGroup(groupData: GroupDTO, classid: string, assignmentNumber: number): Promise { - const studentRepository = getStudentRepository(); - const memberUsernames = (groupData.members as string[]) || []; - const members = (await Promise.all([...memberUsernames].map(async (id) => studentRepository.findByUsername(id)))).filter( - (student) => student !== null - ); + const members = await fetchStudents(memberUsernames); const assignment = await fetchAssignment(classid, assignmentNumber); @@ -73,22 +70,23 @@ export async function createGroup(groupData: GroupDTO, classid: string, assignme assignment: assignment, members: members, }); + await groupRepository.save(newGroup); - return mapToGroupDTO(newGroup); + return mapToGroupDTO(newGroup, newGroup.assignment.within); } -export async function getAllGroups(classId: string, assignmentNumber: number, full: boolean): Promise { +export async function getAllGroups(classId: string, assignmentNumber: number, full: boolean): Promise { const assignment = await fetchAssignment(classId, assignmentNumber); const groupRepository = getGroupRepository(); const groups = await groupRepository.findAllGroupsForAssignment(assignment); if (full) { - return groups.map(mapToGroupDTO); + return groups.map((group) => mapToGroupDTO(group, assignment.within)); } - return groups.map(mapToShallowGroupDTO); + return groups.map((group) => mapToGroupDTOId(group, assignment.within)); } export async function getGroupSubmissions( diff --git a/backend/src/services/students.ts b/backend/src/services/students.ts index b1467886..03a6d8fa 100644 --- a/backend/src/services/students.ts +++ b/backend/src/services/students.ts @@ -7,7 +7,7 @@ import { getSubmissionRepository, } from '../data/repositories.js'; import { mapToClassDTO } from '../interfaces/class.js'; -import { mapToGroupDTO, mapToShallowGroupDTO } from '../interfaces/group.js'; +import { mapToGroupDTO, mapToGroupDTOId } from '../interfaces/group.js'; import { mapToStudent, mapToStudentDTO } from '../interfaces/student.js'; import { mapToSubmissionDTO, mapToSubmissionDTOId } from '../interfaces/submission.js'; import { getAllAssignments } from './assignments.js'; @@ -18,8 +18,8 @@ import { NotFoundException } from '../exceptions/not-found-exception.js'; import { fetchClass } from './classes.js'; import { StudentDTO } from '@dwengo-1/common/interfaces/student'; import { ClassDTO } from '@dwengo-1/common/interfaces/class'; -import { AssignmentDTO } from '@dwengo-1/common/interfaces/assignment'; -import { GroupDTO } from '@dwengo-1/common/interfaces/group'; +import { AssignmentDTO, AssignmentDTOId } from '@dwengo-1/common/interfaces/assignment'; +import { GroupDTO, GroupDTOId } from '@dwengo-1/common/interfaces/group'; import { SubmissionDTO, SubmissionDTOId } from '@dwengo-1/common/interfaces/submission'; import { QuestionDTO, QuestionId } from '@dwengo-1/common/interfaces/question'; import { ClassJoinRequestDTO } from '@dwengo-1/common/interfaces/class-join-request'; @@ -48,6 +48,11 @@ export async function fetchStudent(username: string): Promise { return user; } +export async function fetchStudents(usernames: string[]): Promise { + const members = await Promise.all(usernames.map(async (username) => await fetchStudent(username))); + return members; +} + export async function getStudent(username: string): Promise { const user = await fetchStudent(username); return mapToStudentDTO(user); @@ -83,7 +88,7 @@ export async function getStudentClasses(username: string, full: boolean): Promis return classes.map((cls) => cls.classId!); } -export async function getStudentAssignments(username: string, full: boolean): Promise { +export async function getStudentAssignments(username: string, full: boolean): Promise { const student = await fetchStudent(username); const classRepository = getClassRepository(); @@ -92,17 +97,17 @@ export async function getStudentAssignments(username: string, full: boolean): Pr return (await Promise.all(classes.map(async (cls) => await getAllAssignments(cls.classId!, full)))).flat(); } -export async function getStudentGroups(username: string, full: boolean): Promise { +export async function getStudentGroups(username: string, full: boolean): Promise { const student = await fetchStudent(username); const groupRepository = getGroupRepository(); const groups = await groupRepository.findAllGroupsWithStudent(student); if (full) { - return groups.map(mapToGroupDTO); + return groups.map((group) => mapToGroupDTO(group, group.assignment.within)); } - return groups.map(mapToShallowGroupDTO); + return groups.map((group) => mapToGroupDTOId(group, group.assignment.within)); } export async function getStudentSubmissions(username: string, full: boolean): Promise { diff --git a/backend/src/services/submissions.ts b/backend/src/services/submissions.ts index b6d1600a..1170bf50 100644 --- a/backend/src/services/submissions.ts +++ b/backend/src/services/submissions.ts @@ -33,7 +33,7 @@ export async function getAllSubmissions(loId: LearningObjectIdentifier): Promise export async function createSubmission(submissionDTO: SubmissionDTO): Promise { const submitter = await fetchStudent(submissionDTO.submitter.username); - const group = await getExistingGroupFromGroupDTO(submissionDTO.group); + const group = await getExistingGroupFromGroupDTO(submissionDTO.group!); const submissionRepository = getSubmissionRepository(); const submission = mapToSubmission(submissionDTO, submitter, group); diff --git a/backend/tests/data/assignments/assignments.test.ts b/backend/tests/data/assignments/assignments.test.ts index 49504400..74c858b3 100644 --- a/backend/tests/data/assignments/assignments.test.ts +++ b/backend/tests/data/assignments/assignments.test.ts @@ -16,7 +16,7 @@ describe('AssignmentRepository', () => { it('should return the requested assignment', async () => { const class_ = await classRepository.findById('34d484a1-295f-4e9f-bfdc-3e7a23d86a89'); - const assignment = await assignmentRepository.findByClassAndId(class_!, 2); + const assignment = await assignmentRepository.findByClassAndId(class_!, 21001); expect(assignment).toBeTruthy(); expect(assignment!.title).toBe('tool'); @@ -35,7 +35,7 @@ describe('AssignmentRepository', () => { const result = await assignmentRepository.findAllByResponsibleTeacher('testleerkracht1'); const resultIds = result.map((it) => it.id).sort((a, b) => (a ?? 0) - (b ?? 0)); - expect(resultIds).toEqual([1, 1, 3, 4]); + expect(resultIds).toEqual([21000, 21002, 21003, 21004]); }); it('should not find removed assignment', async () => { diff --git a/backend/tests/data/assignments/groups.test.ts b/backend/tests/data/assignments/groups.test.ts index f7fb3046..efd477ab 100644 --- a/backend/tests/data/assignments/groups.test.ts +++ b/backend/tests/data/assignments/groups.test.ts @@ -19,16 +19,16 @@ describe('GroupRepository', () => { it('should return the requested group', async () => { const class_ = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9'); - const assignment = await assignmentRepository.findByClassAndId(class_!, 1); + const assignment = await assignmentRepository.findByClassAndId(class_!, 21000); - const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 1); + const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 21001); expect(group).toBeTruthy(); }); it('should return all groups for assignment', async () => { const class_ = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9'); - const assignment = await assignmentRepository.findByClassAndId(class_!, 1); + const assignment = await assignmentRepository.findByClassAndId(class_!, 21000); const groups = await groupRepository.findAllGroupsForAssignment(assignment!); @@ -38,9 +38,9 @@ describe('GroupRepository', () => { it('should not find removed group', async () => { const class_ = await classRepository.findById('34d484a1-295f-4e9f-bfdc-3e7a23d86a89'); - const assignment = await assignmentRepository.findByClassAndId(class_!, 2); + const assignment = await assignmentRepository.findByClassAndId(class_!, 21001); - await groupRepository.deleteByAssignmentAndGroupNumber(assignment!, 1); + await groupRepository.deleteByAssignmentAndGroupNumber(assignment!, 21001); const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 1); diff --git a/backend/tests/data/assignments/submissions.test.ts b/backend/tests/data/assignments/submissions.test.ts index dd2cc8c4..2bbd00dc 100644 --- a/backend/tests/data/assignments/submissions.test.ts +++ b/backend/tests/data/assignments/submissions.test.ts @@ -54,8 +54,8 @@ describe('SubmissionRepository', () => { it('should find the most recent submission for a group', async () => { const id = new LearningObjectIdentifier('id03', Language.English, 1); const class_ = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9'); - const assignment = await assignmentRepository.findByClassAndId(class_!, 1); - const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 1); + const assignment = await assignmentRepository.findByClassAndId(class_!, 21000); + const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 21001); const submission = await submissionRepository.findMostRecentSubmissionForGroup(id, group!); expect(submission).toBeTruthy(); @@ -67,7 +67,7 @@ describe('SubmissionRepository', () => { let loId: LearningObjectIdentifier; it('should find all submissions for a certain learning object and assignment', async () => { clazz = await classRepository.findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9'); - assignment = await assignmentRepository.findByClassAndId(clazz!, 1); + assignment = await assignmentRepository.findByClassAndId(clazz!, 21000); loId = { hruid: 'id02', language: Language.English, @@ -92,7 +92,7 @@ describe('SubmissionRepository', () => { }); it('should find only the submissions for a certain learning object and assignment made for the given group', async () => { - const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 2); + const group = await groupRepository.findByAssignmentAndGroupNumber(assignment!, 21002); const result = await submissionRepository.findAllSubmissionsForLearningObjectAndGroup(loId, group!); expect(result).toHaveLength(1); diff --git a/backend/tests/data/questions/questions.test.ts b/backend/tests/data/questions/questions.test.ts index 9565e71d..8ad2d47c 100644 --- a/backend/tests/data/questions/questions.test.ts +++ b/backend/tests/data/questions/questions.test.ts @@ -38,8 +38,8 @@ describe('QuestionRepository', () => { const student = await studentRepository.findByUsername('Noordkaap'); const clazz = await getClassRepository().findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9'); - const assignment = await getAssignmentRepository().findByClassAndId(clazz!, 1); - const group = await getGroupRepository().findByAssignmentAndGroupNumber(assignment!, 1); + const assignment = await getAssignmentRepository().findByClassAndId(clazz!, 21000); + const group = await getGroupRepository().findByAssignmentAndGroupNumber(assignment!, 21001); await questionRepository.createQuestion({ loId: id, inGroup: group!, @@ -57,7 +57,7 @@ describe('QuestionRepository', () => { let loId: LearningObjectIdentifier; it('should find all questions for a certain learning object and assignment', async () => { clazz = await getClassRepository().findById('8764b861-90a6-42e5-9732-c0d9eb2f55f9'); - assignment = await getAssignmentRepository().findByClassAndId(clazz!, 1); + assignment = await getAssignmentRepository().findByClassAndId(clazz!, 21000); loId = { hruid: 'id05', language: Language.English, diff --git a/backend/tests/test_assets/assignments/assignments.testdata.ts b/backend/tests/test_assets/assignments/assignments.testdata.ts index efb20e60..337ec98f 100644 --- a/backend/tests/test_assets/assignments/assignments.testdata.ts +++ b/backend/tests/test_assets/assignments/assignments.testdata.ts @@ -7,8 +7,8 @@ import { getClassWithTestleerlingAndTestleerkracht } from '../classes/classes.te export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assignment[] { assignment01 = em.create(Assignment, { + id: 21000, within: classes[0], - id: 1, title: 'dire straits', description: 'reading', learningPathHruid: 'id02', @@ -17,8 +17,8 @@ export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assign }); assignment02 = em.create(Assignment, { + id: 21001, within: classes[1], - id: 2, title: 'tool', description: 'reading', learningPathHruid: 'id01', @@ -27,8 +27,8 @@ export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assign }); assignment03 = em.create(Assignment, { + id: 21002, within: classes[0], - id: 3, title: 'delete', description: 'will be deleted', learningPathHruid: 'id02', @@ -37,8 +37,8 @@ export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assign }); assignment04 = em.create(Assignment, { + id: 21003, within: classes[0], - id: 4, title: 'another assignment', description: 'with a description', learningPathHruid: 'id01', @@ -48,7 +48,7 @@ export function makeTestAssignemnts(em: EntityManager, classes: Class[]): Assign conditionalPathAssignment = em.create(Assignment, { within: getClassWithTestleerlingAndTestleerkracht(), - id: 1, + id: 21004, title: 'Assignment: Conditional Learning Path', description: 'You have to do the testing learning path with a condition.', learningPathHruid: testLearningPathWithConditions.hruid, diff --git a/backend/tests/test_assets/assignments/groups.testdata.ts b/backend/tests/test_assets/assignments/groups.testdata.ts index 3ace2be9..16674843 100644 --- a/backend/tests/test_assets/assignments/groups.testdata.ts +++ b/backend/tests/test_assets/assignments/groups.testdata.ts @@ -12,7 +12,7 @@ export function makeTestGroups(em: EntityManager, students: Student[], assignmen */ group01 = em.create(Group, { assignment: assignments[0], - groupNumber: 1, + groupNumber: 21001, members: students.slice(0, 2), }); @@ -22,7 +22,7 @@ export function makeTestGroups(em: EntityManager, students: Student[], assignmen */ group02 = em.create(Group, { assignment: assignments[0], - groupNumber: 2, + groupNumber: 21002, members: students.slice(2, 4), }); @@ -32,7 +32,7 @@ export function makeTestGroups(em: EntityManager, students: Student[], assignmen */ group03 = em.create(Group, { assignment: assignments[0], - groupNumber: 3, + groupNumber: 21003, members: students.slice(4, 6), }); @@ -42,7 +42,7 @@ export function makeTestGroups(em: EntityManager, students: Student[], assignmen */ group04 = em.create(Group, { assignment: assignments[1], - groupNumber: 4, + groupNumber: 21004, members: students.slice(3, 4), }); @@ -52,7 +52,7 @@ export function makeTestGroups(em: EntityManager, students: Student[], assignmen */ group05 = em.create(Group, { assignment: assignments[3], - groupNumber: 1, + groupNumber: 21001, members: students.slice(0, 2), }); diff --git a/backend/tool/seed.ts b/backend/tool/seed.ts index f1742b69..3cb4543c 100644 --- a/backend/tool/seed.ts +++ b/backend/tool/seed.ts @@ -34,6 +34,7 @@ export async function seedDatabase(): Promise { const learningPaths = makeTestLearningPaths(em); const classes = makeTestClasses(em, students, teachers); const assignments = makeTestAssignemnts(em, classes); + const groups = makeTestGroups(em, students, assignments); assignments[0].groups = new Collection(groups.slice(0, 3)); diff --git a/common/src/interfaces/assignment.ts b/common/src/interfaces/assignment.ts index 5cb8feff..fb7dfbf0 100644 --- a/common/src/interfaces/assignment.ts +++ b/common/src/interfaces/assignment.ts @@ -7,5 +7,10 @@ export interface AssignmentDTO { description: string; learningPath: string; language: string; - groups?: GroupDTO[] | string[]; // TODO + groups: GroupDTO[] | string[][]; +} + +export interface AssignmentDTOId { + id: number; + within: string; } diff --git a/common/src/interfaces/group.ts b/common/src/interfaces/group.ts index 6baa79a5..77721a1a 100644 --- a/common/src/interfaces/group.ts +++ b/common/src/interfaces/group.ts @@ -8,3 +8,9 @@ export interface GroupDTO { groupNumber: number; members?: string[] | StudentDTO[]; } + +export interface GroupDTOId { + class: string; + assignment: number; + groupNumber: number; +} diff --git a/common/src/interfaces/submission.ts b/common/src/interfaces/submission.ts index 7643f0e6..9101df79 100644 --- a/common/src/interfaces/submission.ts +++ b/common/src/interfaces/submission.ts @@ -9,7 +9,7 @@ export interface SubmissionDTO { submissionNumber?: number; submitter: StudentDTO; time?: Date; - group: GroupDTO; + group?: GroupDTO; content: string; } diff --git a/frontend/src/controllers/assignments.ts b/frontend/src/controllers/assignments.ts index a66f8e84..0d46e311 100644 --- a/frontend/src/controllers/assignments.ts +++ b/frontend/src/controllers/assignments.ts @@ -1,11 +1,11 @@ import { BaseController } from "./base-controller"; -import type { AssignmentDTO } from "@dwengo-1/common/interfaces/assignment"; +import type { AssignmentDTO, AssignmentDTOId } from "@dwengo-1/common/interfaces/assignment"; import type { SubmissionsResponse } from "./submissions"; import type { QuestionsResponse } from "./questions"; import type { GroupsResponse } from "./groups"; export interface AssignmentsResponse { - assignments: AssignmentDTO[] | string[]; + assignments: AssignmentDTO[] | AssignmentDTOId[]; } export interface AssignmentResponse { diff --git a/frontend/src/controllers/groups.ts b/frontend/src/controllers/groups.ts index 4c38290f..47f5c10c 100644 --- a/frontend/src/controllers/groups.ts +++ b/frontend/src/controllers/groups.ts @@ -1,10 +1,10 @@ import { BaseController } from "./base-controller"; -import type { GroupDTO } from "@dwengo-1/common/interfaces/group"; +import type { GroupDTO, GroupDTOId } from "@dwengo-1/common/interfaces/group"; import type { SubmissionsResponse } from "./submissions"; import type { QuestionsResponse } from "./questions"; export interface GroupsResponse { - groups: GroupDTO[]; + groups: GroupDTO[] | GroupDTOId[]; } export interface GroupResponse { diff --git a/package-lock.json b/package-lock.json index 2f47bd8a..1728b06d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,11 +31,11 @@ "name": "@dwengo-1/backend", "version": "0.1.1", "dependencies": { - "@mikro-orm/core": "6.4.9", - "@mikro-orm/knex": "6.4.9", - "@mikro-orm/postgresql": "6.4.9", - "@mikro-orm/reflection": "6.4.9", - "@mikro-orm/sqlite": "6.4.9", + "@mikro-orm/core": "6.4.12", + "@mikro-orm/knex": "6.4.12", + "@mikro-orm/postgresql": "6.4.12", + "@mikro-orm/reflection": "6.4.12", + "@mikro-orm/sqlite": "6.4.12", "axios": "^1.8.2", "cors": "^2.8.5", "cross": "^1.0.0", @@ -58,7 +58,7 @@ "winston-loki": "^6.1.3" }, "devDependencies": { - "@mikro-orm/cli": "6.4.9", + "@mikro-orm/cli": "6.4.12", "@types/cors": "^2.8.17", "@types/express": "^5.0.0", "@types/js-yaml": "^4.0.9", @@ -72,133 +72,6 @@ "vitest": "^3.0.6" } }, - "backend/node_modules/@mikro-orm/cli": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.9.tgz", - "integrity": "sha512-LQzVsmar/0DoJkPGyz3OpB8pa9BCQtvYreEC71h0O+RcizppJjgBQNTkj5tJd2Iqvh4hSaMv6qTv0l5UK6F2Vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jercle/yargonaut": "1.1.5", - "@mikro-orm/core": "6.4.9", - "@mikro-orm/knex": "6.4.9", - "fs-extra": "11.3.0", - "tsconfig-paths": "4.2.0", - "yargs": "17.7.2" - }, - "bin": { - "mikro-orm": "cli", - "mikro-orm-esm": "esm" - }, - "engines": { - "node": ">= 18.12.0" - } - }, - "backend/node_modules/@mikro-orm/core": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.9.tgz", - "integrity": "sha512-osB2TbvSH4ZL1s62LCBQFAnxPqLycX5fakPHOoztudixqfbVD5QQydeGizJXMMh2zKP6vRCwIJy3MeSuFxPjHg==", - "license": "MIT", - "dependencies": { - "dataloader": "2.2.3", - "dotenv": "16.4.7", - "esprima": "4.0.1", - "fs-extra": "11.3.0", - "globby": "11.1.0", - "mikro-orm": "6.4.9", - "reflect-metadata": "0.2.2" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/b4nan" - } - }, - "backend/node_modules/@mikro-orm/knex": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.9.tgz", - "integrity": "sha512-iGXJfe/TziVOQsWuxMIqkOpurysWzQA6kj3+FDtOkHJAijZhqhjSBnfUVHHY/JzU9o0M0rgLrDVJFry/uEaJEA==", - "license": "MIT", - "dependencies": { - "fs-extra": "11.3.0", - "knex": "3.1.0", - "sqlstring": "2.3.3" - }, - "engines": { - "node": ">= 18.12.0" - }, - "peerDependencies": { - "@mikro-orm/core": "^6.0.0", - "better-sqlite3": "*", - "libsql": "*", - "mariadb": "*" - }, - "peerDependenciesMeta": { - "better-sqlite3": { - "optional": true - }, - "libsql": { - "optional": true - }, - "mariadb": { - "optional": true - } - } - }, - "backend/node_modules/@mikro-orm/postgresql": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@mikro-orm/postgresql/-/postgresql-6.4.9.tgz", - "integrity": "sha512-ZdVVFAL/TSbzpEmChGdH0oUpy2KiHLjNIeItZHRQgInn1X9p0qx28VVDR78p8qgRGkQ3LquxGTkvmWI0w7qi3A==", - "license": "MIT", - "dependencies": { - "@mikro-orm/knex": "6.4.9", - "pg": "8.13.3", - "postgres-array": "3.0.4", - "postgres-date": "2.1.0", - "postgres-interval": "4.0.2" - }, - "engines": { - "node": ">= 18.12.0" - }, - "peerDependencies": { - "@mikro-orm/core": "^6.0.0" - } - }, - "backend/node_modules/@mikro-orm/reflection": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.4.9.tgz", - "integrity": "sha512-fgY7yLrcZm3J/8dv9reUC4PQo7C2muImU31jmzz1SxmNKPJFDJl7OzcDZlM5NOisXzsWUBrcNdCyuQiWViVc3A==", - "license": "MIT", - "dependencies": { - "globby": "11.1.0", - "ts-morph": "25.0.1" - }, - "engines": { - "node": ">= 18.12.0" - }, - "peerDependencies": { - "@mikro-orm/core": "^6.0.0" - } - }, - "backend/node_modules/@mikro-orm/sqlite": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-6.4.9.tgz", - "integrity": "sha512-O7Jy/5DrTWpJI/3qkhRJHl+OcECx1N625LHDODAAauOK3+MJB/bj80TrvQhe6d/CHZMmvxZ7m2GzaL1NulKxRw==", - "license": "MIT", - "dependencies": { - "@mikro-orm/knex": "6.4.9", - "fs-extra": "11.3.0", - "sqlite3": "5.1.7", - "sqlstring-sqlite": "0.1.1" - }, - "engines": { - "node": ">= 18.12.0" - }, - "peerDependencies": { - "@mikro-orm/core": "^6.0.0" - } - }, "backend/node_modules/globals": { "version": "15.15.0", "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", @@ -212,48 +85,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "backend/node_modules/mikro-orm": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.9.tgz", - "integrity": "sha512-XwVrWNT4NNwS6kHIKFNDfvy8L1eWcBBEHeTVzFFYcnb2ummATaLxqeVkNEmKA68jmdtfQdUmWBqGdbcIPwtL2Q==", - "license": "MIT", - "engines": { - "node": ">= 18.12.0" - } - }, - "backend/node_modules/pg": { - "version": "8.13.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.3.tgz", - "integrity": "sha512-P6tPt9jXbL9HVu/SSRERNYaYG++MjnscnegFh9pPHihfoBSujsrka0hyuymMzeJKFWrcG8wvCKy8rCe8e5nDUQ==", - "license": "MIT", - "dependencies": { - "pg-connection-string": "^2.7.0", - "pg-pool": "^3.7.1", - "pg-protocol": "^1.7.1", - "pg-types": "^2.1.0", - "pgpass": "1.x" - }, - "engines": { - "node": ">= 8.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.1.1" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "backend/node_modules/pg-connection-string": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", - "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", - "license": "MIT" - }, "common": { "name": "@dwengo-1/common", "version": "0.1.1" @@ -1028,294 +859,6 @@ "resolved": "common", "link": true }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/linux-x64": { "version": "0.25.2", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", @@ -1334,150 +877,6 @@ "node": ">=18" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true, - "engines": { - "node": ">=18" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", @@ -1987,132 +1386,125 @@ "jsep": "^0.4.0||^1.0.0" } }, - "node_modules/@napi-rs/snappy-android-arm-eabi": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm-eabi/-/snappy-android-arm-eabi-7.2.2.tgz", - "integrity": "sha512-H7DuVkPCK5BlAr1NfSU8bDEN7gYs+R78pSHhDng83QxRnCLmVIZk33ymmIwurmoA1HrdTxbkbuNl+lMvNqnytw==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "node_modules/@mikro-orm/cli": { + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/@mikro-orm/cli/-/cli-6.4.12.tgz", + "integrity": "sha512-7rKtrR4GAmeHOCSIPqtL1rtKdAQFvuCghiNxbL2+ck7d5SHRLG/pSCmnW70p5160a9mJ8uCl8vfWIQNOsX94Sw==", + "dev": true, + "dependencies": { + "@jercle/yargonaut": "1.1.5", + "@mikro-orm/core": "6.4.12", + "@mikro-orm/knex": "6.4.12", + "fs-extra": "11.3.0", + "tsconfig-paths": "4.2.0", + "yargs": "17.7.2" + }, + "bin": { + "mikro-orm": "cli", + "mikro-orm-esm": "esm" + }, "engines": { - "node": ">= 10" + "node": ">= 18.12.0" } }, - "node_modules/@napi-rs/snappy-android-arm64": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-android-arm64/-/snappy-android-arm64-7.2.2.tgz", - "integrity": "sha512-2R/A3qok+nGtpVK8oUMcrIi5OMDckGYNoBLFyli3zp8w6IArPRfg1yOfVUcHvpUDTo9T7LOS1fXgMOoC796eQw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "node_modules/@mikro-orm/core": { + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/@mikro-orm/core/-/core-6.4.12.tgz", + "integrity": "sha512-TzJJCFZCdyrVPt/K3UHdao8Iyj4xJSj2r0tYUCY4zNKwuUw6K3RlEYcWGUf85FWIAZJPpYqbv83WTb/H9OiyyQ==", + "dependencies": { + "dataloader": "2.2.3", + "dotenv": "16.4.7", + "esprima": "4.0.1", + "fs-extra": "11.3.0", + "globby": "11.1.0", + "mikro-orm": "6.4.12", + "reflect-metadata": "0.2.2" + }, "engines": { - "node": ">= 10" + "node": ">= 18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/b4nan" } }, - "node_modules/@napi-rs/snappy-darwin-arm64": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-arm64/-/snappy-darwin-arm64-7.2.2.tgz", - "integrity": "sha512-USgArHbfrmdbuq33bD5ssbkPIoT7YCXCRLmZpDS6dMDrx+iM7eD2BecNbOOo7/v1eu6TRmQ0xOzeQ6I/9FIi5g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/@mikro-orm/knex": { + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/@mikro-orm/knex/-/knex-6.4.12.tgz", + "integrity": "sha512-KMocJ4fdAbf52I/K25eV+dZDWXdVJpiIaBuIRt04m+SiJ7HZPP0OTDt/mexX3WHWW2m/d1byDNIZecjmV0eRSA==", + "dependencies": { + "fs-extra": "11.3.0", + "knex": "3.1.0", + "sqlstring": "2.3.3" + }, "engines": { - "node": ">= 10" + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0", + "better-sqlite3": "*", + "libsql": "*", + "mariadb": "*" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "libsql": { + "optional": true + }, + "mariadb": { + "optional": true + } } }, - "node_modules/@napi-rs/snappy-darwin-x64": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-darwin-x64/-/snappy-darwin-x64-7.2.2.tgz", - "integrity": "sha512-0APDu8iO5iT0IJKblk2lH0VpWSl9zOZndZKnBYIc+ei1npw2L5QvuErFOTeTdHBtzvUHASB+9bvgaWnQo4PvTQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/@mikro-orm/postgresql": { + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/@mikro-orm/postgresql/-/postgresql-6.4.12.tgz", + "integrity": "sha512-qWO2oerG2A9Jf6dCP/3tvnwxB/Y7gZGXOByG/iMlnQHeHEZ95G5GDe1TSZ/5Ho52wGoq3Vn3xzeKZwJdajbcEw==", + "dependencies": { + "@mikro-orm/knex": "6.4.12", + "pg": "8.14.1", + "postgres-array": "3.0.4", + "postgres-date": "2.1.0", + "postgres-interval": "4.0.2" + }, "engines": { - "node": ">= 10" + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" } }, - "node_modules/@napi-rs/snappy-freebsd-x64": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-freebsd-x64/-/snappy-freebsd-x64-7.2.2.tgz", - "integrity": "sha512-mRTCJsuzy0o/B0Hnp9CwNB5V6cOJ4wedDTWEthsdKHSsQlO7WU9W1yP7H3Qv3Ccp/ZfMyrmG98Ad7u7lG58WXA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "node_modules/@mikro-orm/reflection": { + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/@mikro-orm/reflection/-/reflection-6.4.12.tgz", + "integrity": "sha512-RZAMFAwe+yBylbiaHTyBDXDZWkqcLVv6IxRAc/YGBhD+Z1NjZbrFRrNg7OQryEW13OUIuIrXTCgKb9C0Mem0cQ==", + "dependencies": { + "globby": "11.1.0", + "ts-morph": "25.0.1" + }, "engines": { - "node": ">= 10" + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" } }, - "node_modules/@napi-rs/snappy-linux-arm-gnueabihf": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm-gnueabihf/-/snappy-linux-arm-gnueabihf-7.2.2.tgz", - "integrity": "sha512-v1uzm8+6uYjasBPcFkv90VLZ+WhLzr/tnfkZ/iD9mHYiULqkqpRuC8zvc3FZaJy5wLQE9zTDkTJN1IvUcZ+Vcg==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@mikro-orm/sqlite": { + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/@mikro-orm/sqlite/-/sqlite-6.4.12.tgz", + "integrity": "sha512-fIR/AkgUxOEKCiGxes8BrkNm86iP7eB0ZhvDjrRbinYxarGHtPIUEub0tY0jvQNbXo4s/GwRIPhA178pr5xEFA==", + "dependencies": { + "@mikro-orm/knex": "6.4.12", + "fs-extra": "11.3.0", + "sqlite3": "5.1.7", + "sqlstring-sqlite": "0.1.1" + }, "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/snappy-linux-arm64-gnu": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-gnu/-/snappy-linux-arm64-gnu-7.2.2.tgz", - "integrity": "sha512-LrEMa5pBScs4GXWOn6ZYXfQ72IzoolZw5txqUHVGs8eK4g1HR9HTHhb2oY5ySNaKakG5sOgMsb1rwaEnjhChmQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/snappy-linux-arm64-musl": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-linux-arm64-musl/-/snappy-linux-arm64-musl-7.2.2.tgz", - "integrity": "sha512-3orWZo9hUpGQcB+3aTLW7UFDqNCQfbr0+MvV67x8nMNYj5eAeUtMmUE/HxLznHO4eZ1qSqiTwLbVx05/Socdlw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "node": ">= 18.12.0" + }, + "peerDependencies": { + "@mikro-orm/core": "^6.0.0" } }, "node_modules/@napi-rs/snappy-linux-x64-gnu": { @@ -2147,54 +1539,6 @@ "node": ">= 10" } }, - "node_modules/@napi-rs/snappy-win32-arm64-msvc": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-arm64-msvc/-/snappy-win32-arm64-msvc-7.2.2.tgz", - "integrity": "sha512-9No0b3xGbHSWv2wtLEn3MO76Yopn1U2TdemZpCaEgOGccz1V+a/1d16Piz3ofSmnA13HGFz3h9NwZH9EOaIgYA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/snappy-win32-ia32-msvc": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-ia32-msvc/-/snappy-win32-ia32-msvc-7.2.2.tgz", - "integrity": "sha512-QiGe+0G86J74Qz1JcHtBwM3OYdTni1hX1PFyLRo3HhQUSpmi13Bzc1En7APn+6Pvo7gkrcy81dObGLDSxFAkQQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/snappy-win32-x64-msvc": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/@napi-rs/snappy-win32-x64-msvc/-/snappy-win32-x64-msvc-7.2.2.tgz", - "integrity": "sha512-a43cyx1nK0daw6BZxVcvDEXxKMFLSBSDTAhsFD0VqSKcC7MGUBMaqyoWUcMiI7LBSz4bxUmxDWKfCYzpEmeb3w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2417,231 +1761,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.38.0.tgz", - "integrity": "sha512-ldomqc4/jDZu/xpYU+aRxo3V4mGCV9HeTgUBANI3oIQMOL+SsxB+S2lxMpkFp5UamSS3XuTMQVbsS24R4J4Qjg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.38.0.tgz", - "integrity": "sha512-VUsgcy4GhhT7rokwzYQP+aV9XnSLkkhlEJ0St8pbasuWO/vwphhZQxYEKUP3ayeCYLhk6gEtacRpYP/cj3GjyQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "peer": true - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.38.0.tgz", - "integrity": "sha512-buA17AYXlW9Rn091sWMq1xGUvWQFOH4N1rqUxGJtEQzhChxWjldGCCup7r/wUnaI6Au8sKXpoh0xg58a7cgcpg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.38.0.tgz", - "integrity": "sha512-Mgcmc78AjunP1SKXl624vVBOF2bzwNWFPMP4fpOu05vS0amnLcX8gHIge7q/lDAHy3T2HeR0TqrriZDQS2Woeg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.38.0.tgz", - "integrity": "sha512-zzJACgjLbQTsscxWqvrEQAEh28hqhebpRz5q/uUd1T7VTwUNZ4VIXQt5hE7ncs0GrF+s7d3S4on4TiXUY8KoQA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.38.0.tgz", - "integrity": "sha512-hCY/KAeYMCyDpEE4pTETam0XZS4/5GXzlLgpi5f0IaPExw9kuB+PDTOTLuPtM10TlRG0U9OSmXJ+Wq9J39LvAg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.38.0.tgz", - "integrity": "sha512-mimPH43mHl4JdOTD7bUMFhBdrg6f9HzMTOEnzRmXbOZqjijCw8LA5z8uL6LCjxSa67H2xiLFvvO67PT05PRKGg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.38.0.tgz", - "integrity": "sha512-tPiJtiOoNuIH8XGG8sWoMMkAMm98PUwlriOFCCbZGc9WCax+GLeVRhmaxjJtz6WxrPKACgrwoZ5ia/uapq3ZVg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.38.0.tgz", - "integrity": "sha512-wZco59rIVuB0tjQS0CSHTTUcEde+pXQWugZVxWaQFdQQ1VYub/sTrNdY76D1MKdN2NB48JDuGABP6o6fqos8mA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.38.0.tgz", - "integrity": "sha512-fQgqwKmW0REM4LomQ+87PP8w8xvU9LZfeLBKybeli+0yHT7VKILINzFEuggvnV9M3x1Ed4gUBmGUzCo/ikmFbQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.38.0.tgz", - "integrity": "sha512-hz5oqQLXTB3SbXpfkKHKXLdIp02/w3M+ajp8p4yWOWwQRtHWiEOCKtc9U+YXahrwdk+3qHdFMDWR5k+4dIlddg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.38.0.tgz", - "integrity": "sha512-NXqygK/dTSibQ+0pzxsL3r4Xl8oPqVoWbZV9niqOnIHV/J92fe65pOir0xjkUZDRSPyFRvu+4YOpJF9BZHQImw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.38.0.tgz", - "integrity": "sha512-GEAIabR1uFyvf/jW/5jfu8gjM06/4kZ1W+j1nWTSSB3w6moZEBm7iBtzwQ3a1Pxos2F7Gz+58aVEnZHU295QTg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.38.0.tgz", - "integrity": "sha512-9EYTX+Gus2EGPbfs+fh7l95wVADtSQyYw4DfSBcYdUEAmP2lqSZY0Y17yX/3m5VKGGJ4UmIH5LHLkMJft3bYoA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.38.0.tgz", - "integrity": "sha512-Mpp6+Z5VhB9VDk7RwZXoG2qMdERm3Jw07RNlXHE0bOnEeX+l7Fy4bg+NxfyN15ruuY3/7Vrbpm75J9QHFqj5+Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "peer": true - }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.38.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.38.0.tgz", @@ -2672,51 +1791,6 @@ ], "peer": true }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.38.0.tgz", - "integrity": "sha512-u/Jbm1BU89Vftqyqbmxdq14nBaQjQX1HhmsdBWqSdGClNaKwhjsg5TpW+5Ibs1mb8Es9wJiMdl86BcmtUVXNZg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.38.0.tgz", - "integrity": "sha512-mqu4PzTrlpNHHbu5qleGvXJoGgHpChBlrBx/mEhTPpnAL1ZAYFlvHD7rLK839LLKQzqEQMFJfGrrOHItN4ZQqA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.38.0.tgz", - "integrity": "sha512-jjqy3uWlecfB98Psxb5cD6Fny9Fupv9LrDSPTQZUROqjvZmcCqNu4UMl7qqhlUUGpwiAkotj6GYu4SZdcr/nLw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "peer": true - }, "node_modules/@scarf/scarf": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", @@ -6177,22 +5251,6 @@ "devOptional": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -7893,6 +6951,14 @@ "node": ">=8.6" } }, + "node_modules/mikro-orm": { + "version": "6.4.12", + "resolved": "https://registry.npmjs.org/mikro-orm/-/mikro-orm-6.4.12.tgz", + "integrity": "sha512-uOJdx0q9Hg0SKYtHeJ73Iu2PhlU8LoyhaMm2PH9n1kvqpyoqUme2vKpwWywELFpZKgXwtkeIA8Ce56caYb593Q==", + "engines": { + "node": ">= 18.12.0" + } + }, "node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", @@ -8688,7 +7754,6 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.14.1.tgz", "integrity": "sha512-0TdbqfjwIun9Fm/r89oB7RFQ0bLgduAhiIqIXOsyKoiC/L54DbuAAzIEN/9Op0f1Po9X7iCPXGoa/Ah+2aI8Xw==", "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.7.0", "pg-pool": "^3.8.0", @@ -8798,8 +7863,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/pgpass": { "version": "1.0.5", @@ -8873,21 +7937,6 @@ "node": ">=18" } }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",