mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-01-26 01:09:10 +01:00
Add REST endpoint for namespace permissions
This commit is contained in:
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.headers.Header;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.repository.Namespace;
|
||||
import sonia.scm.repository.NamespaceManager;
|
||||
import sonia.scm.repository.NamespacePermissions;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.validation.Valid;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static sonia.scm.AlreadyExistsException.alreadyExists;
|
||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||
import static sonia.scm.NotFoundException.notFound;
|
||||
import static sonia.scm.api.v2.resources.RepositoryPermissionDto.GROUP_PREFIX;
|
||||
|
||||
@Slf4j
|
||||
public class NamespacePermissionResource {
|
||||
|
||||
private RepositoryPermissionDtoToRepositoryPermissionMapper dtoToModelMapper;
|
||||
private RepositoryPermissionToRepositoryPermissionDtoMapper modelToDtoMapper;
|
||||
private RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper;
|
||||
private ResourceLinks resourceLinks;
|
||||
private final NamespaceManager manager;
|
||||
|
||||
@Inject
|
||||
public NamespacePermissionResource(
|
||||
RepositoryPermissionDtoToRepositoryPermissionMapper dtoToModelMapper,
|
||||
RepositoryPermissionToRepositoryPermissionDtoMapper modelToDtoMapper,
|
||||
RepositoryPermissionCollectionToDtoMapper repositoryPermissionCollectionToDtoMapper,
|
||||
ResourceLinks resourceLinks,
|
||||
NamespaceManager manager) {
|
||||
this.dtoToModelMapper = dtoToModelMapper;
|
||||
this.modelToDtoMapper = modelToDtoMapper;
|
||||
this.repositoryPermissionCollectionToDtoMapper = repositoryPermissionCollectionToDtoMapper;
|
||||
this.resourceLinks = resourceLinks;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new namespace permission for the user or group
|
||||
*
|
||||
* @param permission permission to add
|
||||
* @return a web response with the status code 201 and the url to GET the added permission
|
||||
*/
|
||||
@POST
|
||||
@Path("")
|
||||
@Consumes(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "Create namespace-specific permission", description = "Adds a new permission to the namespace for the user or group.", tags = {"Namespace", "Permissions"})
|
||||
@ApiResponse(
|
||||
responseCode = "201",
|
||||
description = "creates",
|
||||
headers = @Header(
|
||||
name = "Location",
|
||||
description = "uri of the created permission",
|
||||
schema = @Schema(type = "string")
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "not found",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
@ApiResponse(responseCode = "409", description = "conflict")
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
)
|
||||
)
|
||||
public Response create(@PathParam("namespace") String namespaceName, @Valid RepositoryPermissionDto permission) {
|
||||
log.info("try to add new permission: {}", permission);
|
||||
Namespace namespace = load(namespaceName);
|
||||
NamespacePermissions.permissionWrite().check();
|
||||
checkPermissionAlreadyExists(permission, namespace);
|
||||
namespace.addPermission(dtoToModelMapper.map(permission));
|
||||
manager.modify(namespace);
|
||||
String urlPermissionName = modelToDtoMapper.getUrlPermissionName(permission);
|
||||
return Response.created(URI.create(resourceLinks.namespacePermission().self(namespaceName, urlPermissionName))).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the searched permission with permission name related to a namespace
|
||||
*
|
||||
* @param namespaceName the name of the namespace
|
||||
* @return the http response with a list of permissionDto objects
|
||||
* @throws NotFoundException if the namespace or the permission does not exists
|
||||
*/
|
||||
@GET
|
||||
@Path("{permission-name}")
|
||||
@Produces(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "Get single repository-specific permission", description = "Get the searched permission with permission name related to a repository.", tags = {"Repository", "Permissions"})
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "success",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY_PERMISSION,
|
||||
schema = @Schema(implementation = RepositoryPermissionDto.class)
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "not found",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
)
|
||||
)
|
||||
public RepositoryPermissionDto get(@PathParam("namespace") String namespaceName, @PathParam("permission-name") String permissionName) {
|
||||
Namespace namespace = load(namespaceName);
|
||||
NamespacePermissions.permissionRead().check();
|
||||
return
|
||||
namespace.getPermissions()
|
||||
.stream()
|
||||
.filter(filterPermission(permissionName))
|
||||
.map(permission -> modelToDtoMapper.map(permission, namespace))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> notFound(entity(RepositoryPermission.class, permissionName).in(Namespace.class, namespaceName)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all permissions related to a namespace
|
||||
*
|
||||
* @param namespaceMame the name of the namespace
|
||||
* @return the http response with a list of permissionDto objects
|
||||
* @throws NotFoundException if the namespace does not exists
|
||||
*/
|
||||
@GET
|
||||
@Path("")
|
||||
@Produces(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "List of namespace-specific permissions", description = "Get all permissions related to a namespace.", tags = {"Repository", "Permissions"})
|
||||
@ApiResponse(
|
||||
responseCode = "200",
|
||||
description = "success",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.REPOSITORY_PERMISSION,
|
||||
schema = @Schema(implementation = RepositoryPermissionDto.class)
|
||||
)
|
||||
)
|
||||
@ApiResponse(
|
||||
responseCode = "404",
|
||||
description = "not found",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
))
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
)
|
||||
)
|
||||
public HalRepresentation getAll(@PathParam("namespace") String namespaceMame) {
|
||||
Namespace namespace = load(namespaceMame);
|
||||
NamespacePermissions.permissionRead().check();
|
||||
return repositoryPermissionCollectionToDtoMapper.map(namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a permission to the user or group managed by the repository
|
||||
* ignore the user input for groupPermission and take it from the path parameter (if the group prefix (@) exists it is a group permission)
|
||||
*
|
||||
* @param permission permission to modify
|
||||
* @param permissionName permission to modify
|
||||
* @return a web response with the status code 204
|
||||
*/
|
||||
@PUT
|
||||
@Path("{permission-name}")
|
||||
@Consumes(VndMediaType.REPOSITORY_PERMISSION)
|
||||
@Operation(summary = "Update repository-specific permission", description = "Update a permission to the user or group managed by the repository.", tags = {"Repository", "Permissions"})
|
||||
@ApiResponse(responseCode = "204", description = "update success")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
)
|
||||
)
|
||||
public void update(@PathParam("namespace") String namespaceName,
|
||||
@PathParam("permission-name") String permissionName,
|
||||
@Valid RepositoryPermissionDto permission) {
|
||||
log.info("try to update the permission with name: {}. the modified permission is: {}", permissionName, permission);
|
||||
Namespace namespace = load(namespaceName);
|
||||
NamespacePermissions.permissionWrite().check();
|
||||
String extractedPermissionName = getPermissionName(permissionName);
|
||||
if (!isPermissionExist(new RepositoryPermissionDto(extractedPermissionName, isGroupPermission(permissionName)), namespace)) {
|
||||
throw notFound(entity(RepositoryPermission.class, permissionName).in(Namespace.class, namespaceName));
|
||||
}
|
||||
permission.setGroupPermission(isGroupPermission(permissionName));
|
||||
if (!extractedPermissionName.equals(permission.getName())) {
|
||||
checkPermissionAlreadyExists(permission, namespace);
|
||||
}
|
||||
|
||||
RepositoryPermission existingPermission = namespace.getPermissions()
|
||||
.stream()
|
||||
.filter(filterPermission(permissionName))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> notFound(entity(RepositoryPermission.class, permissionName).in(Namespace.class, namespaceName)));
|
||||
RepositoryPermission newPermission = dtoToModelMapper.map(permission);
|
||||
if (!namespace.removePermission(existingPermission)) {
|
||||
throw new IllegalStateException(String.format("could not delete modified permission %s from namespace %s", existingPermission, namespaceName));
|
||||
}
|
||||
namespace.addPermission(newPermission);
|
||||
manager.modify(namespace);
|
||||
log.info("the permission with name: {} is updated.", permissionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a permission to the user or group managed by the repository
|
||||
*
|
||||
* @param permissionName permission to delete
|
||||
* @return a web response with the status code 204
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{permission-name}")
|
||||
@Operation(summary = "Delete repository-specific permission", description = "Delete a permission with the given name.", tags = {"Repository", "Permissions"})
|
||||
@ApiResponse(responseCode = "204", description = "delete success or nothing to delete")
|
||||
@ApiResponse(responseCode = "401", description = "not authenticated / invalid credentials")
|
||||
@ApiResponse(responseCode = "403", description = "not authorized")
|
||||
@ApiResponse(
|
||||
responseCode = "500",
|
||||
description = "internal server error",
|
||||
content = @Content(
|
||||
mediaType = VndMediaType.ERROR_TYPE,
|
||||
schema = @Schema(implementation = ErrorDto.class)
|
||||
)
|
||||
)
|
||||
public void delete(@PathParam("namespace") String namespaceName,
|
||||
@PathParam("permission-name") String permissionName) {
|
||||
log.info("try to delete the permission with name: {}.", permissionName);
|
||||
Namespace namespace = load(namespaceName);
|
||||
NamespacePermissions.permissionWrite().check();
|
||||
namespace.getPermissions()
|
||||
.stream()
|
||||
.filter(filterPermission(permissionName))
|
||||
.findFirst()
|
||||
.ifPresent(permission -> {
|
||||
namespace.removePermission(permission);
|
||||
manager.modify(namespace);
|
||||
});
|
||||
log.info("the permission with name: {} is deleted.", permissionName);
|
||||
}
|
||||
|
||||
private Predicate<RepositoryPermission> filterPermission(String name) {
|
||||
return permission -> getPermissionName(name).equals(permission.getName())
|
||||
&&
|
||||
permission.isGroupPermission() == isGroupPermission(name);
|
||||
}
|
||||
|
||||
private String getPermissionName(String permissionName) {
|
||||
return Optional.of(permissionName)
|
||||
.filter(p -> !isGroupPermission(permissionName))
|
||||
.orElse(permissionName.substring(1));
|
||||
}
|
||||
|
||||
private boolean isGroupPermission(String permissionName) {
|
||||
return permissionName.startsWith(GROUP_PREFIX);
|
||||
}
|
||||
|
||||
private Namespace load(String namespaceMame) {
|
||||
return manager.get(namespaceMame)
|
||||
.orElseThrow(() -> notFound(entity("Namespace", namespaceMame)));
|
||||
}
|
||||
|
||||
private void checkPermissionAlreadyExists(RepositoryPermissionDto permission, Namespace namespace) {
|
||||
if (isPermissionExist(permission, namespace)) {
|
||||
throw alreadyExists(entity("Permission", permission.getName()).in(Namespace.class, namespace.getNamespace()));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPermissionExist(RepositoryPermissionDto permission, Namespace namespace) {
|
||||
return namespace.getPermissions()
|
||||
.stream()
|
||||
.anyMatch(p -> p.getName().equals(permission.getName()) && p.isGroupPermission() == permission.isGroupPermission());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
@@ -44,11 +45,13 @@ public class NamespaceResource {
|
||||
|
||||
private final RepositoryManager manager;
|
||||
private final NamespaceToNamespaceDtoMapper namespaceMapper;
|
||||
private final Provider<NamespacePermissionResource> namespacePermissionResource;
|
||||
|
||||
@Inject
|
||||
public NamespaceResource(RepositoryManager manager, NamespaceToNamespaceDtoMapper namespaceMapper) {
|
||||
public NamespaceResource(RepositoryManager manager, NamespaceToNamespaceDtoMapper namespaceMapper, Provider<NamespacePermissionResource> namespacePermissionResource) {
|
||||
this.manager = manager;
|
||||
this.namespaceMapper = namespaceMapper;
|
||||
this.namespacePermissionResource = namespacePermissionResource;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,4 +100,8 @@ public class NamespaceResource {
|
||||
.orElseThrow(() -> notFound(entity("Namespace", namespace)));
|
||||
}
|
||||
|
||||
@Path("permissions")
|
||||
public NamespacePermissionResource permissions() {
|
||||
return namespacePermissionResource.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.Links;
|
||||
import sonia.scm.repository.NamespacePermissions;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static de.otto.edison.hal.Link.link;
|
||||
@@ -39,12 +42,15 @@ class NamespaceToNamespaceDtoMapper {
|
||||
}
|
||||
|
||||
NamespaceDto map(String namespace) {
|
||||
return new NamespaceDto(
|
||||
namespace,
|
||||
linkingTo()
|
||||
.self(links.namespace().self(namespace))
|
||||
.single(link("repositories", links.repositoryCollection().forNamespace(namespace)))
|
||||
.build()
|
||||
);
|
||||
Links.Builder linkingTo = linkingTo();
|
||||
linkingTo
|
||||
.self(links.namespace().self(namespace))
|
||||
.single(link("repositories", links.repositoryCollection().forNamespace(namespace)));
|
||||
|
||||
if (NamespacePermissions.permissionRead().isPermitted()) {
|
||||
linkingTo
|
||||
.single(link("permissions", links.namespacePermission().all(namespace)));
|
||||
}
|
||||
return new NamespaceDto(namespace, linkingTo.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,15 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import de.otto.edison.hal.Embedded;
|
||||
import de.otto.edison.hal.HalRepresentation;
|
||||
import de.otto.edison.hal.Links;
|
||||
import sonia.scm.repository.Namespace;
|
||||
import sonia.scm.repository.NamespacePermissions;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
|
||||
@@ -57,6 +59,14 @@ public class RepositoryPermissionCollectionToDtoMapper {
|
||||
return new HalRepresentation(createLinks(repository), embedDtos(repositoryPermissionDtoList));
|
||||
}
|
||||
|
||||
public HalRepresentation map(Namespace namespace) {
|
||||
List<RepositoryPermissionDto> repositoryPermissionDtoList = namespace.getPermissions()
|
||||
.stream()
|
||||
.map(permission -> repositoryPermissionToRepositoryPermissionDtoMapper.map(permission, namespace))
|
||||
.collect(toList());
|
||||
return new HalRepresentation(createLinks(namespace), embedDtos(repositoryPermissionDtoList));
|
||||
}
|
||||
|
||||
private Links createLinks(Repository repository) {
|
||||
RepositoryPermissions.permissionRead(repository).check();
|
||||
Links.Builder linksBuilder = linkingTo()
|
||||
@@ -67,6 +77,16 @@ public class RepositoryPermissionCollectionToDtoMapper {
|
||||
return linksBuilder.build();
|
||||
}
|
||||
|
||||
private Links createLinks(Namespace namespace) {
|
||||
NamespacePermissions.permissionRead().check();
|
||||
Links.Builder linksBuilder = linkingTo()
|
||||
.with(Links.linkingTo().self(resourceLinks.namespacePermission().all(namespace.getNamespace())).build());
|
||||
if (NamespacePermissions.permissionWrite().isPermitted()) {
|
||||
linksBuilder.single(link("create", resourceLinks.namespacePermission().create(namespace.getNamespace())));
|
||||
}
|
||||
return linksBuilder.build();
|
||||
}
|
||||
|
||||
private Embedded embedDtos(List<RepositoryPermissionDto> repositoryPermissionDtoList) {
|
||||
return embeddedBuilder()
|
||||
.with("permissions", repositoryPermissionDtoList)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.Links;
|
||||
@@ -31,6 +31,8 @@ import org.mapstruct.Context;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import sonia.scm.repository.Namespace;
|
||||
import sonia.scm.repository.NamespacePermissions;
|
||||
import sonia.scm.repository.RepositoryPermission;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
@@ -51,18 +53,19 @@ public abstract class RepositoryPermissionToRepositoryPermissionDtoMapper {
|
||||
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
|
||||
public abstract RepositoryPermissionDto map(RepositoryPermission permission, @Context Repository repository);
|
||||
|
||||
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
|
||||
public abstract RepositoryPermissionDto map(RepositoryPermission permission, @Context Namespace namespace);
|
||||
|
||||
@BeforeMapping
|
||||
void validatePermissions(@Context Repository repository) {
|
||||
RepositoryPermissions.permissionRead(repository).check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the self, update and delete links.
|
||||
*
|
||||
* @param target the mapped dto
|
||||
* @param repository the repository
|
||||
*/
|
||||
@BeforeMapping
|
||||
void validatePermissions(@Context Namespace namespace) {
|
||||
NamespacePermissions.permissionRead().check();
|
||||
}
|
||||
|
||||
@AfterMapping
|
||||
void appendLinks(@MappingTarget RepositoryPermissionDto target, @Context Repository repository) {
|
||||
String permissionName = getUrlPermissionName(target);
|
||||
@@ -75,6 +78,18 @@ public abstract class RepositoryPermissionToRepositoryPermissionDtoMapper {
|
||||
target.add(linksBuilder.build());
|
||||
}
|
||||
|
||||
@AfterMapping
|
||||
void appendLinks(@MappingTarget RepositoryPermissionDto target, @Context Namespace namespace) {
|
||||
String permissionName = getUrlPermissionName(target);
|
||||
Links.Builder linksBuilder = linkingTo()
|
||||
.self(resourceLinks.namespacePermission().self(namespace.getNamespace(), permissionName));
|
||||
if (NamespacePermissions.permissionWrite().isPermitted()) {
|
||||
linksBuilder.single(link("update", resourceLinks.namespacePermission().update(namespace.getNamespace(), permissionName)));
|
||||
linksBuilder.single(link("delete", resourceLinks.namespacePermission().delete(namespace.getNamespace(), permissionName)));
|
||||
}
|
||||
target.add(linksBuilder.build());
|
||||
}
|
||||
|
||||
public String getUrlPermissionName(RepositoryPermissionDto repositoryPermissionDto) {
|
||||
return Optional.of(repositoryPermissionDto.getName())
|
||||
.filter(p -> !repositoryPermissionDto.isGroupPermission())
|
||||
|
||||
@@ -916,4 +916,40 @@ class ResourceLinks {
|
||||
return namespaceLinkBuilder.method("getNamespaceResource").parameters().method("get").parameters(namespace).href();
|
||||
}
|
||||
}
|
||||
|
||||
public NamespacePermissionLinks namespacePermission() {
|
||||
return new NamespacePermissionLinks(scmPathInfoStore.get());
|
||||
}
|
||||
|
||||
static class NamespacePermissionLinks {
|
||||
private final LinkBuilder permissionLinkBuilder;
|
||||
|
||||
NamespacePermissionLinks(ScmPathInfo pathInfo) {
|
||||
permissionLinkBuilder = new LinkBuilder(pathInfo, NamespaceRootResource.class, NamespaceResource.class, NamespacePermissionResource.class);
|
||||
}
|
||||
|
||||
String all(String namespace) {
|
||||
return permissionLinkBuilder.method("getNamespaceResource").parameters(namespace).method("permissions").parameters().method("getAll").parameters().href();
|
||||
}
|
||||
|
||||
String create(String namespace) {
|
||||
return permissionLinkBuilder.method("getNamespaceResource").parameters(namespace).method("permissions").parameters().method("create").parameters().href();
|
||||
}
|
||||
|
||||
String self(String namespace, String permissionName) {
|
||||
return getLink(namespace, permissionName, "get");
|
||||
}
|
||||
|
||||
String update(String namespace, String permissionName) {
|
||||
return getLink(namespace, permissionName, "update");
|
||||
}
|
||||
|
||||
String delete(String namespace, String permissionName) {
|
||||
return getLink(namespace, permissionName, "delete");
|
||||
}
|
||||
|
||||
private String getLink(String namespace, String permissionName, String methodName) {
|
||||
return permissionLinkBuilder.method("getNamespaceResource").parameters(namespace).method("permissions").parameters().method(methodName).parameters(permissionName).href();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,10 +64,12 @@ import sonia.scm.net.ahc.XmlContentTransformer;
|
||||
import sonia.scm.plugin.DefaultPluginManager;
|
||||
import sonia.scm.plugin.PluginLoader;
|
||||
import sonia.scm.plugin.PluginManager;
|
||||
import sonia.scm.repository.DefaultNamespaceManager;
|
||||
import sonia.scm.repository.DefaultRepositoryManager;
|
||||
import sonia.scm.repository.DefaultRepositoryProvider;
|
||||
import sonia.scm.repository.DefaultRepositoryRoleManager;
|
||||
import sonia.scm.repository.HealthCheckContextListener;
|
||||
import sonia.scm.repository.NamespaceManager;
|
||||
import sonia.scm.repository.NamespaceStrategy;
|
||||
import sonia.scm.repository.NamespaceStrategyProvider;
|
||||
import sonia.scm.repository.Repository;
|
||||
@@ -191,6 +193,7 @@ class ScmServletModule extends ServletModule {
|
||||
bindDecorated(GroupManager.class, DefaultGroupManager.class,
|
||||
GroupManagerProvider.class);
|
||||
bind(GroupDisplayManager.class, DefaultGroupDisplayManager.class);
|
||||
bind(NamespaceManager.class, DefaultNamespaceManager.class);
|
||||
bind(GroupCollector.class, DefaultGroupCollector.class);
|
||||
bind(CGIExecutorFactory.class, DefaultCGIExecutorFactory.class);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user