diff --git a/goofy-server/src/main/java/de/itvsh/goofy/kommentar/Kommentar.java b/goofy-server/src/main/java/de/itvsh/goofy/kommentar/Kommentar.java index 89eb1615fb6c468455689c949429c01e664907e6..9937eb74be669db72fbade1341a720cdeab908e7 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/kommentar/Kommentar.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/kommentar/Kommentar.java @@ -30,6 +30,8 @@ public class Kommentar implements CommandBody { @JsonIgnore private String id; + @JsonIgnore + private long version; @JsonIgnore private String vorgangId; diff --git a/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarCommandController.java b/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarCommandController.java index 9abe64320c10e549c535c38a1676c30123d21679..dbda8c7029de7dc43d02ced78a65d9f4a87e2d58 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarCommandController.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarCommandController.java @@ -23,7 +23,7 @@ import de.itvsh.goofy.common.user.CurrentUserService; @RequestMapping(KommentarCommandController.KOMMENTAR_COMMANDS) public class KommentarCommandController { - static final String KOMMENTAR_COMMANDS = "/api/kommentars/{kommentarId}/commands"; + static final String KOMMENTAR_COMMANDS = "/api/kommentars/{kommentarId}/{kommentarVersion}/commands"; @Autowired private KommentarService service; @@ -32,8 +32,9 @@ public class KommentarCommandController { private CommandByRelationController commandByRelationController; @PostMapping - public ResponseEntity<Void> createCommand(@RequestBody KommentarCommand kommentarCommand, @PathVariable String kommentarId) { - var command = commandByRelationController.createCommand(buildCommand(service.getById(kommentarId), kommentarCommand), + public ResponseEntity<Void> createCommand(@RequestBody KommentarCommand kommentarCommand, @PathVariable String kommentarId, + @PathVariable long kommentarVersion) { + var command = commandByRelationController.createCommand(buildCommand(service.getById(kommentarId), kommentarCommand, kommentarVersion), KommentarRemoteService.ITEM_NAME); return buildResponseLink(command); } @@ -42,10 +43,11 @@ public class KommentarCommandController { return ResponseEntity.created(linkTo(CommandController.class).slash(createdKommentarCommand.getId()).toUri()).build(); } - CreateCommand buildCommand(Kommentar kommentar, KommentarCommand command) { + CreateCommand buildCommand(Kommentar kommentar, KommentarCommand command, long kommentarVersion) { var commandBuilder = CreateCommand.builder() .order(CommandOrder.UPDATE_ATTACHED_ITEM) .relationId(kommentar.getId()) + .relationVersion(kommentarVersion) .vorgangId(kommentar.getVorgangId()); return commandBuilder.body(updateKommandByCommand(kommentar, command)).build(); @@ -59,7 +61,7 @@ public class KommentarCommandController { @RequestMapping(KommentarCommandByVorgangController.KOMMENTAR_COMMANDS_BY_VORGANG) public static class KommentarCommandByVorgangController { - static final String KOMMENTAR_COMMANDS_BY_VORGANG = "/api/vorgangs/{vorgangId}/kommentarCommands"; + static final String KOMMENTAR_COMMANDS_BY_VORGANG = "/api/vorgangs/{vorgangId}/{relationVersion}/kommentarCommands"; @Autowired private CommandByRelationController commandByRelationController; @@ -67,18 +69,21 @@ public class KommentarCommandController { @Autowired private CurrentUserService userService; - @PostMapping() - public ResponseEntity<Void> createCommand(@RequestBody KommentarCommand command, @PathVariable String vorgangId) { - var createdCommand = commandByRelationController.createCommand(buildCommand(vorgangId, command), KommentarRemoteService.ITEM_NAME); + @PostMapping + public ResponseEntity<Void> createCommand(@RequestBody KommentarCommand command, @PathVariable String vorgangId, + @PathVariable long relationVersion) { + var createdCommand = commandByRelationController.createCommand(buildCommand(vorgangId, command, relationVersion), + KommentarRemoteService.ITEM_NAME); return ResponseEntity.created(linkTo(CommandController.class).slash(createdCommand.getId()).toUri()).build(); } - CreateCommand buildCommand(String vorgangId, KommentarCommand command) { + CreateCommand buildCommand(String vorgangId, KommentarCommand command, long relationVersion) { return CreateCommand.builder() .vorgangId(vorgangId) .order(CommandOrder.CREATE_ATTACHED_ITEM) .relationId(vorgangId) + .relationVersion(relationVersion) .body(buildBody(command.getKommentar())) .build(); } diff --git a/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarMapper.java b/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarMapper.java index c36561d38afa4080e10c69b1782aa37e57095400..370151b741acd26e8de4ad99dca5e1961a0fab70 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarMapper.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarMapper.java @@ -16,6 +16,7 @@ import de.itvsh.ozg.pluto.grpc.command.GrpcCommand; public interface KommentarMapper { static final String ID = "id"; + static final String VERSION = "version"; static final String TEXT = "text"; static final String CREATED_BY = "createdBy"; static final String CREATED_AT = "createdAt"; @@ -28,6 +29,7 @@ public interface KommentarMapper { default Kommentar fromItemMap(Map<String, Object> map) { return Kommentar.builder() .id((String) map.get(ID)) + .version((long) map.get(VERSION)) .createdAt(ZonedDateTime.parse((String) map.get(CREATED_AT))) .createdBy((String) map.get(CREATED_BY)) .text((String) map.get(TEXT)) diff --git a/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarModelAssembler.java b/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarModelAssembler.java index fda3d28ec5f38a9055c7ab517cf284cc5d52bfe3..1025f88a9e7143fbf66eb70424402b56f90fdc00 100644 --- a/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarModelAssembler.java +++ b/goofy-server/src/main/java/de/itvsh/goofy/kommentar/KommentarModelAssembler.java @@ -19,10 +19,12 @@ class KommentarModelAssembler implements RepresentationModelAssembler<Kommentar, static final String REL_CREATE = "create-kommentar"; static final String REL_EDIT = "edit"; + static final long RELATION_ID_ON_CREATE = -1; + @Override public EntityModel<Kommentar> toModel(Kommentar kommentar) { var selfLink = linkTo(KommentarController.class).slash(kommentar.getId()); - var commandLink = linkTo(methodOn(KommentarCommandController.class).createCommand(null, kommentar.getId())); + var commandLink = linkTo(methodOn(KommentarCommandController.class).createCommand(null, kommentar.getId(), kommentar.getVersion())); return ModelBuilder.fromEntity(kommentar).addLink(selfLink.withSelfRel()) .addLink(commandLink.withRel(REL_EDIT)) @@ -32,6 +34,7 @@ class KommentarModelAssembler implements RepresentationModelAssembler<Kommentar, public CollectionModel<EntityModel<Kommentar>> toCollectionModel(Stream<Kommentar> entities, String vorgangId) { return CollectionModel.of(entities.map(this::toModel).collect(Collectors.toList()), linkTo(KommentarController.class).withSelfRel(), - linkTo(methodOn(KommentarCommandByVorgangController.class).createCommand(null, vorgangId)).withRel(REL_CREATE)); + linkTo(methodOn(KommentarCommandByVorgangController.class).createCommand(null, vorgangId, RELATION_ID_ON_CREATE)) + .withRel(REL_CREATE)); } } \ No newline at end of file diff --git a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarCommandControllerTest.java b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarCommandControllerTest.java index 2edb5dd1034f05faaa8733c367aded88ee7af469..219acc66a0825b4d96c68987374a368df05b2228 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarCommandControllerTest.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarCommandControllerTest.java @@ -15,6 +15,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; @@ -39,6 +40,9 @@ class KommentarCommandControllerTest { @Nested class TestCreateKommentarCommandByVorgang { + private static final long RELATION_ID_ON_CREATE = -1; + + @Spy @InjectMocks private KommentarCommandByVorgangController controller; @Mock @@ -69,6 +73,13 @@ class KommentarCommandControllerTest { verify(commandByRelationController).createCommand(any(), eq(KommentarRemoteService.ITEM_NAME)); } + @Test + void shouldBuildCommand() throws Exception { + doRequest(); + + verify(controller).buildCommand(eq(VorgangHeaderTestFactory.ID), any(), eq(RELATION_ID_ON_CREATE)); + } + @Test void shouldGiveCommandToService() throws Exception { doRequest(); @@ -84,8 +95,9 @@ class KommentarCommandControllerTest { } private ResultActions doRequest() throws Exception { - return mockMvc.perform(post(KommentarCommandByVorgangController.KOMMENTAR_COMMANDS_BY_VORGANG, VorgangHeaderTestFactory.ID) - .content(createValidRequestContent()).contentType(MediaType.APPLICATION_JSON)) + return mockMvc.perform( + post(KommentarCommandByVorgangController.KOMMENTAR_COMMANDS_BY_VORGANG, VorgangHeaderTestFactory.ID, RELATION_ID_ON_CREATE) + .content(createValidRequestContent()).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().is2xxSuccessful()); } } @@ -95,6 +107,7 @@ class KommentarCommandControllerTest { final String REPONSE_HEADER = "http://localhost/api/commands/" + KommentarCommandTestFactory.ID; + @Spy @InjectMocks private KommentarCommandController controller; @Mock @@ -123,6 +136,13 @@ class KommentarCommandControllerTest { verify(service).getById(any()); } + @Test + void shouldBuildCommand() throws Exception { + doRequest(); + + verify(controller).buildCommand(any(Kommentar.class), any(KommentarCommand.class), eq(KommentarTestFactory.VERSION)); + } + @Test void shouldGiveCommandToService() throws Exception { doRequest(); @@ -144,7 +164,7 @@ class KommentarCommandControllerTest { ResultActions doRequest() throws Exception { String content = createValidRequestContent(); - return mockMvc.perform(post(KommentarCommandController.KOMMENTAR_COMMANDS, KommentarTestFactory.ID) + return mockMvc.perform(post(KommentarCommandController.KOMMENTAR_COMMANDS, KommentarTestFactory.ID, KommentarTestFactory.VERSION) .content(content).contentType(MediaType.APPLICATION_JSON)) .andExpect(status().is2xxSuccessful()); } diff --git a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarCommandITCase.java b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarCommandITCase.java index 37c96c2c937358f455fab7fcc967503267cf42ab..32783371fc29bcfedc774f68e76e8bd213531a61 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarCommandITCase.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarCommandITCase.java @@ -100,7 +100,7 @@ class KommentarCommandITCase { } private ResultActions doRequestByKommentarId(String content) throws Exception { - return mockMvc.perform(post(KommentarCommandController.KOMMENTAR_COMMANDS, KommentarTestFactory.ID) + return mockMvc.perform(post(KommentarCommandController.KOMMENTAR_COMMANDS, KommentarTestFactory.ID, KommentarTestFactory.VERSION) .contentType(MediaType.APPLICATION_JSON) .content(content)); } @@ -110,6 +110,8 @@ class KommentarCommandITCase { @Nested class TestCreateCommandByVorgangId { + private static final long RELATION_ID_ON_CREATE = -1; + @BeforeEach void initTest() { when(remoteService.getById(any())).thenReturn(KommentarTestFactory.create()); @@ -167,9 +169,10 @@ class KommentarCommandITCase { } private ResultActions doRequestByVorgangId(String content) throws Exception { - return mockMvc.perform(post(KommentarCommandByVorgangController.KOMMENTAR_COMMANDS_BY_VORGANG, VorgangHeaderTestFactory.ID) - .contentType(MediaType.APPLICATION_JSON) - .content(content)); + return mockMvc.perform(post(KommentarCommandByVorgangController.KOMMENTAR_COMMANDS_BY_VORGANG, VorgangHeaderTestFactory.ID, + RELATION_ID_ON_CREATE) + .contentType(MediaType.APPLICATION_JSON) + .content(content)); } } } \ No newline at end of file diff --git a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarMapperTest.java b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarMapperTest.java index 74380e47bbbb5e6315f72c9cac7853d6aaf961a2..1865abc67e4131ec816bf3f90907c7a30f7ea6a7 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarMapperTest.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarMapperTest.java @@ -1,17 +1,18 @@ package de.itvsh.goofy.kommentar; -import static org.assertj.core.api.Assertions.*; - import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mapstruct.factory.Mappers; +import static org.assertj.core.api.Assertions.*; + class KommentarMapperTest { private KommentarMapper mapper = Mappers.getMapper(KommentarMapper.class); @Nested class TestFromItemMap { + @Test void shouldMapId() { var kommentar = map(); @@ -19,6 +20,13 @@ class KommentarMapperTest { assertThat(kommentar.getId()).isEqualTo(KommentarTestFactory.ID); } + @Test + void shouldMapVersion() { + var kommentar = map(); + + assertThat(kommentar.getVersion()).isEqualTo(KommentarTestFactory.VERSION); + } + @Test void shouldMapCreatedBy() { var kommentar = map(); diff --git a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarModelAssemblerTest.java b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarModelAssemblerTest.java index 250e85a35dc78caf6645cf7119933390e194a127..8599e12e747a09a2d0a6fe59ac16e12d87ae2a31 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarModelAssemblerTest.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarModelAssemblerTest.java @@ -1,7 +1,5 @@ package de.itvsh.goofy.kommentar; -import static org.assertj.core.api.Assertions.*; - import java.util.Collections; import org.junit.jupiter.api.Nested; @@ -13,6 +11,8 @@ import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; import org.springframework.hateoas.server.EntityLinks; +import static org.assertj.core.api.Assertions.*; + import de.itvsh.goofy.common.user.UserProfileTestFactory; import de.itvsh.goofy.vorgang.VorgangHeaderTestFactory; @@ -31,7 +31,9 @@ class KommentarModelAssemblerTest { class TestLinksOnModel { final String COMMAND_BY_KOMMENTAR_PATH = // - KommentarCommandController.KOMMENTAR_COMMANDS.replace("{kommentarId}", KommentarTestFactory.ID); + KommentarCommandController.KOMMENTAR_COMMANDS + .replace("{kommentarId}", KommentarTestFactory.ID) + .replace("{kommentarVersion}", String.valueOf(KommentarTestFactory.VERSION)); @Test void shouldHaveSelfLink() { @@ -73,7 +75,8 @@ class KommentarModelAssemblerTest { var link = collectionModel.getLink(KommentarModelAssembler.REL_CREATE); assertThat(link).isPresent(); - assertThat(link.get().getHref()).isEqualTo("/api/vorgangs/" + VorgangHeaderTestFactory.ID + "/kommentarCommands"); + assertThat(link.get().getHref()).isEqualTo( + "/api/vorgangs/" + VorgangHeaderTestFactory.ID + "/" + KommentarModelAssembler.RELATION_ID_ON_CREATE + "/kommentarCommands"); } } } \ No newline at end of file diff --git a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarTestFactory.java b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarTestFactory.java index 99abb0b24b22ca5ab6743ae4de507409dfdf0995..096dcde7839aa6a9ffdc570c0fcc5e9188dea965 100644 --- a/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarTestFactory.java +++ b/goofy-server/src/test/java/de/itvsh/goofy/kommentar/KommentarTestFactory.java @@ -14,6 +14,7 @@ public class KommentarTestFactory { private static Lorem lorem = LoremIpsum.getInstance(); public static final String ID = UUID.randomUUID().toString(); + public static final long VERSION = 73; public static final String CREATED_BY = UserProfileTestFactory.ID.toString(); public static final String CREATED_AT_STR = "2021-01-10T10:30:00Z"; @@ -28,6 +29,7 @@ public class KommentarTestFactory { public static Kommentar.KommentarBuilder createBuilder() { return Kommentar.builder() .id(ID) + .version(VERSION) .text(TEXT) .createdBy(CREATED_BY) .createdAt(CREATED_AT); @@ -36,6 +38,7 @@ public class KommentarTestFactory { public static Map<String, Object> createAsMap() { return Map.of( KommentarMapper.ID, ID, + KommentarMapper.VERSION, VERSION, KommentarMapper.TEXT, TEXT, KommentarMapper.CREATED_BY, CREATED_BY, KommentarMapper.CREATED_AT, CREATED_AT_STR);