Implement git config v2 endpoint

This commit is contained in:
Michael Behlendorf
2018-07-17 13:39:55 +02:00
parent 65e6bb9bc2
commit ada3d6679f
17 changed files with 420 additions and 4 deletions

View File

@@ -0,0 +1,23 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import de.otto.edison.hal.Links;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.xml.bind.annotation.XmlElement;
@NoArgsConstructor
@Getter
@Setter
public class GitConfigDto extends SimpleRepositoryConfigDto {
@XmlElement(name = "gc-expression")
private String gcExpression;
@Override
protected HalRepresentation add(Links links) {
return super.add(links);
}
}

View File

@@ -0,0 +1,11 @@
package sonia.scm.api.v2.resources;
import org.mapstruct.Mapper;
import sonia.scm.repository.GitConfig;
// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection.
@SuppressWarnings("squid:S3306")
@Mapper
public abstract class GitConfigDtoToGitConfigMapper {
public abstract GitConfig map(GitConfigDto dto);
}

View File

@@ -0,0 +1,93 @@
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 org.apache.shiro.SecurityUtils;
import sonia.scm.repository.GitConfig;
import sonia.scm.repository.GitRepositoryHandler;
import sonia.scm.security.Role;
import sonia.scm.web.GitVndMediaType;
import javax.inject.Inject;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@Path(GitConfigResource.GIT_CONFIG_PATH_V2)
public class GitConfigResource {
static final String GIT_CONFIG_PATH_V2 = "v2/config/repository/git";
private final GitConfigDtoToGitConfigMapper dtoToConfigMapper;
private final GitConfigToGitConfigDtoMapper configToDtoMapper;
private final GitRepositoryHandler repositoryHandler;
@Inject
public GitConfigResource(GitConfigDtoToGitConfigMapper dtoToConfigMapper, GitConfigToGitConfigDtoMapper configToDtoMapper, GitRepositoryHandler repositoryHandler) {
this.dtoToConfigMapper = dtoToConfigMapper;
this.configToDtoMapper = configToDtoMapper;
this.repositoryHandler = repositoryHandler;
}
/**
* Returns the git config.
*/
@GET
@Path("")
@Produces(GitVndMediaType.GIT_CONFIG)
@TypeHint(GitConfigDto.class)
@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 git config"),
@ResponseCode(code = 500, condition = "internal server error")
})
public Response get() {
Response response;
if (SecurityUtils.getSubject().hasRole(Role.ADMIN)) {
GitConfig config = repositoryHandler.getConfig();
if (config == null) {
config = new GitConfig();
repositoryHandler.setConfig(config);
}
response = Response.ok(configToDtoMapper.map(config)).build();
} else {
response = Response.status(Response.Status.FORBIDDEN).build();
}
return response;
}
/**
* Modifies the git config.
*
* @param configDto new git configuration as DTO
*/
@PUT
@Path("")
@Consumes(GitVndMediaType.GIT_CONFIG)
@StatusCodes({
@ResponseCode(code = 201, 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 git config"),
@ResponseCode(code = 500, condition = "internal server error")
})
@TypeHint(TypeHint.NO_CONTENT.class)
public Response update(@Context UriInfo uriInfo, GitConfigDto configDto) {
Response response;
if (SecurityUtils.getSubject().hasRole(Role.ADMIN)) {
repositoryHandler.setConfig(dtoToConfigMapper.map(configDto));
repositoryHandler.storeConfig();
response = Response.created(uriInfo.getRequestUri()).build();
} else {
response = Response.status(Response.Status.FORBIDDEN).build();
}
return response;
}
}

View File

@@ -0,0 +1,45 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.Links;
import org.apache.shiro.SecurityUtils;
import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import sonia.scm.repository.GitConfig;
import sonia.scm.security.Role;
import javax.inject.Inject;
import static de.otto.edison.hal.Link.link;
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 GitConfigToGitConfigDtoMapper {
@Inject
private UriInfoStore uriInfoStore;
public abstract GitConfigDto map(GitConfig config);
@AfterMapping
void appendLinks(GitConfig config, @MappingTarget GitConfigDto target) {
Links.Builder linksBuilder = linkingTo().self(self());
// TODO: ConfigPermissions?
if (SecurityUtils.getSubject().hasRole(Role.ADMIN)) {
linksBuilder.single(link("update", update()));
}
target.add(linksBuilder.build());
}
private String self() {
LinkBuilder linkBuilder = new LinkBuilder(uriInfoStore.get(), GitConfigResource.class);
return linkBuilder.method("get").parameters().href();
}
private String update() {
LinkBuilder linkBuilder = new LinkBuilder(uriInfoStore.get(), GitConfigResource.class);
return linkBuilder.method("update").parameters().href();
}
}

View File

@@ -0,0 +1,16 @@
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 {
@Override
protected void configure() {
bind(GitConfigDtoToGitConfigMapper.class).to(Mappers.getMapper(GitConfigDtoToGitConfigMapper.class).getClass());
bind(GitConfigToGitConfigDtoMapper.class).to(Mappers.getMapper(GitConfigToGitConfigDtoMapper.class).getClass());
bind(UriInfoStore.class).in(ServletScopes.REQUEST);
}
}

View File

@@ -0,0 +1,17 @@
package sonia.scm.api.v2.resources;
import de.otto.edison.hal.HalRepresentation;
import lombok.Getter;
import lombok.Setter;
import javax.xml.bind.annotation.XmlElement;
import java.io.File;
@Getter
@Setter
public abstract class SimpleRepositoryConfigDto extends HalRepresentation {
private boolean disabled = false;
@XmlElement(name = "repository-directory")
private File repositoryDirectory;
}

View File

@@ -55,5 +55,8 @@ public class GitConfig extends SimpleRepositoryConfig {
{
return gcExpression;
}
public void setGcExpression(String gcExpression) {
this.gcExpression = gcExpression;
}
}

View File

@@ -0,0 +1,5 @@
package sonia.scm.web;
public class GitVndMediaType {
public static final String GIT_CONFIG = VndMediaType.PREFIX + "gitConfig" + VndMediaType.SUFFIX;
}