Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPSH-1034 #790

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,23 +92,30 @@ export class DBiamPersonenuebersichtController {
this.config,
);

persons.forEach((person: Person<true>) => {
const personenKontexte: Personenkontext<true>[] = allPersonenKontexte.get(person.id) ?? [];
const personenUebersichtenResult: [DBiamPersonenzuordnungResponse[], Date?] | EntityNotFoundError =
dbiamPersonenUebersicht.createZuordnungenForKontexte(personenKontexte, allRollen, allOrganisations);
if (personenUebersichtenResult instanceof EntityNotFoundError) {
throw SchulConnexErrorMapper.mapSchulConnexErrorToHttpException(
SchulConnexErrorMapper.mapDomainErrorToSchulConnexError(personenUebersichtenResult),
await Promise.all(
persons.map(async (person: Person<true>) => {
const personenKontexte: Personenkontext<true>[] = allPersonenKontexte.get(person.id) ?? [];
const personenUebersichtenResult: [DBiamPersonenzuordnungResponse[], Date?] | EntityNotFoundError =
await dbiamPersonenUebersicht.createZuordnungenForKontexte(
personenKontexte,
allRollen,
allOrganisations,
);

if (personenUebersichtenResult instanceof EntityNotFoundError) {
throw SchulConnexErrorMapper.mapSchulConnexErrorToHttpException(
SchulConnexErrorMapper.mapDomainErrorToSchulConnexError(personenUebersichtenResult),
);
}
items.push(
new DBiamPersonenuebersichtResponse(
person,
personenUebersichtenResult[0],
personenUebersichtenResult[1],
),
);
}
items.push(
new DBiamPersonenuebersichtResponse(
person,
personenUebersichtenResult[0],
personenUebersichtenResult[1],
),
);
});
}),
);
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@ export class DBiamPersonenzuordnungResponse {
@ApiProperty({ enum: RollenMerkmal, enumName: RollenMerkmalTypName, nullable: true })
public readonly merkmale?: RollenMerkmal[];

@ApiProperty({ type: [String] })
public readonly admins?: string[];

public constructor(
personenkontext: Personenkontext<true>,
organisation: OrganisationDo<true>,
rolle: Rolle<true>,
editable: boolean,
admins: string[] | undefined,
) {
//use Organisation Aggregate as soon as there is one
this.sskId = personenkontext.organisationId;
Expand All @@ -54,5 +58,6 @@ export class DBiamPersonenzuordnungResponse {
this.editable = editable;
this.merkmale = rolle.merkmale;
this.befristung = personenkontext.befristung;
this.admins = admins;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ describe('Personenuebersicht API Mocked', () => {
);

jest.spyOn(DbiamPersonenuebersicht.prototype, 'createZuordnungenForKontexte').mockImplementation(() => {
return new EntityNotFoundError();
return Promise.resolve(new EntityNotFoundError('Some message here'));
});

personRepositoryMock.findByIds.mockResolvedValueOnce([person]);
Expand Down
9 changes: 5 additions & 4 deletions src/modules/person/domain/dbiam-personenuebersicht.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,12 @@ describe('DbiamPersonenUebersicht', () => {
});

describe('when most recent PK is last or later in list', () => {
it('should set lastModifiedZuordnungen to value of latest PK updatedAt timestamp', () => {
it('should set lastModifiedZuordnungen to value of latest PK updatedAt timestamp', async () => {
personenkontexte = [personenkontextPast, personenkontextRecent];

const res: [DBiamPersonenzuordnungResponse[], Date?] | EntityNotFoundError =
sut.createZuordnungenForKontexte(personenkontexte, rolleMap, orgaMap, undefined);
await sut.createZuordnungenForKontexte(personenkontexte, rolleMap, orgaMap, undefined);

if (res instanceof EntityNotFoundError) throw res;
const [responses, lastModified]: [DBiamPersonenzuordnungResponse[], Date?] = res;

Expand All @@ -130,11 +131,11 @@ describe('DbiamPersonenUebersicht', () => {
});

describe('when most recentPK is first in list', () => {
it('should set lastModifiedZuordnungen to value of latest PK updatedAt timestamp', () => {
it('should set lastModifiedZuordnungen to value of latest PK updatedAt timestamp', async () => {
personenkontexte = [personenkontextRecent, personenkontextPast];

const res: [DBiamPersonenzuordnungResponse[], Date?] | EntityNotFoundError =
sut.createZuordnungenForKontexte(personenkontexte, rolleMap, orgaMap, undefined);
await sut.createZuordnungenForKontexte(personenkontexte, rolleMap, orgaMap, undefined);
if (res instanceof EntityNotFoundError) throw res;
const [responses, lastModified]: [DBiamPersonenzuordnungResponse[], Date?] = res;

Expand Down
45 changes: 25 additions & 20 deletions src/modules/person/domain/dbiam-personenuebersicht.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { DBiamPersonenkontextRepo } from '../../personenkontext/persistence/dbia
import { Person } from './person.js';
import { EntityNotFoundError } from '../../../shared/error/index.js';
import { OrganisationID, PersonID, RolleID } from '../../../shared/types/index.js';
import { RollenSystemRecht } from '../../rolle/domain/rolle.enums.js';
import { RollenArt, RollenSystemRecht } from '../../rolle/domain/rolle.enums.js';
import { Personenkontext } from '../../personenkontext/domain/personenkontext.js';
import { Rolle } from '../../rolle/domain/rolle.js';
import { DBiamPersonenzuordnungResponse } from '../api/personenuebersicht/dbiam-personenzuordnung.response.js';
Expand Down Expand Up @@ -71,7 +71,7 @@ export class DbiamPersonenuebersicht {
); //use Organisation Aggregate as soon as there is one

const result: [DBiamPersonenzuordnungResponse[], Date?] | EntityNotFoundError =
this.createZuordnungenForKontexte(
await this.createZuordnungenForKontexte(
personenKontexte,
rollenForKontexte,
organisationsForKontexte,
Expand All @@ -84,43 +84,48 @@ export class DbiamPersonenuebersicht {
return new DBiamPersonenuebersichtResponse(person, result[0], result[1]);
}

public createZuordnungenForKontexte(
public async createZuordnungenForKontexte(
kontexte: Personenkontext<true>[],
rollen: Map<string, Rolle<true>>,
organisations: Map<string, Organisation<true>>,
organisationIds?: string[],
): [DBiamPersonenzuordnungResponse[], Date?] | EntityNotFoundError {
const personenUebersichten: DBiamPersonenzuordnungResponse[] = [];
): Promise<[DBiamPersonenzuordnungResponse[], Date?] | EntityNotFoundError> {
const personenUebersichtenPromises: Promise<DBiamPersonenzuordnungResponse>[] = [];
let lastModifiedZuordnungen: Date | undefined = undefined;

for (const pk of kontexte) {
const rolle: Rolle<true> | undefined = rollen.get(pk.rolleId);
const organisation: Organisation<true> | undefined = organisations.get(pk.organisationId);

if (!rolle) {
return new EntityNotFoundError('Rolle', pk.rolleId);
}
if (!organisation) {
return new EntityNotFoundError('Organisation', pk.organisationId);
}
// if permissions should not be checked or admin has PERSONEN_VERWALTEN at ROOT level
if (organisationIds === undefined) {
personenUebersichten.push(new DBiamPersonenzuordnungResponse(pk, organisation, rolle, true));
} else {
// if permissions should be checked
if (organisationIds.some((orgaId: OrganisationID) => orgaId === organisation.id)) {
personenUebersichten.push(new DBiamPersonenzuordnungResponse(pk, organisation, rolle, true));
} else {
personenUebersichten.push(new DBiamPersonenzuordnungResponse(pk, organisation, rolle, false));
}
}

if (lastModifiedZuordnungen == undefined) {
const hasAccess: boolean =
organisationIds === undefined || organisationIds.some((orgaId: string) => orgaId === organisation.id);

const zuordnungPromise: Promise<DBiamPersonenzuordnungResponse> =
(async (): Promise<DBiamPersonenzuordnungResponse> => {
let admins: string[] | undefined = undefined;
if (rolle.rollenart !== RollenArt.LEIT) {
admins = await this.personRepository.findOrganisationAdminsByOrganisationId(pk.organisationId);
}

return new DBiamPersonenzuordnungResponse(pk, organisation, rolle, hasAccess, admins);
})();

personenUebersichtenPromises.push(zuordnungPromise);

if (!lastModifiedZuordnungen || lastModifiedZuordnungen.getTime() < pk.updatedAt.getTime()) {
lastModifiedZuordnungen = pk.updatedAt;
} else {
lastModifiedZuordnungen =
lastModifiedZuordnungen.getTime() < pk.updatedAt.getTime() ? pk.updatedAt : lastModifiedZuordnungen;
}
}

const personenUebersichten: DBiamPersonenzuordnungResponse[] = await Promise.all(personenUebersichtenPromises);

return [personenUebersichten, lastModifiedZuordnungen];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2194,5 +2194,39 @@ describe('PersonRepository Integration', () => {
expect(personsWithOrgList).not.toContain(person4.id);
});
});
describe('findOrganisationAdminsByOrganisationId', () => {
it('should return a list of personIds for persons without a personenkontext', async () => {
const personEntity1: PersonEntity = new PersonEntity();
const person1: Person<true> = DoFactory.createPerson(true);
await em.persistAndFlush(personEntity1.assign(mapAggregateToData(person1)));
person1.id = personEntity1.id;

const rolle1: Rolle<false> = DoFactory.createRolle(false, {
name: 'rolle1',
rollenart: RollenArt.LEIT,
merkmale: [RollenMerkmal.KOPERS_PFLICHT],
});
const rolle1Result: Rolle<true> | DomainError = await rolleRepo.save(rolle1);
if (rolle1Result instanceof DomainError) throw Error();

const personenKontext1: Personenkontext<false> = DoFactory.createPersonenkontext(false, {
personId: person1.id,
rolleId: rolle1Result.id,
});
await dbiamPersonenkontextRepoInternal.save(personenKontext1);
// person without personenkontext but within the time limit for org_unassignment_Date
const person4: Person<true> = DoFactory.createPerson(true, { orgUnassignmentDate: new Date() });
const personEntity4: PersonEntity = new PersonEntity();
await em.persistAndFlush(personEntity4.assign(mapAggregateToData(person4)));
person4.id = personEntity4.id;

//get person ids without personenkontext
const admins: string[] = await sut.findOrganisationAdminsByOrganisationId(
personenKontext1.organisationId,
);

expect(admins).toContain(person1.vorname + ' ' + person1.familienname);
});
});
});
});
19 changes: 19 additions & 0 deletions src/modules/person/persistence/person.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -809,4 +809,23 @@ export class PersonRepository {
const personEntities: PersonEntity[] = await this.em.find(PersonEntity, filters);
return personEntities.map((person: PersonEntity) => person.id);
}

public async findOrganisationAdminsByOrganisationId(organisation_id: string): Promise<string[]> {
const filters: QBFilterQuery<PersonEntity> = {
$and: [
{
personenKontexte: {
$some: {
organisationId: organisation_id,
rolleId: {
rollenart: 'LEIT',
},
},
},
},
],
};
const admins: PersonEntity[] = await this.em.find(PersonEntity, filters);
return admins.map((admin: PersonEntity) => admin.vorname + ' ' + admin.familienname);
}
}
Loading