This commit is contained in:
René Pfeuffer
2018-11-06 09:26:41 +01:00
119 changed files with 8479 additions and 5472 deletions

View File

@@ -0,0 +1,43 @@
package sonia.scm.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import sonia.scm.api.v2.resources.ErrorDto;
import sonia.scm.api.v2.resources.ExceptionWithContextToErrorDtoMapper;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import java.util.Collections;
@Provider
public class FallbackExceptionMapper implements ExceptionMapper<Exception> {
private static final Logger logger = LoggerFactory.getLogger(FallbackExceptionMapper.class);
private static final String ERROR_CODE = "CmR8GCJb31";
private final ExceptionWithContextToErrorDtoMapper mapper;
@Inject
public FallbackExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
this.mapper = mapper;
}
@Override
public Response toResponse(Exception exception) {
logger.debug("map {} to status code 500", exception);
ErrorDto errorDto = new ErrorDto();
errorDto.setMessage("internal server error");
errorDto.setContext(Collections.emptyList());
errorDto.setErrorCode(ERROR_CODE);
errorDto.setTransactionId(MDC.get("transaction_id"));
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(errorDto)
.type(VndMediaType.ERROR_TYPE)
.build();
}
}

View File

@@ -13,7 +13,7 @@ public class ContextualExceptionMapper<E extends ExceptionWithContext> implement
private static final Logger logger = LoggerFactory.getLogger(ContextualExceptionMapper.class);
private ExceptionWithContextToErrorDtoMapper mapper;
private final ExceptionWithContextToErrorDtoMapper mapper;
private final Response.Status status;
private final Class<E> type;

View File

@@ -0,0 +1,17 @@
package sonia.scm.api.v2;
import sonia.scm.NotSupportedFeatureException;
import sonia.scm.api.rest.ContextualExceptionMapper;
import sonia.scm.api.v2.resources.ExceptionWithContextToErrorDtoMapper;
import javax.inject.Inject;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;
@Provider
public class NotSupportedFeatureExceptionMapper extends ContextualExceptionMapper<NotSupportedFeatureException> {
@Inject
public NotSupportedFeatureExceptionMapper(ExceptionWithContextToErrorDtoMapper mapper) {
super(NotSupportedFeatureException.class, Response.Status.BAD_REQUEST, mapper);
}
}

View File

@@ -23,6 +23,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.util.Optional;
@Slf4j
@@ -94,8 +95,12 @@ public class ChangesetRootResource {
.setStartChangeset(id)
.setEndChangeset(id)
.getChangesets();
if (changesets != null && changesets.getChangesets() != null && changesets.getChangesets().size() == 1) {
return Response.ok(changesetToChangesetDtoMapper.map(changesets.getChangesets().get(0), repository)).build();
if (changesets != null && changesets.getChangesets() != null && !changesets.getChangesets().isEmpty()) {
Optional<Changeset> changeset = changesets.getChangesets().stream().filter(ch -> ch.getId().equals(id)).findFirst();
if (!changeset.isPresent()) {
return Response.status(Response.Status.NOT_FOUND).build();
}
return Response.ok(changesetToChangesetDtoMapper.map(changeset.get(), repository)).build();
} else {
return Response.status(Response.Status.NOT_FOUND).build();
}

View File

@@ -122,7 +122,7 @@ public class ContentResource {
private void appendContentHeader(String path, byte[] head, Response.ResponseBuilder responseBuilder) {
ContentType contentType = ContentTypes.detect(path, head);
responseBuilder.header("Content-Type", contentType.getRaw());
contentType.getLanguage().ifPresent(language -> responseBuilder.header("Language", language));
contentType.getLanguage().ifPresent(language -> responseBuilder.header("X-Programming-Language", language));
}
private byte[] getHead(String revision, String path, RepositoryService repositoryService) throws IOException {

View File

@@ -4,22 +4,29 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
import sonia.scm.NotFoundException;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.api.DiffFormat;
import sonia.scm.repository.api.RepositoryService;
import sonia.scm.repository.api.RepositoryServiceFactory;
import sonia.scm.util.HttpUtil;
import sonia.scm.web.VndMediaType;
import javax.inject.Inject;
import javax.validation.constraints.Pattern;
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 javax.ws.rs.core.StreamingOutput;
public class DiffRootResource {
public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
private static final String DIFF_FORMAT_VALUES_REGEX = "NATIVE|GIT|UNIFIED";
private final RepositoryServiceFactory serviceFactory;
@Inject
@@ -48,12 +55,14 @@ public class DiffRootResource {
@ResponseCode(code = 404, condition = "not found, no revision with the specified param for the repository available or repository not found"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision){
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("revision") String revision , @Pattern(regexp = DIFF_FORMAT_VALUES_REGEX) @DefaultValue("NATIVE") @QueryParam("format") String format ){
HttpUtil.checkForCRLFInjection(revision);
DiffFormat diffFormat = DiffFormat.valueOf(format);
try (RepositoryService repositoryService = serviceFactory.create(new NamespaceAndName(namespace, name))) {
StreamingOutput responseEntry = output -> {
repositoryService.getDiffCommand()
.setRevision(revision)
.setFormat(diffFormat)
.retriveContent(output);
};
return Response.ok(responseEntry)

View File

@@ -17,7 +17,7 @@ public class ErrorDto {
private List<ContextEntry> context;
private String message;
@XmlElement(name = "violation")
@JsonInclude(JsonInclude.Include.NON_NULL)
@XmlElementWrapper(name = "violations")
private List<ConstraintViolationDto> violations;