diff --git a/alfa-server/src/main/resources/application-dev.yml b/alfa-server/src/main/resources/application-dev.yml index 18feb5c73f71f7e5cfda4ffc5ea23530d8797f34..0b2ff4f5d986874d51c24f2e1ea49e42ec0f30c2 100644 --- a/alfa-server/src/main/resources/application-dev.yml +++ b/alfa-server/src/main/resources/application-dev.yml @@ -11,6 +11,7 @@ ozgcloud: feature: reply-always-allowed: true collaboration-enabled: true + forward-by-ozg-cloud-enabled: true production: false stage: production: false diff --git a/alfa-server/src/main/resources/application-e2e.yml b/alfa-server/src/main/resources/application-e2e.yml index d56ddccb468a1ec933afa67796cc933a031851a8..e1104d4169b4fd601ae25ba33fe7d8950e4fcccb 100644 --- a/alfa-server/src/main/resources/application-e2e.yml +++ b/alfa-server/src/main/resources/application-e2e.yml @@ -5,6 +5,7 @@ ozgcloud: feature: reply-always-allowed: true collaboration-enabled: true + forward-by-ozg-cloud-enabled: true forwarding: lninfo: url: classpath:files/LandesnetzInfo.html diff --git a/alfa-server/src/main/resources/application-local.yml b/alfa-server/src/main/resources/application-local.yml index 76f4ccb48052de1ee266058c1f7377dafdac11b0..6c0f901bcd2e416639d72d9c02c178e87a4fb1f6 100644 --- a/alfa-server/src/main/resources/application-local.yml +++ b/alfa-server/src/main/resources/application-local.yml @@ -24,6 +24,7 @@ ozgcloud: feature: reply-always-allowed: true collaboration-enabled: true + forward-by-ozg-cloud-enabled: true production: false user-assistance: documentation: diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java index 9fe15e7d929b643995dc46717453e60be8f58304..52e3396fd8b1e5002bbbf80b22faf14794184e25 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java @@ -44,4 +44,9 @@ public class FeatureToggleProperties { * Enable collaboration-feature in Vorgang */ private boolean collaborationEnabled = false; + + /** + * Enable forwarding feature + */ + private boolean forwardByOzgCloudEnabled = false; } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessor.java index 38e6b3c7e13f35faeab1684111fc787a69361da3..a5014ff3e7ac1482d61d7c3b6e3b509f744b7fae 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessor.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessor.java @@ -39,15 +39,12 @@ import org.springframework.stereotype.Component; import de.ozgcloud.alfa.attachment.AttachmentByVorgangController; import de.ozgcloud.alfa.common.ModelBuilder; import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController; -import de.ozgcloud.alfa.common.user.CurrentUserService; import de.ozgcloud.alfa.common.user.UserManagerUrlProvider; -import de.ozgcloud.alfa.common.user.UserRole; import de.ozgcloud.alfa.historie.HistorieController; import de.ozgcloud.alfa.kommentar.KommentarController.KommentarByVorgangController; import de.ozgcloud.alfa.postfach.PostfachMailController; import de.ozgcloud.alfa.representation.RepresentationByVorgangController; import de.ozgcloud.alfa.vorgang.VorgangProperties.VorgangProperty; -import de.ozgcloud.alfa.vorgang.forwarding.ForwardingController; import lombok.RequiredArgsConstructor; @Component @@ -68,7 +65,6 @@ class VorgangWithEingangProcessor implements RepresentationModelProcessor<Entity static final String USER_PROFILE_SEARCH_ORGANISATIONS_EINHEIT_ID_PARAM = "organisationsEinheitId"; private final PostfachMailController postfachMailController; - private final CurrentUserService userService; private final UserManagerUrlProvider userManagerUrlProvider; private final VorgangProcessorProperties vorgangProcessorProperties; @@ -99,8 +95,6 @@ class VorgangWithEingangProcessor implements RepresentationModelProcessor<Entity .withRel(REL_REPRESENTATIONS)) .ifMatch(this::isPostfachConfigured) .addLink(linkTo(methodOn(PostfachMailController.class).getAll(vorgang.getId())).withRel(REL_POSTFACH_MAILS)) - .ifMatch(this::isEinheitlicherAnsprechpartner) - .addLink(linkTo(methodOn(ForwardingController.class).findByVorgangId(vorgang.getId())).withRel(REL_VORGANG_FORWARDING)) .addLink(linkTo(methodOn(HistorieController.class).getAll(vorgang.getId())).withRel(REL_HISTORIE)) .ifMatch(() -> userManagerUrlProvider.isConfiguredForSearchUserProfile() && hasOrganisationsEinheitId(vorgang)) .addLink(this::buildSearchUserProfilesLink) @@ -115,10 +109,6 @@ class VorgangWithEingangProcessor implements RepresentationModelProcessor<Entity return postfachMailController.isPostfachConfigured(); } - private boolean isEinheitlicherAnsprechpartner(VorgangWithEingang vorgang) { - return userService.hasRole(UserRole.EINHEITLICHER_ANSPRECHPARTNER); - } - private Link buildSearchUserProfilesLink(VorgangWithEingang vorgang) { return Link.of(userManagerUrlProvider.getSearchUserProfilesTemplate() .queryParam(USER_PROFILE_SEARCH_DELETED_PARAM, false) diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingVorgangWithEingangProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingVorgangWithEingangProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..46e63f18aaa609c1e638354c09833fd075f6b3e6 --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingVorgangWithEingangProcessor.java @@ -0,0 +1,62 @@ +package de.ozgcloud.alfa.vorgang.forwarding; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; + +import java.util.Optional; + +import org.springframework.hateoas.EntityModel; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; +import org.springframework.hateoas.server.RepresentationModelProcessor; +import org.springframework.stereotype.Component; + +import de.ozgcloud.alfa.common.FeatureToggleProperties; +import de.ozgcloud.alfa.common.command.CommandController; +import de.ozgcloud.alfa.common.user.CurrentUserService; +import de.ozgcloud.alfa.common.user.UserRole; +import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus; +import de.ozgcloud.alfa.vorgang.VorgangWithEingang; +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +class ForwardingVorgangWithEingangProcessor implements RepresentationModelProcessor<EntityModel<VorgangWithEingang>> { + + static final LinkRelation REL_FORWARD_BY_OZGCLOUD = LinkRelation.of("forwardByOzgCloud"); + static final LinkRelation REL_FORWARD_BY_EMAIL = LinkRelation.of("forwardByEmail"); + + private final FeatureToggleProperties featureToggleProperties; + private final CurrentUserService userService; + + @Override + public EntityModel<VorgangWithEingang> process(EntityModel<VorgangWithEingang> model) { + + Optional.ofNullable(model.getContent()) + .ifPresent(vorgang -> model + .addIf(isForwardableByOzgCloud(vorgang), () -> buildForwardByOzgCloudLink(vorgang)) + .addIf(isEinheitlicherAnsprechpartner(), () -> buildForwardByEmailLink(vorgang))); + return model; + } + + boolean isForwardableByOzgCloud(VorgangWithEingang vorgang) { + return featureToggleProperties.isForwardByOzgCloudEnabled() && isStatusNeu(vorgang); + } + + private boolean isStatusNeu(VorgangWithEingang vorgang) { + return vorgang.getStatus() == VorgangStatus.NEU; + } + + private Link buildForwardByOzgCloudLink(VorgangWithEingang vorgang) { + return linkTo(methodOn(CommandController.CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), + vorgang.getVersion(), null)).withRel(REL_FORWARD_BY_OZGCLOUD); + } + + private boolean isEinheitlicherAnsprechpartner() { + return userService.hasRole(UserRole.EINHEITLICHER_ANSPRECHPARTNER); + } + + private Link buildForwardByEmailLink(VorgangWithEingang vorgang) { + return linkTo(methodOn(ForwardingController.class).findByVorgangId(vorgang.getId())).withRel(REL_FORWARD_BY_EMAIL); + } + +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessorTest.java index 87d377093b7b9438cef8bd144f1f736f34656072..987b09227e8f17d3beeb0709b2385e6f7f45f930 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessorTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/VorgangWithEingangProcessorTest.java @@ -33,8 +33,6 @@ 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.EnumSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; @@ -46,11 +44,8 @@ import org.springframework.web.util.UriTemplate; import de.ozgcloud.alfa.common.UserProfileUrlProvider; import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController; -import de.ozgcloud.alfa.common.user.CurrentUserService; import de.ozgcloud.alfa.common.user.UserManagerUrlProvider; -import de.ozgcloud.alfa.common.user.UserRole; import de.ozgcloud.alfa.postfach.PostfachMailController; -import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus; class VorgangWithEingangProcessorTest { @@ -60,8 +55,6 @@ class VorgangWithEingangProcessorTest { @Mock private PostfachMailController postfachMailController; @Mock - private CurrentUserService userService; - @Mock private UserManagerUrlProvider userManagerUrlProvider; @Mock @@ -205,43 +198,6 @@ class VorgangWithEingangProcessorTest { } } - @Nested - class TestForwardingLink { - - @DisplayName("should NOT be present in other Role then EA") - @ParameterizedTest - @EnumSource - void shouldNotBePresentWithoutRole(Vorgang.VorgangStatus status) { - when(userService.hasRole(UserRole.EINHEITLICHER_ANSPRECHPARTNER)).thenReturn(false); - - var link = processor.process(buildVorgangInStatus(status)).getLink(VorgangWithEingangProcessor.REL_VORGANG_FORWARDING); - - assertThat(link).isEmpty(); - } - - @DisplayName("with role EinheitlicherAnsprechpartner") - @Nested - class TestWithRoleEinheitlicherAnsprechpartner { - @BeforeEach - void init() { - when(userService.hasRole(UserRole.EINHEITLICHER_ANSPRECHPARTNER)).thenReturn(true); - } - - @DisplayName("should be present in any Status") - @ParameterizedTest - @EnumSource() - void shouldBePresent(VorgangStatus status) { - var link = processor.process(buildVorgangInStatus(status)).getLink(VorgangWithEingangProcessor.REL_VORGANG_FORWARDING); - - assertThat(link).isPresent().get().extracting(Link::getHref).isEqualTo("/api/forwardings?vorgangId=" + VorgangHeaderTestFactory.ID); - } - } - - private EntityModel<VorgangWithEingang> buildVorgangInStatus(VorgangStatus status) { - return EntityModel.of(VorgangWithEingangTestFactory.createBuilder().status(status).build()); - } - } - @DisplayName("Historie Link") @Nested class TestHistorieLink { diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingVorgangWithEingangProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingVorgangWithEingangProcessorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..12f00f572675a4a17ed38e45549f965fb15ded99 --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/vorgang/forwarding/ForwardingVorgangWithEingangProcessorTest.java @@ -0,0 +1,200 @@ +package de.ozgcloud.alfa.vorgang.forwarding; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; + +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.EnumSource; +import org.junit.jupiter.params.provider.EnumSource.Mode; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.hateoas.EntityModel; +import org.springframework.hateoas.Link; +import org.springframework.web.util.UriComponentsBuilder; + +import de.ozgcloud.alfa.common.FeatureToggleProperties; +import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController; +import de.ozgcloud.alfa.common.user.CurrentUserService; +import de.ozgcloud.alfa.common.user.UserRole; +import de.ozgcloud.alfa.vorgang.Vorgang; +import de.ozgcloud.alfa.vorgang.Vorgang.VorgangStatus; +import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory; +import de.ozgcloud.alfa.vorgang.VorgangWithEingang; +import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory; + +class ForwardingVorgangWithEingangProcessorTest { + + @InjectMocks + @Spy + private ForwardingVorgangWithEingangProcessor processor; + + @Mock + private CurrentUserService userService; + @Mock + private FeatureToggleProperties featureToggleProperties; + + @Nested + class TestProcess { + + @Test + void shouldReturnSameModelOnEmptyEntity() { + EntityModel<VorgangWithEingang> inputModel = when(mock(EntityModel.class).getContent()).thenReturn(null).getMock(); + + var model = processor.process(inputModel); + + assertThat(model).isSameAs(inputModel); + } + + @Test + void shouldReturnSameModel() { + var inputModel = EntityModel.of(VorgangWithEingangTestFactory.create()); + + var model = processor.process(inputModel); + + assertThat(model).isSameAs(inputModel); + } + + @Nested + class TestForwardByOzgCloudLink { + + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + + @Test + void shouldCallIsForwardableByOzgCloud() { + processor.process(EntityModel.of(vorgang)); + + verify(processor).isForwardableByOzgCloud(vorgang); + } + + @Nested + class TestOnIsNotForwardableByOzgCloud { + @BeforeEach + void givenIsNotForwardableByOzgCloud() { + doReturn(false).when(processor).isForwardableByOzgCloud(any()); + } + + @Test + void shouldNotAddLink() { + var model = processor.process(EntityModel.of(vorgang)); + + assertThat(model.getLink(ForwardingVorgangWithEingangProcessor.REL_FORWARD_BY_OZGCLOUD)).isEmpty(); + } + } + + @Nested + class TestOnIsForwardableByOzgCloud { + @BeforeEach + void givenIsNotForwardableByOzgCloud() { + doReturn(true).when(processor).isForwardableByOzgCloud(any()); + } + + @Test + void shouldAddForwardByOzgCloudLink() { + var expectedHref = UriComponentsBuilder.fromUriString(CommandByRelationController.COMMAND_BY_RELATION_PATH) + .buildAndExpand(VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION).toString(); + + var model = processor.process(EntityModel.of(vorgang)); + + assertThat(model.getLink(ForwardingVorgangWithEingangProcessor.REL_FORWARD_BY_OZGCLOUD)).get() + .extracting(Link::getHref) + .isEqualTo(expectedHref); + } + } + } + + @Nested + class TestForwardingLink { + + @DisplayName("should NOT be present in other Role then EA") + @ParameterizedTest + @EnumSource + void shouldNotBePresentWithoutRole(Vorgang.VorgangStatus status) { + when(userService.hasRole(UserRole.EINHEITLICHER_ANSPRECHPARTNER)).thenReturn(false); + + var link = processor.process(buildVorgangInStatus(status)).getLink(ForwardingVorgangWithEingangProcessor.REL_FORWARD_BY_EMAIL); + + assertThat(link).isEmpty(); + } + + @DisplayName("with role EinheitlicherAnsprechpartner") + @Nested + class TestWithRoleEinheitlicherAnsprechpartner { + @BeforeEach + void init() { + when(userService.hasRole(UserRole.EINHEITLICHER_ANSPRECHPARTNER)).thenReturn(true); + } + + @DisplayName("should be present in any Status") + @ParameterizedTest + @EnumSource() + void shouldBePresent(VorgangStatus status) { + var link = processor.process(buildVorgangInStatus(status)).getLink(ForwardingVorgangWithEingangProcessor.REL_FORWARD_BY_EMAIL); + + assertThat(link).isPresent().get().extracting(Link::getHref) + .isEqualTo("/api/forwardings?vorgangId=" + VorgangHeaderTestFactory.ID); + } + } + + private EntityModel<VorgangWithEingang> buildVorgangInStatus(VorgangStatus status) { + return EntityModel.of(VorgangWithEingangTestFactory.createBuilder().status(status).build()); + } + } + } + + @Nested + class TestIsForwardableByOzgCloud { + + @Nested + class TestOnFeatureDisabled { + + @BeforeEach + void givenFeatureDisabled() { + when(featureToggleProperties.isForwardByOzgCloudEnabled()).thenReturn(false); + } + + @ParameterizedTest + @EnumSource + void shouldReturnFalse(VorgangStatus status) { + var vorgang = VorgangWithEingangTestFactory.createBuilder().status(status).build(); + + var forwardableByOzgCloud = processor.isForwardableByOzgCloud(vorgang); + + assertThat(forwardableByOzgCloud).isFalse(); + } + } + + @Nested + class TestOnFeatureEnabled { + + @BeforeEach + void givenFeatureEnabled() { + when(featureToggleProperties.isForwardByOzgCloudEnabled()).thenReturn(true); + } + + @ParameterizedTest + @EnumSource(mode = Mode.EXCLUDE, names = { "NEU" }) + void shouldReturnFalseOnVorgangStatusNotNeu(VorgangStatus status) { + var vorgang = VorgangWithEingangTestFactory.createBuilder().status(status).build(); + + var forwardableByOzgCloud = processor.isForwardableByOzgCloud(vorgang); + + assertThat(forwardableByOzgCloud).isFalse(); + } + + @Test + void shouldReturnTrueOnVorgangStatusNeu() { + var vorgang = VorgangWithEingangTestFactory.createBuilder().status(VorgangStatus.NEU).build(); + + var forwardableByOzgCloud = processor.isForwardableByOzgCloud(vorgang); + + assertThat(forwardableByOzgCloud).isTrue(); + } + } + } +}