diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.model.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.model.ts index e0da72cebbd87689172262fba7a0393652b18302..2a984d4ddbdc07d828802be92d46d770002a6fdf 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.model.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.model.ts @@ -62,7 +62,8 @@ export interface CreatePostfachMailCommand extends CreateCommand { export interface PostfachMailResource extends Resource, PostfachMail {} export interface PostfachMailListResource extends ListResource { - features: Features; + features: PostfachFeatures; + settings: PostfachSettings; } export enum PostfachNachrichtenCount { @@ -80,7 +81,10 @@ export interface PostfachMailFormDialogData extends FixedDialogData { postfachNachricht?: PostfachMailResource; } -export interface Features { - //TODO Rename to PostfachFeatures +export interface PostfachFeatures { reply: boolean; } + +export interface PostfachSettings { + signatur: string; +} diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts index 1d00b7d41af9f9851a34f07c3035251d140eeb2c..3d23e1126c898d3b4d1df1ce5da9edad93b8d477 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.service.spec.ts @@ -21,7 +21,6 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { MatDialog } from '@angular/material/dialog'; import { BinaryFileListResource, BinaryFileResource, @@ -37,6 +36,7 @@ import { import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; import { VorgangService, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { MatDialog } from '@angular/material/dialog'; import { createBinaryFileListResource, createBinaryFileResource, @@ -49,9 +49,11 @@ import { import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; import { BehaviorSubject, of } from 'rxjs'; import { + createPostfachFeatures, createPostfachMail, createPostfachMailListResource, createPostfachMailResource, + createPostfachSettings, } from '../../test/postfach'; import { PostfachFacade } from './+state/postfach.facade'; import { PostfachMailLinkRel, PostfachMailListLinkRel } from './postfach.linkrel'; @@ -630,7 +632,20 @@ describe('PostfachService', () => { ); service.getFeatures().subscribe((features) => { - expect(features).toEqual({ reply: true }); + expect(features).toEqual(createPostfachFeatures()); + done(); + }); + }); + }); + + describe('getSettings', () => { + it('should return settings by list stateResource', (done) => { + service.postfachMailList$ = new BehaviorSubject( + createStateResource(createPostfachMailListResource()), + ); + + service.getSettings().subscribe((settings) => { + expect(settings).toEqual(createPostfachSettings()); done(); }); }); diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts index f4bc26e4687c2ce05b1cc7b3d36560b76a5a21df..4fda384295d5f2cf511064bccd84941fd78d3a8c 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.service.ts @@ -58,10 +58,11 @@ import { PostfachMailLinkRel, PostfachMailListLinkRel } from './postfach.linkrel import { PostfachMessages } from './postfach.message'; import { CreatePostfachMailCommand, - Features, + PostfachFeatures, PostfachMail, PostfachMailListResource, PostfachMailResource, + PostfachSettings, } from './postfach.model'; import { PostfachRepository } from './postfach.repository'; import { createResendPostfachMailCommand, createSendPostfachMailCommand } from './postfach.util'; @@ -372,7 +373,7 @@ export class PostfachService { this.postfachFacade.clearAttachmentList(); } - public getFeatures(): Observable<Features> { + public getFeatures(): Observable<PostfachFeatures> { return this.getPostfachMailListByVorgang().pipe( map( (listStateResource: StateResource<PostfachMailListResource>) => @@ -380,4 +381,13 @@ export class PostfachService { ), ); } + + public getSettings(): Observable<PostfachSettings> { + return this.getPostfachMailListByVorgang().pipe( + map( + (listStateResource: StateResource<PostfachMailListResource>) => + listStateResource.resource.settings, + ), + ); + } } diff --git a/alfa-client/libs/postfach-shared/test/postfach.ts b/alfa-client/libs/postfach-shared/test/postfach.ts index fb0fa71451c5d4409d18ba8c879e592eae198030..0ca6f2c9f377754a92d123e1692ae567597fa410 100644 --- a/alfa-client/libs/postfach-shared/test/postfach.ts +++ b/alfa-client/libs/postfach-shared/test/postfach.ts @@ -21,8 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { faker } from '@faker-js/faker'; import { EMPTY_ARRAY, createStateResource } from '@alfa-client/tech-shared'; +import { faker } from '@faker-js/faker'; import { Resource } from '@ngxp/rest'; import { toResource } from 'libs/tech-shared/test/resource'; import { times } from 'lodash-es'; @@ -30,10 +30,12 @@ import { PostfachMailListLinkRel } from '../src/lib/postfach.linkrel'; import { PostfachNachrichtMessageCode } from '../src/lib/postfach.message-code'; import { Direction, + PostfachFeatures, PostfachMail, PostfachMailFormDialogData, PostfachMailListResource, PostfachMailResource, + PostfachSettings, ReplyOption, } from '../src/lib/postfach.model'; @@ -62,13 +64,27 @@ export function createPostfachMailResources(linkRelations: string[] = []): Postf export function createPostfachMailListResource( linkRelations: string[] = [], ): PostfachMailListResource { - return toResource(createPostfachMailListWithAllowedReplyFeature(), [...linkRelations], { + return toResource(createPostfachMailList(), [...linkRelations], { [PostfachMailListLinkRel.POSTFACH_MAIL_LIST]: createPostfachMailResources(), }); } -function createPostfachMailListWithAllowedReplyFeature(): Resource { - return toResource({ features: { reply: true } }, ['sendPostfachMail']); +function createPostfachMailList(): Resource { + return toResource({ features: createPostfachFeatures(), settings: createPostfachSettings() }, [ + 'sendPostfachMail', + ]); +} + +export function createPostfachFeatures(): PostfachFeatures { + return { reply: true }; +} + +export function createPostfachSettings(): PostfachSettings { + return { signatur: 'Best regards' }; +} + +export function createEmptyPostfachSettings(): PostfachSettings { + return { signatur: '' }; } export class PostfachTestFactory { diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail.formservice.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail.formservice.spec.ts index 0825838a83338418ca10cc5a43bbbd001c23987a..fbf54ddd0d162ea4c311122f05077b078e05165d 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail.formservice.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail.formservice.spec.ts @@ -21,25 +21,29 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { UntypedFormBuilder } from '@angular/forms'; import { CommandResource } from '@alfa-client/command-shared'; -import { PostfachService } from '@alfa-client/postfach-shared'; +import { PostfachService, PostfachSettings } from '@alfa-client/postfach-shared'; import { StateResource, createStateResource } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; +import { UntypedFormBuilder } from '@angular/forms'; import { createCommandResource } from 'libs/command-shared/test/command'; -import { createPostfachMailResource } from 'libs/postfach-shared/test/postfach'; +import { + createEmptyPostfachSettings, + createPostfachMailResource, + createPostfachSettings, +} from 'libs/postfach-shared/test/postfach'; import { of } from 'rxjs'; import { PostfachMailFormservice } from './postfach-mail.formservice'; describe('PostfachMailFormservice', () => { let formService: PostfachMailFormservice; - let service: Mock<any>; + let service: Mock<any> = mock(PostfachService); const formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); + const postfachSettings: PostfachSettings = createPostfachSettings(); beforeEach(() => { - service = mock(PostfachService); - + service.getSettings.mockReturnValue(of(postfachSettings)); formService = new PostfachMailFormservice(formBuilder, useFromMock(service)); }); @@ -84,4 +88,29 @@ describe('PostfachMailFormservice', () => { }); }); }); + + describe('initMailBody', () => { + it('should call service', () => { + formService.initMailBody(); + + expect(service.getSettings).toHaveBeenCalled(); + }); + + it('should set field mail body with signatur and newline if signatur is not empty', () => { + formService.initMailBody(); + + const mailBodyValue = formService.form.get(PostfachMailFormservice.FIELD_MAIL_BODY).value; + expect(mailBodyValue).toBe(`\n${postfachSettings.signatur}`); + }); + + it('should not set field mail body if signatur is empty', () => { + service.getSettings.mockReturnValue(of(createEmptyPostfachSettings())); + formService = new PostfachMailFormservice(formBuilder, useFromMock(service)); + + formService.initMailBody(); + + const mailBodyValue = formService.form.get(PostfachMailFormservice.FIELD_MAIL_BODY).value; + expect(mailBodyValue).toBe(null); + }); + }); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail.formservice.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail.formservice.ts index 3e7de900cdaa45e7ebfbbdc66994fb9b874ae594..20b16bb775a0abc4bd57866ec93170756dcf4aa8 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail.formservice.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail.formservice.ts @@ -21,6 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { CommandResource } from '@alfa-client/command-shared'; +import { PostfachService, PostfachSettings } from '@alfa-client/postfach-shared'; +import { AbstractFormService, StateResource } from '@alfa-client/tech-shared'; import { Injectable } from '@angular/core'; import { UntypedFormArray, @@ -28,11 +31,8 @@ import { UntypedFormControl, UntypedFormGroup, } from '@angular/forms'; -import { CommandResource } from '@alfa-client/command-shared'; -import { PostfachService } from '@alfa-client/postfach-shared'; -import { AbstractFormService, StateResource } from '@alfa-client/tech-shared'; import { ReplyOption } from 'libs/postfach-shared/src/lib/postfach.model'; -import { Observable } from 'rxjs'; +import { Observable, first } from 'rxjs'; @Injectable() export class PostfachMailFormservice extends AbstractFormService { @@ -48,6 +48,7 @@ export class PostfachMailFormservice extends AbstractFormService { private postfachService: PostfachService, ) { super(formBuilder); + this.initMailBody(); } protected initForm(): UntypedFormGroup { @@ -59,6 +60,25 @@ export class PostfachMailFormservice extends AbstractFormService { }); } + public initMailBody(): void { + this.postfachService + .getSettings() + .pipe(first((settings) => Boolean(settings.signatur))) + .subscribe((settings: PostfachSettings) => { + this.patchMailBodyWithSignaturAndNewline(settings.signatur); + }); + } + + private patchMailBodyWithSignaturAndNewline(signatur: string) { + this.form + .get(PostfachMailFormservice.FIELD_MAIL_BODY) + .setValue(this.addNewlineAtBeginning(signatur)); + } + + private addNewlineAtBeginning(value: string): string { + return `\n${value}`; + } + protected getPathPrefix(): string { return PostfachMailFormservice.FIELD_PATH_PREFIX; } diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.ts index 1e6ae6bea4559a733a50f29c4411aedc738c8e1c..71a0fc57deeb55ffbadac5d10f4a9cf49ddecd71 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.ts @@ -1,12 +1,12 @@ -import { Component, OnInit } from '@angular/core'; import { - Features, FORBIDDEN_REPLY_OPTION_ITEM, POSSIBLE_REPLY_OPTION_ITEM, + PostfachFeatures, PostfachService, } from '@alfa-client/postfach-shared'; import { FormProvider } from '@alfa-client/tech-shared'; import { CheckboxEnumEditorItem } from '@alfa-client/ui'; +import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { PostfachMailFormservice } from '../postfach-mail.formservice'; @@ -19,7 +19,7 @@ import { PostfachMailFormservice } from '../postfach-mail.formservice'; export class PostfachNachrichtReplyEditorContainerComponent implements OnInit { public readonly formServiceClass = PostfachMailFormservice; - public postfachFeatures$: Observable<Features>; + public postfachFeatures$: Observable<PostfachFeatures>; public checkedItem: CheckboxEnumEditorItem = POSSIBLE_REPLY_OPTION_ITEM; public uncheckedItem: CheckboxEnumEditorItem = FORBIDDEN_REPLY_OPTION_ITEM; diff --git a/alfa-server/pom.xml b/alfa-server/pom.xml index 352336b4ac3074f81a411207f393d1b590933cbf..8310c3d2875b5bd9052d1a8704a958ecb3957786 100644 --- a/alfa-server/pom.xml +++ b/alfa-server/pom.xml @@ -24,18 +24,19 @@ <artifactId>alfa-service</artifactId> <version>${project.version}</version> </dependency> - <dependency> <groupId>de.ozgcloud.alfa</groupId> <artifactId>alfa-xdomea</artifactId> <version>${project.version}</version> </dependency> - <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> - + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-starter-config</artifactId> + </dependency> <!-- aspectJ --> <dependency> <groupId>org.aspectj</groupId> @@ -130,4 +131,4 @@ </plugins> </build> -</project> +</project> \ No newline at end of file diff --git a/alfa-server/src/main/resources/application.yml b/alfa-server/src/main/resources/application.yml index 0f0c8e24b2ea7023c57f11e22b8f3d7c997864e3..f5642fefecceda5c3f88a333ad14c835c5394bc1 100644 --- a/alfa-server/src/main/resources/application.yml +++ b/alfa-server/src/main/resources/application.yml @@ -23,6 +23,8 @@ spring: jwt: issuer-uri: ${ozgcloud.oauth2.issuer-uri} jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs + config: + import: optional:configserver:${ozgcloud_administration_address:http://localhost:8888}/configserver/ server: http2: @@ -51,7 +53,7 @@ management: endpoints: web: exposure: - include: health,prometheus + include: health,prometheus,refresh grpc: client: diff --git a/alfa-service/pom.xml b/alfa-service/pom.xml index 24d69e9a5b0678baaea9c632062d636ba513d436..86daeeea0530386f5a9b708e593c5b46362e622d 100644 --- a/alfa-service/pom.xml +++ b/alfa-service/pom.xml @@ -84,6 +84,10 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-starter-config</artifactId> + </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailController.java index 42bc7f1da0053aaabad81228c24faf6e82ecf20a..8f985cf34a9f199baf42d7d7f0761b6d5d30a2c3 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailController.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailController.java @@ -66,7 +66,8 @@ public class PostfachMailController { static final String PDF_NAME_TEMPLATE = "%s_%s_Nachrichten.pdf"; static final DateTimeFormatter PDF_NAME_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); - private final PostfachMailService service; + private final PostfachMailService postfachMailService; + private final PostfachSettingsService postfachSettingsService; private final PostfachMailModelAssembler assembler; @@ -74,18 +75,10 @@ public class PostfachMailController { private final BinaryFileController binaryFileController; @GetMapping(params = PARAM_VORGANG_ID) - public RepresentationModel<EntityModel<Postfach>> getAll(@RequestParam String vorgangId) { + public RepresentationModel<EntityModel<PostfachSettings>> getAll(@RequestParam String vorgangId) { var vorgang = getVorgang(vorgangId); - - return assembler.toCollectionModel(sort(service.getAll(vorgangId)), buildPostfach(vorgang), vorgang); - } - - Postfach buildPostfach(VorgangWithEingang vorgang) { - return Postfach.builder() - .features(Features.builder() - .reply(service.isReplyToMessageAllowed(vorgang)) - .build()) - .build(); + var postfachSetting = postfachSettingsService.getPostfachSettings(vorgang); + return assembler.toCollectionModel(sort(postfachMailService.getAll(vorgangId)), vorgang, postfachSetting); } Stream<PostfachMail> sort(Stream<PostfachMail> nachrichten) { @@ -104,7 +97,7 @@ public class PostfachMailController { } StreamingResponseBody createDownloadStreamingBody(VorgangWithEingang vorgang) { - return out -> service.getAllAsPdf(vorgang, out); + return out -> postfachMailService.getAllAsPdf(vorgang, out); } ResponseEntity<StreamingResponseBody> buildResponseEntity(VorgangWithEingang vorgang, StreamingResponseBody responseBody) { @@ -119,12 +112,12 @@ public class PostfachMailController { } public boolean isPostfachConfigured() { - return service.isPostfachConfigured(); + return postfachSettingsService.isPostfachConfigured(); } @GetMapping("{nachrichtId}/attachments") public CollectionModel<EntityModel<OzgFile>> findAttachments(@PathVariable PostfachNachrichtId nachrichtId) { - var postfachNachricht = service.findById(nachrichtId); + var postfachNachricht = postfachMailService.findById(nachrichtId); return binaryFileController.getFiles(postfachNachricht.getAttachments()); } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssembler.java index 52c0ba965c916de9bbcf463f4fc6a411c5be7c08..e82e85c2618727e310645ac8cf573ceef5d981de 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssembler.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssembler.java @@ -32,7 +32,6 @@ import java.util.stream.Stream; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.Link; import org.springframework.hateoas.RepresentationModel; @@ -50,8 +49,10 @@ import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus; import de.ozgcloud.alfa.vorgang.VorgangController; import de.ozgcloud.alfa.vorgang.VorgangHead; import de.ozgcloud.alfa.vorgang.VorgangWithEingang; +import lombok.RequiredArgsConstructor; @Component +@RequiredArgsConstructor class PostfachMailModelAssembler implements RepresentationModelAssembler<PostfachMail, EntityModel<PostfachMail>> { public static final String REL_SEND_POSTFACH_MAIL = "sendPostfachMail"; @@ -77,17 +78,12 @@ class PostfachMailModelAssembler implements RepresentationModelAssembler<Postfac private static final Predicate<PostfachMail> SENT_BY_CLIENT_USER = postfachNachricht -> Optional.ofNullable(postfachNachricht.getCreatedBy()) .map(createdBy -> !createdBy.toString().startsWith(SYSTEM_USER_IDENTIFIER)).orElse(false); - @Autowired - private UserManagerUrlProvider userManagerUrlProvider; + private final UserManagerUrlProvider userManagerUrlProvider; - public RepresentationModel<EntityModel<Postfach>> toCollectionModel( - Stream<PostfachMail> postfachMails, Postfach postfach, VorgangWithEingang vorgang) { + public RepresentationModel<EntityModel<PostfachSettings>> toCollectionModel(Stream<PostfachMail> postfachMails, VorgangWithEingang vorgang, + PostfachSettings postfachSettings) { - RepresentationModel<EntityModel<Postfach>> model = HalModelBuilder - .halModelOf(postfach) - .link(linkTo(methodOn(PostfachMailController.class).getAll(vorgang.getId())).withSelfRel()) - .embed(postfachMails.map(this::toModel)) - .build(); + var model = buildHalRepresentationModel(postfachMails, vorgang, postfachSettings); if (hasServiceKonto(vorgang)) { addPostfachNachrichtLinks(model, vorgang); @@ -95,10 +91,35 @@ class PostfachMailModelAssembler implements RepresentationModelAssembler<Postfac return model; } + RepresentationModel<EntityModel<PostfachSettings>> buildHalRepresentationModel(Stream<PostfachMail> postfachMails, VorgangWithEingang vorgang, + PostfachSettings postfachSettings) { + return HalModelBuilder + .halModelOf(postfachSettings) + .link(linkTo(methodOn(PostfachMailController.class).getAll(vorgang.getId())).withSelfRel()) + .embed(postfachMails.map(this::toModel)) + .build(); + } + boolean hasServiceKonto(VorgangWithEingang vorgang) { return Optional.ofNullable(vorgang.getHeader()).map(VorgangHead::getServiceKonto).isPresent(); } + void addPostfachNachrichtLinks(RepresentationModel<EntityModel<PostfachSettings>> model, VorgangWithEingang vorgang) { + var vorgangId = vorgang.getId(); + + if (vorgang.getStatus() != VorgangStatus.ZU_LOESCHEN) { + model.add(linkTo(methodOn(PostfachMailCommandByVorgangController.class).sendPostfachMail(vorgangId, null)) + .withRel(REL_SEND_POSTFACH_MAIL)); + } + + model.add(linkTo(BinaryFileController.class).slash(vorgangId).slash(POSTFACH_NACHRICHT_ATTACHMENT_FIELD).slash(FILE_PATH) + .withRel(REL_UPLOAD_ATTACHMENT)); + + if (vorgang.isHasNewPostfachNachricht()) { + model.add(linkTo(VorgangController.class).slash(vorgangId).slash(HAS_NEW_POSTFACH_NACHRICHT_FIELD).withRel(REL_RESET_NEW_POSTFACH_MAIL)); + } + } + @Override public EntityModel<PostfachMail> toModel(PostfachMail postfachMail) { var selfLink = linkTo(PostfachMailController.class).slash(postfachMail.getId()); @@ -120,20 +141,4 @@ class PostfachMailModelAssembler implements RepresentationModelAssembler<Postfac .buildModel(); } - private void addPostfachNachrichtLinks(RepresentationModel<EntityModel<Postfach>> model, VorgangWithEingang vorgang) { - var vorgangId = vorgang.getId(); - - if (vorgang.getStatus() != VorgangStatus.ZU_LOESCHEN) { - model.add(linkTo(methodOn(PostfachMailCommandByVorgangController.class).sendPostfachMail(vorgangId, null)) - .withRel(REL_SEND_POSTFACH_MAIL)); - } - - model.add(linkTo(BinaryFileController.class).slash(vorgangId).slash(POSTFACH_NACHRICHT_ATTACHMENT_FIELD).slash(FILE_PATH) - .withRel(REL_UPLOAD_ATTACHMENT)); - - if (vorgang.isHasNewPostfachNachricht()) { - model.add(linkTo(VorgangController.class).slash(vorgangId).slash(HAS_NEW_POSTFACH_NACHRICHT_FIELD).withRel(REL_RESET_NEW_POSTFACH_MAIL)); - } - } - } \ No newline at end of file diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailService.java index 17c5a69936b94b265c1eaf802fcc4f49802aca91..b46e278275cb133aca63f025afa69c75633a4a05 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailService.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailService.java @@ -28,14 +28,12 @@ import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; import org.springframework.stereotype.Service; -import de.ozgcloud.alfa.common.FeatureToggleProperties; import de.ozgcloud.alfa.common.binaryfile.BinaryFileService; import de.ozgcloud.alfa.common.binaryfile.FileId; import de.ozgcloud.alfa.common.command.Command; @@ -46,7 +44,6 @@ import de.ozgcloud.alfa.common.file.OzgFile; import de.ozgcloud.alfa.common.user.UserManagerUrlProvider; import de.ozgcloud.alfa.common.user.UserProfile; import de.ozgcloud.alfa.common.user.UserService; -import de.ozgcloud.alfa.vorgang.ServiceKonto; import de.ozgcloud.alfa.vorgang.VorgangWithEingang; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @@ -56,16 +53,12 @@ import lombok.extern.log4j.Log4j2; @Service class PostfachMailService { - private PostfachConfigGroup postfachConfigGroup; - private final PostfachMailRemoteService remoteService; private final PostfachNachrichtPdfService pdfService; private final BinaryFileService fileService; private final UserService userService; private final CommandService commandService; - private final FeatureToggleProperties featureToggleProperties; - public PostfachMail findById(PostfachNachrichtId nachrichtId) { return remoteService.findById(nachrichtId) .orElseThrow(() -> new ResourceNotFoundException(PostfachMail.class, nachrichtId)); @@ -85,13 +78,6 @@ class PostfachMailService { } } - public boolean isPostfachConfigured() { - if (Objects.isNull(postfachConfigGroup)) { - postfachConfigGroup = remoteService.getPostfachConfig(); - } - return postfachConfigGroup.isConfigured(); - } - public OutputStream getAllAsPdf(VorgangWithEingang vorgang, OutputStream out) { var postfachNachrichtPdfDataList = buildPostfachNachrichtPdfDataList(vorgang.getId()); @@ -143,27 +129,4 @@ class PostfachMailService { .map(created -> UserProfile.builder().id(created).build()) .orElseGet(() -> null); } - - public boolean isReplyToMessageAllowed(VorgangWithEingang vorgang) { - return Optional.ofNullable(vorgang.getHeader().getServiceKonto()) - .map(ServiceKonto::getType) - .map(this::isReplyAllowed) - .orElse(false); - } - - boolean isReplyAllowed(String serviceKontoType) { - if (featureToggleProperties.isReplyAlwaysAllowed()) { - return true; - } - - if (!isPostfachConfigured()) { - return false; - } - - return postfachConfigGroup.getPostfachConfigs().stream() - .filter(postfachConfig -> postfachConfig.getType().equalsIgnoreCase(serviceKontoType)) - .map(PostfachConfig::isReplyAllowed) - .findFirst() - .orElse(false); - } } \ No newline at end of file diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachProperties.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..e6d7b0dea5e3fd6e4951c8df5447ab43a45d2a97 --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachProperties.java @@ -0,0 +1,24 @@ +package de.ozgcloud.alfa.postfach; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Configuration; + +import lombok.Getter; +import lombok.Setter; + +@Configuration +@ConfigurationProperties(prefix = PostfachProperties.PREFIX) +@RefreshScope +@Getter +@Setter +public class PostfachProperties { + + static final String PREFIX = "ozgcloud.postfach"; + + /** + * Signature appended to messages. Configured by administration config server. + */ + private String signatur = ""; + +} diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/Postfach.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachSettings.java similarity index 80% rename from alfa-service/src/main/java/de/ozgcloud/alfa/postfach/Postfach.java rename to alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachSettings.java index 804b5396f6dd1312d65f5be8c4758d0782b753c7..bae33daefcdda7f03967c0d8d36d3cee8e9750e9 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/Postfach.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachSettings.java @@ -9,8 +9,9 @@ import lombok.Setter; @Setter @AllArgsConstructor @Builder -class Postfach { +class PostfachSettings { private Features features; + private Settings settings; } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachSettingsService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachSettingsService.java new file mode 100644 index 0000000000000000000000000000000000000000..e42fc707246eba12df26de9cb20c31a6f6598262 --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachSettingsService.java @@ -0,0 +1,74 @@ +package de.ozgcloud.alfa.postfach; + +import java.util.Objects; +import java.util.Optional; + +import org.springframework.cloud.endpoint.RefreshEndpoint; +import org.springframework.stereotype.Service; + +import de.ozgcloud.alfa.common.FeatureToggleProperties; +import de.ozgcloud.alfa.vorgang.ServiceKonto; +import de.ozgcloud.alfa.vorgang.VorgangWithEingang; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Service +class PostfachSettingsService { + + private PostfachConfigGroup postfachConfigGroup; + + private final PostfachMailRemoteService remoteService; + private final RefreshEndpoint refreshEndpoint; + private final PostfachProperties postfachProperties; + private final FeatureToggleProperties featureToggleProperties; + + public boolean isPostfachConfigured() { + if (Objects.isNull(postfachConfigGroup)) { + postfachConfigGroup = remoteService.getPostfachConfig(); + } + return postfachConfigGroup.isConfigured(); + } + + public PostfachSettings getPostfachSettings(VorgangWithEingang vorgang) { + return PostfachSettings.builder() + .features(Features.builder() + .reply(isReplyToMessageAllowed(vorgang)) + .build()) + .settings(Settings.builder() + .signatur(getSignatur()) + .build()) + .build(); + } + + String getSignatur() { + refreshPostfachProperties(); + return postfachProperties.getSignatur(); + } + + void refreshPostfachProperties() { + refreshEndpoint.refresh(); + } + + boolean isReplyToMessageAllowed(VorgangWithEingang vorgang) { + return Optional.ofNullable(vorgang.getHeader().getServiceKonto()) + .map(ServiceKonto::getType) + .map(this::isReplyAllowed) + .orElse(false); + } + + boolean isReplyAllowed(String serviceKontoType) { + if (featureToggleProperties.isReplyAlwaysAllowed()) { + return true; + } + + if (!isPostfachConfigured()) { + return false; + } + + return postfachConfigGroup.getPostfachConfigs().stream() + .filter(postfachConfig -> postfachConfig.getType().equalsIgnoreCase(serviceKontoType)) + .map(PostfachConfig::isReplyAllowed) + .findFirst() + .orElse(false); + } +} diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/Settings.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/Settings.java new file mode 100644 index 0000000000000000000000000000000000000000..8f28f2aea75d803f8c95e0851b384833087f343f --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/Settings.java @@ -0,0 +1,12 @@ +package de.ozgcloud.alfa.postfach; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +class Settings { + + private String signatur; + +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailControllerTest.java index 17f732923cf5995bae45c8521461e328b84b490c..d33010bf633ca9ecff42b8816dc23f4ea38bf980 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailControllerTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailControllerTest.java @@ -23,7 +23,6 @@ */ package de.ozgcloud.alfa.postfach; -import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; @@ -63,7 +62,10 @@ class PostfachMailControllerTest { private PostfachMailController controller; @Mock - private PostfachMailService service; + private PostfachMailService postfachMailService; + + @Mock + private PostfachSettingsService postfachSettingsService; @Mock private PostfachMailModelAssembler assembler; @@ -85,23 +87,23 @@ class PostfachMailControllerTest { class TestGetAll { private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); - private final Postfach postfach = PostfachTestFactory.create(); private final Stream<PostfachMail> postfachMails = Stream.of(PostfachMailTestFactory.create()); private final Stream<PostfachMail> sortedPostfachMails = Stream.of(PostfachMailTestFactory.create()); + private final PostfachSettings postfachSettings = PostfachSettingsTestFactory.create(); @BeforeEach void mockVorgangController() { when(vorgangController.getVorgang(anyString())).thenReturn(vorgang); - when(service.getAll(VorgangHeaderTestFactory.ID)).thenReturn(postfachMails); - doReturn(postfach).when(controller).buildPostfach(vorgang); + when(postfachMailService.getAll(VorgangHeaderTestFactory.ID)).thenReturn(postfachMails); doReturn(sortedPostfachMails).when(controller).sort(postfachMails); + when(postfachSettingsService.getPostfachSettings(vorgang)).thenReturn(postfachSettings); } @Test void shouldCallService() { doRequest(); - verify(service).getAll(VorgangHeaderTestFactory.ID); + verify(postfachMailService).getAll(VorgangHeaderTestFactory.ID); } @Test @@ -112,24 +114,24 @@ class PostfachMailControllerTest { } @Test - void shouldCallModelAssembler() { + void shouldGetPostfachSettings() { doRequest(); - verify(assembler).toCollectionModel(sortedPostfachMails, postfach, vorgang); + verify(postfachSettingsService).getPostfachSettings(vorgang); } @Test - void shouldSortPostfachMails() { + void shouldCallModelAssembler() { doRequest(); - verify(controller).sort(postfachMails); + verify(assembler).toCollectionModel(sortedPostfachMails, vorgang, postfachSettings); } @Test - void shouldBuildPostfach() { + void shouldSortPostfachMails() { doRequest(); - verify(controller).buildPostfach(vorgang); + verify(controller).sort(postfachMails); } @SneakyThrows @@ -139,32 +141,6 @@ class PostfachMailControllerTest { } } - @Nested - class TestBuildPostfach { - - private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); - - @Test - void shouldCheckIsReplyAllowed() { - callController(); - - verify(service).isReplyToMessageAllowed(any(VorgangWithEingang.class)); - } - - @Test - void shouldSetIsReplyAllowedFeature() { - when(service.isReplyToMessageAllowed(vorgang)).thenReturn(true); - - var postfach = callController(); - - assertThat(postfach.getFeatures().isReply()).isTrue(); - } - - private Postfach callController() { - return controller.buildPostfach(vorgang); - } - } - @DisplayName("Get all as pdf") @Nested class TestGetAllAsPdf { @@ -191,7 +167,7 @@ class PostfachMailControllerTest { void shouldCallService() { doRequest(); - verify(service).getAllAsPdf(eq(vorgang), any(OutputStream.class)); + verify(postfachMailService).getAllAsPdf(eq(vorgang), any(OutputStream.class)); } @Test @@ -258,7 +234,7 @@ class PostfachMailControllerTest { void shouldCallServiceGetAllAsPdf() throws IOException { controller.createDownloadStreamingBody(vorgang).writeTo(out); - verify(service).getAllAsPdf(eq(vorgang), any()); + verify(postfachMailService).getAllAsPdf(eq(vorgang), any()); } } @@ -269,7 +245,7 @@ class PostfachMailControllerTest { @BeforeEach void init() { - when(service.findById(any())).thenReturn(PostfachMailTestFactory.create()); + when(postfachMailService.findById(any())).thenReturn(PostfachMailTestFactory.create()); } @Test @@ -281,7 +257,7 @@ class PostfachMailControllerTest { void shouldCallService() throws Exception { doRequest(); - verify(service).findById(PostfachNachrichtId.from(PostfachMailTestFactory.ID)); + verify(postfachMailService).findById(PostfachNachrichtId.from(PostfachMailTestFactory.ID)); } @Test @@ -305,7 +281,7 @@ class PostfachMailControllerTest { void shouldCallService() { controller.isPostfachConfigured(); - verify(service).isPostfachConfigured(); + verify(postfachSettingsService).isPostfachConfigured(); } } diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssemblerTest.java index c69adafddb5363490bd3e172e9be3edc81732bf6..1338bf82ddf79b9680a48e3dd866eb6d93f46f90 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssemblerTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailModelAssemblerTest.java @@ -24,9 +24,9 @@ package de.ozgcloud.alfa.postfach; import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; -import java.util.List; import java.util.UUID; import java.util.stream.Stream; @@ -36,35 +36,44 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; import org.springframework.hateoas.RepresentationModel; +import org.springframework.hateoas.mediatype.hal.HalModelBuilder; +import org.springframework.web.util.UriComponentsBuilder; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import de.ozgcloud.alfa.common.user.UserId; import de.ozgcloud.alfa.common.user.UserManagerUrlProvider; import de.ozgcloud.alfa.postfach.PostfachMail.Direction; import de.ozgcloud.alfa.postfach.PostfachMailController.PostfachMailCommandByVorgangController; +import de.ozgcloud.alfa.vorgang.ServiceKontoTestFactory; import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus; import de.ozgcloud.alfa.vorgang.VorgangHeadTestFactory; import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory; import de.ozgcloud.alfa.vorgang.VorgangWithEingang; import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory; +import lombok.SneakyThrows; class PostfachMailModelAssemblerTest { @InjectMocks + @Spy private PostfachMailModelAssembler modelAssembler; @Mock private UserManagerUrlProvider userManagerUrlProvider; - @BeforeEach - void mock() { - when(userManagerUrlProvider.isConfiguredForUserProfile()).thenReturn(false); - } - @Nested - class TestLinksOnModel { + class TestToModel { + + @BeforeEach + void mock() { + when(userManagerUrlProvider.isConfiguredForUserProfile()).thenReturn(false); + } @Test void shouldHaveSelfLink() { @@ -78,7 +87,7 @@ class PostfachMailModelAssemblerTest { @DisplayName("if 'sentSuccessful' is false, add link") @Test - void shouldHaveResendLink() { + void shouldBePresent() { var link = modelAssembler.toModel(PostfachMailTestFactory.createBuilder().sentSuccessful(false).build()) .getLink(PostfachMailModelAssembler.REL_RESEND_POSTFACH_MAIL); @@ -86,78 +95,51 @@ class PostfachMailModelAssemblerTest { .isEqualTo("/api/postfachMails/" + PostfachMailTestFactory.ID + "/commands"); } - @Nested - class ShouldNOTHaveResendLink { - - @DisplayName("if 'sentSuccessful' is true, hide link") - @Test - void ifSuccessfulSent() { - var link = modelAssembler.toModel(PostfachMailTestFactory.createBuilder().sentSuccessful(true).build()) - .getLink(PostfachMailModelAssembler.REL_RESEND_POSTFACH_MAIL); - - assertThat(link).isNotPresent(); - } - - @Test - void ifNotJetTriedToSend() { - var nachricht = PostfachMailTestFactory.createBuilder().sentSuccessful(false).sentAt(null).build(); - - var link = modelAssembler.toModel(nachricht).getLink(PostfachMailModelAssembler.REL_RESEND_POSTFACH_MAIL); + @DisplayName("if 'sentSuccessful' is true, hide link") + @Test + void shouldNotBePresentIfSuccessfulSent() { + var link = modelAssembler.toModel(PostfachMailTestFactory.createBuilder().sentSuccessful(true).build()) + .getLink(PostfachMailModelAssembler.REL_RESEND_POSTFACH_MAIL); - assertThat(link).isNotPresent(); - } + assertThat(link).isNotPresent(); } - @Nested - class SendLink { - @DisplayName("should be present if nachricht not jet tried to send") - @Test - void shouldBePresent() { - var nachricht = PostfachMailTestFactory.createBuilder().sentSuccessful(false).sentAt(null).build(); - - var link = modelAssembler.toModel(nachricht).getLink(PostfachMailModelAssembler.REL_SEND); - - assertThat(link).isPresent().get().extracting(Link::getHref) - .isEqualTo("/api/postfachMails/" + PostfachMailTestFactory.ID + "/commands"); - } + @Test + void shouldNotBePresentIfNotYetTriedToSend() { + var nachricht = PostfachMailTestFactory.createBuilder().sentSuccessful(false).sentAt(null).build(); - @Nested - class ShouldNOTBePresent { - @Test - void ifNachrichtSent() { - var nachricht = PostfachMailTestFactory.createBuilder().sentSuccessful(true).build(); + var link = modelAssembler.toModel(nachricht).getLink(PostfachMailModelAssembler.REL_RESEND_POSTFACH_MAIL); - assertThat(modelAssembler.toModel(nachricht).getLink(PostfachMailModelAssembler.REL_SEND)).isNotPresent(); - } - } + assertThat(link).isNotPresent(); } + } @Nested - class ResetHasNewPostfachNachricht { - Stream<PostfachMail> mails = List.of(PostfachMailTestFactory.create()).stream(); + class SendLink { + @DisplayName("should be present if nachricht not jet tried to send") @Test - void shouldHaveLink() { - var link = modelAssembler.toCollectionModel(mails, PostfachTestFactory.create(), VorgangWithEingangTestFactory.create()) - .getLink(PostfachMailModelAssembler.REL_RESET_NEW_POSTFACH_MAIL); + void shouldBePresent() { + var nachricht = PostfachMailTestFactory.createBuilder().sentSuccessful(false).sentAt(null).build(); - assertThat(link).isPresent(); + var link = modelAssembler.toModel(nachricht).getLink(PostfachMailModelAssembler.REL_SEND); + + assertThat(link).isPresent().get().extracting(Link::getHref) + .isEqualTo("/api/postfachMails/" + PostfachMailTestFactory.ID + "/commands"); } @Test - void shouldNotNaveLink() { - var link = modelAssembler - .toCollectionModel(mails, PostfachTestFactory.create(), - VorgangWithEingangTestFactory.createBuilder().hasNewPostfachNachricht(false).build()) - .getLink(PostfachMailModelAssembler.REL_RESET_NEW_POSTFACH_MAIL); + void shouldNotBePresentIfNachrichtSent() { + var nachricht = PostfachMailTestFactory.createBuilder().sentSuccessful(true).build(); - assertThat(link).isNotPresent(); + assertThat(modelAssembler.toModel(nachricht).getLink(PostfachMailModelAssembler.REL_SEND)).isNotPresent(); } + } @Nested - class ToAttachments { + class AttachmentsLink { @Test @DisplayName("should be present if attachments present") @@ -170,7 +152,7 @@ class PostfachMailModelAssemblerTest { @Test @DisplayName("should NOT be present if there are no attachments") - void shouldNOTBePresent() { + void shouldNotBePresentOnNoAttachments() { var link = modelAssembler.toModel(PostfachMailTestFactory.createBuilder().clearAttachments().build()) .getLink(PostfachMailModelAssembler.REL_ATTACHMENTS); @@ -204,7 +186,7 @@ class PostfachMailModelAssemblerTest { @DisplayName("should not be present if the value of createdBy starts with 'system'") @Test - void shouldNOTBePresentOnSystemUser() { + void shouldNotBePresentOnSystemUser() { var link = modelAssembler .toModel(PostfachMailTestFactory.createBuilder() .createdBy(UserId.from(PostfachMailModelAssembler.SYSTEM_USER_IDENTIFIER + UUID.randomUUID().toString())).build()) @@ -300,108 +282,214 @@ class PostfachMailModelAssemblerTest { } } - @DisplayName("On collection model link") @Nested - class TestLinksOnCollectionModel { + class TestToCollectionModel { + + private final Stream<PostfachMail> mails = Stream.of(PostfachMailTestFactory.create()); + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + private final PostfachSettings postfachSettings = PostfachSettingsTestFactory.create(); + + @Mock + private RepresentationModel<EntityModel<PostfachSettings>> model; + + @BeforeEach + void setUpMocks() { + doReturn(model).when(modelAssembler).buildHalRepresentationModel(mails, vorgang, postfachSettings); + } @Test - void shouldHaveSelfLink() { - var model = modelAssembler - .toCollectionModel(Stream.of(PostfachMailTestFactory.create()), PostfachTestFactory.create(), - VorgangWithEingangTestFactory.create()); - var selfLink = model.getLink(IanaLinkRelations.SELF_VALUE); + void shouldBuildHalRepresentationModel() { + callModelAssembler(); - assertThat(selfLink).isPresent(); - assertThat(selfLink.get().getHref()).isEqualTo( - String.format("%s?%s=%s", PostfachMailController.PATH, PostfachMailController.PARAM_VORGANG_ID, VorgangHeaderTestFactory.ID)); + verify(modelAssembler).buildHalRepresentationModel(mails, vorgang, postfachSettings); } - @DisplayName("send postfach mail") @Nested - class SendPostfachMailLink { - - private final String sendPostfachMailLinkRel = PostfachMailModelAssembler.REL_SEND_POSTFACH_MAIL; + class OnHasServiceKonto { @Test - void shouldExistsOnExistingServiceKonto() { - var link = toCollectionModel(VorgangWithEingangTestFactory.create()).getLink(sendPostfachMailLinkRel); + void shouldAddPostfachNachrichtLinks() { + doReturn(true).when(modelAssembler).hasServiceKonto(vorgang); + + callModelAssembler(); - assertThat(link).isPresent(); - assertThat(link.get().getHref()) - .isEqualTo(PostfachMailCommandByVorgangController.PATH.replace("{vorgangId}", - VorgangHeaderTestFactory.ID)); + verify(modelAssembler).addPostfachNachrichtLinks(model, vorgang); } + } + + @Nested + class OnHasNotServiceKonto { @Test - void shouldNotExist() { - var link = toCollectionModel(VorgangWithEingangTestFactory.createBuilder().status(VorgangStatus.ZU_LOESCHEN).build()).getLink( - sendPostfachMailLinkRel); + void shouldAddPostfachNachrichtLinks() { + doReturn(false).when(modelAssembler).hasServiceKonto(vorgang); - assertThat(link).isEmpty(); + callModelAssembler(); + + verify(modelAssembler, never()).addPostfachNachrichtLinks(any(), any()); } + } - @DisplayName("should NOT exists") - @Nested - class TestNotExists { + @Test + void shouldReturnModel() { + var returnedModel = callModelAssembler(); - @Test - void onMissingVorgangHeader() { - var vorgangWithoutHeader = VorgangWithEingangTestFactory.createBuilder().header(null).build(); + assertThat(returnedModel).isEqualTo(model); + } - var link = toCollectionModel(vorgangWithoutHeader).getLink(sendPostfachMailLinkRel); + private RepresentationModel<EntityModel<PostfachSettings>> callModelAssembler() { + return modelAssembler.toCollectionModel(mails, vorgang, postfachSettings); + } + } - assertThat(link).isNotPresent(); - } + @Nested + class TestBuildHalRepresentationModel { - @Test - void onMissingServiceKonto() { - var vorgangWithoutServiceKonto = VorgangWithEingangTestFactory.createBuilder().header( - VorgangHeadTestFactory.createBuilder().serviceKonto(null).build()).build(); + private final PostfachMail postfachMail = PostfachMailTestFactory.create(); + private final Stream<PostfachMail> mails = Stream.of(postfachMail); + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + private final PostfachSettings postfachSettings = PostfachSettingsTestFactory.create(); - var link = toCollectionModel(vorgangWithoutServiceKonto).getLink(sendPostfachMailLinkRel); + @Test + void shouldHavePostfachAsContent() { + var model = (EntityModel<PostfachSettings>) callModelAssembler(); - assertThat(link).isNotPresent(); - } + assertThat(model.getContent()).isEqualTo(postfachSettings); + } + + @Test + void shouldAddSelfLink() { + var model = callModelAssembler(); + var selfLink = model.getLink(IanaLinkRelations.SELF_VALUE); + + assertThat(selfLink).get().extracting(Link::getHref).isEqualTo( + String.format("%s?%s=%s", PostfachMailController.PATH, PostfachMailController.PARAM_VORGANG_ID, VorgangHeaderTestFactory.ID)); + } + + @Test + void shouldCallToModel() { + callModelAssembler(); + + verify(modelAssembler).toModel(postfachMail); + } + + @Test + @SneakyThrows + void shouldContainPostfachMails() { + var objectMapper = new ObjectMapper().registerModule(new JavaTimeModule()); + doReturn(EntityModel.of(postfachMail)).when(modelAssembler).toModel(postfachMail); + + var model = callModelAssembler(); + + assertThat(objectMapper.writeValueAsString(model)).contains(objectMapper.writeValueAsString(EntityModel.of(postfachMail))); + } + + private RepresentationModel<EntityModel<PostfachSettings>> callModelAssembler() { + return modelAssembler.buildHalRepresentationModel(mails, vorgang, postfachSettings); + } + + } + + @Nested + class TestHasServiceKonto { + + @Test + void shouldReturnTrueIfServicekontoIsPresent() { + var hasServiceKonto = modelAssembler.hasServiceKonto(VorgangWithEingangTestFactory.createBuilder() + .header(VorgangHeadTestFactory.createBuilder().serviceKonto(ServiceKontoTestFactory.create()).build()).build()); + + assertThat(hasServiceKonto).isTrue(); + } + + @Test + void shouldReturnFalseIfServicekontoIsNotPresent() { + var hasServiceKonto = modelAssembler.hasServiceKonto(VorgangWithEingangTestFactory.createBuilder() + .header(VorgangHeadTestFactory.createBuilder().serviceKonto(null).build()).build()); + + assertThat(hasServiceKonto).isFalse(); + } + + @Test + void shouldReturnFalseOnMissingVorgangHeader() { + var hasServiceKonto = modelAssembler.hasServiceKonto(VorgangWithEingangTestFactory.createBuilder() + .header(null).build()); + + assertThat(hasServiceKonto).isFalse(); + } + } + + @Nested + class TestAddPostfachNachrichtLinks { + + private final PostfachSettings postfach = PostfachSettingsTestFactory.create(); + + private RepresentationModel<EntityModel<PostfachSettings>> model = HalModelBuilder + .halModelOf(postfach) + .build(); + + @Nested + class ResetNewPostfachNachrichtLink { + @Test + void shouldBePresent() { + callModelAssembler(VorgangWithEingangTestFactory.create()); + + var link = model.getLink(PostfachMailModelAssembler.REL_RESET_NEW_POSTFACH_MAIL); + assertThat(link).isPresent().get().extracting(Link::getHref) + .isEqualTo(UriComponentsBuilder.fromUriString("/api/vorgangs") + .pathSegment(VorgangHeaderTestFactory.ID, "hasNewPostfachNachricht") + .build().toString()); + } + + @Test + void shouldNotBePresent() { + callModelAssembler(VorgangWithEingangTestFactory.createBuilder().hasNewPostfachNachricht(false).build()); + + var link = model.getLink(PostfachMailModelAssembler.REL_RESET_NEW_POSTFACH_MAIL); + assertThat(link).isNotPresent(); } } + @DisplayName("send postfach mail") @Nested - class UploadAttachmentLink { + class SendPostfachMailLink { - private final String uploadAttachmentLinkRel = PostfachMailModelAssembler.REL_UPLOAD_ATTACHMENT; + private final String sendPostfachMailLinkRel = PostfachMailModelAssembler.REL_SEND_POSTFACH_MAIL; @Test - void shouldHaveLink() { - var link = toCollectionModel(VorgangWithEingangTestFactory.create()).getLink(uploadAttachmentLinkRel); + void shouldExist() { + callModelAssembler(VorgangWithEingangTestFactory.create()); - assertThat(link).isPresent(); - assertThat(link.get().getHref()) - .isEqualTo(String.format("/api/binaryFiles/%s/postfachNachrichtAttachment/file", VorgangHeaderTestFactory.ID)); + var link = model.getLink(sendPostfachMailLinkRel); + assertThat(link).get().extracting(Link::getHref) + .isEqualTo(PostfachMailCommandByVorgangController.PATH.replace("{vorgangId}", VorgangHeaderTestFactory.ID)); } @Test - void shouldNotHaveLink() { - var vorgangWithoutServiceKonto = VorgangWithEingangTestFactory.createBuilder().header( - VorgangHeadTestFactory.createBuilder().serviceKonto(null).build()).build(); - var link = toCollectionModel(vorgangWithoutServiceKonto).getLink(uploadAttachmentLinkRel); + void shouldNotExistOnStatusZuLoeschen() { + callModelAssembler(VorgangWithEingangTestFactory.createBuilder().status(VorgangStatus.ZU_LOESCHEN).build()); - assertThat(link).isNotPresent(); + var link = model.getLink(sendPostfachMailLinkRel); + assertThat(link).isEmpty(); } } - private RepresentationModel<EntityModel<Postfach>> toCollectionModel(VorgangWithEingang vorgang) { - return modelAssembler.toCollectionModel( - Stream.of(PostfachMailTestFactory.create()), - buildPostfach(), - vorgang); + @Nested + class UploadAttachmentLink { + + private final String uploadAttachmentLinkRel = PostfachMailModelAssembler.REL_UPLOAD_ATTACHMENT; + + @Test + void shouldBePresent() { + callModelAssembler(VorgangWithEingangTestFactory.create()); + + var link = model.getLink(uploadAttachmentLinkRel); + assertThat(link).get().extracting(Link::getHref) + .isEqualTo(String.format("/api/binaryFiles/%s/postfachNachrichtAttachment/file", VorgangHeaderTestFactory.ID)); + } } - private Postfach buildPostfach() { - return PostfachTestFactory.createBuilder() - .features(FeaturesTestFactory.createBuilder() - .reply(FeaturesTestFactory.REPLY_FORBIDDEN) - .build()) - .build(); + private void callModelAssembler(VorgangWithEingang vorgang) { + modelAssembler.addPostfachNachrichtLinks(model, vorgang); } } -} \ No newline at end of file +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailServiceTest.java index f31e143f6a0b1723b19a82771fced255d102340f..33d902c17f9c72aaa03d6cd36e7e7145f9328a59 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailServiceTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailServiceTest.java @@ -38,17 +38,11 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentMatcher; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; -import org.springframework.test.util.ReflectionTestUtils; -import com.thedeanda.lorem.LoremIpsum; - -import de.ozgcloud.alfa.common.FeatureToggleProperties; import de.ozgcloud.alfa.common.binaryfile.BinaryFileService; import de.ozgcloud.alfa.common.binaryfile.BinaryFileTestFactory; import de.ozgcloud.alfa.common.binaryfile.FileId; @@ -62,8 +56,6 @@ import de.ozgcloud.alfa.common.user.UserId; import de.ozgcloud.alfa.common.user.UserProfile; import de.ozgcloud.alfa.common.user.UserProfileTestFactory; import de.ozgcloud.alfa.common.user.UserService; -import de.ozgcloud.alfa.vorgang.ServiceKontoTestFactory; -import de.ozgcloud.alfa.vorgang.VorgangHeadTestFactory; import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory; import de.ozgcloud.alfa.vorgang.VorgangWithEingang; import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory; @@ -84,9 +76,6 @@ class PostfachMailServiceTest { @Mock private CommandService commandService; - @Mock - private FeatureToggleProperties featureToggleProperties; - @DisplayName("Get all") @Nested class TestGetAll { @@ -158,60 +147,6 @@ class PostfachMailServiceTest { } } - @DisplayName("Is postfach configured") - @Nested - class TestIsPostfachConfigured { - - @Test - void shouldCallRemoteServiceOnMissingProperty() { - when(remoteService.getPostfachConfig()).thenReturn(PostfachConfigGroupTestFactory.create()); - - service.isPostfachConfigured(); - - verify(remoteService).getPostfachConfig(); - } - - @Test - void shouldNotCallRemoteServiceOnExistingProperty() { - setPostfachConfigGroup(PostfachConfigGroupTestFactory.create()); - - service.isPostfachConfigured(); - - verifyNoInteractions(remoteService); - } - - @Test - void shoulCallRemoteServiceOnlyOnce() { - when(remoteService.getPostfachConfig()).thenReturn(PostfachConfigGroupTestFactory.create()); - - service.isPostfachConfigured(); - service.isPostfachConfigured(); - - verify(remoteService, times(1)).getPostfachConfig(); - } - - @ParameterizedTest - @ValueSource(booleans = { false, true }) - void shouldReturnValueFromRemoteService(boolean expectedConfigured) { - var serviceResponse = PostfachConfigGroupTestFactory.createBuilder().configured(expectedConfigured).build(); - when(remoteService.getPostfachConfig()).thenReturn(serviceResponse); - - var configured = service.isPostfachConfigured(); - - assertThat(configured).isEqualTo(expectedConfigured); - } - - @ParameterizedTest - @ValueSource(booleans = { false, true }) - void shouldReturnCachedValue(boolean expectedConfigured) { - setPostfachConfigGroup(PostfachConfigGroupTestFactory.createBuilder().configured(expectedConfigured).build()); - - var configured = service.isPostfachConfigured(); - - assertThat(configured).isEqualTo(expectedConfigured); - } - } - @DisplayName("Get all as pdf") @Nested class TestGetAllAsPdf { @@ -507,133 +442,4 @@ class PostfachMailServiceTest { } } } - - @Nested - @DisplayName("Is reply to a message allowed for given Vorgang") - class TestIsReplyToMessageAllowed { - - @Test - void shouldCallIsReplyAllowed() { - doReturn(true).when(service).isReplyAllowed(any()); - - service.isReplyToMessageAllowed(VorgangWithEingangTestFactory.create()); - - verify(service).isReplyAllowed(ServiceKontoTestFactory.TYPE); - } - - @ParameterizedTest - @ValueSource(booleans = { false, true }) - void shouldReturnResultOfIsReplyAllowed(boolean expectedReplyAllowed) { - doReturn(expectedReplyAllowed).when(service).isReplyAllowed(any()); - - var replyAllowed = service.isReplyToMessageAllowed(VorgangWithEingangTestFactory.create()); - - assertThat(replyAllowed).isEqualTo(expectedReplyAllowed); - } - - @Test - void shouldReturnFalseForNotExistingServiceKonto() { - var vorgangWithEingang = VorgangWithEingangTestFactory.createBuilder() - .header(VorgangHeadTestFactory.createBuilder() - .serviceKonto(null) - .build()) - .build(); - - var replyToMessageAllowed = service.isReplyToMessageAllowed(vorgangWithEingang); - - assertThat(replyToMessageAllowed).isFalse(); - } - } - - @Nested - class TestIsReplyAllowed { - - private static final String DUMMY_SERVICE_KONTO_TYPE = LoremIpsum.getInstance().getWords(1); - - @BeforeEach - void setUp() { - when(featureToggleProperties.isReplyAlwaysAllowed()).thenReturn(false); - } - - @Test - @DisplayName("reply not allowed if postfach not configured") - void shouldReturnFalseIfPostfachNotConfigured() { - setPostfachConfigGroup(PostfachConfigGroupTestFactory.createBuilder().postfachConfigs(List.of()).build()); - doReturn(false).when(service).isPostfachConfigured(); - - var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE); - - assertThat(replyAllowed).isFalse(); - } - - @Test - @DisplayName("given ServiceKonto-type is not configured") - void shouldReturnFalseForNotConfiguredType() { - setPostfachConfigGroup(PostfachConfigGroupTestFactory.createBuilder().postfachConfigs(List.of()).build()); - doReturn(true).when(service).isPostfachConfigured(); - - var replyAllowed = service.isReplyAllowed(DUMMY_SERVICE_KONTO_TYPE); - - assertThat(replyAllowed).isFalse(); - } - - @Test - @DisplayName("given ServiceKonto-type is null") - void shouldReturnFalseForUnknownType() { - setPostfachConfigGroup(PostfachConfigGroupTestFactory.create()); - doReturn(true).when(service).isPostfachConfigured(); - - var replyAllowed = service.isReplyAllowed(null); - - assertThat(replyAllowed).isFalse(); - } - - @Test - @DisplayName("reply not allowed for given ServiceKonto-type") - void shouldReturnFalseIfReplyNotAllowed() { - setPostfachConfigGroup(PostfachConfigGroupTestFactory.createBuilder() - .postfachConfigs(List.of(PostfachConfigTestFactory.createBuilder().replyAllowed(false).build())) - .build()); - doReturn(true).when(service).isPostfachConfigured(); - - var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE); - - assertThat(replyAllowed).isFalse(); - } - - @Test - @DisplayName("reply allowed for given ServiceKonto-type") - void shouldReturnTrueIfReplyIsAllowed() { - setPostfachConfigGroup(PostfachConfigGroupTestFactory.create()); - doReturn(true).when(service).isPostfachConfigured(); - - var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE); - - assertThat(replyAllowed).isTrue(); - } - - @Test - @DisplayName("reply allowed for given lower case ServiceKonto-type") - void shouldReturnTrueIfReplyIsAllowedForLowerCaseServiceKontoType() { - setPostfachConfigGroup(PostfachConfigGroupTestFactory.create()); - doReturn(true).when(service).isPostfachConfigured(); - - var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE.toLowerCase()); - - assertThat(replyAllowed).isTrue(); - } - - @Test - void shouldReturnTrueIfAlwaysAllowed() { - when(featureToggleProperties.isReplyAlwaysAllowed()).thenReturn(true); - - var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE); - - assertThat(replyAllowed).isTrue(); - } - } - - private void setPostfachConfigGroup(PostfachConfigGroup postfachConfigGroup) { - ReflectionTestUtils.setField(service, "postfachConfigGroup", postfachConfigGroup); - } } \ No newline at end of file diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachSettingsServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachSettingsServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2898c5ecf7fde5ead5dab2eb396bbeeae8f3861d --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachSettingsServiceTest.java @@ -0,0 +1,320 @@ +package de.ozgcloud.alfa.postfach; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.cloud.endpoint.RefreshEndpoint; +import org.springframework.test.util.ReflectionTestUtils; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.alfa.common.FeatureToggleProperties; +import de.ozgcloud.alfa.vorgang.ServiceKontoTestFactory; +import de.ozgcloud.alfa.vorgang.VorgangHeadTestFactory; +import de.ozgcloud.alfa.vorgang.VorgangWithEingang; +import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory; + +class PostfachSettingsServiceTest { + + @Spy + @InjectMocks + private PostfachSettingsService service; + @Mock + private PostfachMailRemoteService remoteService; + @Mock + private RefreshEndpoint refreshEndpoint; + @Mock + private PostfachProperties postfachProperties; + @Mock + private FeatureToggleProperties featureToggleProperties; + + @DisplayName("Is postfach configured") + @Nested + class TestIsPostfachConfigured { + + @Test + void shouldCallRemoteServiceOnMissingProperty() { + when(remoteService.getPostfachConfig()).thenReturn(PostfachConfigGroupTestFactory.create()); + + callService(); + + verify(remoteService).getPostfachConfig(); + } + + @Test + void shouldNotCallRemoteServiceOnExistingProperty() { + setPostfachConfigGroup(PostfachConfigGroupTestFactory.create()); + + callService(); + + verifyNoInteractions(remoteService); + } + + @Test + void shoulCallRemoteServiceOnlyOnce() { + when(remoteService.getPostfachConfig()).thenReturn(PostfachConfigGroupTestFactory.create()); + + callService(); + callService(); + + verify(remoteService, times(1)).getPostfachConfig(); + } + + @ParameterizedTest + @ValueSource(booleans = { false, true }) + void shouldReturnValueFromRemoteService(boolean expectedConfigured) { + var serviceResponse = PostfachConfigGroupTestFactory.createBuilder().configured(expectedConfigured).build(); + when(remoteService.getPostfachConfig()).thenReturn(serviceResponse); + + var configured = callService(); + + assertThat(configured).isEqualTo(expectedConfigured); + } + + @ParameterizedTest + @ValueSource(booleans = { false, true }) + void shouldReturnCachedValue(boolean expectedConfigured) { + setPostfachConfigGroup(PostfachConfigGroupTestFactory.createBuilder().configured(expectedConfigured).build()); + + var configured = callService(); + + assertThat(configured).isEqualTo(expectedConfigured); + } + + private boolean callService() { + return service.isPostfachConfigured(); + } + } + + @Nested + class TestGetPostfachSettings { + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + + @BeforeEach + void mockService() { + doReturn(true).when(service).isReplyToMessageAllowed(vorgang); + + } + + @Test + void shouldCheckIsReplyAllowed() { + callService(); + + verify(service).isReplyToMessageAllowed(vorgang); + } + + @ParameterizedTest + @ValueSource(booleans = { true, false }) + void shouldSetIsReplyAllowedFeature(boolean replyAllowed) { + when(service.isReplyToMessageAllowed(vorgang)).thenReturn(replyAllowed); + + var postfach = callService(); + + assertThat(postfach.getFeatures().isReply()).isEqualTo(replyAllowed); + } + + @Test + void shouldGetSignatur() { + callService(); + + verify(service).getSignatur(); + } + + @Test + void shouldSetSignatur() { + doReturn(SettingsTestFactory.SIGNATUR).when(service).getSignatur(); + + var postfach = callService(); + + assertThat(postfach.getSettings().getSignatur()).isEqualTo(SettingsTestFactory.SIGNATUR); + } + + private PostfachSettings callService() { + return service.getPostfachSettings(vorgang); + } + } + + @Nested + class TestGetSignatur { + + @Test + void shouldRefreshCloudProperties() { + callService(); + + verify(service).refreshPostfachProperties(); + } + + @Test + void shouldGetSignatur() { + callService(); + + verify(postfachProperties).getSignatur(); + + } + + @Test + void shouldReturnSignatur() { + when(postfachProperties.getSignatur()).thenReturn(SettingsTestFactory.SIGNATUR); + + var signatur = callService(); + + assertThat(signatur).isEqualTo(SettingsTestFactory.SIGNATUR); + } + + private String callService() { + return service.getSignatur(); + } + } + + @Nested + class TestRefreshPostfachProperties { + + @Test + void shouldCallRefreshEndpoint() { + service.refreshPostfachProperties(); + + verify(refreshEndpoint).refresh(); + } + } + + @Nested + @DisplayName("Is reply to a message allowed for given Vorgang") + class TestIsReplyToMessageAllowed { + + @Test + void shouldCallIsReplyAllowed() { + doReturn(true).when(service).isReplyAllowed(ServiceKontoTestFactory.TYPE); + + service.isReplyToMessageAllowed(VorgangWithEingangTestFactory.create()); + + verify(service).isReplyAllowed(ServiceKontoTestFactory.TYPE); + } + + @ParameterizedTest + @ValueSource(booleans = { false, true }) + void shouldReturnResultOfIsReplyAllowed(boolean expectedReplyAllowed) { + doReturn(expectedReplyAllowed).when(service).isReplyAllowed(ServiceKontoTestFactory.TYPE); + + var replyAllowed = service.isReplyToMessageAllowed(VorgangWithEingangTestFactory.create()); + + assertThat(replyAllowed).isEqualTo(expectedReplyAllowed); + } + + @Test + void shouldReturnFalseForNotExistingServiceKonto() { + var vorgangWithEingang = VorgangWithEingangTestFactory.createBuilder() + .header(VorgangHeadTestFactory.createBuilder() + .serviceKonto(null) + .build()) + .build(); + + var replyToMessageAllowed = service.isReplyToMessageAllowed(vorgangWithEingang); + + assertThat(replyToMessageAllowed).isFalse(); + } + } + + @Nested + class TestIsReplyAllowed { + + private static final String DUMMY_SERVICE_KONTO_TYPE = LoremIpsum.getInstance().getWords(1); + + @BeforeEach + void setUp() { + when(featureToggleProperties.isReplyAlwaysAllowed()).thenReturn(false); + } + + @Test + @DisplayName("reply not allowed if postfach not configured") + void shouldReturnFalseIfPostfachNotConfigured() { + setPostfachConfigGroup(PostfachConfigGroupTestFactory.createBuilder().postfachConfigs(List.of()).build()); + doReturn(false).when(service).isPostfachConfigured(); + + var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE); + + assertThat(replyAllowed).isFalse(); + } + + @Test + @DisplayName("given ServiceKonto-type is not configured") + void shouldReturnFalseForNotConfiguredType() { + setPostfachConfigGroup(PostfachConfigGroupTestFactory.createBuilder().postfachConfigs(List.of()).build()); + doReturn(true).when(service).isPostfachConfigured(); + + var replyAllowed = service.isReplyAllowed(DUMMY_SERVICE_KONTO_TYPE); + + assertThat(replyAllowed).isFalse(); + } + + @Test + @DisplayName("given ServiceKonto-type is null") + void shouldReturnFalseForUnknownType() { + setPostfachConfigGroup(PostfachConfigGroupTestFactory.create()); + doReturn(true).when(service).isPostfachConfigured(); + + var replyAllowed = service.isReplyAllowed(null); + + assertThat(replyAllowed).isFalse(); + } + + @Test + @DisplayName("reply not allowed for given ServiceKonto-type") + void shouldReturnFalseIfReplyNotAllowed() { + setPostfachConfigGroup(PostfachConfigGroupTestFactory.createBuilder() + .postfachConfigs(List.of(PostfachConfigTestFactory.createBuilder().replyAllowed(false).build())) + .build()); + doReturn(true).when(service).isPostfachConfigured(); + + var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE); + + assertThat(replyAllowed).isFalse(); + } + + @Test + @DisplayName("reply allowed for given ServiceKonto-type") + void shouldReturnTrueIfReplyIsAllowed() { + setPostfachConfigGroup(PostfachConfigGroupTestFactory.create()); + doReturn(true).when(service).isPostfachConfigured(); + + var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE); + + assertThat(replyAllowed).isTrue(); + } + + @Test + @DisplayName("reply allowed for given lower case ServiceKonto-type") + void shouldReturnTrueIfReplyIsAllowedForLowerCaseServiceKontoType() { + setPostfachConfigGroup(PostfachConfigGroupTestFactory.create()); + doReturn(true).when(service).isPostfachConfigured(); + + var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE.toLowerCase()); + + assertThat(replyAllowed).isTrue(); + } + + @Test + void shouldReturnTrueIfAlwaysAllowed() { + when(featureToggleProperties.isReplyAlwaysAllowed()).thenReturn(true); + + var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE); + + assertThat(replyAllowed).isTrue(); + } + } + + private void setPostfachConfigGroup(PostfachConfigGroup postfachConfigGroup) { + ReflectionTestUtils.setField(service, "postfachConfigGroup", postfachConfigGroup); + } + +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachSettingsTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachSettingsTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..6db1a82014fdc494a7fa8ce083214dd624fdb10c --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachSettingsTestFactory.java @@ -0,0 +1,17 @@ +package de.ozgcloud.alfa.postfach; + +public class PostfachSettingsTestFactory { + + public static final Features FEATURES = FeaturesTestFactory.create(); + public static final Settings SETTINGS = SettingsTestFactory.create(); + + public static PostfachSettings create() { + return createBuilder().build(); + } + + public static PostfachSettings.PostfachSettingsBuilder createBuilder() { + return PostfachSettings.builder() + .features(FEATURES) + .settings(SETTINGS); + } +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachTestFactory.java deleted file mode 100644 index 2fafe4b9cd22e28321b5abb0210e77308dd5d476..0000000000000000000000000000000000000000 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachTestFactory.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.ozgcloud.alfa.postfach; - -public class PostfachTestFactory { - - public static final Features FEATURES = FeaturesTestFactory.create(); - - public static Postfach create() { - return createBuilder().build(); - } - - public static Postfach.PostfachBuilder createBuilder() { - return Postfach.builder().features(FEATURES); - } -} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/SettingsTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/SettingsTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..03fa58cccc956240f7bade5eceb693477618aa50 --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/SettingsTestFactory.java @@ -0,0 +1,17 @@ +package de.ozgcloud.alfa.postfach; + +import com.thedeanda.lorem.LoremIpsum; + +public class SettingsTestFactory { + + public static final String SIGNATUR = LoremIpsum.getInstance().getParagraphs(2, 2); + + public static Settings create() { + return createBuilder().build(); + } + + public static Settings.SettingsBuilder createBuilder() { + return Settings.builder() + .signatur(SIGNATUR); + } +} diff --git a/alfa-service/src/test/resources/application.yml b/alfa-service/src/test/resources/application.yml index d2f9d0715b8ff905923e8bb5387f518ff77213af..ea81cad0839dc0d94a6ee477c178dd42c66b44fe 100644 --- a/alfa-service/src/test/resources/application.yml +++ b/alfa-service/src/test/resources/application.yml @@ -22,12 +22,12 @@ ozgcloud: url: https://localhost profile-template: /api/userProfiles/%s search-template: /api/userProfiles/?searchBy={searchBy} - + jwt: auth: converter: resource-id: alfa - principle-attribute: preferred_username + principle-attribute: preferred_username spring: mvc: @@ -42,13 +42,15 @@ spring: multipart: max-file-size: 2GB max-request-size: 2GB + config: + import: optional:configserver:http://localhost:8888/ security: oauth2: resourceserver: jwt: issuer-uri: ${ozgcloud.keycloak.auth-server-url}/realms/${ozgcloud.keycloak.realm} jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs - + server: http2: enabled: true @@ -76,8 +78,8 @@ management: endpoints: web: exposure: - include: health,prometheus - + include: health,prometheus,refresh + grpc: client: vorgang-manager: diff --git a/pom.xml b/pom.xml index 1989d2bfc0f915073d913b26e94eadfed20299bc..5c3018e62bf6370472aba1576215d06d0e43067d 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,7 @@ <ozgcloud-common-pdf.version>3.0.1</ozgcloud-common-pdf.version> <user-manager.version>2.2.0</user-manager.version> <zufi-manager.version>1.2.0</zufi-manager.version> + <spring-cloud-config-client.version>4.1.3</spring-cloud-config-client.version> <!-- TODO: die Version über ozgcloud-common ziehen --> <jjwt.version>0.11.5</jjwt.version> @@ -158,6 +159,11 @@ <version>${jjwt.version}</version> <scope>runtime</scope> </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-starter-config</artifactId> + <version>${spring-cloud-config-client.version}</version> + </dependency> </dependencies> </dependencyManagement> diff --git a/src/main/helm/templates/_helpers.tpl b/src/main/helm/templates/_helpers.tpl index 2277556ced3553ea475b105264fc156bada77eb6..a20881dd0de555971004516d03a0a3767809c394 100644 --- a/src/main/helm/templates/_helpers.tpl +++ b/src/main/helm/templates/_helpers.tpl @@ -57,6 +57,10 @@ app.kubernetes.io/namespace: {{ include "app.namespace" . }} {{ printf "%s.%s:9000" ( coalesce .Values.usermanagerName "user-manager" ) .Release.Namespace }} {{- end -}} +{{- define "app.spring_cloud_config_administration_address" -}} +{{ printf "http://%s.%s:8080" ( coalesce .Values.administrationName "administration" ) .Release.Namespace }} +{{- end -}} + {{- define "app.baseUrl" -}} {{- required "baseUrl muss angegeben sein" .Values.baseUrl }} {{- end -}} diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml index edfb381cc4c6e5a540411f140df4b359727c044d..585408d9e599665f5ac4777b117051c601ebeaec 100644 --- a/src/main/helm/templates/deployment.yaml +++ b/src/main/helm/templates/deployment.yaml @@ -109,6 +109,8 @@ spec: value: {{ ((.Values.ozgcloud).xdomea).behoerdenschluesselUri}} - name: ozgcloud_xdomea_behoerdenschluesselVersion value: {{ ((.Values.ozgcloud).xdomea).behoerdenschluesselVersion | quote }} + - name: ozgcloud_administration_address + value: {{ include "app.spring_cloud_config_administration_address" . }} - name: grpc_client_zufi-manager_address value: {{ .Values.zufiManager.address }} - name: grpc_client_zufi-manager_negotiationType diff --git a/src/main/helm/templates/network_policy.yaml b/src/main/helm/templates/network_policy.yaml index 174b22aba6b25c8f4e2219e8db7234b21b6e442a..fe9816c1f6700cc2b82b051eaa6c9741fd51a725 100644 --- a/src/main/helm/templates/network_policy.yaml +++ b/src/main/helm/templates/network_policy.yaml @@ -33,7 +33,7 @@ spec: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: {{ required "zufiManager.namespace must be set if zufiManager server is enabled" (.Values.zufiManager).namespace }} - podSelector: + podSelector: matchLabels: component: zufi-server ports: @@ -41,15 +41,22 @@ spec: protocol: TCP {{- end }} - to: - - podSelector: + - podSelector: matchLabels: component: vorgang-manager ports: - port: 9090 protocol: TCP + - to: + - podSelector: + matchLabels: + component: administration + ports: + - port: 8080 + protocol: TCP # public keycloak ip - to: - - ipBlock: + - ipBlock: cidr: {{ required "networkPolicy.ssoPublicIp must be set" (.Values.networkPolicy).ssoPublicIp }} - to: - namespaceSelector: @@ -65,7 +72,7 @@ spec: - port: 5353 protocol: TCP - to: - - podSelector: + - podSelector: matchLabels: component: user-manager ports: diff --git a/src/test/helm/deployment_config_client_env_test.yaml b/src/test/helm/deployment_config_client_env_test.yaml new file mode 100644 index 0000000000000000000000000000000000000000..62ef728deb884eca479351daa21a1080ef30c23f --- /dev/null +++ b/src/test/helm/deployment_config_client_env_test.yaml @@ -0,0 +1,32 @@ +suite: deployment collaboration env +release: + name: alfa + namespace: sh-helm-test +templates: + - templates/deployment.yaml +set: + baseUrl: test.company.local + ozgcloud: + environment: test + bundesland: sh + bezeichner: helm + sso: + serverUrl: https://sso.company.local + imagePullSecret: image-pull-secret +tests: + - it: should set default administration server address + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ozgcloud_administration_address + value: http://administration.sh-helm-test:8080 + - it: should have set administration server address + set: + administrationName: custom_admin_name + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ozgcloud_administration_address + value: http://custom_admin_name.sh-helm-test:8080 diff --git a/src/test/helm/network_policy_test.yaml b/src/test/helm/network_policy_test.yaml index e4f349ce5591852828a2d7c511244c12e239e652..37eadd62d18c858ec89095fb7849c3144c035988 100644 --- a/src/test/helm/network_policy_test.yaml +++ b/src/test/helm/network_policy_test.yaml @@ -91,6 +91,13 @@ tests: ports: - port: 9090 protocol: TCP + - to: + - podSelector: + matchLabels: + component: administration + ports: + - port: 8080 + protocol: TCP # public keycloak ip - to: - ipBlock: