diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java index 6aea500c78..b1e2a4cffe 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BaseMapper.java @@ -1,11 +1,15 @@ package sonia.scm.api.v2.resources; +import de.otto.edison.hal.HalRepresentation; +import sonia.scm.ModelObject; import sonia.scm.util.AssertUtil; import java.time.Instant; import java.util.Optional; -class BaseMapper { +abstract class BaseMapper { + + public abstract D map(T user); Instant mapTime(Long epochMilli) { AssertUtil.assertIsNotNull(epochMilli); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BasicCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BasicCollectionToDtoMapper.java new file mode 100644 index 0000000000..dfa8702849 --- /dev/null +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/BasicCollectionToDtoMapper.java @@ -0,0 +1,69 @@ +package sonia.scm.api.v2.resources; + +import de.otto.edison.hal.Embedded; +import de.otto.edison.hal.HalRepresentation; +import de.otto.edison.hal.Links; +import de.otto.edison.hal.paging.NumberedPaging; +import de.otto.edison.hal.paging.PagingRel; +import sonia.scm.ModelObject; +import sonia.scm.PageResult; + +import javax.inject.Inject; +import java.util.EnumSet; +import java.util.List; + +import static com.damnhandy.uri.template.UriTemplate.fromTemplate; +import static de.otto.edison.hal.Embedded.embeddedBuilder; +import static de.otto.edison.hal.Link.link; +import static de.otto.edison.hal.Links.linkingTo; +import static de.otto.edison.hal.paging.NumberedPaging.zeroBasedNumberedPaging; +import static java.util.stream.Collectors.toList; + +abstract class BasicCollectionToDtoMapper { + + private final String collectionName; + private final BaseMapper entityToDtoMapper; + + @Inject + public BasicCollectionToDtoMapper(String collectionName, BaseMapper entityToDtoMapper) { + this.collectionName = collectionName; + this.entityToDtoMapper = entityToDtoMapper; + } + + public CollectionDto map(int pageNumber, int pageSize, PageResult pageResult) { + NumberedPaging paging = zeroBasedNumberedPaging(pageNumber, pageSize, pageResult.getOverallCount()); + List dtos = pageResult.getEntities().stream().map(entityToDtoMapper::map).collect(toList()); + + CollectionDto collectionDto = new CollectionDto( + createLinks(paging), + embedDtos(dtos) + ); + collectionDto.setPage(pageNumber); + return collectionDto; + } + + private Links createLinks(NumberedPaging page) { + String baseUrl = createSelfLink(); + + Links.Builder linksBuilder = linkingTo() + .with(page.links( + fromTemplate(baseUrl + "{?page,pageSize}"), + EnumSet.allOf(PagingRel.class))); + if (isCreatePermitted()) { + linksBuilder.single(link("create", createCreateLink())); + } + return linksBuilder.build(); + } + + abstract boolean isCreatePermitted(); + + abstract String createCreateLink(); + + abstract String createSelfLink(); + + private Embedded embedDtos(List dtos) { + return embeddedBuilder() + .with(collectionName, dtos) + .build(); + } +} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/CollectionDto.java similarity index 68% rename from scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionDto.java rename to scm-webapp/src/main/java/sonia/scm/api/v2/resources/CollectionDto.java index 96b41dae94..80a1b7d455 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionDto.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/CollectionDto.java @@ -6,12 +6,12 @@ import de.otto.edison.hal.Links; import lombok.Data; @Data -public class UserCollectionDto extends HalRepresentation { +public class CollectionDto extends HalRepresentation { private int page; private int pageTotal; - public UserCollectionDto(Links links, Embedded embedded) { + public CollectionDto(Links links, Embedded embedded) { super(links, embedded); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionDto.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionDto.java deleted file mode 100644 index 916c327f7a..0000000000 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package sonia.scm.api.v2.resources; - -import de.otto.edison.hal.Embedded; -import de.otto.edison.hal.HalRepresentation; -import de.otto.edison.hal.Links; -import lombok.Data; - -@Data -public class GroupCollectionDto extends HalRepresentation { - - private int page; - private int pageTotal; - - public GroupCollectionDto(Links links, Embedded embedded) { - super(links, embedded); - } -} diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapper.java index 915573e5b0..7b09d91a9f 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapper.java @@ -1,64 +1,34 @@ package sonia.scm.api.v2.resources; -import de.otto.edison.hal.Embedded; -import de.otto.edison.hal.Links; -import de.otto.edison.hal.paging.NumberedPaging; -import de.otto.edison.hal.paging.PagingRel; -import sonia.scm.PageResult; import sonia.scm.group.Group; import sonia.scm.group.GroupPermissions; import javax.inject.Inject; -import java.util.EnumSet; -import java.util.List; -import static com.damnhandy.uri.template.UriTemplate.fromTemplate; -import static de.otto.edison.hal.Embedded.embeddedBuilder; -import static de.otto.edison.hal.Link.link; -import static de.otto.edison.hal.Links.linkingTo; -import static de.otto.edison.hal.paging.NumberedPaging.zeroBasedNumberedPaging; -import static java.util.stream.Collectors.toList; import static sonia.scm.api.v2.resources.ResourceLinks.groupCollection; -public class GroupCollectionToDtoMapper { +public class GroupCollectionToDtoMapper extends BasicCollectionToDtoMapper { - private final GroupToGroupDtoMapper groupToDtoMapper; private final UriInfoStore uriInfoStore; @Inject public GroupCollectionToDtoMapper(GroupToGroupDtoMapper groupToDtoMapper, UriInfoStore uriInfoStore) { - this.groupToDtoMapper = groupToDtoMapper; + super("groups", groupToDtoMapper); this.uriInfoStore = uriInfoStore; } - public GroupCollectionDto map(int pageNumber, int pageSize, PageResult pageResult) { - NumberedPaging paging = zeroBasedNumberedPaging(pageNumber, pageSize, pageResult.getOverallCount()); - List dtos = pageResult.getEntities().stream().map(groupToDtoMapper::map).collect(toList()); - - GroupCollectionDto groupCollectionDto = new GroupCollectionDto( - createLinks(paging), - embedDtos(dtos) - ); - groupCollectionDto.setPage(pageNumber); - return groupCollectionDto; + @Override + String createCreateLink() { + return groupCollection(uriInfoStore.get()).create(); } - private Links createLinks(NumberedPaging page) { - String baseUrl = groupCollection(uriInfoStore.get()).self(); - - Links.Builder linksBuilder = linkingTo() - .with(page.links( - fromTemplate(baseUrl + "{?page,pageSize}"), - EnumSet.allOf(PagingRel.class))); - if (GroupPermissions.create().isPermitted()) { - linksBuilder.single(link("create", groupCollection(uriInfoStore.get()).create())); - } - return linksBuilder.build(); + @Override + String createSelfLink() { + return groupCollection(uriInfoStore.get()).self(); } - private Embedded embedDtos(List dtos) { - return embeddedBuilder() - .with("groups", dtos) - .build(); + @Override + boolean isCreatePermitted() { + return GroupPermissions.create().isPermitted(); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupToGroupDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupToGroupDtoMapper.java index d439a148fa..969737974b 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupToGroupDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupToGroupDtoMapper.java @@ -17,13 +17,11 @@ import static sonia.scm.api.v2.resources.ResourceLinks.group; import static sonia.scm.api.v2.resources.ResourceLinks.user; @Mapper -public abstract class GroupToGroupDtoMapper extends BaseMapper { +public abstract class GroupToGroupDtoMapper extends BaseMapper { @Inject private UriInfoStore uriInfoStore; - public abstract GroupDto map(Group group); - @AfterMapping void appendLinks(Group group, @MappingTarget GroupDto target) { Links.Builder linksBuilder = linkingTo().self(group(uriInfoStore.get()).self(target.getName())); diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapper.java index 9cfdfff87d..015ba04ae9 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapper.java @@ -1,64 +1,34 @@ package sonia.scm.api.v2.resources; -import de.otto.edison.hal.Embedded; -import de.otto.edison.hal.Links; -import de.otto.edison.hal.paging.NumberedPaging; -import de.otto.edison.hal.paging.PagingRel; -import sonia.scm.PageResult; import sonia.scm.user.User; import sonia.scm.user.UserPermissions; import javax.inject.Inject; -import java.util.EnumSet; -import java.util.List; -import static com.damnhandy.uri.template.UriTemplate.fromTemplate; -import static de.otto.edison.hal.Embedded.embeddedBuilder; -import static de.otto.edison.hal.Link.link; -import static de.otto.edison.hal.Links.linkingTo; -import static de.otto.edison.hal.paging.NumberedPaging.zeroBasedNumberedPaging; -import static java.util.stream.Collectors.toList; import static sonia.scm.api.v2.resources.ResourceLinks.userCollection; -public class UserCollectionToDtoMapper { +public class UserCollectionToDtoMapper extends BasicCollectionToDtoMapper { - private final UserToUserDtoMapper userToDtoMapper; private final UriInfoStore uriInfoStore; @Inject public UserCollectionToDtoMapper(UserToUserDtoMapper userToDtoMapper, UriInfoStore uriInfoStore) { - this.userToDtoMapper = userToDtoMapper; + super("users", userToDtoMapper); this.uriInfoStore = uriInfoStore; } - public UserCollectionDto map(int pageNumber, int pageSize, PageResult pageResult) { - NumberedPaging paging = zeroBasedNumberedPaging(pageNumber, pageSize, pageResult.getOverallCount()); - List dtos = pageResult.getEntities().stream().map(userToDtoMapper::map).collect(toList()); - - UserCollectionDto userCollectionDto = new UserCollectionDto( - createLinks(paging), - embedDtos(dtos) - ); - userCollectionDto.setPage(pageNumber); - return userCollectionDto; + @Override + String createCreateLink() { + return userCollection(uriInfoStore.get()).create(); } - private Links createLinks(NumberedPaging page) { - String baseUrl = userCollection(uriInfoStore.get()).self(); - - Links.Builder linksBuilder = linkingTo() - .with(page.links( - fromTemplate(baseUrl + "{?page,pageSize}"), - EnumSet.allOf(PagingRel.class))); - if (UserPermissions.create().isPermitted()) { - linksBuilder.single(link("create", userCollection(uriInfoStore.get()).create())); - } - return linksBuilder.build(); + @Override + String createSelfLink() { + return userCollection(uriInfoStore.get()).self(); } - private Embedded embedDtos(List dtos) { - return embeddedBuilder() - .with("users", dtos) - .build(); + @Override + boolean isCreatePermitted() { + return UserPermissions.create().isPermitted(); } } diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserToUserDtoMapper.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserToUserDtoMapper.java index 66e3d57fb1..80d747ece0 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserToUserDtoMapper.java +++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UserToUserDtoMapper.java @@ -15,13 +15,11 @@ import static de.otto.edison.hal.Links.linkingTo; import static sonia.scm.api.v2.resources.ResourceLinks.user; @Mapper -public abstract class UserToUserDtoMapper extends BaseMapper { +public abstract class UserToUserDtoMapper extends BaseMapper { @Inject private UriInfoStore uriInfoStore; - public abstract UserDto map(User user); - @AfterMapping void removePassword(@MappingTarget UserDto target) { target.setPassword(UserResource.DUMMY_PASSWORT); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapperTest.java index 2b00b32791..2d9cc3ba70 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupCollectionToDtoMapperTest.java @@ -56,29 +56,29 @@ public class GroupCollectionToDtoMapperTest { @Test public void shouldSetPageNumber() { PageResult pageResult = mockPageResult("nobodies"); - GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult); - assertEquals(1, groupCollectionDto.getPage()); + CollectionDto collectionDto = mapper.map(1, 1, pageResult); + assertEquals(1, collectionDto.getPage()); } @Test public void shouldHaveSelfLink() { PageResult pageResult = mockPageResult("nobodies"); - GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult); - assertTrue(groupCollectionDto.getLinks().getLinkBy("self").get().getHref().startsWith(expectedBaseUri.toString())); + CollectionDto collectionDto = mapper.map(1, 1, pageResult); + assertTrue(collectionDto.getLinks().getLinkBy("self").get().getHref().startsWith(expectedBaseUri.toString())); } @Test public void shouldCreateNextPageLink_whenHasMore() { PageResult pageResult = createPage(createGroups("nobodies", "bosses"), 0, 1); - GroupCollectionDto groupCollectionDto = mapper.map(0, 1, pageResult); - assertTrue(groupCollectionDto.getLinks().getLinkBy("next").get().getHref().contains("page=1")); + CollectionDto collectionDto = mapper.map(0, 1, pageResult); + assertTrue(collectionDto.getLinks().getLinkBy("next").get().getHref().contains("page=1")); } @Test public void shouldNotCreateNextPageLink_whenNoMore() { PageResult pageResult = mockPageResult("nobodies"); - GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult); - assertFalse(groupCollectionDto.getLinks().stream().anyMatch(link -> link.getHref().contains("page=2"))); + CollectionDto collectionDto = mapper.map(1, 1, pageResult); + assertFalse(collectionDto.getLinks().stream().anyMatch(link -> link.getHref().contains("page=2"))); } @Test @@ -86,9 +86,9 @@ public class GroupCollectionToDtoMapperTest { PageResult pageResult = mockPageResult("nobodies"); when(subject.isPermitted("group:create")).thenReturn(true); - GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult); + CollectionDto collectionDto = mapper.map(1, 1, pageResult); - assertTrue(groupCollectionDto.getLinks().getLinkBy("create").isPresent()); + assertTrue(collectionDto.getLinks().getLinkBy("create").isPresent()); } @Test @@ -96,16 +96,16 @@ public class GroupCollectionToDtoMapperTest { PageResult pageResult = mockPageResult("nobodies"); when(subject.isPermitted("group:create")).thenReturn(false); - GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult); + CollectionDto collectionDto = mapper.map(1, 1, pageResult); - assertFalse(groupCollectionDto.getLinks().getLinkBy("create").isPresent()); + assertFalse(collectionDto.getLinks().getLinkBy("create").isPresent()); } @Test public void shouldMapGroups() { PageResult pageResult = mockPageResult("nobodies", "bosses"); - GroupCollectionDto groupCollectionDto = mapper.map(1, 2, pageResult); - List groups = groupCollectionDto.getEmbedded().getItemsBy("groups"); + CollectionDto collectionDto = mapper.map(1, 2, pageResult); + List groups = collectionDto.getEmbedded().getItemsBy("groups"); assertEquals(2, groups.size()); assertEquals("nobodies", ((GroupDto) groups.get(0)).getName()); assertEquals("bosses", ((GroupDto) groups.get(1)).getName()); diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapperTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapperTest.java index cd6a054c54..93cacaaf6d 100644 --- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapperTest.java +++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/UserCollectionToDtoMapperTest.java @@ -63,30 +63,30 @@ public class UserCollectionToDtoMapperTest { @Test public void shouldSetPageNumber() { PageResult pageResult = mockPageResult("Hannes"); - UserCollectionDto userCollectionDto = mapper.map(0, 1, pageResult); - assertEquals(0, userCollectionDto.getPage()); + CollectionDto collectionDto = mapper.map(0, 1, pageResult); + assertEquals(0, collectionDto.getPage()); } @Test public void shouldHaveSelfLink() { PageResult pageResult = mockPageResult("Hannes"); - UserCollectionDto userCollectionDto = mapper.map(0, 1, pageResult); - assertTrue(userCollectionDto.getLinks().getLinkBy("self").get().getHref().startsWith(expectedBaseUri.toString())); + CollectionDto collectionDto = mapper.map(0, 1, pageResult); + assertTrue(collectionDto.getLinks().getLinkBy("self").get().getHref().startsWith(expectedBaseUri.toString())); } @Test public void shouldCreateNextPageLink_whenHasMore() { PageResult pageResult = createPage(createUsers("Hannes", "Karl"), 0, 1); - UserCollectionDto userCollectionDto = mapper.map(0, 1, pageResult); - assertTrue(userCollectionDto.getLinks().getLinkBy("next").get().getHref().contains("page=1")); + CollectionDto collectionDto = mapper.map(0, 1, pageResult); + assertTrue(collectionDto.getLinks().getLinkBy("next").get().getHref().contains("page=1")); } @Test public void shouldNotCreateNextPageLink_whenNoMore() { PageResult pageResult = mockPageResult("Hannes", "Wurst", "X"); - UserCollectionDto userCollectionDto = mapper.map(0, 10, pageResult); - assertFalse(userCollectionDto.getLinks().getLinkBy("next").isPresent()); + CollectionDto collectionDto = mapper.map(0, 10, pageResult); + assertFalse(collectionDto.getLinks().getLinkBy("next").isPresent()); } @Test @@ -94,9 +94,9 @@ public class UserCollectionToDtoMapperTest { PageResult pageResult = mockPageResult("Hannes"); when(subject.isPermitted("user:create")).thenReturn(true); - UserCollectionDto userCollectionDto = mapper.map(0, 1, pageResult); + CollectionDto collectionDto = mapper.map(0, 1, pageResult); - assertTrue(userCollectionDto.getLinks().getLinkBy("create").isPresent()); + assertTrue(collectionDto.getLinks().getLinkBy("create").isPresent()); } @Test @@ -104,16 +104,16 @@ public class UserCollectionToDtoMapperTest { PageResult pageResult = mockPageResult("Hannes"); when(subject.isPermitted("user:create")).thenReturn(false); - UserCollectionDto userCollectionDto = mapper.map(0, 1, pageResult); + CollectionDto collectionDto = mapper.map(0, 1, pageResult); - assertFalse(userCollectionDto.getLinks().getLinkBy("create").isPresent()); + assertFalse(collectionDto.getLinks().getLinkBy("create").isPresent()); } @Test public void shouldMapUsers() { PageResult pageResult = mockPageResult("Hannes", "Wurst"); - UserCollectionDto userCollectionDto = mapper.map(0, 2, pageResult); - List users = userCollectionDto.getEmbedded().getItemsBy("users"); + CollectionDto collectionDto = mapper.map(0, 2, pageResult); + List users = collectionDto.getEmbedded().getItemsBy("users"); assertEquals(2, users.size()); assertEquals("Hannes", ((UserDto) users.get(0)).getName()); assertEquals("Wurst", ((UserDto) users.get(1)).getName());