Skip to content

Commit

Permalink
SPSH-860: Refactored the personenkontext-workflow aggregate & control…
Browse files Browse the repository at this point in the history
…ler, added person-administration controller & service.
  • Loading branch information
phaelcg committed Jul 16, 2024
1 parent e05936b commit 98d9b4b
Show file tree
Hide file tree
Showing 9 changed files with 415 additions and 209 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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<PersonPermissions> = 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 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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<FindRollenResponse> {
const anlage: PersonenkontextWorkflowAggregate = this.personenkontextWorkflowFactory.createNew();
const rollen: Rolle<true>[] = 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.',
Expand Down
Original file line number Diff line number Diff line change
@@ -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<PersonPermissionsRepo>;

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<PersonPermissionsRepo>(),
},
{
provide: APP_INTERCEPTOR,
useValue: {
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
const req: Request = context.switchToHttp().getRequest();
req.passportUser = createMock<PassportUser>({
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<PersonPermissions> = 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);
});
});
});
Original file line number Diff line number Diff line change
@@ -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<FindRollenResponse> {
const rollen: Rolle<true>[] = await this.personAdministrationService.findAuthorizedRollen(
permissions,
params.rolleName,
params.limit,
);
const response: FindRollenResponse = new FindRollenResponse(rollen, rollen.length);

return response;
}
}
Loading

0 comments on commit 98d9b4b

Please sign in to comment.