diff --git a/apps/server/src/modules/group/controller/dto/request/group-pagination.params.ts b/apps/server/src/modules/group/controller/dto/request/group-pagination.params.ts new file mode 100644 index 00000000000..c96860abf04 --- /dev/null +++ b/apps/server/src/modules/group/controller/dto/request/group-pagination.params.ts @@ -0,0 +1,9 @@ +import { ApiPropertyOptional } from '@nestjs/swagger'; +import { PaginationParams } from '@shared/controller'; +import { IsInt } from 'class-validator'; + +export class GroupPaginationParams extends PaginationParams { + @IsInt() + @ApiPropertyOptional({ description: 'Page limit, defaults to 10.' }) + override limit?: number = 10; +} diff --git a/apps/server/src/modules/group/controller/dto/request/index.ts b/apps/server/src/modules/group/controller/dto/request/index.ts index ceef988aa92..cb39cb2f9c5 100644 --- a/apps/server/src/modules/group/controller/dto/request/index.ts +++ b/apps/server/src/modules/group/controller/dto/request/index.ts @@ -1,3 +1,4 @@ export * from './class-sort-params'; export * from './group-id-params'; export * from './class-filter-params'; +export { GroupPaginationParams } from './group-pagination.params'; diff --git a/apps/server/src/modules/group/controller/group.controller.ts b/apps/server/src/modules/group/controller/group.controller.ts index 2a0e94893a7..7a5117466b7 100644 --- a/apps/server/src/modules/group/controller/group.controller.ts +++ b/apps/server/src/modules/group/controller/group.controller.ts @@ -1,12 +1,18 @@ import { Authenticate, CurrentUser, ICurrentUser } from '@modules/authentication'; import { Controller, Get, HttpStatus, Param, Query } from '@nestjs/common'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; -import { PaginationParams } from '@shared/controller'; import { Page } from '@shared/domain/domainobject'; import { ErrorResponse } from '@src/core/error/dto'; import { GroupUc } from '../uc'; import { ClassInfoDto, ResolvedGroupDto } from '../uc/dto'; -import { ClassFilterParams, ClassInfoSearchListResponse, ClassSortParams, GroupIdParams, GroupResponse } from './dto'; +import { + ClassFilterParams, + ClassInfoSearchListResponse, + ClassSortParams, + GroupIdParams, + GroupResponse, + GroupPaginationParams, +} from './dto'; import { GroupResponseMapper } from './mapper'; @ApiTags('Group') @@ -21,7 +27,7 @@ export class GroupController { @ApiResponse({ status: '5XX', type: ErrorResponse }) @Get('/class') public async findClasses( - @Query() pagination: PaginationParams, + @Query() pagination: GroupPaginationParams, @Query() sortingQuery: ClassSortParams, @Query() filterParams: ClassFilterParams, @CurrentUser() currentUser: ICurrentUser 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 d1cb9748e7d..e49179202c1 100644 --- a/apps/server/src/modules/group/uc/group.uc.spec.ts +++ b/apps/server/src/modules/group/uc/group.uc.spec.ts @@ -522,7 +522,7 @@ describe('GroupUc', () => { }); describe('when accessing as a user with elevated permission', () => { - const setup = () => { + const setup = (generateClasses = false) => { const school: LegacySchoolDo = legacySchoolDoFactory.buildWithId(); const { studentUser } = UserAndAccountTestFactory.buildStudent(); const { teacherUser } = UserAndAccountTestFactory.buildTeacher(); @@ -551,6 +551,15 @@ describe('GroupUc', () => { roles: [{ id: studentUser.roles[0].id, name: studentUser.roles[0].name }], }); const schoolYear: SchoolYearEntity = schoolYearFactory.buildWithId(); + let clazzes: Class[] = []; + if (generateClasses) { + clazzes = classFactory.buildList(11, { + name: 'A', + teacherIds: [teacherUser.id], + source: 'LDAP', + year: schoolYear.id, + }); + } const clazz: Class = classFactory.build({ name: 'A', teacherIds: [teacherUser.id], @@ -579,7 +588,7 @@ describe('GroupUc', () => { schoolService.getSchoolById.mockResolvedValueOnce(school); authorizationService.getUserWithPermissions.mockResolvedValueOnce(adminUser); authorizationService.hasAllPermissions.mockReturnValueOnce(true); - classService.findClassesForSchool.mockResolvedValueOnce([clazz]); + classService.findClassesForSchool.mockResolvedValueOnce([...clazzes, clazz]); groupService.findGroupsBySchoolIdAndGroupTypes.mockResolvedValueOnce([group, groupWithSystem]); systemService.findById.mockResolvedValue(system); @@ -788,6 +797,34 @@ describe('GroupUc', () => { total: 3, }); }); + + it('should return classes with expected limit', async () => { + const { adminUser } = setup(true); + + const result: Page = await uc.findAllClasses( + adminUser.id, + adminUser.school.id, + undefined, + 0, + 5 + ); + + expect(result.data.length).toEqual(5); + }); + + it('should return all classes without limit', async () => { + const { adminUser } = setup(true); + + const result: Page = await uc.findAllClasses( + adminUser.id, + adminUser.school.id, + undefined, + 0, + -1 + ); + + expect(result.data.length).toEqual(14); + }); }); }); diff --git a/apps/server/src/modules/group/uc/group.uc.ts b/apps/server/src/modules/group/uc/group.uc.ts index 13e4741b289..272019c5e77 100644 --- a/apps/server/src/modules/group/uc/group.uc.ts +++ b/apps/server/src/modules/group/uc/group.uc.ts @@ -331,8 +331,14 @@ export class GroupUc { return resolvedGroupUsers; } - private applyPagination(combinedClassInfo: ClassInfoDto[], skip: number, limit: number | undefined) { - const page: ClassInfoDto[] = combinedClassInfo.slice(skip, limit ? skip + limit : combinedClassInfo.length); + private applyPagination(combinedClassInfo: ClassInfoDto[], skip: number, limit: number | undefined): ClassInfoDto[] { + let page: ClassInfoDto[]; + + if (limit === -1) { + page = combinedClassInfo.slice(skip); + } else { + page = combinedClassInfo.slice(skip, limit ? skip + limit : combinedClassInfo.length); + } return page; } diff --git a/apps/server/src/modules/legacy-school/controller/school.controller.ts b/apps/server/src/modules/legacy-school/controller/school.controller.ts index 1eef6d58229..50c6c0773ef 100644 --- a/apps/server/src/modules/legacy-school/controller/school.controller.ts +++ b/apps/server/src/modules/legacy-school/controller/school.controller.ts @@ -3,6 +3,7 @@ import { Body, Controller, Get, Param, Post } from '@nestjs/common'; import { ApiBody, ApiCreatedResponse, + ApiExtraModels, ApiForbiddenResponse, ApiNotFoundResponse, ApiOkResponse, @@ -45,6 +46,7 @@ export class SchoolController { @ApiForbiddenResponse() @ApiUnprocessableEntityResponse() @ApiNotFoundResponse() + @ApiExtraModels(SchulConneXProvisioningOptionsResponse) public async getProvisioningOptions( @CurrentUser() currentUser: ICurrentUser, @Param() params: SchoolSystemParams @@ -79,6 +81,7 @@ export class SchoolController { @ApiForbiddenResponse() @ApiUnprocessableEntityResponse() @ApiNotFoundResponse() + @ApiExtraModels(SchulConneXProvisioningOptionsResponse) public async setProvisioningOptions( @CurrentUser() currentUser: ICurrentUser, @Param() params: SchoolSystemParams,