diff --git a/scm-webapp/pom.xml b/scm-webapp/pom.xml
index 26b0919d7b..226593e298 100644
--- a/scm-webapp/pom.xml
+++ b/scm-webapp/pom.xml
@@ -403,6 +403,20 @@
${org.mapstruct.version}
provided
+
+
+
+
+ javax.validation
+ validation-api
+ 2.0.1.Final
+
+
+
+ org.hibernate
+ hibernate-validator
+ 6.0.10.Final
+
diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java b/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java
new file mode 100644
index 0000000000..de0f1dd626
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/api/rest/UriInfoFilter.java
@@ -0,0 +1,24 @@
+package sonia.scm.api.rest;
+
+import sonia.scm.api.v2.resources.UriInfoStore;
+
+import javax.inject.Inject;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+public class UriInfoFilter implements ContainerRequestFilter {
+
+ private final javax.inject.Provider storeProvider;
+
+ @Inject
+ public UriInfoFilter(javax.inject.Provider storeProvider) {
+ this.storeProvider = storeProvider;
+ }
+
+ @Override
+ public void filter(ContainerRequestContext requestContext) {
+ storeProvider.get().set(requestContext.getUriInfo());
+ }
+}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionResource.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionResource.java
index d38de35dcf..930641d4ce 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionResource.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/GroupCollectionResource.java
@@ -35,12 +35,14 @@ public class GroupCollectionResource extends AbstractManagerResource pageResult = fetchPage(sortby, desc, page, pageSize);
- return Response.ok(new GroupCollectionToDtoMapper(groupToDtoMapper).map(uriInfo, page, pageSize, pageResult)).build();
+ return Response.ok(groupCollectionToDtoMapper.map(page, pageSize, pageResult)).build();
}
@Override
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 547d05ce08..c4ff5c1949 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
@@ -9,7 +9,6 @@ import sonia.scm.group.Group;
import sonia.scm.group.GroupPermissions;
import javax.inject.Inject;
-import javax.ws.rs.core.UriInfo;
import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;
@@ -24,33 +23,35 @@ import static sonia.scm.api.v2.resources.ResourceLinks.groupCollection;
public class GroupCollectionToDtoMapper {
private final GroupToGroupDtoMapper groupToDtoMapper;
+ private final UriInfoStore uriInfoStore;
@Inject
- public GroupCollectionToDtoMapper(GroupToGroupDtoMapper groupToDtoMapper) {
+ public GroupCollectionToDtoMapper(GroupToGroupDtoMapper groupToDtoMapper, UriInfoStore uriInfoStore) {
this.groupToDtoMapper = groupToDtoMapper;
+ this.uriInfoStore = uriInfoStore;
}
- public GroupCollectionDto map(UriInfo uriInfo, int pageNumber, int pageSize, PageResult pageResult) {
+ public GroupCollectionDto map(int pageNumber, int pageSize, PageResult pageResult) {
NumberedPaging paging = zeroBasedNumberedPaging(pageNumber, pageSize, pageResult.hasMore());
- List dtos = pageResult.getEntities().stream().map(user -> groupToDtoMapper.map(user, uriInfo)).collect(Collectors.toList());
+ List dtos = pageResult.getEntities().stream().map(user -> groupToDtoMapper.map(user, uriInfoStore.get())).collect(Collectors.toList());
GroupCollectionDto groupCollectionDto = new GroupCollectionDto(
- createLinks(uriInfo, paging),
+ createLinks(paging),
embedDtos(dtos)
);
groupCollectionDto.setPage(pageNumber);
return groupCollectionDto;
}
- private static Links createLinks(UriInfo uriInfo, NumberedPaging page) {
- String baseUrl = groupCollection(uriInfo).self();
+ 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(uriInfo).create()));
+ linksBuilder.single(link("create", groupCollection(uriInfoStore.get()).create()));
}
return linksBuilder.build();
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java
index 3642d3508e..fec2a677b5 100644
--- a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/MapperModule.java
@@ -1,6 +1,7 @@
package sonia.scm.api.v2.resources;
import com.google.inject.AbstractModule;
+import com.google.inject.servlet.ServletScopes;
import org.mapstruct.factory.Mappers;
public class MapperModule extends AbstractModule {
@@ -8,8 +9,12 @@ public class MapperModule extends AbstractModule {
protected void configure() {
bind(UserDtoToUserMapper.class).to(Mappers.getMapper(UserDtoToUserMapper.class).getClass());
bind(UserToUserDtoMapper.class).to(Mappers.getMapper(UserToUserDtoMapper.class).getClass());
+ bind(UserCollectionToDtoMapper.class);
- bind(GroupToGroupDtoMapper.class).to(Mappers.getMapper(GroupToGroupDtoMapper.class).getClass());
bind(GroupDtoToGroupMapper.class).to(Mappers.getMapper(GroupDtoToGroupMapper.class).getClass());
+ bind(GroupToGroupDtoMapper.class).to(Mappers.getMapper(GroupToGroupDtoMapper.class).getClass());
+ bind(GroupCollectionToDtoMapper.class);
+
+ bind(UriInfoStore.class).in(ServletScopes.REQUEST);
}
}
diff --git a/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java
new file mode 100644
index 0000000000..2f61383cfd
--- /dev/null
+++ b/scm-webapp/src/main/java/sonia/scm/api/v2/resources/UriInfoStore.java
@@ -0,0 +1,19 @@
+package sonia.scm.api.v2.resources;
+
+import javax.ws.rs.core.UriInfo;
+
+public class UriInfoStore {
+
+ private UriInfo uriInfo;
+
+ public UriInfo get() {
+ return uriInfo;
+ }
+
+ public void set(UriInfo uriInfo) {
+ if (this.uriInfo != null) {
+ throw new IllegalStateException("UriInfo already set");
+ }
+ this.uriInfo = uriInfo;
+ }
+}
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 6a1c2246b3..d6560de8bb 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
@@ -28,16 +28,18 @@ import static org.mockito.Mockito.when;
public class GroupCollectionToDtoMapperTest {
private final UriInfo uriInfo = mock(UriInfo.class);
+ private final UriInfoStore uriInfoStore = new UriInfoStore();
private final GroupToGroupDtoMapper groupToDtoMapper = mock(GroupToGroupDtoMapper.class);
private final Subject subject = mock(Subject.class);
private final ThreadState subjectThreadState = new SubjectThreadState(subject);
- private final GroupCollectionToDtoMapper mapper = new GroupCollectionToDtoMapper(groupToDtoMapper);
+ private final GroupCollectionToDtoMapper mapper = new GroupCollectionToDtoMapper(groupToDtoMapper, uriInfoStore);
private URI expectedBaseUri;
@Before
public void init() throws URISyntaxException {
+// uriInfoStore.set(uriInfo);
URI baseUri = new URI("http://example.com/base/");
expectedBaseUri = baseUri.resolve(GroupV2Resource.GROUPS_PATH_V2 + "/");
when(uriInfo.getBaseUri()).thenReturn(baseUri);
@@ -53,28 +55,28 @@ public class GroupCollectionToDtoMapperTest {
@Test
public void shouldSetPageNumber() {
PageResult pageResult = mockPageResult(true, "nobodies");
- GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult);
+ GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertEquals(1, groupCollectionDto.getPage());
}
@Test
public void shouldHaveSelfLink() {
PageResult pageResult = mockPageResult(true, "nobodies");
- GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult);
+ GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertTrue(groupCollectionDto.getLinks().getLinkBy("self").get().getHref().startsWith(expectedBaseUri.toString()));
}
@Test
public void shouldCreateNextPageLink_whenHasMore() {
PageResult pageResult = mockPageResult(true, "nobodies");
- GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult);
+ GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertTrue(groupCollectionDto.getLinks().getLinkBy("next").get().getHref().contains("page=2"));
}
@Test
public void shouldNotCreateNextPageLink_whenNoMore() {
PageResult pageResult = mockPageResult(false, "nobodies");
- GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult);
+ GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertFalse(groupCollectionDto.getLinks().stream().anyMatch(link -> link.getHref().contains("page=2")));
}
@@ -83,7 +85,7 @@ public class GroupCollectionToDtoMapperTest {
PageResult pageResult = mockPageResult(false, "nobodies");
when(subject.isPermitted("group:create")).thenReturn(true);
- GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult);
+ GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertTrue(groupCollectionDto.getLinks().getLinkBy("create").isPresent());
}
@@ -93,7 +95,7 @@ public class GroupCollectionToDtoMapperTest {
PageResult pageResult = mockPageResult(false, "nobodies");
when(subject.isPermitted("group:create")).thenReturn(false);
- GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 1, pageResult);
+ GroupCollectionDto groupCollectionDto = mapper.map(1, 1, pageResult);
assertFalse(groupCollectionDto.getLinks().getLinkBy("create").isPresent());
}
@@ -101,7 +103,7 @@ public class GroupCollectionToDtoMapperTest {
@Test
public void shouldMapGroups() {
PageResult pageResult = mockPageResult(false, "nobodies", "bosses");
- GroupCollectionDto groupCollectionDto = mapper.map(uriInfo, 1, 2, pageResult);
+ GroupCollectionDto groupCollectionDto = mapper.map(1, 2, pageResult);
List groups = groupCollectionDto.getEmbedded().getItemsBy("groups");
assertEquals(2, groups.size());
assertEquals("nobodies", ((GroupDto) groups.get(0)).getName());
diff --git a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupV2ResourceTest.java b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupV2ResourceTest.java
index 9ce5181f74..219941e655 100644
--- a/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupV2ResourceTest.java
+++ b/scm-webapp/src/test/java/sonia/scm/api/v2/resources/GroupV2ResourceTest.java
@@ -45,10 +45,14 @@ public class GroupV2ResourceTest {
@Mock
private GroupManager groupManager;
+ private final UriInfoStore uriInfoStore = new UriInfoStore();
@InjectMocks
GroupDtoToGroupMapperImpl dtoToGroupMapper;
@InjectMocks
GroupToGroupDtoMapperImpl groupToDtoMapper;
+ @InjectMocks
+ GroupCollectionToDtoMapper groupCollectionToDtoMapper;
+
ArgumentCaptor groupCaptor = ArgumentCaptor.forClass(Group.class);
@@ -63,7 +67,7 @@ public class GroupV2ResourceTest {
group.setMembers(Collections.singletonList("user"));
when(groupManager.get("admin")).thenReturn(group);
- GroupCollectionResource groupCollectionResource = new GroupCollectionResource(groupManager, dtoToGroupMapper, groupToDtoMapper);
+ GroupCollectionResource groupCollectionResource = new GroupCollectionResource(groupManager, dtoToGroupMapper, groupToDtoMapper, groupCollectionToDtoMapper);
GroupSubResource groupSubResource = new GroupSubResource(groupManager, groupToDtoMapper);
GroupV2Resource groupV2Resource = new GroupV2Resource(groupCollectionResource, groupSubResource);