diff --git a/src/modules/personenkontext/api/dbiam-personenkontext-workflow.controller.integration-spec.ts b/src/modules/personenkontext/api/dbiam-personenkontext-workflow.controller.integration-spec.ts index 1de614391..420c304c2 100644 --- a/src/modules/personenkontext/api/dbiam-personenkontext-workflow.controller.integration-spec.ts +++ b/src/modules/personenkontext/api/dbiam-personenkontext-workflow.controller.integration-spec.ts @@ -25,7 +25,6 @@ import { Observable } from 'rxjs'; import { PassportUser } from '../../authentication/types/user.js'; import { Request } from 'express'; import { PersonPermissions } from '../../authentication/domain/person-permissions.js'; -import { FindRollenResponse } from './response/find-rollen.response.js'; import { OrganisationDo } from '../../organisation/domain/organisation.do.js'; import { PersonenkontextFactory } from '../domain/personenkontext.factory.js'; import { DBiamPersonenkontextRepo } from '../persistence/dbiam-personenkontext.repo.js'; @@ -549,51 +548,6 @@ describe('DbiamPersonenkontextWorkflowController Integration Test', () => { }); }); - describe('/GET rollen for personenkontext', () => { - it('should return all rollen for a personenkontext without filter, if the user is Landesadmin', async () => { - const rolleName: string = faker.string.alpha({ length: 10 }); - await rolleRepo.save(createRolle(rolleFactory, { name: rolleName, rollenart: RollenArt.SYSADMIN })); - const schuladminRolleName: string = faker.string.alpha({ length: 10 }); - await rolleRepo.save(createRolle(rolleFactory, { name: schuladminRolleName, rollenart: RollenArt.LEIT })); - - const personpermissions: DeepMocked = createMock(); - personpermissions.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisationRepo.ROOT_ORGANISATION_ID]); - personpermissionsRepoMock.loadPersonPermissions.mockResolvedValue(personpermissions); - - const response: Response = await request(app.getHttpServer() as App) - .get('/personenkontext-workflow/rollen') - .send(); - - expect(response.status).toBe(200); - expect(response.body).toBeInstanceOf(Object); - expect(response.body).toEqual( - expect.objectContaining({ - total: 2, - }) as FindRollenResponse, - ); - }); - - it('should return all rollen for a personenkontext based on PersonenkontextAnlage', async () => { - const rolleName: string = faker.string.alpha({ length: 10 }); - await rolleRepo.save(createRolle(rolleFactory, { name: rolleName })); - const response: Response = await request(app.getHttpServer() as App) - .get(`/personenkontext-workflow/rollen?rolleName=${rolleName}&limit=25`) - .send(); - - expect(response.status).toBe(200); - expect(response.body).toBeInstanceOf(Object); - }); - - it('should return empty list', async () => { - const response: Response = await request(app.getHttpServer() as App) - .get(`/personenkontext-workflow/rollen?rolleName=${faker.string.alpha()}&limit=25`) - .send(); - - expect(response.status).toBe(200); - expect(response.body).toBeInstanceOf(Object); - }); - }); - describe('/GET schulstrukturknoten for personenkontext', () => { it('should return all schulstrukturknoten for a personenkontext based on PersonenkontextAnlage', async () => { const rolleName: string = faker.string.alpha({ length: 10 }); diff --git a/src/modules/personenkontext/api/dbiam-personenkontext-workflow.controller.ts b/src/modules/personenkontext/api/dbiam-personenkontext-workflow.controller.ts index 99461f862..e41ecc590 100644 --- a/src/modules/personenkontext/api/dbiam-personenkontext-workflow.controller.ts +++ b/src/modules/personenkontext/api/dbiam-personenkontext-workflow.controller.ts @@ -25,9 +25,7 @@ import { ApiUnauthorizedResponse, } from '@nestjs/swagger'; import { SchulConnexValidationErrorFilter } from '../../../shared/error/schulconnex-validation-error.filter.js'; -import { FindPersonenkontextRollenBodyParams } from './param/find-personenkontext-rollen.body.params.js'; import { FindPersonenkontextSchulstrukturknotenBodyParams } from './param/find-personenkontext-schulstrukturknoten.body.params.js'; -import { FindRollenResponse } from './response/find-rollen.response.js'; import { FindSchulstrukturknotenResponse } from './response/find-schulstrukturknoten.response.js'; import { PersonenkontextWorkflowAggregate } from '../domain/personenkontext-workflow.js'; import { Rolle } from '../../rolle/domain/rolle.js'; @@ -160,25 +158,6 @@ export class DbiamPersonenkontextWorkflowController { return new PersonenkontexteUpdateResponse(updateResult); } - @Get('rollen') - @ApiOkResponse({ - description: 'The rollen for a personenkontext were successfully returned.', - type: FindRollenResponse, - }) - @ApiUnauthorizedResponse({ description: 'Not authorized to get available rolen for personenkontexte.' }) - @ApiForbiddenResponse({ description: 'Insufficient permission to get rollen for personenkontext.' }) - @ApiInternalServerErrorResponse({ description: 'Internal server error while getting rollen for personenkontexte.' }) - public async findRollen( - @Query() params: FindPersonenkontextRollenBodyParams, - @Permissions() permissions: PersonPermissions, - ): Promise { - const anlage: PersonenkontextWorkflowAggregate = this.personenkontextWorkflowFactory.createNew(); - const rollen: Rolle[] = await anlage.findAuthorizedRollen(permissions, params.rolleName, params.limit); - const response: FindRollenResponse = new FindRollenResponse(rollen, rollen.length); - - return response; - } - @Get('schulstrukturknoten') @ApiOkResponse({ description: 'The schulstrukturknoten for a personenkontext were successfully returned.', diff --git a/src/modules/personenkontext/api/person-administration.controller.integration-spec.ts b/src/modules/personenkontext/api/person-administration.controller.integration-spec.ts new file mode 100644 index 000000000..cc1705e19 --- /dev/null +++ b/src/modules/personenkontext/api/person-administration.controller.integration-spec.ts @@ -0,0 +1,140 @@ +import { faker } from '@faker-js/faker'; +import { MikroORM } from '@mikro-orm/core'; +import { CallHandler, ExecutionContext, INestApplication } from '@nestjs/common'; +import { APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core'; +import { Test, TestingModule } from '@nestjs/testing'; +import request, { Response } from 'supertest'; +import { App } from 'supertest/types.js'; +import { + ConfigTestModule, + DatabaseTestModule, + DoFactory, + KeycloakConfigTestModule, + MapperTestModule, +} from '../../../../test/utils/index.js'; +import { GlobalValidationPipe } from '../../../shared/validation/index.js'; +import { OrganisationRepo } from '../../organisation/persistence/organisation.repo.js'; +import { RolleRepo } from '../../rolle/repo/rolle.repo.js'; +import { PersonenKontextApiModule } from '../personenkontext-api.module.js'; +import { RollenArt } from '../../rolle/domain/rolle.enums.js'; +import { PersonPermissionsRepo } from '../../authentication/domain/person-permission.repo.js'; +import { DeepMocked, createMock } from '@golevelup/ts-jest'; +import { Observable } from 'rxjs'; +import { PassportUser } from '../../authentication/types/user.js'; +import { Request } from 'express'; +import { PersonPermissions } from '../../authentication/domain/person-permissions.js'; +import { FindRollenResponse } from './response/find-rollen.response.js'; +import { KeycloakAdministrationModule } from '../../keycloak-administration/keycloak-administration.module.js'; +import { KeycloakConfigModule } from '../../keycloak-administration/keycloak-config.module.js'; + +describe('PersonAdministrationController Integration Test', () => { + let app: INestApplication; + let orm: MikroORM; + let organisationRepo: OrganisationRepo; + let rolleRepo: RolleRepo; + let personpermissionsRepoMock: DeepMocked; + + beforeAll(async () => { + const module: TestingModule = await Test.createTestingModule({ + imports: [ + MapperTestModule, + ConfigTestModule, + DatabaseTestModule.forRoot({ isDatabaseRequired: true }), + PersonenKontextApiModule, + KeycloakAdministrationModule, + ], + providers: [ + { + provide: APP_PIPE, + useClass: GlobalValidationPipe, + }, + { + provide: PersonPermissionsRepo, + useValue: createMock(), + }, + { + provide: APP_INTERCEPTOR, + useValue: { + intercept(context: ExecutionContext, next: CallHandler): Observable { + const req: Request = context.switchToHttp().getRequest(); + req.passportUser = createMock({ + async personPermissions() { + return personpermissionsRepoMock.loadPersonPermissions(''); + }, + }); + return next.handle(); + }, + }, + }, + ], + }) + .overrideModule(KeycloakConfigModule) + .useModule(KeycloakConfigTestModule.forRoot({ isKeycloakRequired: true })) + .compile(); + + orm = module.get(MikroORM); + organisationRepo = module.get(OrganisationRepo); + rolleRepo = module.get(RolleRepo); + personpermissionsRepoMock = module.get(PersonPermissionsRepo); + + await DatabaseTestModule.setupDatabase(orm); + app = module.createNestApplication(); + await app.init(); + }, 10000000); + + afterAll(async () => { + await orm.close(); + await app.close(); + }); + + beforeEach(async () => { + await DatabaseTestModule.clearDatabase(orm); + }); + + describe('/GET rollen for personenkontext', () => { + it('should return all rollen for a logged-in user without filter, if the user is Landesadmin', async () => { + const rolleName: string = faker.string.alpha({ length: 10 }); + await rolleRepo.save(DoFactory.createRolle(false, { name: rolleName, rollenart: RollenArt.SYSADMIN })); + const schuladminRolleName: string = faker.string.alpha({ length: 10 }); + await rolleRepo.save( + DoFactory.createRolle(false, { name: schuladminRolleName, rollenart: RollenArt.LEIT }), + ); + + const personpermissions: DeepMocked = createMock(); + personpermissions.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisationRepo.ROOT_ORGANISATION_ID]); + personpermissionsRepoMock.loadPersonPermissions.mockResolvedValue(personpermissions); + + const response: Response = await request(app.getHttpServer() as App) + .get('/person-administration/rollen') + .send(); + + expect(response.status).toBe(200); + expect(response.body).toBeInstanceOf(Object); + expect(response.body).toEqual( + expect.objectContaining({ + total: 2, + }) as FindRollenResponse, + ); + }); + + it('should return all rollen for a logged-in user based on search filter', async () => { + const rolleName: string = faker.string.alpha({ length: 10 }); + await rolleRepo.save(DoFactory.createRolle(false, { name: rolleName })); + const response: Response = await request(app.getHttpServer() as App) + .get(`/person-administration/rollen?rolleName=${rolleName}&limit=25`) + .send(); + + expect(response.status).toBe(200); + expect(response.body).toBeInstanceOf(Object); + }); + + it('should return empty list, if rollen do not exist', async () => { + const response: Response = await request(app.getHttpServer() as App) + .get(`/person-administration/rollen?rolleName=${faker.string.alpha()}&limit=25`) + .send(); + + expect(response.status).toBe(200); + expect(response.body).toBeInstanceOf(Object); + }); + }); +}); diff --git a/src/modules/personenkontext/api/person-administration.controller.ts b/src/modules/personenkontext/api/person-administration.controller.ts new file mode 100644 index 000000000..3c07d5e81 --- /dev/null +++ b/src/modules/personenkontext/api/person-administration.controller.ts @@ -0,0 +1,51 @@ +import { Controller, Get, Query, UseFilters } from '@nestjs/common'; +import { + ApiBearerAuth, + ApiForbiddenResponse, + ApiInternalServerErrorResponse, + ApiOAuth2, + ApiOkResponse, + ApiTags, + ApiUnauthorizedResponse, +} from '@nestjs/swagger'; +import { SchulConnexValidationErrorFilter } from '../../../shared/error/schulconnex-validation-error.filter.js'; +import { FindPersonenkontextRollenBodyParams } from './param/find-personenkontext-rollen.body.params.js'; +import { FindRollenResponse } from './response/find-rollen.response.js'; +import { Rolle } from '../../rolle/domain/rolle.js'; +import { Permissions } from '../../authentication/api/permissions.decorator.js'; +import { PersonPermissions } from '../../authentication/domain/person-permissions.js'; +import { PersonenkontextExceptionFilter } from './personenkontext-exception-filter.js'; +import { PersonAdministrationService } from '../domain/person-administration.service.js'; + +@UseFilters(SchulConnexValidationErrorFilter, new PersonenkontextExceptionFilter()) +@ApiTags('person-administration') +@ApiBearerAuth() +@ApiOAuth2(['openid']) +@Controller({ path: 'person-administration' }) +export class PersonAdministrationController { + public constructor(private readonly personAdministrationService: PersonAdministrationService) {} + + @Get('rollen') + @ApiOkResponse({ + description: 'The rollen for the logged-in user were successfully returned.', + type: FindRollenResponse, + }) + @ApiUnauthorizedResponse({ description: 'Not authorized to get available rollen for the logged-in user.' }) + @ApiForbiddenResponse({ description: 'Insufficient permission to get rollen for the logged-in user.' }) + @ApiInternalServerErrorResponse({ + description: 'Internal server error while getting rollen for the logged-in user.', + }) + public async findRollen( + @Query() params: FindPersonenkontextRollenBodyParams, + @Permissions() permissions: PersonPermissions, + ): Promise { + const rollen: Rolle[] = await this.personAdministrationService.findAuthorizedRollen( + permissions, + params.rolleName, + params.limit, + ); + const response: FindRollenResponse = new FindRollenResponse(rollen, rollen.length); + + return response; + } +} diff --git a/src/modules/personenkontext/domain/person-administration.service.spec.ts b/src/modules/personenkontext/domain/person-administration.service.spec.ts new file mode 100644 index 000000000..22d39477b --- /dev/null +++ b/src/modules/personenkontext/domain/person-administration.service.spec.ts @@ -0,0 +1,160 @@ +import { Mapper } from '@automapper/core'; +import { getMapperToken } from '@automapper/nestjs'; +import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { Test, TestingModule } from '@nestjs/testing'; +import { DoFactory } from '../../../../test/utils/do-factory.js'; +import { RolleRepo } from '../../rolle/repo/rolle.repo.js'; +import { PersonPermissions } from '../../authentication/domain/person-permissions.js'; +import { OrganisationRepository } from '../../organisation/persistence/organisation.repository.js'; +import { Organisation } from '../../organisation/domain/organisation.js'; +import { Rolle } from '../../rolle/domain/rolle.js'; +import { RollenArt } from '../../rolle/domain/rolle.enums.js'; +import { OrganisationsTyp } from '../../organisation/domain/organisation.enums.js'; +import { PersonAdministrationService } from './person-administration.service.js'; + +describe('PersonAdministrationService', () => { + let module: TestingModule; + let sut: PersonAdministrationService; + let rolleRepoMock: DeepMocked; + let organisationRepositoryMock: DeepMocked; + let personpermissionsMock: DeepMocked; + + beforeAll(async () => { + module = await Test.createTestingModule({ + providers: [ + PersonAdministrationService, + { + provide: getMapperToken(), + useValue: createMock(), + }, + { + provide: RolleRepo, + useValue: createMock(), + }, + { + provide: OrganisationRepository, + useValue: createMock(), + }, + { + provide: PersonPermissions, + useValue: createMock(), + }, + ], + }).compile(); + sut = module.get(PersonAdministrationService); + rolleRepoMock = module.get(RolleRepo); + organisationRepositoryMock = module.get(OrganisationRepository); + personpermissionsMock = module.get(PersonPermissions); + }); + + afterAll(async () => { + await module.close(); + }); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should be defined', () => { + expect(sut).toBeDefined(); + }); + + describe('findAuthorizedRollen', () => { + it('should return list of all rollen when they exist, if the user is Landesadmin', async () => { + const rolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.SYSADMIN }); + const leitRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEIT }); + const lehrRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEHR }); + const lernRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LERN }); + + const rollen: Rolle[] = [rolle, leitRolle, lehrRolle, lernRolle]; + rolleRepoMock.find.mockResolvedValue(rollen); + + personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([ + organisationRepositoryMock.ROOT_ORGANISATION_ID, + ]); + + const result: Rolle[] = await sut.findAuthorizedRollen(personpermissionsMock); + expect(result).toEqual(rollen); + }); + + it('should return list of all rollen when they exist Except Landesadmin, if the user is NOT Landesadmin', async () => { + const rolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.SYSADMIN }); + const leitRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEIT }); + const lehrRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEHR }); + const lernRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LERN }); + + const rollen: Rolle[] = [rolle, leitRolle, lehrRolle, lernRolle]; + rolleRepoMock.find.mockResolvedValue(rollen); + + const organisation: Organisation = DoFactory.createOrganisation(true, { + typ: OrganisationsTyp.SCHULE, + }); + const organisationMap: Map> = new Map(); + organisationMap.set(organisation.id, organisation); + organisationRepositoryMock.findByIds.mockResolvedValueOnce(organisationMap); + + personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisation.id]); + + const result: Rolle[] = await sut.findAuthorizedRollen(personpermissionsMock); + expect(result).not.toContain(rolle); + }); + + it('should return list of rollen when they exist', async () => { + const rolle: Rolle = DoFactory.createRolle(true); + rolleRepoMock.findByName.mockResolvedValue([rolle]); + + personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([ + organisationRepositoryMock.ROOT_ORGANISATION_ID, + ]); + + const result: Rolle[] = await sut.findAuthorizedRollen(personpermissionsMock, rolle.name); + expect(result).toEqual([rolle]); + }); + + it('should return empty list when no rollen exist', async () => { + rolleRepoMock.findByName.mockResolvedValue(undefined); + + const result: Rolle[] = await sut.findAuthorizedRollen(personpermissionsMock, 'nonexistent'); + expect(result).toEqual([]); + }); + + it('should return list of limited rollen, if the user is Landesadmin and the limit is set', async () => { + const rolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.SYSADMIN }); + const leitRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEIT }); + const lehrRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEHR }); + const lernRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LERN }); + + const rollen: Rolle[] = [rolle, leitRolle, lehrRolle, lernRolle]; + rolleRepoMock.find.mockResolvedValue(rollen); + + personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([ + organisationRepositoryMock.ROOT_ORGANISATION_ID, + ]); + + const result: Rolle[] = await sut.findAuthorizedRollen(personpermissionsMock, undefined, 2); + expect(result).toHaveLength(2); + }); + + it('should return list of limited allowedRollen, if the user is NOT Landesadmin and the limit is set', async () => { + const rolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.SYSADMIN }); + const leitRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEIT }); + const lehrRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEHR }); + const lernRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LERN }); + + const rollen: Rolle[] = [rolle, leitRolle, lehrRolle, lernRolle]; + rolleRepoMock.find.mockResolvedValue(rollen); + + const organisationDo: Organisation = DoFactory.createOrganisation(true, { + typ: OrganisationsTyp.SCHULE, + }); + const organisationMap: Map> = new Map(); + organisationMap.set(organisationDo.id, organisationDo); + organisationRepositoryMock.findByIds.mockResolvedValueOnce(organisationMap); + + personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisationDo.id]); + + const result: Rolle[] = await sut.findAuthorizedRollen(personpermissionsMock, undefined, 2); + expect(result).toHaveLength(2); + }); + }); +}); diff --git a/src/modules/personenkontext/domain/person-administration.service.ts b/src/modules/personenkontext/domain/person-administration.service.ts new file mode 100644 index 000000000..91ad04f64 --- /dev/null +++ b/src/modules/personenkontext/domain/person-administration.service.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@nestjs/common'; +import { PersonPermissions } from '../../authentication/domain/person-permissions.js'; +import { OrganisationRepository } from '../../organisation/persistence/organisation.repository.js'; +import { Rolle } from '../../rolle/domain/rolle.js'; +import { RolleRepo } from '../../rolle/repo/rolle.repo.js'; +import { OrganisationID } from '../../../shared/types/aggregate-ids.types.js'; +import { OrganisationMatchesRollenart } from '../specification/organisation-matches-rollenart.js'; +import { RollenSystemRecht } from '../../rolle/domain/rolle.enums.js'; +import { Organisation } from '../../organisation/domain/organisation.js'; + +@Injectable() +export class PersonAdministrationService { + public constructor( + private readonly rolleRepo: RolleRepo, + private readonly organisationRepository: OrganisationRepository, + ) {} + + public async findAuthorizedRollen( + permissions: PersonPermissions, + rolleName?: string, + limit?: number, + ): Promise[]> { + let rollen: Option[]>; + + if (rolleName) { + rollen = await this.rolleRepo.findByName(rolleName); + } else { + rollen = await this.rolleRepo.find(); + } + + if (!rollen) return []; + + const orgsWithRecht: OrganisationID[] = await permissions.getOrgIdsWithSystemrecht( + [RollenSystemRecht.PERSONEN_VERWALTEN], + true, + ); + + //Landesadmin can view all roles. + if (orgsWithRecht.includes(this.organisationRepository.ROOT_ORGANISATION_ID)) { + return limit ? rollen.slice(0, limit) : rollen; + } + + const allowedRollen: Rolle[] = []; + const organisationMatchesRollenart: OrganisationMatchesRollenart = new OrganisationMatchesRollenart(); + (await this.organisationRepository.findByIds(orgsWithRecht)).forEach(function (orga: Organisation) { + rollen.forEach(function (rolle: Rolle) { + if (organisationMatchesRollenart.isSatisfiedBy(orga, rolle) && !allowedRollen.includes(rolle)) { + allowedRollen.push(rolle); + } + }); + }); + + return limit ? allowedRollen.slice(0, limit) : allowedRollen; + } +} diff --git a/src/modules/personenkontext/domain/personenkontext-workflow.spec.ts b/src/modules/personenkontext/domain/personenkontext-workflow.spec.ts index cce6e947e..49af2e434 100644 --- a/src/modules/personenkontext/domain/personenkontext-workflow.spec.ts +++ b/src/modules/personenkontext/domain/personenkontext-workflow.spec.ts @@ -1077,107 +1077,4 @@ describe('PersonenkontextWorkflow', () => { }); }); }); - - describe('findAuthorizedRollen', () => { - it('should return list of all rollen when they exist, if the user is Landesadmin', async () => { - const rolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.SYSADMIN }); - const leitRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEIT }); - const lehrRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEHR }); - const lernRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LERN }); - - const rollen: Rolle[] = [rolle, leitRolle, lehrRolle, lernRolle]; - rolleRepoMock.find.mockResolvedValue(rollen); - - personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([ - organisationRepoMock.ROOT_ORGANISATION_ID, - ]); - - const result: Rolle[] = await anlage.findAuthorizedRollen(personpermissionsMock); - expect(result).toEqual(rollen); - }); - - it('should return list of all rollen when they exist Except Landesadmin, if the user is NOT Landesadmin', async () => { - const rolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.SYSADMIN }); - const leitRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEIT }); - const lehrRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEHR }); - const lernRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LERN }); - - const rollen: Rolle[] = [rolle, leitRolle, lehrRolle, lernRolle]; - rolleRepoMock.find.mockResolvedValue(rollen); - - const organisationDo: OrganisationDo = DoFactory.createOrganisation(true, { - typ: OrganisationsTyp.SCHULE, - }); - const organisationMap: Map> = new Map(); - organisationMap.set(organisationDo.id, organisationDo); - organisationRepoMock.findByIds.mockResolvedValueOnce(organisationMap); - - personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisationDo.id]); - - const result: Rolle[] = await anlage.findAuthorizedRollen(personpermissionsMock); - expect(result).not.toContain(rolle); - }); - - it('should return list of rollen when they exist', async () => { - const rolle: Rolle = DoFactory.createRolle(true); - rolleRepoMock.findByName.mockResolvedValue([rolle]); - - personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([ - organisationRepoMock.ROOT_ORGANISATION_ID, - ]); - - const result: Rolle[] = await anlage.findAuthorizedRollen(personpermissionsMock, rolle.name, LIMIT); - expect(result).toEqual([rolle]); - }); - - it('should return empty list when no rollen exist', async () => { - rolleRepoMock.findByName.mockResolvedValue(undefined); - - const result: Rolle[] = await anlage.findAuthorizedRollen( - personpermissionsMock, - 'nonexistent', - LIMIT, - ); - expect(result).toEqual([]); - }); - - it('should return list of limited rollen, if the user is Landesadmin and the limit is set', async () => { - const rolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.SYSADMIN }); - const leitRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEIT }); - const lehrRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEHR }); - const lernRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LERN }); - - const rollen: Rolle[] = [rolle, leitRolle, lehrRolle, lernRolle]; - rolleRepoMock.find.mockResolvedValue(rollen); - - personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([ - organisationRepoMock.ROOT_ORGANISATION_ID, - ]); - - const result: Rolle[] = await anlage.findAuthorizedRollen(personpermissionsMock, undefined, 2); - expect(result).toHaveLength(2); - }); - - it('should return list of limited allowedRollen, if the user is NOT Landesadmin and the limit is set', async () => { - const rolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.SYSADMIN }); - const leitRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEIT }); - const lehrRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LEHR }); - const lernRolle: Rolle = DoFactory.createRolle(true, { rollenart: RollenArt.LERN }); - - const rollen: Rolle[] = [rolle, leitRolle, lehrRolle, lernRolle]; - rolleRepoMock.find.mockResolvedValue(rollen); - - const organisationDo: OrganisationDo = DoFactory.createOrganisation(true, { - typ: OrganisationsTyp.SCHULE, - }); - const organisationMap: Map> = new Map(); - organisationMap.set(organisationDo.id, organisationDo); - organisationRepoMock.findByIds.mockResolvedValueOnce(organisationMap); - - personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisationDo.id]); - - const result: Rolle[] = await anlage.findAuthorizedRollen(personpermissionsMock, undefined, 2); - expect(result).toHaveLength(2); - }); - }); }); diff --git a/src/modules/personenkontext/domain/personenkontext-workflow.ts b/src/modules/personenkontext/domain/personenkontext-workflow.ts index 1001584ab..364ea8d6a 100644 --- a/src/modules/personenkontext/domain/personenkontext-workflow.ts +++ b/src/modules/personenkontext/domain/personenkontext-workflow.ts @@ -291,42 +291,4 @@ export class PersonenkontextWorkflowAggregate { return orgas.slice(0, limit); } - - public async findAuthorizedRollen( - permissions: PersonPermissions, - rolleName?: string, - limit?: number, - ): Promise[]> { - let rollen: Option[]>; - - if (rolleName) { - rollen = await this.rolleRepo.findByName(rolleName); - } else { - rollen = await this.rolleRepo.find(); - } - - if (!rollen) return []; - - const orgsWithRecht: OrganisationID[] = await permissions.getOrgIdsWithSystemrecht( - [RollenSystemRecht.PERSONEN_VERWALTEN], - true, - ); - - //Landesadmin can view all roles. - if (orgsWithRecht.includes(this.organisationRepo.ROOT_ORGANISATION_ID)) { - return limit ? rollen.slice(0, limit) : rollen; - } - - const allowedRollen: Rolle[] = []; - const organisationMatchesRollenart: OrganisationMatchesRollenart = new OrganisationMatchesRollenart(); - (await this.organisationRepo.findByIds(orgsWithRecht)).forEach(function (orga: OrganisationDo) { - rollen.forEach(function (rolle: Rolle) { - if (organisationMatchesRollenart.isSatisfiedBy(orga, rolle) && !allowedRollen.includes(rolle)) { - allowedRollen.push(rolle); - } - }); - }); - - return limit ? allowedRollen.slice(0, limit) : allowedRollen; - } } diff --git a/src/modules/personenkontext/personenkontext-api.module.ts b/src/modules/personenkontext/personenkontext-api.module.ts index 52938fb1d..a4df65fc5 100644 --- a/src/modules/personenkontext/personenkontext-api.module.ts +++ b/src/modules/personenkontext/personenkontext-api.module.ts @@ -17,6 +17,8 @@ import { DbiamPersonenkontextFactory } from './domain/dbiam-personenkontext.fact import { EventModule } from '../../core/eventbus/index.js'; import { PersonenkontextFactory } from './domain/personenkontext.factory.js'; import { PersonenkontextCreationService } from './domain/personenkontext-creation.service.js'; +import { PersonAdministrationService } from './domain/person-administration.service.js'; +import { PersonAdministrationController } from './api/person-administration.controller.js'; @Module({ imports: [ @@ -37,7 +39,13 @@ import { PersonenkontextCreationService } from './domain/personenkontext-creatio DbiamPersonenkontextFactory, PersonenkontextFactory, PersonenkontextCreationService, + PersonAdministrationService, + ], + controllers: [ + PersonenkontextController, + DBiamPersonenkontextController, + DbiamPersonenkontextWorkflowController, + PersonAdministrationController, ], - controllers: [PersonenkontextController, DBiamPersonenkontextController, DbiamPersonenkontextWorkflowController], }) export class PersonenKontextApiModule {}