diff --git a/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheit.java b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheit.java index 470a29e850ac9929ac8229c8211b036484f1c0f4..012a2343ca6c64140adfd28740791b94c1ec8769 100644 --- a/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheit.java +++ b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheit.java @@ -21,6 +21,7 @@ import lombok.extern.jackson.Jacksonized; public class OrganisationsEinheit { static final String COLLECTION_NAME = "organisationsEinheit"; + static final String FIELD_SETTINGS = "settings"; @JsonIgnore @Id diff --git a/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitController.java b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitController.java index 3e40411d38eca6d07c75ad84db0c5164ba120d1a..bf9bf619ecda0c736f2b3d32ab92871f708c287c 100644 --- a/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitController.java +++ b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitController.java @@ -3,7 +3,9 @@ package de.ozgcloud.admin.organisationseinheit; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -36,4 +38,11 @@ public class OrganisationsEinheitController { var children = organisationsEinheitService.getChildren(id); return assembler.toChildrenCollectionModel(id, children); } + + @PatchMapping("/{id}") + public EntityModel<OrganisationsEinheit> editOrganisationsEinheit(@PathVariable String id, + @RequestBody OrganisationsEinheitPatch organisationsEinheitPatch) { + var patched = organisationsEinheitService.editOrganisationsEinheit(id, organisationsEinheitPatch); + return assembler.toModel(patched); + } } diff --git a/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitModelAssembler.java b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitModelAssembler.java index 6ac15d9d36936471e22321829f262a55f5ad36fd..3c332dcb266b65253092b1755d74078a752922b4 100644 --- a/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitModelAssembler.java +++ b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitModelAssembler.java @@ -20,6 +20,8 @@ class OrganisationsEinheitModelAssembler static final String REL_CHILD_ORGANISATIONS_EINHEITEN = "childList"; + static final String REL_EDIT = "edit"; + @Override public EntityModel<OrganisationsEinheit> toModel(OrganisationsEinheit organisationsEinheit) { var halModelBuilder = HalModelBuilder.halModelOf(organisationsEinheit); @@ -28,7 +30,8 @@ class OrganisationsEinheitModelAssembler return halModelBuilder .<EntityModel<OrganisationsEinheit>>build() - .add(linkTo(methodOn(OrganisationsEinheitController.class).getById(organisationsEinheit.getId())).withSelfRel()); + .add(linkTo(methodOn(OrganisationsEinheitController.class).getById(organisationsEinheit.getId())).withSelfRel()) + .add(linkTo(methodOn(OrganisationsEinheitController.class).editOrganisationsEinheit(organisationsEinheit.getId(), null)).withRel(REL_EDIT)); } void embedChildOrganisationsEinheiten(OrganisationsEinheit organisationsEinheit, HalModelBuilder halModelBuilder) { diff --git a/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitPatch.java b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitPatch.java new file mode 100644 index 0000000000000000000000000000000000000000..332886555b925f58afd2728dee48b6acb6f54f2f --- /dev/null +++ b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitPatch.java @@ -0,0 +1,18 @@ +package de.ozgcloud.admin.organisationseinheit; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@AllArgsConstructor(access = AccessLevel.PUBLIC) +@ToString +@Builder +@Getter +public class OrganisationsEinheitPatch { + + private String signatur; +} diff --git a/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitService.java b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitService.java index dc0a1873b90d57cbcbdeda7c67fd61fbb68abeca..275b082d6248b4b7b23f4da7aee978f0d1e4a6b4 100644 --- a/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitService.java +++ b/src/main/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitService.java @@ -6,6 +6,7 @@ import java.util.Objects; import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.stereotype.Service; +import de.ozgcloud.common.errorhandling.TechnicalException; import lombok.RequiredArgsConstructor; @Service @@ -40,4 +41,19 @@ class OrganisationsEinheitService { public List<OrganisationsEinheit> getChildren(String parentId) { return repository.findChildren(parentId); } + + public OrganisationsEinheit editOrganisationsEinheit(String id, OrganisationsEinheitPatch organisationsEinheitPatch) { + return repository.findById(id) + .map(organisationsEinheit -> patchOrganisationsEinheit(organisationsEinheit, organisationsEinheitPatch)) + .map(repository::save) + .orElseThrow(() -> new TechnicalException("Organisationseinheit with id " + id + " not found")); + } + + OrganisationsEinheit patchOrganisationsEinheit(OrganisationsEinheit organisationsEinheit, OrganisationsEinheitPatch patch) { + var organisationsEinheitBuilder = organisationsEinheit.toBuilder(); + if (Objects.nonNull(patch.getSignatur())) { + organisationsEinheitBuilder.settings(organisationsEinheit.getSettings().toBuilder().signatur(patch.getSignatur()).build()); + } + return organisationsEinheitBuilder.build(); + } } diff --git a/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitControllerTest.java b/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitControllerTest.java index a913eb55dcfaeeb4c89da5a8085b04a3bef75e22..fbf00adebbb5aeb5e7b8c5edd6f2a6ce4d76f09f 100644 --- a/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitControllerTest.java +++ b/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitControllerTest.java @@ -10,18 +10,25 @@ import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; +import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import com.fasterxml.jackson.databind.ObjectMapper; + import lombok.SneakyThrows; class OrganisationsEinheitControllerTest { + private final ObjectMapper objectMapper = new ObjectMapper(); + @InjectMocks private OrganisationsEinheitController controller; @@ -176,4 +183,60 @@ class OrganisationsEinheitControllerTest { return mockMvc.perform(get(OrganisationsEinheitController.PATH + "/" + OrganisationsEinheitTestFactory.ID + "/children")); } } + + @Nested + class TestEditOrganisationsEinheit { + + private final OrganisationsEinheit patchedOrganisationsEinheit = OrganisationsEinheitTestFactory.create(); + + @Captor + private ArgumentCaptor<OrganisationsEinheitPatch> organisationsEinheitPatchArgumentCaptor; + + @BeforeEach + void setUp() { + when(organisationsEinheitService.editOrganisationsEinheit(eq(OrganisationsEinheitTestFactory.ID), any())).thenReturn( + patchedOrganisationsEinheit); + when(assembler.toModel(patchedOrganisationsEinheit)).thenReturn(EntityModel.of(patchedOrganisationsEinheit)); + } + + @Test + void shouldCallService() { + doRequest(); + + verify(organisationsEinheitService).editOrganisationsEinheit(eq(OrganisationsEinheitTestFactory.ID), + organisationsEinheitPatchArgumentCaptor.capture()); + assertThat(organisationsEinheitPatchArgumentCaptor.getValue()) + .usingRecursiveComparison() + .isEqualTo(OrganisationsEinheitPatchTestFactory.create()); + } + + @SneakyThrows + @Test + void shouldReturnStatusOk() { + doRequest().andExpect(status().isOk()); + } + + @Test + void shouldCallAssembler() { + doRequest(); + + verify(assembler).toModel(patchedOrganisationsEinheit); + } + + @SneakyThrows + @Test + void shouldReturnModel() { + var model = controller.editOrganisationsEinheit(OrganisationsEinheitTestFactory.ID, OrganisationsEinheitPatchTestFactory.create()); + + assertThat(model).usingRecursiveComparison().isEqualTo(EntityModel.of(patchedOrganisationsEinheit)); + } + + @SneakyThrows + private ResultActions doRequest() { + return mockMvc.perform( + patch(OrganisationsEinheitController.PATH + "/" + OrganisationsEinheitTestFactory.ID) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(OrganisationsEinheitPatchTestFactory.create()))); + } + } } \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitModelAssemblerTest.java b/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitModelAssemblerTest.java index c726c6b5219bdadedb46e336c2baa9fed5edee5f..51c34967555f7f69218f28da26d4e48fd1a8701e 100644 --- a/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitModelAssemblerTest.java +++ b/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitModelAssemblerTest.java @@ -63,6 +63,17 @@ class OrganisationsEinheitModelAssemblerTest { verify(assembler).embedChildOrganisationsEinheiten(eq(organisationsEinheit), any()); } + + @Test + void shouldAddEditLink() { + var model = assembler.toModel(organisationsEinheit); + + assertThat(model.getLink(OrganisationsEinheitModelAssembler.REL_EDIT)) + .isNotEmpty() + .get() + .extracting(Link::getHref) + .isEqualTo(new UriTemplate(OrganisationsEinheitController.PATH + "/{id}").expand(OrganisationsEinheitTestFactory.ID).toString()); + } } @Nested diff --git a/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitPatchTestFactory.java b/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitPatchTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..a9dcd12c86798872a046e026f1edfcc0aec7305f --- /dev/null +++ b/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitPatchTestFactory.java @@ -0,0 +1,16 @@ +package de.ozgcloud.admin.organisationseinheit; + +import com.thedeanda.lorem.LoremIpsum; + +public class OrganisationsEinheitPatchTestFactory { + + public static final String SIGNATUR = LoremIpsum.getInstance().getWords(3); + + public static OrganisationsEinheitPatch create() { + return createBuilder().build(); + } + + public static OrganisationsEinheitPatch.OrganisationsEinheitPatchBuilder createBuilder() { + return OrganisationsEinheitPatch.builder().signatur(SIGNATUR); + } +} diff --git a/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitServiceTest.java b/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitServiceTest.java index e151636ee95ef52d2dab645c0e19ad5b134f1114..aaf92457a1ca0d94efb929733852e1dbf022b03b 100644 --- a/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitServiceTest.java +++ b/src/test/java/de/ozgcloud/admin/organisationseinheit/OrganisationsEinheitServiceTest.java @@ -15,6 +15,8 @@ import org.mockito.Mock; import org.mockito.Spy; import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import de.ozgcloud.common.errorhandling.TechnicalException; + class OrganisationsEinheitServiceTest { @Spy @@ -158,4 +160,107 @@ class OrganisationsEinheitServiceTest { assertThat(children).containsExactly(organisationsEinheit); } } + + @Nested + class TestEditOrganisationsEinheit { + + private final OrganisationsEinheit organisationsEinheit = OrganisationsEinheitTestFactory.create(); + private final OrganisationsEinheit patchedOrganisationsEinheit = OrganisationsEinheitTestFactory.create(); + private final OrganisationsEinheitPatch organisationsEinheitPatch = OrganisationsEinheitPatchTestFactory.create(); + + @Nested + class OrgnisationsEinheitExists { + + @BeforeEach + void setUp() { + when(repository.findById(OrganisationsEinheitTestFactory.ID)).thenReturn(Optional.of(organisationsEinheit)); + doReturn(patchedOrganisationsEinheit).when(service).patchOrganisationsEinheit(organisationsEinheit, organisationsEinheitPatch); + doReturn(patchedOrganisationsEinheit).when(repository).save(patchedOrganisationsEinheit); + } + + @Test + void shouldLoadOrganisationsEinheit() { + service.editOrganisationsEinheit(OrganisationsEinheitTestFactory.ID, organisationsEinheitPatch); + + verify(repository).findById(OrganisationsEinheitTestFactory.ID); + } + + @Test + void shouldPatch() { + service.editOrganisationsEinheit(OrganisationsEinheitTestFactory.ID, organisationsEinheitPatch); + + verify(service).patchOrganisationsEinheit(organisationsEinheit, organisationsEinheitPatch); + } + + @Test + void shouldSavedPatchedOrganisationsEinheit() { + service.editOrganisationsEinheit(OrganisationsEinheitTestFactory.ID, organisationsEinheitPatch); + + verify(repository).save(patchedOrganisationsEinheit); + } + + @Test + void shouldReturnPatchedOrganisationsEinheit() { + var patched = service.editOrganisationsEinheit(OrganisationsEinheitTestFactory.ID, organisationsEinheitPatch); + + assertThat(patched) + .usingRecursiveComparison() + .isEqualTo(patchedOrganisationsEinheit); + } + } + + @Nested + class OrganisationsEinheitDoesNotExists { + + @BeforeEach + void setUp() { + when(repository.findById(OrganisationsEinheitTestFactory.ID)).thenReturn(Optional.empty()); + } + + @Test + void shouldThrowTechnicalException() { + assertThatThrownBy(() -> + service.editOrganisationsEinheit(OrganisationsEinheitTestFactory.ID, OrganisationsEinheitPatchTestFactory.create())) + .isInstanceOf(TechnicalException.class) + .hasMessageStartingWith("Organisationseinheit with id " + OrganisationsEinheitTestFactory.ID + " not found"); + } + } + } + + @Nested + class TestPatchOrganisationsEinheit { + + @Test + void shouldPatchSignatur() { + var organisationsEinheit = OrganisationsEinheitTestFactory.create(); + var organisationsEinheitPatch = OrganisationsEinheitPatchTestFactory.create(); + + var patched = service.patchOrganisationsEinheit(organisationsEinheit, organisationsEinheitPatch); + + assertThat(patched.getSettings().getSignatur()).isEqualTo(OrganisationsEinheitPatchTestFactory.SIGNATUR); + } + + @Test + void shouldNotPatchOtherFields() { + var organisationsEinheit = OrganisationsEinheitTestFactory.create(); + var organisationsEinheitPatch = OrganisationsEinheitPatchTestFactory.create(); + + var patched = service.patchOrganisationsEinheit(organisationsEinheit, organisationsEinheitPatch); + + assertThat(patched) + .usingRecursiveComparison() + .ignoringFields(OrganisationsEinheit.FIELD_SETTINGS) + .isEqualTo(organisationsEinheit); + } + + @Test + void shouldNotPatchSignaturIfNull() { + var organisationsEinheit = OrganisationsEinheitTestFactory.create(); + var organisationsEinheitPatch = OrganisationsEinheitPatchTestFactory.createBuilder().signatur(null).build(); + + var patched = service.patchOrganisationsEinheit(organisationsEinheit, organisationsEinheitPatch); + + assertThat(patched.getSettings().getSignatur()).isEqualTo(OrganisationsEinheitSettingsTestFactory.SIGNATUR); + } + } } \ No newline at end of file