From 1bab7ae3c25143af649bd97610bbac78798d92f1 Mon Sep 17 00:00:00 2001 From: Yannick Clausen Date: Tue, 14 Jan 2025 15:23:48 +0100 Subject: [PATCH 1/2] add istTechnisch field to person --- .../.snapshot-dbildungs-iam-server.json | 10 +++ migrations/Migration20250114120248-S.ts | 11 +++ migrations/Migration20250114133700-D.ts | 9 +++ src/console/dbseed/domain/db-seed.service.ts | 1 + src/console/dbseed/file/person-file.ts | 2 + src/modules/person/domain/person.spec.ts | 77 +++++++++++++++++++ src/modules/person/domain/person.ts | 8 ++ .../person/persistence/person.entity.ts | 4 + .../person.repository.integration-spec.ts | 2 + .../person/persistence/person.repository.ts | 2 + .../person.scope.integration-spec.ts | 7 +- .../person/persistence/person.scope.ts | 4 +- test/utils/do-factory.ts | 1 + 13 files changed, 129 insertions(+), 9 deletions(-) create mode 100644 migrations/Migration20250114120248-S.ts create mode 100644 migrations/Migration20250114133700-D.ts diff --git a/migrations/.snapshot-dbildungs-iam-server.json b/migrations/.snapshot-dbildungs-iam-server.json index c8c1fa86a..814d5bc75 100644 --- a/migrations/.snapshot-dbildungs-iam-server.json +++ b/migrations/.snapshot-dbildungs-iam-server.json @@ -2177,6 +2177,16 @@ "nullable": true, "length": 6, "mappedType": "datetime" + }, + "ist_technisch": { + "name": "ist_technisch", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "false", + "mappedType": "boolean" } }, "name": "person", diff --git a/migrations/Migration20250114120248-S.ts b/migrations/Migration20250114120248-S.ts new file mode 100644 index 000000000..8af00bd3a --- /dev/null +++ b/migrations/Migration20250114120248-S.ts @@ -0,0 +1,11 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20250114120248 extends Migration { + public async up(): Promise { + this.addSql('alter table "person" add column "ist_technisch" boolean not null default false;'); + } + + public override async down(): Promise { + this.addSql('alter table "person" drop column "ist_technisch";'); + } +} diff --git a/migrations/Migration20250114133700-D.ts b/migrations/Migration20250114133700-D.ts new file mode 100644 index 000000000..d45f6d73f --- /dev/null +++ b/migrations/Migration20250114133700-D.ts @@ -0,0 +1,9 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20250114120248 extends Migration { + public async up(): Promise { + this.addSql( + 'update person as p set ist_technisch = true where p.id in (select pk.person_id from personenkontext as pk join rolle as r on r.id = pk.rolle_id where r.ist_technisch = true);', + ); + } +} diff --git a/src/console/dbseed/domain/db-seed.service.ts b/src/console/dbseed/domain/db-seed.service.ts index 8cb9970a4..db1c237e4 100644 --- a/src/console/dbseed/domain/db-seed.service.ts +++ b/src/console/dbseed/domain/db-seed.service.ts @@ -314,6 +314,7 @@ export class DbSeedService { vorname: file.vorname, username: file.username, password: file.password, + istTechnisch: true, }; const person: Person | DomainError = await this.personFactory.createNew(creationParams); diff --git a/src/console/dbseed/file/person-file.ts b/src/console/dbseed/file/person-file.ts index 23ecb3db4..390acab39 100644 --- a/src/console/dbseed/file/person-file.ts +++ b/src/console/dbseed/file/person-file.ts @@ -54,4 +54,6 @@ export class PersonFile { public revision!: string; public personalnummer?: string; + + public istTechnisch?: string; } diff --git a/src/modules/person/domain/person.spec.ts b/src/modules/person/domain/person.spec.ts index c24f07663..16e5013bd 100644 --- a/src/modules/person/domain/person.spec.ts +++ b/src/modules/person/domain/person.spec.ts @@ -75,6 +75,7 @@ describe('Person', () => { expect(person).toBeInstanceOf(Person); expect(person.revision).toEqual('5'); expect(person.userLock).toEqual([]); + expect(person.istTechnisch).toEqual(false); }); }); @@ -296,12 +297,88 @@ describe('Person', () => { faker.lorem.word(), faker.string.uuid(), ); + const initialIstTechnisch: boolean = person.istTechnisch; const result: void | DomainError = person.update('5', undefined, undefined, 'abc'); expect(result).not.toBeInstanceOf(DomainError); expect(person.vorname).toEqual('Max'); expect(person.familienname).toEqual('Mustermann'); expect(person.referrer).toEqual('abc'); + expect(person.istTechnisch).toEqual(initialIstTechnisch); + }); + }); + describe('revision does match and istTechnisch is updated', () => { + it('should update istTechnisch in the person', () => { + const person: Person = Person.construct( + faker.string.uuid(), + faker.date.past(), + faker.date.recent(), + 'Mustermann', + 'Max', + '5', + faker.lorem.word(), + faker.lorem.word(), + faker.string.uuid(), + ); + let result: void | DomainError = person.update( + '5', + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + '', + true, + ); + expect(result).not.toBeInstanceOf(DomainError); + expect(person.istTechnisch).toEqual(true); + + result = person.update( + '6', + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + '', + false, + ); + expect(result).not.toBeInstanceOf(DomainError); + expect(person.istTechnisch).toEqual(false); }); }); describe('revision does not match', () => { diff --git a/src/modules/person/domain/person.ts b/src/modules/person/domain/person.ts index c2c22f883..25bac5d87 100644 --- a/src/modules/person/domain/person.ts +++ b/src/modules/person/domain/person.ts @@ -36,6 +36,7 @@ export type PersonCreationParams = { userLock?: UserLock[]; isLocked?: boolean; orgUnassignmentDate?: Date; + istTechnisch?: boolean; }; export class Person { @@ -79,8 +80,10 @@ export class Person { public isLocked: boolean | undefined, public email: string | undefined, public oxUserId: string | undefined, + public istTechnisch: boolean, ) { this.mandant = Person.CREATE_PERSON_DTO_MANDANT_UUID; + this.istTechnisch = istTechnisch ?? false; } public get newPassword(): string | undefined { @@ -122,6 +125,7 @@ export class Person { isLocked?: boolean, email?: string, oxUserId?: string, + istTechnisch?: boolean, ): Person { return new Person( id, @@ -154,6 +158,7 @@ export class Person { isLocked, email, oxUserId, + istTechnisch ?? false, ); } @@ -202,6 +207,7 @@ export class Person { undefined, undefined, undefined, + creationParams.istTechnisch ?? false, ); if (creationParams.password) { @@ -252,6 +258,7 @@ export class Person { orgUnassignmentDate?: Date, isLocked?: boolean, email?: string, + istTechnisch?: boolean, ): void | DomainError { if (this.revision !== revision) { return new MismatchedRevisionError( @@ -295,6 +302,7 @@ export class Person { this.isLocked = isLocked; this.email = email; this.userLock = userLock ?? []; + if (istTechnisch !== undefined) this.istTechnisch = istTechnisch; } public resetPassword(): void { diff --git a/src/modules/person/persistence/person.entity.ts b/src/modules/person/persistence/person.entity.ts index 0a3312b5c..69fca1222 100644 --- a/src/modules/person/persistence/person.entity.ts +++ b/src/modules/person/persistence/person.entity.ts @@ -175,4 +175,8 @@ export class PersonEntity extends TimestampedEntity { orphanRemoval: true, }) public userLocks: Collection = new Collection(this); + + @AutoMap() + @Property({ default: false }) + public istTechnisch!: boolean; } diff --git a/src/modules/person/persistence/person.repository.integration-spec.ts b/src/modules/person/persistence/person.repository.integration-spec.ts index b5a96439f..1a51c1954 100644 --- a/src/modules/person/persistence/person.repository.integration-spec.ts +++ b/src/modules/person/persistence/person.repository.integration-spec.ts @@ -1109,6 +1109,7 @@ describe('PersonRepository Integration', () => { 'auskunftssperre', 'dataProvider', 'revision', + 'istTechnisch', ]; const result: RequiredEntityData = mapAggregateToData(person); @@ -1271,6 +1272,7 @@ describe('PersonRepository Integration', () => { it('should return DomainError when user is technical', async () => { const person1: Person = DoFactory.createPerson(true); + person1.istTechnisch = true; const personEntity: PersonEntity = new PersonEntity(); await em.persistAndFlush(personEntity.assign(mapAggregateToData(person1))); person1.id = personEntity.id; diff --git a/src/modules/person/persistence/person.repository.ts b/src/modules/person/persistence/person.repository.ts index 502fc9080..f30265c30 100644 --- a/src/modules/person/persistence/person.repository.ts +++ b/src/modules/person/persistence/person.repository.ts @@ -88,6 +88,7 @@ export function mapAggregateToData(person: Person): RequiredEntityData< revision: person.revision, personalnummer: person.personalnummer, orgUnassignmentDate: person.orgUnassignmentDate, + istTechnisch: person.istTechnisch, }; } @@ -123,6 +124,7 @@ export function mapEntityToAggregate(entity: PersonEntity): Person { undefined, getEnabledOrAlternativeEmailAddress(entity), getOxUserId(entity), + entity.istTechnisch, ); } diff --git a/src/modules/person/persistence/person.scope.integration-spec.ts b/src/modules/person/persistence/person.scope.integration-spec.ts index 5a5343ea3..e5183cd30 100644 --- a/src/modules/person/persistence/person.scope.integration-spec.ts +++ b/src/modules/person/persistence/person.scope.integration-spec.ts @@ -301,16 +301,11 @@ describe('PersonScope', () => { }); it('should not return technical users', async () => { - const orgnisationID: string = faker.string.uuid(); const person1: PersonEntity = createPersonEntity(); const person2: PersonEntity = createPersonEntity(); - const rolle: Rolle | DomainError = await rolleRepo.save( - DoFactory.createRolle(false, { istTechnisch: true }), - ); - if (rolle instanceof DomainError) throw Error(); + person2.istTechnisch = true; await em.persistAndFlush([person1, person2]); - await createPersonenkontext(person1.id, orgnisationID, rolle.id); const scope: PersonScope = new PersonScope() .findBy({ ids: [person1.id, person2.id] }) diff --git a/src/modules/person/persistence/person.scope.ts b/src/modules/person/persistence/person.scope.ts index 977ba3a20..928e7270c 100644 --- a/src/modules/person/persistence/person.scope.ts +++ b/src/modules/person/persistence/person.scope.ts @@ -29,9 +29,7 @@ export class PersonScope extends ScopeBase { findProps.organisationen !== undefined && { personenKontexte: { $some: { organisationId: { $in: findProps.organisationen } } }, }, - { - personenKontexte: { $none: { rolleId: { istTechnisch: true } } }, - }, + { istTechnisch: false }, ].filter(Boolean), }; diff --git a/test/utils/do-factory.ts b/test/utils/do-factory.ts index 721a03fed..3ad13e1df 100644 --- a/test/utils/do-factory.ts +++ b/test/utils/do-factory.ts @@ -51,6 +51,7 @@ export class DoFactory { personalnummer: faker.string.numeric({ length: 7 }), revision: '1', }; + person.istTechnisch = false; return Object.assign(Object.create(Person.prototype) as Person, person, props); } From fc42a2ed67c4bee475bb67b0de20beae019b2eb2 Mon Sep 17 00:00:00 2001 From: Yannick Clausen Date: Tue, 14 Jan 2025 16:05:43 +0100 Subject: [PATCH 2/2] cover branches --- src/modules/person/domain/person.spec.ts | 44 ++++++++++++++++++++++++ src/modules/person/domain/person.ts | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/modules/person/domain/person.spec.ts b/src/modules/person/domain/person.spec.ts index 16e5013bd..9964ee27c 100644 --- a/src/modules/person/domain/person.spec.ts +++ b/src/modules/person/domain/person.spec.ts @@ -77,6 +77,50 @@ describe('Person', () => { expect(person.userLock).toEqual([]); expect(person.istTechnisch).toEqual(false); }); + + it.each([ + [true, true], + [false, false], + [undefined, false], + ])('when input is %s, it should set istTechnisch to %s', (input: boolean | undefined, expected: boolean) => { + const person: Person = Person.construct( + faker.string.uuid(), + faker.date.past(), + faker.date.recent(), + faker.person.lastName(), + faker.person.firstName(), + '5', + faker.lorem.word(), + faker.lorem.word(), + faker.string.uuid(), + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + input, + ); + + expect(person).toBeDefined(); + expect(person).toBeInstanceOf(Person); + expect(person.istTechnisch).toEqual(expected); + }); }); describe('createNew', () => { diff --git a/src/modules/person/domain/person.ts b/src/modules/person/domain/person.ts index 25bac5d87..1abd9e655 100644 --- a/src/modules/person/domain/person.ts +++ b/src/modules/person/domain/person.ts @@ -83,7 +83,7 @@ export class Person { public istTechnisch: boolean, ) { this.mandant = Person.CREATE_PERSON_DTO_MANDANT_UUID; - this.istTechnisch = istTechnisch ?? false; + this.istTechnisch = istTechnisch; } public get newPassword(): string | undefined {