diff --git a/.github/workflows/image-and-helm-publish-check-deploy-on-push-scheduled.yml b/.github/workflows/image-and-helm-publish-check-deploy-on-push-scheduled.yml index 6ca7416c1..56e4fe9e1 100644 --- a/.github/workflows/image-and-helm-publish-check-deploy-on-push-scheduled.yml +++ b/.github/workflows/image-and-helm-publish-check-deploy-on-push-scheduled.yml @@ -8,7 +8,7 @@ on: branches: - "**" schedule: - - cron: '0 2 * * *' + - cron: '0 2 * * *' delete: concurrency: @@ -133,11 +133,12 @@ jobs: - create_branch_identifier - release_helm - build_image_on_push - uses: dBildungsplattform/spsh-app-deploy/.github/workflows/deploy.yml@4 + uses: dBildungsplattform/spsh-app-deploy/.github/workflows/deploy.yml@5 with: dbildungs_iam_server_branch: ${{ needs.branch_meta.outputs.ticket }} schulportal_client_branch: ${{ needs.branch_meta.outputs.ticket }} dbildungs_iam_keycloak_branch: ${{ needs.branch_meta.outputs.ticket }} + dbildungs_iam_ldap_branch: ${{ needs.branch_meta.outputs.ticket }} namespace: ${{ needs.create_branch_identifier.outputs.namespace_from_branch }} secrets: inherit diff --git a/src/modules/organisation/persistence/organisation.repo.integration-spec.ts b/src/modules/organisation/persistence/organisation.repo.integration-spec.ts index 5fd752ed4..933e8d73c 100644 --- a/src/modules/organisation/persistence/organisation.repo.integration-spec.ts +++ b/src/modules/organisation/persistence/organisation.repo.integration-spec.ts @@ -16,6 +16,7 @@ import { OrganisationScope } from './organisation.scope.js'; import { Mapper } from '@automapper/core'; import { getMapperToken } from '@automapper/nestjs'; import { EventModule } from '../../../core/eventbus/index.js'; +import { OrganisationsTyp } from '../domain/organisation.enums.js'; describe('OrganisationRepo', () => { let module: TestingModule; @@ -269,4 +270,59 @@ describe('OrganisationRepo', () => { }); }); }); + + describe('findByNameOrKennungAndExcludeByOrganisationType', () => { + describe('when matching organisations by name were found', () => { + it('should return found organizations', async () => { + const orgaName: string = 'Test-Orga'; + const excludeOrgaType: OrganisationsTyp = OrganisationsTyp.KLASSE; + const organisationDoSchule: OrganisationDo = DoFactory.createOrganisation(false, { + name: orgaName, + typ: OrganisationsTyp.SCHULE, + }); + await sut.save(organisationDoSchule); + + const organisationDoKlasse: OrganisationDo = DoFactory.createOrganisation(false, { + name: orgaName + '1', + typ: excludeOrgaType, + }); + await sut.save(organisationDoKlasse); + + const organisationDoSchule2: OrganisationDo = DoFactory.createOrganisation(false, { + typ: OrganisationsTyp.SCHULE, + }); + await sut.save(organisationDoSchule2); + + const foundOrganisations: Option[]> = + await sut.findByNameOrKennungAndExcludeByOrganisationType(excludeOrgaType, orgaName); + expect(foundOrganisations).toBeInstanceOf(Array); + expect(foundOrganisations).toHaveLength(1); + }); + }); + + describe('when matching organisations were found and search is limit', () => { + it('should return limited found organizations', async () => { + const excludeOrgaType: OrganisationsTyp = OrganisationsTyp.KLASSE; + const organisationDoSchule: OrganisationDo = DoFactory.createOrganisation(false, { + typ: OrganisationsTyp.SCHULE, + }); + await sut.save(organisationDoSchule); + + const organisationDoSchule2: OrganisationDo = DoFactory.createOrganisation(false, { + typ: OrganisationsTyp.SCHULE, + }); + await sut.save(organisationDoSchule2); + + const organisationDoKlasse: OrganisationDo = DoFactory.createOrganisation(false, { + typ: excludeOrgaType, + }); + await sut.save(organisationDoKlasse); + + const foundOrganisations: Option[]> = + await sut.findByNameOrKennungAndExcludeByOrganisationType(excludeOrgaType, undefined, 1); + expect(foundOrganisations).toBeInstanceOf(Array); + expect(foundOrganisations).toHaveLength(1); + }); + }); + }); }); diff --git a/src/modules/organisation/persistence/organisation.repo.ts b/src/modules/organisation/persistence/organisation.repo.ts index d03d03362..6c1b95bd1 100644 --- a/src/modules/organisation/persistence/organisation.repo.ts +++ b/src/modules/organisation/persistence/organisation.repo.ts @@ -12,6 +12,7 @@ import { OrganisationID } from '../../../shared/types/aggregate-ids.types.js'; import { SchuleCreatedEvent } from '../../../shared/events/schule-created.event.js'; import { EventService } from '../../../core/eventbus/index.js'; import { OrganisationsTyp } from '../domain/organisation.enums.js'; +import { ScopeOperator } from '../../../shared/persistence/scope.enums.js'; @Injectable() export class OrganisationRepo { @@ -143,4 +144,25 @@ export class OrganisationRepo { } return []; } + + public async findByNameOrKennungAndExcludeByOrganisationType( + excludeOrganisationType: OrganisationsTyp, + searchStr?: string, + limit?: number, + ): Promise[]> { + const scope: OrganisationScope = new OrganisationScope(); + if (searchStr) { + scope + .searchString(searchStr) + .setScopeWhereOperator(ScopeOperator.AND) + .excludeTyp([excludeOrganisationType]); + } else { + scope.excludeTyp([excludeOrganisationType]).paged(0, limit); + } + + let foundOrganisations: OrganisationDo[] = []; + [foundOrganisations] = await this.findBy(scope); + + return foundOrganisations; + } } diff --git a/src/modules/personenkontext/domain/personenkontext-workflow.spec.ts b/src/modules/personenkontext/domain/personenkontext-workflow.spec.ts index 18f39842d..cce6e947e 100644 --- a/src/modules/personenkontext/domain/personenkontext-workflow.spec.ts +++ b/src/modules/personenkontext/domain/personenkontext-workflow.spec.ts @@ -147,7 +147,7 @@ describe('PersonenkontextWorkflow', () => { it('should return only the organisations that the admin has rights on', async () => { const organisation: OrganisationDo = DoFactory.createOrganisation(true); const organisations: OrganisationDo[] = [organisation]; - organisationRepoMock.findBy.mockResolvedValue([organisations, organisations.length]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue(organisations); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisation.id]); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -161,7 +161,7 @@ describe('PersonenkontextWorkflow', () => { it('should return organisations based on name or kennung if provided', async () => { const organisation: OrganisationDo = DoFactory.createOrganisation(true); const organisations: OrganisationDo[] = [organisation]; - organisationRepoMock.findBy.mockResolvedValue([organisations, organisations.length]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue(organisations); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([organisation.id]); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -173,7 +173,7 @@ describe('PersonenkontextWorkflow', () => { }); it('should return an empty array if no organisations are found', async () => { - organisationRepoMock.findBy.mockResolvedValue([[], 0]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValueOnce([]); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -197,7 +197,12 @@ describe('PersonenkontextWorkflow', () => { const org4: OrganisationDo = DoFactory.createOrganisation(true, { kennung: 'K3' }); const orgsWithRecht: string[] = [org1.id, org2.id, org3.id, org4.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2, org3, org4], 4]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([ + org1, + org2, + org3, + org4, + ]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -214,7 +219,7 @@ describe('PersonenkontextWorkflow', () => { const org2: OrganisationDo = DoFactory.createOrganisation(true, { kennung: 'K1' }); const orgsWithRecht: string[] = [org1.id, org2.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2], 2]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -232,7 +237,7 @@ describe('PersonenkontextWorkflow', () => { const org3: OrganisationDo = DoFactory.createOrganisation(true, {}); const orgsWithRecht: string[] = [org1.id, org2.id, org3.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2, org3], 3]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2, org3]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -250,7 +255,7 @@ describe('PersonenkontextWorkflow', () => { const org3: OrganisationDo = DoFactory.createOrganisation(true, {}); const orgsWithRecht: string[] = [org1.id, org2.id, org3.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2, org3], 3]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2, org3]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -271,7 +276,7 @@ describe('PersonenkontextWorkflow', () => { const org3: OrganisationDo = DoFactory.createOrganisation(true, {}); const orgsWithRecht: string[] = [org1.id, org2.id, org3.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2, org3], 3]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2, org3]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -287,7 +292,7 @@ describe('PersonenkontextWorkflow', () => { const org2: OrganisationDo = DoFactory.createOrganisation(true, {}); const orgsWithRecht: string[] = [org1.id, org2.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2], 2]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -309,7 +314,12 @@ describe('PersonenkontextWorkflow', () => { const org4: OrganisationDo = DoFactory.createOrganisation(true, {}); const orgsWithRecht: string[] = [org1.id, org2.id, org3.id, org4.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2, org3, org4], 4]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([ + org1, + org2, + org3, + org4, + ]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -326,7 +336,7 @@ describe('PersonenkontextWorkflow', () => { const org2: OrganisationDo = DoFactory.createOrganisation(true, { name: 'Alpha School' }); const orgsWithRecht: string[] = [org1.id, org2.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2], 2]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -348,7 +358,7 @@ describe('PersonenkontextWorkflow', () => { }); const orgsWithRecht: string[] = [org1.id, org2.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2], 2]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -370,7 +380,7 @@ describe('PersonenkontextWorkflow', () => { }); const orgsWithRecht: string[] = [org1.id, org2.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2], 2]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -392,7 +402,7 @@ describe('PersonenkontextWorkflow', () => { }); const orgsWithRecht: string[] = [org1.id, org2.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2], 2]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -414,7 +424,7 @@ describe('PersonenkontextWorkflow', () => { }); const orgsWithRecht: string[] = [org1.id, org2.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2], 2]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -436,7 +446,7 @@ describe('PersonenkontextWorkflow', () => { }); const orgsWithRecht: string[] = [org1.id, org2.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2], 2]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -458,7 +468,7 @@ describe('PersonenkontextWorkflow', () => { }); const orgsWithRecht: string[] = [org1.id, org2.id]; - organisationRepoMock.findBy.mockResolvedValue([[org1, org2], 2]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([org1, org2]); personpermissionsMock.getOrgIdsWithSystemrecht.mockResolvedValue(orgsWithRecht); const result: OrganisationDo[] = await anlage.findAllSchulstrukturknoten( @@ -1052,7 +1062,7 @@ describe('PersonenkontextWorkflow', () => { typ: OrganisationsTyp.KLASSE, }); - organisationRepoMock.findBy.mockResolvedValue([[], 0]); + organisationRepoMock.findByNameOrKennungAndExcludeByOrganisationType.mockResolvedValue([]); rolleRepoMock.findById.mockResolvedValueOnce(rolle); organisationRepoMock.findById.mockResolvedValue(organisationDo); //mock call to find parent in findSchulstrukturknoten organisationRepoMock.findChildOrgasForIds.mockResolvedValueOnce([organisationDo]); diff --git a/src/modules/personenkontext/domain/personenkontext-workflow.ts b/src/modules/personenkontext/domain/personenkontext-workflow.ts index 2d56f401d..1001584ab 100644 --- a/src/modules/personenkontext/domain/personenkontext-workflow.ts +++ b/src/modules/personenkontext/domain/personenkontext-workflow.ts @@ -17,8 +17,6 @@ import { PersonenkontexteUpdate } from './personenkontexte-update.js'; import { DbiamPersonenkontextFactory } from './dbiam-personenkontext.factory.js'; import { DbiamPersonenkontextBodyParams } from '../api/param/dbiam-personenkontext.body.params.js'; import { OrganisationRepository } from '../../organisation/persistence/organisation.repository.js'; -import { OrganisationScope } from '../../organisation/persistence/organisation.scope.js'; -import { ScopeOperator } from '../../../shared/persistence/scope.enums.js'; export class PersonenkontextWorkflowAggregate { public selectedOrganisationId?: string; @@ -58,24 +56,16 @@ export class PersonenkontextWorkflowAggregate { organisationName: string | undefined, limit?: number, ): Promise[]> { - const scope: OrganisationScope = new OrganisationScope(); - let allOrganisationsExceptKlassen: OrganisationDo[] = []; - let total: number = 0; // If the search string for organisation is present then search for Name or Kennung - if (organisationName) { - scope - .searchString(organisationName) - .setScopeWhereOperator(ScopeOperator.AND) - .excludeTyp([OrganisationsTyp.KLASSE]); - [allOrganisationsExceptKlassen, total] = await this.organisationRepo.findBy(scope); - } else { - // Otherwise just retrieve all orgas - scope.excludeTyp([OrganisationsTyp.KLASSE]).paged(0, limit); - [allOrganisationsExceptKlassen, total] = await this.organisationRepo.findBy(scope); - } - if (total === 0) return []; + allOrganisationsExceptKlassen = await this.organisationRepo.findByNameOrKennungAndExcludeByOrganisationType( + OrganisationsTyp.KLASSE, + organisationName, + limit, + ); + + if (allOrganisationsExceptKlassen.length === 0) return []; const orgsWithRecht: OrganisationID[] = await permissions.getOrgIdsWithSystemrecht( [RollenSystemRecht.PERSONEN_VERWALTEN], @@ -262,19 +252,17 @@ export class PersonenkontextWorkflowAggregate { this.selectedRolleId = rolleId; let organisationsFoundByName: OrganisationDo[] = []; - let total: number = 0; if (excludeKlassen) { - const scope: OrganisationScope = new OrganisationScope(); - scope.searchString(sskName).setScopeWhereOperator(ScopeOperator.AND).excludeTyp([OrganisationsTyp.KLASSE]); - - [organisationsFoundByName, total] = await this.organisationRepo.findBy(scope); + organisationsFoundByName = await this.organisationRepo.findByNameOrKennungAndExcludeByOrganisationType( + OrganisationsTyp.KLASSE, + sskName, + ); } else { organisationsFoundByName = await this.organisationRepo.findByNameOrKennung(sskName); - total = organisationsFoundByName.length; } - if (total === 0) return []; + if (organisationsFoundByName.length === 0) return []; const rolleResult: Option> = await this.rolleRepo.findById(rolleId); if (!rolleResult) return [];