diff --git a/apps/server/src/modules/group/loggable/unknown-query-type-loggable-exception.spec.ts b/apps/server/src/modules/group/loggable/unknown-query-type-loggable-exception.spec.ts new file mode 100644 index 00000000000..c4f87e6a21a --- /dev/null +++ b/apps/server/src/modules/group/loggable/unknown-query-type-loggable-exception.spec.ts @@ -0,0 +1,31 @@ +import { UnknownQueryTypeLoggableException } from './unknown-query-type-loggable-exception'; + +describe('UnknownQueryTypeLoggableException', () => { + describe('getLogMessage', () => { + const setup = () => { + const unknownQueryType = 'unknwon'; + + const exception = new UnknownQueryTypeLoggableException(unknownQueryType); + + return { + exception, + unknownQueryType, + }; + }; + + it('should log the correct message', () => { + const { exception, unknownQueryType } = setup(); + + const result = exception.getLogMessage(); + + expect(result).toEqual({ + type: 'INTERNAL_SERVER_ERROR', + stack: expect.any(String), + message: 'Unable to process unknown query type for class years.', + data: { + unknownQueryType, + }, + }); + }); + }); +}); diff --git a/apps/server/src/modules/group/loggable/unknown-query-type-loggable-exception.ts b/apps/server/src/modules/group/loggable/unknown-query-type-loggable-exception.ts new file mode 100644 index 00000000000..758b4c1fb6b --- /dev/null +++ b/apps/server/src/modules/group/loggable/unknown-query-type-loggable-exception.ts @@ -0,0 +1,19 @@ +import { ErrorLogMessage, Loggable, LogMessage, ValidationErrorLogMessage } from '@src/core/logger'; +import { InternalServerErrorException } from '@nestjs/common'; + +export class UnknownQueryTypeLoggableException extends InternalServerErrorException implements Loggable { + constructor(private readonly unknownQueryType: string) { + super(); + } + + getLogMessage(): LogMessage | ErrorLogMessage | ValidationErrorLogMessage { + return { + type: 'INTERNAL_SERVER_ERROR', + stack: this.stack, + message: 'Unable to process unknown query type for class years.', + data: { + unknownQueryType: this.unknownQueryType, + }, + }; + } +} diff --git a/apps/server/src/modules/group/uc/group.uc.spec.ts b/apps/server/src/modules/group/uc/group.uc.spec.ts index da9109bd7ee..71bae1e44a8 100644 --- a/apps/server/src/modules/group/uc/group.uc.spec.ts +++ b/apps/server/src/modules/group/uc/group.uc.spec.ts @@ -29,6 +29,7 @@ import { ClassInfoDto, ResolvedGroupDto } from './dto'; import { ClassRootType } from './dto/class-root-type'; import { GroupUc } from './group.uc'; import { SchoolYearQueryType } from '../controller/dto'; +import { UnknownQueryTypeLoggableException } from '../loggable/unknown-query-type-loggable-exception'; describe('GroupUc', () => { let module: TestingModule; @@ -169,6 +170,12 @@ describe('GroupUc', () => { teacherIds: [teacherUser.id], year: nextSchoolYear.id, }); + const classWithoutSchoolYear = classFactory.build({ + name: 'NoYear', + teacherIds: [teacherUser.id], + year: undefined, + }); + const system: SystemDto = new SystemDto({ id: new ObjectId().toHexString(), displayName: 'External System', @@ -190,7 +197,7 @@ describe('GroupUc', () => { schoolService.getSchoolById.mockResolvedValueOnce(school); authorizationService.getUserWithPermissions.mockResolvedValueOnce(teacherUser); - classService.findClassesForSchool.mockResolvedValueOnce([clazz, successorClass]); + classService.findClassesForSchool.mockResolvedValueOnce([clazz, successorClass, classWithoutSchoolYear]); groupService.findClassesForSchool.mockResolvedValueOnce([group, groupWithSystem]); systemService.findById.mockResolvedValue(system); userService.findById.mockImplementation((userId: string): Promise => { @@ -224,6 +231,7 @@ describe('GroupUc', () => { school, clazz, successorClass, + classWithoutSchoolYear, group, groupWithSystem, system, @@ -249,8 +257,17 @@ describe('GroupUc', () => { describe('when no pagination is given', () => { it('should return all classes sorted by name', async () => { - const { teacherUser, clazz, successorClass, group, groupWithSystem, system, schoolYear, nextSchoolYear } = - setup(); + const { + teacherUser, + clazz, + successorClass, + classWithoutSchoolYear, + group, + groupWithSystem, + system, + schoolYear, + nextSchoolYear, + } = setup(); const result: Page = await uc.findAllClassesForSchool( teacherUser.id, @@ -275,13 +292,24 @@ describe('GroupUc', () => { name: successorClass.gradeLevel ? `${successorClass.gradeLevel}${successorClass.name}` : successorClass.name, - externalSourceName: successorClass.source, type: ClassRootType.CLASS, + externalSourceName: successorClass.source, teachers: [teacherUser.lastName], schoolYear: nextSchoolYear.name, isUpgradable: false, studentCount: 2, }, + { + id: classWithoutSchoolYear.id, + name: classWithoutSchoolYear.gradeLevel + ? `${classWithoutSchoolYear.gradeLevel}${classWithoutSchoolYear.name}` + : classWithoutSchoolYear.name, + type: ClassRootType.CLASS, + externalSourceName: classWithoutSchoolYear.source, + teachers: [teacherUser.lastName], + isUpgradable: false, + studentCount: 2, + }, { id: group.id, name: group.name, @@ -298,14 +326,14 @@ describe('GroupUc', () => { studentCount: 1, }, ], - total: 4, + total: 5, }); }); }); describe('when sorting by external source name in descending order', () => { it('should return all classes sorted by external source name in descending order', async () => { - const { teacherUser, clazz, group, groupWithSystem, system, schoolYear } = setup(); + const { teacherUser, clazz, classWithoutSchoolYear, group, groupWithSystem, system, schoolYear } = setup(); const result: Page = await uc.findAllClassesForSchool( teacherUser.id, @@ -319,6 +347,17 @@ describe('GroupUc', () => { expect(result).toEqual>({ data: [ + { + id: classWithoutSchoolYear.id, + name: classWithoutSchoolYear.gradeLevel + ? `${classWithoutSchoolYear.gradeLevel}${classWithoutSchoolYear.name}` + : classWithoutSchoolYear.name, + type: ClassRootType.CLASS, + externalSourceName: classWithoutSchoolYear.source, + teachers: [teacherUser.lastName], + isUpgradable: false, + studentCount: 2, + }, { id: clazz.id, name: clazz.gradeLevel ? `${clazz.gradeLevel}${clazz.name}` : clazz.name, @@ -345,7 +384,7 @@ describe('GroupUc', () => { studentCount: 0, }, ], - total: 3, + total: 4, }); }); }); @@ -358,7 +397,7 @@ describe('GroupUc', () => { teacherUser.id, teacherUser.school.id, SchoolYearQueryType.CURRENT_YEAR, - 1, + 2, 1, 'name', SortOrder.asc @@ -374,7 +413,7 @@ describe('GroupUc', () => { studentCount: 0, }, ], - total: 3, + total: 4, }); }); }); @@ -425,6 +464,17 @@ describe('GroupUc', () => { }); }); }); + + describe('when querying for not existing type', () => { + it('should throw', async () => { + const { teacherUser } = setup(); + + const func = async () => + uc.findAllClassesForSchool(teacherUser.id, teacherUser.school.id, 'notAType' as SchoolYearQueryType); + + await expect(func).rejects.toThrow(UnknownQueryTypeLoggableException); + }); + }); }); }); diff --git a/apps/server/src/modules/group/uc/group.uc.ts b/apps/server/src/modules/group/uc/group.uc.ts index 2f37673b696..4ec850c42e9 100644 --- a/apps/server/src/modules/group/uc/group.uc.ts +++ b/apps/server/src/modules/group/uc/group.uc.ts @@ -14,6 +14,7 @@ import { SortHelper } from '../util'; import { ClassInfoDto, ResolvedGroupDto, ResolvedGroupUser } from './dto'; import { GroupUcMapper } from './mapper/group-uc.mapper'; import { SchoolYearQueryType } from '../controller/dto'; +import { UnknownQueryTypeLoggableException } from '../loggable/unknown-query-type-loggable-exception'; @Injectable() export class GroupUc { @@ -141,7 +142,7 @@ export class GroupUc { case SchoolYearQueryType.PREVIOUS_YEARS: return schoolYear.startDate < currentYear.startDate; default: - return true; + throw new UnknownQueryTypeLoggableException(schoolYearQueryType); } }