From f7b8cc5f5e2cb3abee1abc1c3e713c02e99d696c Mon Sep 17 00:00:00 2001 From: Nael-Alshowaikh <153004766+Nael-Alshowaikh@users.noreply.github.com> Date: Wed, 26 Jun 2024 17:22:39 +0200 Subject: [PATCH 1/4] renamed to Land Schleswig Holstein (#556) * renamed to Land Schleswig Holstein * added - in Schleswig-Holstein --- .../dbildungs-iam-server/seeding/dev/01_organisation.json | 6 +++--- seeding/dev/01/01_organisation.json | 6 +++--- .../organisation/06_kuerzel-is-root.json | 4 +--- .../organisation/api/organisation.controller.spec.ts | 4 ++-- .../persistence/organisation.repository.integration-spec.ts | 4 ++-- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/charts/dbildungs-iam-server/seeding/dev/01_organisation.json b/charts/dbildungs-iam-server/seeding/dev/01_organisation.json index c6bcac4b1..d594e850c 100644 --- a/charts/dbildungs-iam-server/seeding/dev/01_organisation.json +++ b/charts/dbildungs-iam-server/seeding/dev/01_organisation.json @@ -3,7 +3,7 @@ "entities": [ { "id": 0, - "name": "Wurzel Land Schleswig Holstein", + "name": "Land Schleswig-Holstein", "kuerzel": "Root", "typ": "ROOT", "administriertVon": null, @@ -11,7 +11,7 @@ }, { "id": 1, - "name": "Öffentliche Schulen Land Schleswig Holstein", + "name": "Öffentliche Schulen Land Schleswig-Holstein", "kuerzel": "Öffentl. Schulen", "typ": "LAND", "administriertVon": 0, @@ -19,7 +19,7 @@ }, { "id": 2, - "name": "Ersatzschulen Land Schleswig Holstein", + "name": "Ersatzschulen Land Schleswig-Holstein", "kuerzel": "Ersatzschulen", "typ": "LAND", "administriertVon": 0, diff --git a/seeding/dev/01/01_organisation.json b/seeding/dev/01/01_organisation.json index c6bcac4b1..d594e850c 100644 --- a/seeding/dev/01/01_organisation.json +++ b/seeding/dev/01/01_organisation.json @@ -3,7 +3,7 @@ "entities": [ { "id": 0, - "name": "Wurzel Land Schleswig Holstein", + "name": "Land Schleswig-Holstein", "kuerzel": "Root", "typ": "ROOT", "administriertVon": null, @@ -11,7 +11,7 @@ }, { "id": 1, - "name": "Öffentliche Schulen Land Schleswig Holstein", + "name": "Öffentliche Schulen Land Schleswig-Holstein", "kuerzel": "Öffentl. Schulen", "typ": "LAND", "administriertVon": 0, @@ -19,7 +19,7 @@ }, { "id": 2, - "name": "Ersatzschulen Land Schleswig Holstein", + "name": "Ersatzschulen Land Schleswig-Holstein", "kuerzel": "Ersatzschulen", "typ": "LAND", "administriertVon": 0, diff --git a/seeding/seeding-integration-test/organisation/06_kuerzel-is-root.json b/seeding/seeding-integration-test/organisation/06_kuerzel-is-root.json index 6b4e62919..90f6ebc14 100644 --- a/seeding/seeding-integration-test/organisation/06_kuerzel-is-root.json +++ b/seeding/seeding-integration-test/organisation/06_kuerzel-is-root.json @@ -3,7 +3,7 @@ "entities": [ { "id": 0, - "name": "Wurzel Land Schleswig Holstein", + "name": "Land Schleswig-Holstein", "kuerzel": "Root", "typ": "ROOT", "administriertVon": null, @@ -11,5 +11,3 @@ } ] } - - diff --git a/src/modules/organisation/api/organisation.controller.spec.ts b/src/modules/organisation/api/organisation.controller.spec.ts index 9c5c88e9a..b6f50ad76 100644 --- a/src/modules/organisation/api/organisation.controller.spec.ts +++ b/src/modules/organisation/api/organisation.controller.spec.ts @@ -336,7 +336,7 @@ describe('OrganisationController', () => { faker.string.uuid(), faker.string.uuid(), faker.string.numeric(), - 'Öffentliche Schulen Land Schleswig Holstein', + 'Öffentliche Schulen Land Schleswig-Holstein', faker.lorem.word(), faker.string.uuid(), OrganisationsTyp.ROOT, @@ -349,7 +349,7 @@ describe('OrganisationController', () => { faker.string.uuid(), faker.string.uuid(), faker.string.numeric(), - 'Ersatzschulen Land Schleswig Holstein', + 'Ersatzschulen Land Schleswig-Holstein', faker.lorem.word(), faker.string.uuid(), OrganisationsTyp.SCHULE, diff --git a/src/modules/organisation/persistence/organisation.repository.integration-spec.ts b/src/modules/organisation/persistence/organisation.repository.integration-spec.ts index ab82a0708..fa0593d4f 100644 --- a/src/modules/organisation/persistence/organisation.repository.integration-spec.ts +++ b/src/modules/organisation/persistence/organisation.repository.integration-spec.ts @@ -430,7 +430,7 @@ describe('OrganisationRepository', () => { ROOT_ORGANISATION_ID, faker.string.uuid(), faker.string.numeric(), - 'Öffentliche Schulen Land Schleswig Holstein', + 'Öffentliche Schulen Land Schleswig-Holstein', faker.lorem.word(), faker.string.uuid(), OrganisationsTyp.ROOT, @@ -443,7 +443,7 @@ describe('OrganisationRepository', () => { ROOT_ORGANISATION_ID, faker.string.uuid(), faker.string.numeric(), - 'Ersatzschulen Land Schleswig Holstein', + 'Ersatzschulen Land Schleswig-Holstein', faker.lorem.word(), faker.string.uuid(), OrganisationsTyp.SCHULE, From 596b93e8ab4fa4e11cf380b67ead46856413ce14 Mon Sep 17 00:00:00 2001 From: Caspar Neumann <146704428+casparneumann-cap@users.noreply.github.com> Date: Thu, 27 Jun 2024 11:07:06 +0200 Subject: [PATCH 2/4] SPSH-730 Clean Data (#555) --- seeding/dev/01/04_rolle.json | 9 +++++++++ .../domain/keycloak-user.service.ts | 7 +++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/seeding/dev/01/04_rolle.json b/seeding/dev/01/04_rolle.json index eb1d89673..b7f45cc04 100644 --- a/seeding/dev/01/04_rolle.json +++ b/seeding/dev/01/04_rolle.json @@ -116,6 +116,15 @@ "MIGRATION_DURCHFUEHREN" ], "serviceProviderIds": [] + }, + { + "id": 6, + "administeredBySchulstrukturknoten": 0, + "name": "Schulbegleitung", + "rollenart": "LERN", + "merkmale": [], + "systemrechte": [], + "serviceProviderIds": [] } ] } diff --git a/src/modules/keycloak-administration/domain/keycloak-user.service.ts b/src/modules/keycloak-administration/domain/keycloak-user.service.ts index 3440666fe..16d58b50e 100644 --- a/src/modules/keycloak-administration/domain/keycloak-user.service.ts +++ b/src/modules/keycloak-administration/domain/keycloak-user.service.ts @@ -87,9 +87,10 @@ export class KeycloakUserService { } let algorithm: string; let hashIterations: number | undefined; + let passwordValue: string; if (hashedPassword.startsWith('{BCRYPT}')) { algorithm = 'bcrypt'; - const parts: string[] = hashedPassword.split('$'); + const parts: string[] = hashedPassword.split('$'); //Only Everything After and including the First $ if (parts.length < 4 || !parts[2]) { return { ok: false, @@ -97,6 +98,7 @@ export class KeycloakUserService { }; } hashIterations = parseInt(parts[2]); + passwordValue = hashedPassword.substring(hashedPassword.indexOf('$')); } else if (hashedPassword.startsWith('{crypt}')) { algorithm = 'crypt'; const parts: string[] = hashedPassword.split('$'); @@ -107,6 +109,7 @@ export class KeycloakUserService { }; } hashIterations = undefined; + passwordValue = hashedPassword.substring(hashedPassword.indexOf('$')); } else { return { ok: false, @@ -144,7 +147,7 @@ export class KeycloakUserService { algorithm: algorithm, }), secretData: JSON.stringify({ - value: hashedPassword, + value: passwordValue, }), type: 'password', }, From 3ecbfec3d488c1996090ed784c180d155de55d44 Mon Sep 17 00:00:00 2001 From: Philipp Kleybolte Date: Mon, 1 Jul 2024 13:23:39 +0200 Subject: [PATCH 3/4] remove unnecessary providers (#567) --- src/modules/person/person-api.module.ts | 12 +----------- src/modules/rolle/rolle.module.ts | 3 +-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/modules/person/person-api.module.ts b/src/modules/person/person-api.module.ts index 6efab4d8b..41d53efd9 100644 --- a/src/modules/person/person-api.module.ts +++ b/src/modules/person/person-api.module.ts @@ -6,13 +6,10 @@ import { PersonModule } from './person.module.js'; import { PersonFrontendController } from './api/person.frontend.controller.js'; import { PersonenkontextUc } from '../personenkontext/api/personenkontext.uc.js'; import { PersonenKontextModule } from '../personenkontext/personenkontext.module.js'; -import { UsernameGeneratorService } from './domain/username-generator.service.js'; -import { PersonRepository } from './persistence/person.repository.js'; import { RolleModule } from '../rolle/rolle.module.js'; import { OrganisationModule } from '../organisation/organisation.module.js'; import { KeycloakAdministrationModule } from '../keycloak-administration/keycloak-administration.module.js'; import { DBiamPersonenuebersichtController } from './api/personenuebersicht/dbiam-personenuebersicht.controller.js'; -import { DBiamPersonenkontextRepo } from '../personenkontext/persistence/dbiam-personenkontext.repo.js'; import { PersonInfoController } from './api/person-info.controller.js'; import { PersonApiMapper } from './mapper/person-api.mapper.js'; import { DBiamPersonController } from './api/dbiam-person.controller.js'; @@ -29,14 +26,7 @@ import { EventModule } from '../../core/eventbus/event.module.js'; LoggerModule.register(PersonApiModule.name), EventModule, ], - providers: [ - PersonApiMapperProfile, - PersonenkontextUc, - UsernameGeneratorService, - PersonRepository, - DBiamPersonenkontextRepo, - PersonApiMapper, - ], + providers: [PersonApiMapperProfile, PersonenkontextUc, PersonApiMapper], controllers: [ PersonController, PersonFrontendController, diff --git a/src/modules/rolle/rolle.module.ts b/src/modules/rolle/rolle.module.ts index 0f466d70d..d5813194f 100644 --- a/src/modules/rolle/rolle.module.ts +++ b/src/modules/rolle/rolle.module.ts @@ -2,13 +2,12 @@ import { Module } from '@nestjs/common'; import { LoggerModule } from '../../core/logging/logger.module.js'; import { RolleRepo } from './repo/rolle.repo.js'; import { ServiceProviderModule } from '../service-provider/service-provider.module.js'; -import { ServiceProviderRepo } from '../service-provider/repo/service-provider.repo.js'; import { RolleFactory } from './domain/rolle.factory.js'; import { OrganisationModule } from '../organisation/organisation.module.js'; @Module({ imports: [ServiceProviderModule, LoggerModule.register(RolleModule.name), OrganisationModule], - providers: [RolleRepo, RolleFactory, ServiceProviderRepo], + providers: [RolleRepo, RolleFactory], exports: [RolleRepo, RolleFactory], }) export class RolleModule {} From a36d16c39fcafb6f6ce7a313d0e8dffa2c2666c2 Mon Sep 17 00:00:00 2001 From: Youssef Bouchara <101522419+YoussefBouch@users.noreply.github.com> Date: Mon, 1 Jul 2024 14:18:52 +0200 Subject: [PATCH 4/4] SPSH-816-permissions-rollen (#564) * findRollen only with permissions * fixed failing test * more tests * fixed array check * check for Rollen * SPSH-816: PR Review --------- Co-authored-by: Phael Mouko --- .../api/rolle.controller.integration-spec.ts | 41 ++++++++++- .../rolle/api/rolle.controller.spec.ts | 6 +- src/modules/rolle/api/rolle.controller.ts | 21 +++--- src/modules/rolle/repo/rolle.repo.spec.ts | 70 +++++++++++++++++++ src/modules/rolle/repo/rolle.repo.ts | 39 ++++++++++- 5 files changed, 163 insertions(+), 14 deletions(-) diff --git a/src/modules/rolle/api/rolle.controller.integration-spec.ts b/src/modules/rolle/api/rolle.controller.integration-spec.ts index 0c1af824b..3d492e642 100644 --- a/src/modules/rolle/api/rolle.controller.integration-spec.ts +++ b/src/modules/rolle/api/rolle.controller.integration-spec.ts @@ -1,7 +1,7 @@ import { faker } from '@faker-js/faker'; import { EntityManager, MikroORM } from '@mikro-orm/core'; -import { INestApplication } from '@nestjs/common'; -import { APP_PIPE } from '@nestjs/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'; @@ -30,6 +30,11 @@ import { RolleWithServiceProvidersResponse } from './rolle-with-serviceprovider. import { OrganisationRepository } from '../../organisation/persistence/organisation.repository.js'; import { PagedResponse } from '../../../shared/paging/index.js'; import { ServiceProviderIdNameResponse } from './serviceprovider-id-name.response.js'; +import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { Observable } from 'rxjs'; +import { PersonPermissionsRepo } from '../../authentication/domain/person-permission.repo.js'; +import { PassportUser } from '../../authentication/types/user.js'; +import { Request } from 'express'; describe('Rolle API', () => { let app: INestApplication; @@ -37,6 +42,7 @@ describe('Rolle API', () => { let em: EntityManager; let rolleRepo: RolleRepo; let serviceProviderRepo: ServiceProviderRepo; + let personpermissionsRepoMock: DeepMocked; beforeAll(async () => { const module: TestingModule = await Test.createTestingModule({ @@ -51,6 +57,24 @@ describe('Rolle API', () => { provide: APP_PIPE, useClass: GlobalValidationPipe, }, + { + 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(); + }, + }, + }, + { + provide: PersonPermissionsRepo, + useValue: createMock(), + }, OrganisationRepository, RolleFactory, ServiceProviderRepo, @@ -61,6 +85,7 @@ describe('Rolle API', () => { em = module.get(EntityManager); rolleRepo = module.get(RolleRepo); serviceProviderRepo = module.get(ServiceProviderRepo); + personpermissionsRepoMock = module.get(PersonPermissionsRepo); await DatabaseTestModule.setupDatabase(module.get(MikroORM)); app = module.createNestApplication(); await app.init(); @@ -211,6 +236,18 @@ describe('Rolle API', () => { expect(pagedResponse.items).toHaveLength(3); }); + it('should return no rollen', async () => { + const response: Response = await request(app.getHttpServer() as App) + .get('/rolle') + .send(); + + expect(response.status).toBe(200); + expect(response.body).toBeInstanceOf(Object); + const pagedResponse: PagedResponse = + response.body as PagedResponse; + expect(pagedResponse.items).toHaveLength(0); + }); + it('should return rollen with the given queried name', async () => { const testRolle: { name: string } = await rolleRepo.save(DoFactory.createRolle(false)); diff --git a/src/modules/rolle/api/rolle.controller.spec.ts b/src/modules/rolle/api/rolle.controller.spec.ts index 851871b11..1a55a8441 100644 --- a/src/modules/rolle/api/rolle.controller.spec.ts +++ b/src/modules/rolle/api/rolle.controller.spec.ts @@ -14,6 +14,7 @@ import { FindRolleByIdParams } from './find-rolle-by-id.params.js'; import { OrganisationService } from '../../organisation/domain/organisation.service.js'; import { OrganisationRepository } from '../../organisation/persistence/organisation.repository.js'; import { RolleNameQueryParams } from './rolle-name-query.param.js'; +import { PersonPermissions } from '../../authentication/domain/person-permissions.js'; describe('Rolle API with mocked ServiceProviderRepo', () => { let rolleRepoMock: DeepMocked; @@ -84,11 +85,14 @@ describe('Rolle API with mocked ServiceProviderRepo', () => { const params: RolleNameQueryParams = { searchStr: faker.string.alpha(), }; + const permissions: DeepMocked = createMock(); + permissions.getOrgIdsWithSystemrecht.mockResolvedValueOnce([]); + //mock getRollenByName rolleRepoMock.findByName.mockResolvedValueOnce(undefined); //mock call to get sp (direct in controller-method) serviceProviderRepoMock.findById.mockResolvedValueOnce(undefined); - await expect(rolleController.findRollen(params)).resolves.not.toThrow(Error); + await expect(rolleController.findRollen(params, permissions)).resolves.not.toThrow(Error); }); }); }); diff --git a/src/modules/rolle/api/rolle.controller.ts b/src/modules/rolle/api/rolle.controller.ts index 4bd325dde..6e73ebb4b 100644 --- a/src/modules/rolle/api/rolle.controller.ts +++ b/src/modules/rolle/api/rolle.controller.ts @@ -49,6 +49,8 @@ import { ServiceProviderResponse } from '../../service-provider/api/service-prov import { SchulConnexError } from '../../../shared/error/schul-connex.error.js'; import { RolleExceptionFilter } from './rolle-exception-filter.js'; import { Paged, PagedResponse, PagingHeadersObject } from '../../../shared/paging/index.js'; +import { Permissions } from '../../authentication/api/permissions.decorator.js'; +import { PersonPermissions } from '../../authentication/domain/person-permissions.js'; @UseFilters(new SchulConnexValidationErrorFilter(), new RolleExceptionFilter()) @ApiTags('rolle') @@ -75,18 +77,16 @@ export class RolleController { @ApiInternalServerErrorResponse({ description: 'Internal server error while getting all rollen.' }) public async findRollen( @Query() queryParams: RolleNameQueryParams, + @Permissions() permissions: PersonPermissions, ): Promise> { - let rollen: Option[]>; - - if (queryParams.searchStr) { - rollen = await this.rolleRepo.findByName(queryParams.searchStr, queryParams.limit, queryParams.offset); - } else { - rollen = await this.rolleRepo.find(queryParams.limit, queryParams.offset); - } - - const serviceProviders: ServiceProvider[] = await this.serviceProviderRepo.find(); + const rollen: Option[]> = await this.rolleRepo.findRollenAuthorized( + permissions, + queryParams.searchStr, + queryParams.limit, + queryParams.offset, + ); - if (!rollen) { + if (!rollen || rollen.length === 0) { const pagedRolleWithServiceProvidersResponse: Paged = { total: 0, offset: 0, @@ -95,6 +95,7 @@ export class RolleController { }; return new PagedResponse(pagedRolleWithServiceProvidersResponse); } + const serviceProviders: ServiceProvider[] = await this.serviceProviderRepo.find(); const rollenWithServiceProvidersResponses: RolleWithServiceProvidersResponse[] = rollen.map( (r: Rolle) => { diff --git a/src/modules/rolle/repo/rolle.repo.spec.ts b/src/modules/rolle/repo/rolle.repo.spec.ts index 1c3d67e3d..54a7df4f0 100644 --- a/src/modules/rolle/repo/rolle.repo.spec.ts +++ b/src/modules/rolle/repo/rolle.repo.spec.ts @@ -16,6 +16,9 @@ import { ServiceProviderRepo } from '../../service-provider/repo/service-provide import { ServiceProvider } from '../../service-provider/domain/service-provider.js'; import { EventService } from '../../../core/eventbus/index.js'; import { OrganisationRepository } from '../../organisation/persistence/organisation.repository.js'; +import { PersonPermissions } from '../../authentication/domain/person-permissions.js'; +import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { OrganisationID } from '../../../shared/types/index.js'; describe('RolleRepo', () => { let module: TestingModule; @@ -118,7 +121,74 @@ describe('RolleRepo', () => { expect(rolle).toBeNull(); }); }); + describe('findRollenAuthorized', () => { + it('should return no rollen because there are none', async () => { + const organisationId: OrganisationID = faker.string.uuid(); + const permissions: DeepMocked = createMock(); + permissions.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisationId]); + + const rolleResult: Option[]> = await sut.findRollenAuthorized(permissions, undefined, 10, 0); + + expect(rolleResult?.length).toBe(0); + }); + + it('should return the rollen when permissions are sufficient', async () => { + const organisationId: OrganisationID = faker.string.uuid(); + await sut.save(DoFactory.createRolle(false, { administeredBySchulstrukturknoten: organisationId })); + + const permissions: DeepMocked = createMock(); + permissions.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisationId]); + + const rolleResult: Option[]> = await sut.findRollenAuthorized(permissions, undefined, 10, 0); + + expect(rolleResult?.length).toBe(1); + }); + + it('should return empty array when permissions are insufficient', async () => { + const organisationId: OrganisationID = faker.string.uuid(); + await sut.save(DoFactory.createRolle(false, { administeredBySchulstrukturknoten: organisationId })); + + const permissions: DeepMocked = createMock(); + permissions.getOrgIdsWithSystemrecht.mockResolvedValueOnce([]); + + const rolleResult: Option[]> = await sut.findRollenAuthorized(permissions, undefined, 10, 0); + + expect(rolleResult?.length).toBe(0); + }); + + it('should filter rollen based on search string and permissions', async () => { + const organisationId: OrganisationID = faker.string.uuid(); + await sut.save( + DoFactory.createRolle(false, { administeredBySchulstrukturknoten: organisationId, name: 'Test' }), + ); + await sut.save( + DoFactory.createRolle(false, { + administeredBySchulstrukturknoten: organisationId, + name: 'AnotherName', + }), + ); + + const permissions: DeepMocked = createMock(); + permissions.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisationId]); + + const rolleResult: Option[]> = await sut.findRollenAuthorized(permissions, 'Test', 10, 0); + + expect(rolleResult?.length).toBe(1); + }); + + it('should return all rollen when no search string is provided and permissions are sufficient', async () => { + const organisationId: OrganisationID = faker.string.uuid(); + await sut.save(DoFactory.createRolle(false, { administeredBySchulstrukturknoten: organisationId })); + + const permissions: DeepMocked = createMock(); + permissions.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisationId]); + + const rolleResult: Option[]> = await sut.findRollenAuthorized(permissions, undefined, 10, 0); + + expect(rolleResult?.length).toBe(1); + }); + }); describe('findByName', () => { it('should return the rolle', async () => { const rolle: Rolle = await sut.save(DoFactory.createRolle(false)); diff --git a/src/modules/rolle/repo/rolle.repo.ts b/src/modules/rolle/repo/rolle.repo.ts index de63c2275..7b72a8896 100644 --- a/src/modules/rolle/repo/rolle.repo.ts +++ b/src/modules/rolle/repo/rolle.repo.ts @@ -7,8 +7,9 @@ import { RolleMerkmalEntity } from '../entity/rolle-merkmal.entity.js'; import { RolleEntity } from '../entity/rolle.entity.js'; import { RolleFactory } from '../domain/rolle.factory.js'; import { RolleServiceProviderEntity } from '../entity/rolle-service-provider.entity.js'; -import { RolleID } from '../../../shared/types/index.js'; +import { OrganisationID, RolleID } from '../../../shared/types/index.js'; import { RolleSystemrechtEntity } from '../entity/rolle-systemrecht.entity.js'; +import { PersonPermissions } from '../../authentication/domain/person-permissions.js'; /** * @deprecated Not for use outside of rolle-repo, export will be removed at a later date @@ -129,6 +130,42 @@ export class RolleRepo { return rollen.map((rolle: RolleEntity) => mapEntityToAggregate(rolle, this.rolleFactory)); } + public async findRollenAuthorized( + permissions: PersonPermissions, + searchStr?: string, + limit?: number, + offset?: number, + ): Promise[]>> { + let rollen: Option; + if (searchStr) { + rollen = await this.em.find( + this.entityName, + { name: { $ilike: '%' + searchStr + '%' } }, + { populate: ['merkmale', 'systemrechte', 'serviceProvider'] as const, limit: limit, offset: offset }, + ); + } else { + rollen = await this.em.findAll(this.entityName, { + populate: ['merkmale', 'systemrechte', 'serviceProvider'] as const, + limit: limit, + offset: offset, + }); + } + if (rollen.length === 0) { + return []; + } + + const orgIdsWithRecht: OrganisationID[] = await permissions.getOrgIdsWithSystemrecht( + [RollenSystemRecht.ROLLEN_VERWALTEN], + true, + ); + + const filteredRollen: RolleEntity[] = rollen.filter((rolle: RolleEntity) => + orgIdsWithRecht.includes(rolle.administeredBySchulstrukturknoten), + ); + + return filteredRollen.map((rolle: RolleEntity) => mapEntityToAggregate(rolle, this.rolleFactory)); + } + public async exists(id: RolleID): Promise { const rolle: Option> = await this.em.findOne( RolleEntity,