file history endpoint

This commit is contained in:
Mohamed Karray
2018-09-06 11:33:39 +02:00
parent 753349ae18
commit 56d323793e
14 changed files with 363 additions and 11 deletions

View File

@@ -6,11 +6,12 @@ import sonia.scm.repository.Repository;
import javax.inject.Inject;
import java.util.Optional;
import java.util.function.Supplier;
public class ChangesetCollectionToDtoMapper extends BasicCollectionToDtoMapper<Changeset, ChangesetDto, ChangesetToChangesetDtoMapper> {
private final ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper;
private final ResourceLinks resourceLinks;
protected final ResourceLinks resourceLinks;
@Inject
public ChangesetCollectionToDtoMapper(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) {
@@ -20,10 +21,14 @@ public class ChangesetCollectionToDtoMapper extends BasicCollectionToDtoMapper<C
}
public CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository) {
return super.map(pageNumber, pageSize, pageResult, createSelfLink(repository), Optional.empty(), changeset -> changesetToChangesetDtoMapper.map(changeset, repository));
return this.map(pageNumber, pageSize, pageResult, repository, () -> createSelfLink(repository));
}
private String createSelfLink(Repository repository) {
public CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository, Supplier<String> selfLinkSupplier) {
return super.map(pageNumber, pageSize, pageResult, selfLinkSupplier.get(), Optional.empty(), changeset -> changesetToChangesetDtoMapper.map(changeset, repository));
}
protected String createSelfLink(Repository repository) {
return resourceLinks.changeset().all(repository.getNamespace(), repository.getName());
}
}

View File

@@ -0,0 +1,24 @@
package sonia.scm.api.v2.resources;
import sonia.scm.PageResult;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.Repository;
import javax.inject.Inject;
public class FileHistoryCollectionToDtoMapper extends ChangesetCollectionToDtoMapper {
@Inject
public FileHistoryCollectionToDtoMapper(ChangesetToChangesetDtoMapper changesetToChangesetDtoMapper, ResourceLinks resourceLinks) {
super(changesetToChangesetDtoMapper, resourceLinks);
}
public CollectionDto map(int pageNumber, int pageSize, PageResult<Changeset> pageResult, Repository repository, String revision, String path) {
return super.map(pageNumber, pageSize, pageResult, repository, () -> createSelfLink(repository, revision, path));
}
protected String createSelfLink(Repository repository, String revision, String path) {
return super.resourceLinks.fileHistory().self(repository.getNamespace(), repository.getName(), revision, path);
}
}

View File

@@ -0,0 +1,78 @@
package sonia.scm.api.v2.resources;
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import com.webcohesion.enunciate.metadata.rs.TypeHint;
import lombok.extern.slf4j.Slf4j;
import sonia.scm.PageResult;
import sonia.scm.repository.Changeset;
import sonia.scm.repository.ChangesetPagingResult;
import sonia.scm.repository.InternalRepositoryException;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository;
import sonia.scm.repository.RepositoryNotFoundException;
import sonia.scm.repository.RevisionNotFoundException;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.io.IOException;
@Slf4j
public class FileHistoryRootResource {
private final RepositoryServiceFactory serviceFactory;
private final FileHistoryCollectionToDtoMapper fileHistoryCollectionToDtoMapper;
@Inject
public FileHistoryRootResource(RepositoryServiceFactory serviceFactory, FileHistoryCollectionToDtoMapper fileHistoryCollectionToDtoMapper) {
this.serviceFactory = serviceFactory;
this.fileHistoryCollectionToDtoMapper = fileHistoryCollectionToDtoMapper;
}
@GET
@Path("{revision}/{path: .*}")
@StatusCodes({
@ResponseCode(code = 200, condition = "success"),
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to read the changeset"),
@ResponseCode(code = 404, condition = "not found, no changesets available in the repository"),
@ResponseCode(code = 500, condition = "internal server error")
})
@Produces(VndMediaType.CHANGESET_COLLECTION)
@TypeHint(CollectionDto.class)
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name,
@PathParam("revision") String revision,
@PathParam("path") String path,
@DefaultValue("0") @QueryParam("page") int page,
@DefaultValue("10") @QueryParam("pageSize") int pageSize) throws IOException, RevisionNotFoundException, RepositoryNotFoundException {
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
log.info("Get changesets of the file {} and revision {}", path, revision);
Repository repository = repositoryService.getRepository();
ChangesetPagingResult changesets = repositoryService.getLogCommand()
.setPagingStart(page)
.setPagingLimit(pageSize)
.setPath(path)
.setStartChangeset(revision)
.getChangesets();
if (changesets != null && changesets.getChangesets() != null) {
PageResult<Changeset> pageResult = new PageResult<>(changesets.getChangesets(), changesets.getTotal());
return Response.ok(fileHistoryCollectionToDtoMapper.map(page, pageSize, pageResult, repository, revision, path)).build();
} else {
String message = String.format("for the revision %s and the file %s there is no changesets", revision, path);
log.error(message);
throw new InternalRepositoryException(message);
}
}
}
}

View File

@@ -12,6 +12,8 @@ import sonia.scm.repository.SubRepository;
import javax.inject.Inject;
import java.net.URI;
import static de.otto.edison.hal.Link.link;
@Mapper
public abstract class FileObjectToFileObjectDtoMapper extends BaseMapper<FileObject, FileObjectDto> {
@@ -30,6 +32,7 @@ public abstract class FileObjectToFileObjectDtoMapper extends BaseMapper<FileObj
links.self(addPath(resourceLinks.source().sourceWithPath(namespaceAndName.getNamespace(), namespaceAndName.getName(), revision, ""), path));
} else {
links.self(addPath(resourceLinks.source().content(namespaceAndName.getNamespace(), namespaceAndName.getName(), revision, ""), path));
links.single(link("history", resourceLinks.fileHistory().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), revision, path)));
}
dto.add(links.build());

View File

@@ -0,0 +1,15 @@
package sonia.scm.api.v2.resources;
import sonia.scm.api.rest.StatusExceptionMapper;
import sonia.scm.repository.InternalRepositoryException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
@Provider
public class InternalRepositoryExceptionMapper extends StatusExceptionMapper<InternalRepositoryException> {
public InternalRepositoryExceptionMapper() {
super(InternalRepositoryException.class, Response.Status.INTERNAL_SERVER_ERROR);
}
}

View File

@@ -40,6 +40,7 @@ public class RepositoryResource {
private final Provider<ContentResource> contentResource;
private final Provider<PermissionRootResource> permissionRootResource;
private final Provider<DiffRootResource> diffRootResource;
private final Provider<FileHistoryRootResource> fileHistoryRootResource;
@Inject
public RepositoryResource(
@@ -50,7 +51,8 @@ public class RepositoryResource {
Provider<ChangesetRootResource> changesetRootResource,
Provider<SourceRootResource> sourceRootResource, Provider<ContentResource> contentResource,
Provider<PermissionRootResource> permissionRootResource,
Provider<DiffRootResource> diffRootResource) {
Provider<DiffRootResource> diffRootResource,
Provider<FileHistoryRootResource> fileHistoryRootResource) {
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
this.manager = manager;
this.repositoryToDtoMapper = repositoryToDtoMapper;
@@ -62,6 +64,7 @@ public class RepositoryResource {
this.contentResource = contentResource;
this.permissionRootResource = permissionRootResource;
this.diffRootResource = diffRootResource;
this.fileHistoryRootResource = fileHistoryRootResource;
}
/**
@@ -165,6 +168,11 @@ public class RepositoryResource {
return changesetRootResource.get();
}
@Path("history/")
public FileHistoryRootResource history() {
return fileHistoryRootResource.get();
}
@Path("sources/")
public SourceRootResource sources() {
return sourceRootResource.get();

View File

@@ -307,6 +307,23 @@ class ResourceLinks {
}
}
public FileHistoryLinks fileHistory() {
return new FileHistoryLinks(uriInfoStore.get());
}
static class FileHistoryLinks {
private final LinkBuilder fileHistoryLinkBuilder;
FileHistoryLinks(UriInfo uriInfo) {
fileHistoryLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, FileHistoryRootResource.class);
}
String self(String namespace, String name, String changesetId, String path) {
return fileHistoryLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("history").parameters().method("getAll").parameters(changesetId, path).href();
}
}
public SourceLinks source() {
return new SourceLinks(uriInfoStore.get());
}