Added links to sources ressource / refactored code and fixed issues

This commit is contained in:
Philipp Czora
2018-08-14 17:16:10 +02:00
parent f375e076e4
commit f3925fa311
9 changed files with 120 additions and 54 deletions

View File

@@ -1,6 +1,7 @@
package sonia.scm.api.v2.resources; package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation; import de.otto.edison.hal.HalRepresentation;
import de.otto.edison.hal.Links;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@@ -17,6 +18,12 @@ public class BrowserResultDto extends HalRepresentation implements Iterable<File
private String branch; private String branch;
private List<FileObjectDto> files; private List<FileObjectDto> files;
@Override
@SuppressWarnings("squid:S1185") // We want to have this method available in this package
protected HalRepresentation add(Links links) {
return super.add(links);
}
@Override @Override
public Iterator<FileObjectDto> iterator() { public Iterator<FileObjectDto> iterator() {
Iterator<FileObjectDto> it = null; Iterator<FileObjectDto> it = null;

View File

@@ -1,18 +1,27 @@
package sonia.scm.api.v2.resources; package sonia.scm.api.v2.resources;
import org.mapstruct.Mapper; import de.otto.edison.hal.Links;
import sonia.scm.repository.BrowserResult; import sonia.scm.repository.BrowserResult;
import sonia.scm.repository.FileObject; import sonia.scm.repository.FileObject;
import sonia.scm.repository.NamespaceAndName;
import javax.inject.Inject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Mapper public class BrowserResultMapper {
public abstract class BrowserResultMapper extends BaseMapper<BrowserResult, BrowserResultDto> {
abstract FileObjectDto mapFileObject(FileObject fileObject); @Inject
private FileObjectMapper fileObjectMapper;
public BrowserResultDto map(BrowserResult browserResult) { @Inject
private ResourceLinks resourceLinks;
private FileObjectDto mapFileObject(FileObject fileObject, NamespaceAndName namespaceAndName, String revision) {
return fileObjectMapper.map(fileObject, namespaceAndName, revision);
}
public BrowserResultDto map(BrowserResult browserResult, NamespaceAndName namespaceAndName) {
BrowserResultDto browserResultDto = new BrowserResultDto(); BrowserResultDto browserResultDto = new BrowserResultDto();
browserResultDto.setTag(browserResult.getTag()); browserResultDto.setTag(browserResult.getTag());
@@ -21,11 +30,17 @@ public abstract class BrowserResultMapper extends BaseMapper<BrowserResult, Brow
List<FileObjectDto> fileObjectDtoList = new ArrayList<>(); List<FileObjectDto> fileObjectDtoList = new ArrayList<>();
for (FileObject fileObject : browserResult.getFiles()) { for (FileObject fileObject : browserResult.getFiles()) {
fileObjectDtoList.add(mapFileObject(fileObject)); fileObjectDtoList.add(mapFileObject(fileObject, namespaceAndName, browserResult.getRevision()));
} }
browserResultDto.setFiles(fileObjectDtoList); browserResultDto.setFiles(fileObjectDtoList);
this.addLinks(browserResult, browserResultDto, namespaceAndName);
return browserResultDto; return browserResultDto;
} }
private void addLinks(BrowserResult browserResult, BrowserResultDto dto, NamespaceAndName namespaceAndName) {
dto.add(Links.linkingTo().self(resourceLinks.source().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), browserResult.getRevision())).build());
}
} }

View File

@@ -1,8 +1,25 @@
package sonia.scm.api.v2.resources; package sonia.scm.api.v2.resources;
import de.otto.edison.hal.Links;
import org.mapstruct.AfterMapping;
import org.mapstruct.Context;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import sonia.scm.repository.FileObject; import sonia.scm.repository.FileObject;
import sonia.scm.repository.NamespaceAndName;
import javax.inject.Inject;
@Mapper @Mapper
public abstract class FileObjectMapper extends BaseMapper<FileObject, FileObjectDto> { public abstract class FileObjectMapper extends BaseMapper<FileObject, FileObjectDto> {
@Inject
private ResourceLinks resourceLinks;
protected abstract FileObjectDto map(FileObject fileObject, @Context NamespaceAndName namespaceAndName, @Context String revision);
@AfterMapping
void addLinks(FileObject fileObject, @MappingTarget FileObjectDto dto, @Context NamespaceAndName namespaceAndName, @Context String revision) {
dto.add(Links.linkingTo().self(resourceLinks.source().withPath(namespaceAndName.getNamespace(), namespaceAndName.getName(), revision, fileObject.getName())).build());
}
} }

View File

@@ -26,7 +26,7 @@ public class MapperModule extends AbstractModule {
bind(BranchToBranchDtoMapper.class).to(Mappers.getMapper(BranchToBranchDtoMapper.class).getClass()); bind(BranchToBranchDtoMapper.class).to(Mappers.getMapper(BranchToBranchDtoMapper.class).getClass());
bind(BrowserResultMapper.class).to(Mappers.getMapper(BrowserResultMapper.class).getClass()); bind(FileObjectMapper.class).to(Mappers.getMapper(FileObjectMapper.class).getClass());
bind(UriInfoStore.class).in(ServletScopes.REQUEST); bind(UriInfoStore.class).in(ServletScopes.REQUEST);
} }

View File

@@ -36,7 +36,7 @@ public abstract class RepositoryToRepositoryDtoMapper extends BaseMapper<Reposit
linksBuilder.single(link("tags", resourceLinks.tagCollection().self(target.getNamespace(), target.getName()))); linksBuilder.single(link("tags", resourceLinks.tagCollection().self(target.getNamespace(), target.getName())));
linksBuilder.single(link("branches", resourceLinks.branchCollection().self(target.getNamespace(), target.getName()))); linksBuilder.single(link("branches", resourceLinks.branchCollection().self(target.getNamespace(), target.getName())));
linksBuilder.single(link("changesets", resourceLinks.changeset().self(target.getNamespace(), target.getName()))); linksBuilder.single(link("changesets", resourceLinks.changeset().self(target.getNamespace(), target.getName())));
linksBuilder.single(link("sources", resourceLinks.source().self(target.getNamespace(), target.getName()))); linksBuilder.single(link("sources", resourceLinks.source().withoutRevision(target.getNamespace(), target.getName())));
target.add(linksBuilder.build()); target.add(linksBuilder.build());
} }
} }

View File

@@ -290,13 +290,21 @@ class ResourceLinks {
sourceLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, SourceRootResource.class); sourceLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, SourceRootResource.class);
} }
String self(String namespace, String name) { String self(String namespace, String name, String revision) {
return sourceLinkBuilder.method("getRepositoryResource").parameters(namespace, name, revision).method("sources").parameters().method("getAll").parameters().href();
}
String withoutRevision(String namespace, String name) {
return sourceLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("sources").parameters().method("getAll").parameters().href(); return sourceLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("sources").parameters().method("getAll").parameters().href();
} }
public String source(String namespace, String name, String revision) { public String source(String namespace, String name, String revision) {
return sourceLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("sources").parameters().method("get").parameters(revision).href(); return sourceLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("sources").parameters().method("get").parameters(revision).href();
} }
public String withPath(String namespace, String name, String revision, String path) {
return sourceLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("sources").parameters().method("get").parameters(revision, path).href();
}
} }
public PermissionCollectionLinks permissionCollection() { public PermissionCollectionLinks permissionCollection() {

View File

@@ -23,7 +23,6 @@ public class SourceRootResource {
private final BrowserResultMapper browserResultMapper; private final BrowserResultMapper browserResultMapper;
@Inject @Inject
public SourceRootResource(RepositoryServiceFactory serviceFactory, BrowserResultMapper browserResultMapper) { public SourceRootResource(RepositoryServiceFactory serviceFactory, BrowserResultMapper browserResultMapper) {
this.serviceFactory = serviceFactory; this.serviceFactory = serviceFactory;
@@ -35,23 +34,30 @@ public class SourceRootResource {
@Path("") @Path("")
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) { public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) {
BrowserResult browserResult = null; BrowserResult browserResult;
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) { Response response;
NamespaceAndName namespaceAndName = new NamespaceAndName(namespace, name);
try (RepositoryService repositoryService = serviceFactory.create(namespaceAndName)) {
BrowseCommandBuilder browseCommand = repositoryService.getBrowseCommand(); BrowseCommandBuilder browseCommand = repositoryService.getBrowseCommand();
browseCommand.setPath("/"); browseCommand.setPath("/");
browserResult = browseCommand.getBrowserResult(); browserResult = browseCommand.getBrowserResult();
if (browserResult != null) {
response = Response.ok(browserResultMapper.map(browserResult, namespaceAndName)).build();
} else {
response = Response.status(Response.Status.NOT_FOUND).build();
}
} catch (RepositoryNotFoundException e) { } catch (RepositoryNotFoundException e) {
e.printStackTrace(); response = Response.status(Response.Status.NOT_FOUND).build();
} catch (RepositoryException e) { } catch (RepositoryException | IOException e) {
e.printStackTrace(); response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
} catch (IOException e) {
e.printStackTrace();
} }
return Response.ok(browserResultMapper.map(browserResult)).build(); return response;
} }
@GET @GET
@Path("{revision}") @Path("{revision}/{path: .*}")
public Response get() { public Response get() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@@ -6,47 +6,79 @@ import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.util.ThreadState; import org.apache.shiro.util.ThreadState;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.Mock;
import sonia.scm.repository.BrowserResult; import sonia.scm.repository.BrowserResult;
import sonia.scm.repository.FileObject; import sonia.scm.repository.FileObject;
import sonia.scm.repository.NamespaceAndName;
import java.time.Instant; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.MockitoAnnotations.initMocks; import static org.mockito.MockitoAnnotations.initMocks;
@RunWith(MockitoJUnitRunner.class)
public class BrowserResultMapperTest { public class BrowserResultMapperTest {
private final URI baseUri = URI.create("http://example.com/base/");
@SuppressWarnings("unused") // Is injected
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
@Mock
private FileObjectMapper fileObjectMapper;
@InjectMocks @InjectMocks
private BrowserResultMapperImpl mapper; private BrowserResultMapper mapper;
private final Subject subject = mock(Subject.class); private final Subject subject = mock(Subject.class);
private final ThreadState subjectThreadState = new SubjectThreadState(subject); private final ThreadState subjectThreadState = new SubjectThreadState(subject);
private FileObject fileObject1 = new FileObject();
private FileObject fileObject2 = new FileObject();
@Before @Before
public void init() { public void init() {
initMocks(this); initMocks(this);
subjectThreadState.bind(); subjectThreadState.bind();
ThreadContext.bind(subject); ThreadContext.bind(subject);
fileObject1.setName("FO 1");
fileObject1.setLength(100);
fileObject1.setLastModified(0L);
fileObject1.setPath("/path/object/1");
fileObject1.setDescription("description of file object 1");
fileObject1.setDirectory(false);
fileObject2.setName("FO 2");
fileObject2.setLength(100);
fileObject2.setLastModified(101L);
fileObject2.setPath("/path/object/2");
fileObject2.setDescription("description of file object 2");
fileObject2.setDirectory(true);
} }
@Test @Test
public void shouldMapAttributesCorrectly() { public void shouldMapAttributesCorrectly() {
BrowserResult browserResult = createBrowserResult(); BrowserResult browserResult = createBrowserResult();
BrowserResultDto dto = mapper.map(browserResult); BrowserResultDto dto = mapper.map(browserResult, new NamespaceAndName("foo", "bar"));
assertEqualAttributes(browserResult, dto); assertEqualAttributes(browserResult, dto);
}
assertEqualFileObjectAttributes(browserResult.getFiles().get(0), dto.getFiles().get(0)); @Test
assertEqualFileObjectAttributes(browserResult.getFiles().get(1), dto.getFiles().get(1)); public void shouldDelegateToFileObjectsMapper() {
BrowserResult browserResult = createBrowserResult();
NamespaceAndName namespaceAndName = new NamespaceAndName("foo", "bar");
BrowserResultDto dto = mapper.map(browserResult, namespaceAndName);
verify(fileObjectMapper).map(fileObject1, namespaceAndName, "Revision");
verify(fileObjectMapper).map(fileObject2, namespaceAndName, "Revision");
} }
private BrowserResult createBrowserResult() { private BrowserResult createBrowserResult() {
@@ -62,22 +94,6 @@ public class BrowserResultMapperTest {
private List<FileObject> createFileObjects() { private List<FileObject> createFileObjects() {
List<FileObject> fileObjects = new ArrayList<>(); List<FileObject> fileObjects = new ArrayList<>();
FileObject fileObject1 = new FileObject();
fileObject1.setName("FO 1");
fileObject1.setLength(100);
fileObject1.setLastModified(0L);
fileObject1.setPath("/path/object/1");
fileObject1.setDescription("description of file object 1");
fileObject1.setDirectory(false);
FileObject fileObject2 = new FileObject();
fileObject2.setName("FO 2");
fileObject2.setLength(100);
fileObject2.setLastModified(101L);
fileObject2.setPath("/path/object/2");
fileObject2.setDescription("description of file object 2");
fileObject2.setDirectory(true);
fileObjects.add(fileObject1); fileObjects.add(fileObject1);
fileObjects.add(fileObject2); fileObjects.add(fileObject2);
return fileObjects; return fileObjects;
@@ -89,12 +105,4 @@ public class BrowserResultMapperTest {
assertThat(dto.getRevision()).isEqualTo(browserResult.getRevision()); assertThat(dto.getRevision()).isEqualTo(browserResult.getRevision());
} }
private void assertEqualFileObjectAttributes(FileObject fileObject, FileObjectDto dto) {
assertThat(dto.getName()).isEqualTo(fileObject.getName());
assertThat(dto.getLength()).isEqualTo(fileObject.getLength());
assertThat(dto.getLastModified()).isEqualTo(Instant.ofEpochMilli(fileObject.getLastModified()));
assertThat(dto.isDirectory()).isEqualTo(fileObject.isDirectory());
assertThat(dto.getDescription()).isEqualTo(fileObject.getDescription());
assertThat(dto.getPath()).isEqualTo(fileObject.getPath());
}
} }

View File

@@ -147,13 +147,18 @@ public class ResourceLinksTest {
@Test @Test
public void shouldCreateCorrectSourceCollectionUrl() { public void shouldCreateCorrectSourceCollectionUrl() {
String url = resourceLinks.source().self("space", "repo"); String url = resourceLinks.source().withoutRevision("space", "repo");
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/sources/", url); assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/sources/", url);
} }
@Test
public void shouldCreateCorrectSourceUrlWithFilename() {
String url = resourceLinks.source().withPath("foo", "bar", "rev", "file");
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "foo/bar/sources/rev/file", url);
}
@Test @Test
public void shouldCreateCorrectPermissionCollectionUrl() { public void shouldCreateCorrectPermissionCollectionUrl() {
String url = resourceLinks.source().self("space", "repo"); String url = resourceLinks.source().withoutRevision("space", "repo");
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/sources/", url); assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/sources/", url);
} }