merge with branch feature/repository_config_v2_endpoint

This commit is contained in:
Philipp Czora
2018-08-08 15:41:29 +02:00
72 changed files with 2948 additions and 198 deletions

View File

@@ -1,16 +0,0 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import org.mapstruct.Mapping;
import java.time.Instant;
abstract class BaseMapper<T, D extends HalRepresentation> {
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
public abstract D map(T object);
Instant mapTime(Long epochMilli) {
return epochMilli == null? null: Instant.ofEpochMilli(epochMilli);
}
}

View File

@@ -33,6 +33,7 @@ public class ConfigDto extends HalRepresentation {
private String pluginUrl;
private long loginAttemptLimitTimeout;
private boolean enabledXsrfProtection;
private String defaultNamespaceStrategy;
@Override
@SuppressWarnings("squid:S1185") // We want to have this method available in this package

View File

@@ -14,9 +14,7 @@ import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
/**
* RESTful Web Service Resource to manage the configuration.
@@ -46,7 +44,7 @@ public class ConfigResource {
@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 global config"),
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"configuration:read:global\" privilege"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response get() {
@@ -61,19 +59,19 @@ public class ConfigResource {
/**
* Modifies the global scm config.
*
* @param configDto new global scm configuration as DTO
* @param configDto new configuration object
*/
@PUT
@Path("")
@Consumes(VndMediaType.CONFIG)
@StatusCodes({
@ResponseCode(code = 201, condition = "update success"),
@ResponseCode(code = 204, condition = "update success"),
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
@ResponseCode(code = 403, condition = "not authorized, the current user has no privileges to update the global config"),
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"configuration:write:global\" privilege"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(TypeHint.NO_CONTENT.class)
public Response update(ConfigDto configDto, @Context UriInfo uriInfo) {
public Response update(ConfigDto configDto) {
// This *could* be moved to ScmConfiguration or ScmConfigurationUtil classes.
// But to where to check? load() or store()? Leave it for now, SCMv1 legacy that can be cleaned up later.

View File

@@ -24,6 +24,7 @@ public class GroupDto extends HalRepresentation {
private List<String> members;
@Override
@SuppressWarnings("squid:S1185") // We want to have this method available in this package
protected HalRepresentation add(Links links) {
return super.add(links);
}

View File

@@ -1,115 +0,0 @@
package sonia.scm.api.v2.resources;
import com.google.common.collect.ImmutableList;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.util.Arrays;
/**
* This class is used to create links for JAX-RS resources. Create a new instance specifying all resource classes used
* to process the request. Then for each of these classes call <code>builder.method(...).parameters(...)</code> for each
* of these classes consecutively. The builder itself is immutable, so that each instance is reusable and you get a new
* builder for each method.
*
* <pre>
* LinkBuilder builder = new LinkBuilder(uriInfo, MainResource.class, SubResource.class);
* Link link = builder
* .method("sub")
* .parameters("param")
* .method("x")
* .parameters("param_1", "param_2")
* .create();
* </pre>
*/
class LinkBuilder {
private final UriInfo uriInfo;
private final Class[] classes;
private final ImmutableList<Call> calls;
LinkBuilder(UriInfo uriInfo, Class... classes) {
this(uriInfo, classes, ImmutableList.of());
}
private LinkBuilder(UriInfo uriInfo, Class[] classes, ImmutableList<Call> calls) {
this.uriInfo = uriInfo;
this.classes = classes;
this.calls = calls;
}
Parameters method(String method) {
if (calls.size() >= classes.length) {
throw new IllegalStateException("no more classes for methods");
}
return new Parameters(method);
}
URI create() {
if (calls.size() < classes.length) {
throw new IllegalStateException("not enough methods for all classes");
}
URI baseUri = uriInfo.getBaseUri();
URI relativeUri = createRelativeUri();
URI absoluteUri = baseUri.resolve(relativeUri);
return absoluteUri;
}
String href() {
return create().toString();
}
private LinkBuilder add(String method, String[] parameters) {
return new LinkBuilder(uriInfo, classes, appendNewCall(method, parameters));
}
private ImmutableList<Call> appendNewCall(String method, String[] parameters) {
return ImmutableList.<Call> builder().addAll(calls).add(createNewCall(method, parameters)).build();
}
private Call createNewCall(String method, String[] parameters) {
return new Call(LinkBuilder.this.classes[calls.size()], method, parameters);
}
private URI createRelativeUri() {
UriBuilder uriBuilder = userUriBuilder();
calls.forEach(call -> uriBuilder.path(call.clazz, call.method));
String[] concatenatedParameters = calls
.stream()
.map(call -> call.parameters)
.flatMap(Arrays::stream)
.toArray(String[]::new);
return uriBuilder.build((Object[]) concatenatedParameters);
}
private UriBuilder userUriBuilder() {
return UriBuilder.fromResource(classes[0]);
}
class Parameters {
private final String method;
private Parameters(String method) {
this.method = method;
}
LinkBuilder parameters(String... parameters) {
return LinkBuilder.this.add(method, parameters);
}
}
private static class Call {
private final Class clazz;
private final String method;
private final String[] parameters;
private Call(Class clazz, String method, String[] parameters) {
this.clazz = clazz;
this.method = method;
this.parameters = parameters;
}
}
}

View File

@@ -15,13 +15,11 @@ import static de.otto.edison.hal.Links.linkingTo;
// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection.
@SuppressWarnings("squid:S3306")
@Mapper
public abstract class ScmConfigurationToConfigDtoMapper {
public abstract class ScmConfigurationToConfigDtoMapper extends BaseMapper<ScmConfiguration, ConfigDto> {
@Inject
private ResourceLinks resourceLinks;
public abstract ConfigDto map(ScmConfiguration config);
@AfterMapping
void appendLinks(ScmConfiguration config, @MappingTarget ConfigDto target) {
Links.Builder linksBuilder = linkingTo().self(resourceLinks.config().self());

View File

@@ -1,19 +0,0 @@
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;
}
}