diff --git a/goofy-server/src/main/java/de/itvsh/goofy/attachment/AttachmentController.java b/goofy-server/src/main/java/de/itvsh/goofy/attachment/AttachmentController.java new file mode 100644 index 0000000000000000000000000000000000000000..61a21483744a68ba3eceda5aec301cc3127a02a2 --- /dev/null +++ b/goofy-server/src/main/java/de/itvsh/goofy/attachment/AttachmentController.java @@ -0,0 +1,24 @@ +package de.itvsh.goofy.attachment; + +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import de.itvsh.goofy.file.File; + +@RestController +@RequestMapping(AttachmentController.ATTACHMENT_PATH) +public class AttachmentController { + + static final String ATTACHMENT_PATH = "/api/attachments"; // NOSONAR + + static final String PARAM_EINGANG_ID = "eingangId"; + + @GetMapping(params = PARAM_EINGANG_ID) + public CollectionModel<EntityModel<File>> getAllByEingang(@RequestParam String eingangId) { + return CollectionModel.empty(); + } +} \ No newline at end of file diff --git a/goofy-server/src/main/java/de/itvsh/goofy/representation/RepresentationController.java b/goofy-server/src/main/java/de/itvsh/goofy/representation/RepresentationController.java new file mode 100644 index 0000000000000000000000000000000000000000..abd2f2a68b1158bc3997bec35843dffea2f59886 --- /dev/null +++ b/goofy-server/src/main/java/de/itvsh/goofy/representation/RepresentationController.java @@ -0,0 +1,24 @@ +package de.itvsh.goofy.representation; + +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import de.itvsh.goofy.file.File; + +@RestController +@RequestMapping(RepresentationController.REPRESENTATIONS_PATH) +public class RepresentationController { + + static final String REPRESENTATIONS_PATH = "/api/representations"; // NOSONAR + + static final String PARAM_EINGANG_ID = "eingangId"; + + @GetMapping(params = PARAM_EINGANG_ID) + public CollectionModel<EntityModel<File>> getAllByEingang(@RequestParam String eingangId) { + return CollectionModel.empty(); + } +} diff --git a/goofy-server/src/main/java/de/itvsh/goofy/vorgang/VorgangModelAssembler.java b/goofy-server/src/main/java/de/itvsh/goofy/vorgang/VorgangModelAssembler.java index 7282865f803ce2f611c2b38604fd27f879f952e4..910d304d012dba315a5aca8b1bd0aaa923ecdf3d 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/vorgang/VorgangModelAssembler.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/vorgang/VorgangModelAssembler.java @@ -2,6 +2,7 @@ package de.itvsh.goofy.vorgang; import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -12,8 +13,10 @@ import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.server.RepresentationModelAssembler; import org.springframework.stereotype.Component; +import de.itvsh.goofy.attachment.AttachmentController; import de.itvsh.goofy.common.ResourceBuilder; import de.itvsh.goofy.common.command.CommandController; +import de.itvsh.goofy.representation.RepresentationController; import de.itvsh.goofy.wiedervorlage.WiedervorlageCommandController.WiedervorlageCommandByVorgangController; import de.itvsh.goofy.wiedervorlage.WiedervorlageController.WiedervorlageByVorgangController; @@ -30,6 +33,8 @@ class VorgangModelAssembler implements RepresentationModelAssembler<Vorgang, Ent public static final String REL_CREATE_WIEDERVORLAGE = "create-wiedervorlage"; public static final String REL_PENDING_COMMANDS = "pending-commands"; + public static final String REL_ATTACHMENTS = "attachments"; + public static final String REL_REPRESENTATIONS = "representations"; @Override public EntityModel<Vorgang> toModel(Vorgang vorgang) { @@ -42,9 +47,18 @@ class VorgangModelAssembler implements RepresentationModelAssembler<Vorgang, Ent .withRel(REL_CREATE_WIEDERVORLAGE)) .ifMatch(this::existsPendingCommands) .addLink(() -> linkTo(methodOn(CommandController.class).getPendingCommands(true, vorgang.getId())).withRel(REL_PENDING_COMMANDS)) + .ifMatch(this::existsEingang) + .addLinks( + () -> linkTo(methodOn(AttachmentController.class).getAllByEingang(getEingangId(vorgang))).withRel(REL_ATTACHMENTS), + () -> linkTo(methodOn(RepresentationController.class).getAllByEingang(getEingangId(vorgang))) + .withRel(REL_REPRESENTATIONS)) .buildResource(); } + private String getEingangId(Vorgang vorgang) { + return ((VorgangWithEingang) vorgang).getEingang().getId(); + } + public CollectionModel<EntityModel<Vorgang>> toCollectionModel(Stream<Vorgang> entities, Optional<Integer> prevPage, Optional<Integer> nextPage) { var model = CollectionModel.of(entities.map(this::toModel).collect(Collectors.toList()), @@ -59,4 +73,13 @@ class VorgangModelAssembler implements RepresentationModelAssembler<Vorgang, Ent private boolean existsPendingCommands(Vorgang vorgang) { return commandController.existsPendingCommands(vorgang.getId()); } + + private boolean existsEingang(Vorgang vorgang) { + if (vorgang instanceof VorgangWithEingang) { + var withEingang = (VorgangWithEingang) vorgang; + + return !Objects.isNull(withEingang.getEingang()); + } + return false; + } } diff --git a/goofy-server/src/test/java/de/itvsh/goofy/attachment/AttachmentControllerTest.java b/goofy-server/src/test/java/de/itvsh/goofy/attachment/AttachmentControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fec2cbc008b92c9f1c8d9a9e2545e2f1fe2761b8 --- /dev/null +++ b/goofy-server/src/test/java/de/itvsh/goofy/attachment/AttachmentControllerTest.java @@ -0,0 +1,39 @@ +package de.itvsh.goofy.attachment; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +class AttachmentControllerTest { + + private final String PATH = AttachmentController.ATTACHMENT_PATH; + + @InjectMocks + private AttachmentController controller; + + private MockMvc mockMvc; + + @BeforeEach + void initTest() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Nested + class TestGetAttachmentsByEingang { + + @Test + void shouldCallEndpoint() throws Exception { + callEndpoint(); + } + + private void callEndpoint() throws Exception { + mockMvc.perform(get(PATH).param(AttachmentController.PARAM_EINGANG_ID, "1")).andExpect(status().isOk()); + } + } +} \ No newline at end of file diff --git a/goofy-server/src/test/java/de/itvsh/goofy/representation/RepresentationControllerTest.java b/goofy-server/src/test/java/de/itvsh/goofy/representation/RepresentationControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fd3761252df21ea66561e61a375ce3648053ca22 --- /dev/null +++ b/goofy-server/src/test/java/de/itvsh/goofy/representation/RepresentationControllerTest.java @@ -0,0 +1,39 @@ +package de.itvsh.goofy.representation; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +class RepresentationControllerTest { + + private final String PATH = RepresentationController.REPRESENTATIONS_PATH; + + @InjectMocks + private RepresentationController controller; + + private MockMvc mockMvc; + + @BeforeEach + void init() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Nested + class TestGetRepresentationsByEingang { + + @Test + void shouldCallEndpoint() throws Exception { + callEndpoint(); + } + + private void callEndpoint() throws Exception { + mockMvc.perform(get(PATH).param(RepresentationController.PARAM_EINGANG_ID, "1")).andExpect(status().isOk()); + } + } +} \ No newline at end of file diff --git a/goofy-server/src/test/java/de/itvsh/goofy/vorgang/EingangTestFactory.java b/goofy-server/src/test/java/de/itvsh/goofy/vorgang/EingangTestFactory.java index d1d852caa90cdc5c1949109559dbaeb56d213aa6..d37066f6925f248ad47bca3fda82db003e505039 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/vorgang/EingangTestFactory.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/vorgang/EingangTestFactory.java @@ -5,7 +5,7 @@ import java.util.UUID; public class EingangTestFactory { - private static final String ID = UUID.randomUUID().toString(); + public static final String ID = UUID.randomUUID().toString(); public static final String SINGLE_FIELD_NAME = "name"; public static final String SINGLE_FIELD_VALUE = "Thea"; diff --git a/goofy-server/src/test/java/de/itvsh/goofy/vorgang/VorgangModelAssemblerTest.java b/goofy-server/src/test/java/de/itvsh/goofy/vorgang/VorgangModelAssemblerTest.java index ef8da589c813c6b15dbb348ef35208a02bbbaa15..e2eec469360ed626e61bdd588e6e66dcb2bd0f65 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/vorgang/VorgangModelAssemblerTest.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/vorgang/VorgangModelAssemblerTest.java @@ -7,16 +7,18 @@ import static org.mockito.Mockito.*; import java.util.Optional; import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.springframework.hateoas.CollectionModel; import org.springframework.hateoas.EntityModel; -import org.springframework.hateoas.IanaLinkRelations; +import org.springframework.hateoas.Link; import org.springframework.hateoas.server.EntityLinks; import de.itvsh.goofy.common.command.CommandController; +import io.grpc.netty.shaded.io.netty.util.internal.StringUtil; class VorgangModelAssemblerTest { @@ -43,43 +45,34 @@ class VorgangModelAssemblerTest { @Test void shouldHaveSelfLink() { - EntityModel<Vorgang> entityModel = modelAssembler.toModel(VorgangHeaderTestFactory.create()); - - var link = entityModel.getLink(IanaLinkRelations.SELF); - - assertThat(link).isPresent(); - assertThat(link.get().getHref()).isEqualTo(BASE_PATH + VorgangHeaderTestFactory.ID); + verifyModelLinkRelation(VorgangModelAssembler.REL_VORGANG_MIT_EINGANG); } @Test void shouldHaveVorgangMitEingangLink() { - EntityModel<Vorgang> entityModel = modelAssembler.toModel(VorgangHeaderTestFactory.create()); - - var link = entityModel.getLink(VorgangModelAssembler.REL_VORGANG_MIT_EINGANG); - - assertThat(link).isPresent(); - assertThat(link.get().getHref()).isEqualTo(BASE_PATH + VorgangHeaderTestFactory.ID); + verifyModelLinkRelation(VorgangModelAssembler.REL_VORGANG_MIT_EINGANG); } @Test void shouldHaveWiedervorlagenLink() { - EntityModel<Vorgang> entityModel = modelAssembler.toModel(VorgangHeaderTestFactory.create()); - - var link = entityModel.getLink(VorgangModelAssembler.REL_WIEDERVORLAGEN); - - assertThat(link).isPresent(); - assertThat(link.get().getHref()).isEqualTo(BASE_PATH + VorgangHeaderTestFactory.ID + "/wiedervorlages"); + verifyModelLinkRelation(VorgangModelAssembler.REL_WIEDERVORLAGEN, "/wiedervorlages"); } @Test void shouldHaveCreateWiedervorlageLink() { - EntityModel<Vorgang> entityModel = modelAssembler.toModel(VorgangHeaderTestFactory.create()); + verifyModelLinkRelation(VorgangModelAssembler.REL_CREATE_WIEDERVORLAGE, "/wiedervorlageCommands"); + } - var link = entityModel.getLink(VorgangModelAssembler.REL_CREATE_WIEDERVORLAGE); + private void verifyModelLinkRelation(String linkRel) { + verifyModelLinkRelation(linkRel, StringUtil.EMPTY_STRING); + } + + private void verifyModelLinkRelation(String linkRel, String additionalPathValue) { + verifyLinkExistOnModel(VorgangHeaderTestFactory.create(), linkRel, buildLinkPath(additionalPathValue)); + } - assertThat(link).isPresent(); - assertThat(link.get().getHref()) - .isEqualTo("/api/vorgangs/" + VorgangHeaderTestFactory.ID + "/wiedervorlageCommands"); + private String buildLinkPath(String additionalPathValue) { + return BASE_PATH + VorgangHeaderTestFactory.ID + additionalPathValue; } } @@ -90,23 +83,69 @@ class VorgangModelAssemblerTest { void shouldExists() { when(commandController.existsPendingCommands(any())).thenReturn(true); - EntityModel<Vorgang> entityModel = modelAssembler.toModel(VorgangHeaderTestFactory.create()); + String expectedHref = "/api/commands?pending=true&vorgangId=" + VorgangHeaderTestFactory.ID; - var link = entityModel.getLink(VorgangModelAssembler.REL_PENDING_COMMANDS); - - assertThat(link).isPresent(); - assertThat(link.get().getHref()).isEqualTo("/api/commands?pending=true&vorgangId=" + VorgangHeaderTestFactory.ID); + verifyLinkExistOnModel(VorgangMitEingangTestFactory.create(), VorgangModelAssembler.REL_PENDING_COMMANDS, expectedHref); } @Test void shouldNotExists() { when(commandController.existsPendingCommands(any())).thenReturn(false); - EntityModel<Vorgang> entityModel = modelAssembler.toModel(VorgangHeaderTestFactory.create()); + verifyLinkNotExistsOnModel(VorgangHeaderTestFactory.create(), VorgangModelAssembler.REL_PENDING_COMMANDS); + } + } + + @Nested + class TestAttachmentLink { + + @DisplayName("Attachment Link should exists if vorgang has an eingang") + @Test + void shouldExistsAttachmentLinks() { + String expectedHref = "/api/attachments?eingangId=" + EingangTestFactory.ID; - var link = entityModel.getLink(VorgangModelAssembler.REL_PENDING_COMMANDS); + verifyLinkExistOnModel(VorgangMitEingangTestFactory.create(), VorgangModelAssembler.REL_ATTACHMENTS, expectedHref); + } - assertThat(link).isNotPresent(); + @DisplayName("Attachment Link should NOT exists if vorgang has no eingang") + @Test + void shouldNotExists() { + verifyLinkNotExistsOnModel(VorgangHeaderTestFactory.create(), VorgangModelAssembler.REL_ATTACHMENTS); } } + + @Nested + class TestRepresentationLink { + + @DisplayName("Representation Link should exists if vorgang has an eingang") + @Test + void shouldExistsAttachmentLinks() { + String expectedHref = "/api/representations?eingangId=" + EingangTestFactory.ID; + + verifyLinkExistOnModel(VorgangMitEingangTestFactory.create(), VorgangModelAssembler.REL_REPRESENTATIONS, expectedHref); + } + + @DisplayName("Attachment Link should NOT exists if vorgang has no eingang") + @Test + void shouldNotExists() { + verifyLinkNotExistsOnModel(VorgangHeaderTestFactory.create(), VorgangModelAssembler.REL_REPRESENTATIONS); + } + } + + private void verifyLinkExistOnModel(Vorgang vorgang, String linkRel, String expectedLinkHref) { + var link = getLinkFromModel(vorgang, linkRel); + + assertThat(link).isPresent(); + assertThat(link.get().getHref()).isEqualTo(expectedLinkHref); + } + + private void verifyLinkNotExistsOnModel(Vorgang vorgang, String linkRel) { + var link = getLinkFromModel(vorgang, linkRel); + + assertThat(link).isNotPresent(); + } + + private Optional<Link> getLinkFromModel(Vorgang vorgang, String linkRel) { + return modelAssembler.toModel(vorgang).getLink(linkRel); + } } \ No newline at end of file