mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-11 07:55:47 +01:00
Merge with 2.0.0-m3
This commit is contained in:
@@ -8,15 +8,8 @@ import java.time.Instant;
|
||||
|
||||
|
||||
@Mapper
|
||||
public abstract class GroupDtoToGroupMapper {
|
||||
public abstract class GroupDtoToGroupMapper extends BaseDtoMapper {
|
||||
|
||||
@Mapping(target = "creationDate", ignore = true)
|
||||
public abstract Group map(GroupDto groupDto);
|
||||
|
||||
Long mapDate(Instant value) {
|
||||
if (value != null) {
|
||||
return value.toEpochMilli();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
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.Repository;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.otto.edison.hal.Embedded.embeddedBuilder;
|
||||
import static de.otto.edison.hal.Link.link;
|
||||
import static de.otto.edison.hal.Links.linkingTo;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
public class PermissionCollectionToDtoMapper {
|
||||
|
||||
private final ResourceLinks resourceLinks;
|
||||
private final PermissionToPermissionDtoMapper permissionToPermissionDtoMapper;
|
||||
|
||||
@Inject
|
||||
public PermissionCollectionToDtoMapper(PermissionToPermissionDtoMapper permissionToPermissionDtoMapper, ResourceLinks resourceLinks) {
|
||||
this.resourceLinks = resourceLinks;
|
||||
this.permissionToPermissionDtoMapper = permissionToPermissionDtoMapper;
|
||||
}
|
||||
|
||||
public HalRepresentation map(Repository repository) {
|
||||
List<PermissionDto> permissionDtoList = repository.getPermissions()
|
||||
.stream()
|
||||
.map(permission -> permissionToPermissionDtoMapper.map(permission, repository))
|
||||
.collect(toList());
|
||||
return new HalRepresentation(createLinks(repository), embedDtos(permissionDtoList));
|
||||
}
|
||||
|
||||
private Links createLinks(Repository repository) {
|
||||
RepositoryPermissions.permissionRead(repository).check();
|
||||
Links.Builder linksBuilder = linkingTo()
|
||||
.with(Links.linkingTo().self(resourceLinks.permission().all(repository.getNamespace(), repository.getName())).build());
|
||||
if (RepositoryPermissions.permissionWrite(repository).isPermitted()) {
|
||||
linksBuilder.single(link("create", resourceLinks.permission().create(repository.getNamespace(), repository.getName())));
|
||||
}
|
||||
return linksBuilder.build();
|
||||
}
|
||||
|
||||
private Embedded embedDtos(List<PermissionDto> permissionDtoList) {
|
||||
return embeddedBuilder()
|
||||
.with("permissions", permissionDtoList)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import sonia.scm.repository.Permission;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryNotFoundException;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
import sonia.scm.web.VndMediaType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -26,23 +27,23 @@ import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
public class PermissionRootResource {
|
||||
|
||||
private PermissionDtoToPermissionMapper dtoToModelMapper;
|
||||
private PermissionToPermissionDtoMapper modelToDtoMapper;
|
||||
private PermissionCollectionToDtoMapper permissionCollectionToDtoMapper;
|
||||
private ResourceLinks resourceLinks;
|
||||
private final RepositoryManager manager;
|
||||
|
||||
|
||||
@Inject
|
||||
public PermissionRootResource(PermissionDtoToPermissionMapper dtoToModelMapper, PermissionToPermissionDtoMapper modelToDtoMapper, ResourceLinks resourceLinks, RepositoryManager manager) {
|
||||
public PermissionRootResource(PermissionDtoToPermissionMapper dtoToModelMapper, PermissionToPermissionDtoMapper modelToDtoMapper, PermissionCollectionToDtoMapper permissionCollectionToDtoMapper, ResourceLinks resourceLinks, RepositoryManager manager) {
|
||||
this.dtoToModelMapper = dtoToModelMapper;
|
||||
this.modelToDtoMapper = modelToDtoMapper;
|
||||
this.permissionCollectionToDtoMapper = permissionCollectionToDtoMapper;
|
||||
this.resourceLinks = resourceLinks;
|
||||
this.manager = manager;
|
||||
}
|
||||
@@ -65,9 +66,11 @@ public class PermissionRootResource {
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes(VndMediaType.PERMISSION)
|
||||
@Path("")
|
||||
public Response create(@PathParam("namespace") String namespace, @PathParam("name") String name, PermissionDto permission) throws Exception {
|
||||
log.info("try to add new permission: {}", permission);
|
||||
Repository repository = load(namespace, name);
|
||||
RepositoryPermissions.permissionWrite(repository).check();
|
||||
checkPermissionAlreadyExists(permission, repository);
|
||||
repository.getPermissions().add(dtoToModelMapper.map(permission));
|
||||
manager.modify(repository);
|
||||
@@ -94,11 +97,12 @@ public class PermissionRootResource {
|
||||
@Path("{permission-name}")
|
||||
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name, @PathParam("permission-name") String permissionName) throws NotFoundException {
|
||||
Repository repository = load(namespace, name);
|
||||
RepositoryPermissions.permissionRead(repository).check();
|
||||
return Response.ok(
|
||||
repository.getPermissions()
|
||||
.stream()
|
||||
.filter(permission -> permissionName.equals(permission.getName()))
|
||||
.map(permission -> modelToDtoMapper.map(permission, new NamespaceAndName(repository.getNamespace(), repository.getName())))
|
||||
.map(permission -> modelToDtoMapper.map(permission, repository))
|
||||
.findFirst()
|
||||
.orElseThrow(NotFoundException::new)
|
||||
).build();
|
||||
@@ -124,11 +128,8 @@ public class PermissionRootResource {
|
||||
@Path("")
|
||||
public Response getAll(@PathParam("namespace") String namespace, @PathParam("name") String name) throws RepositoryNotFoundException {
|
||||
Repository repository = load(namespace, name);
|
||||
List<PermissionDto> permissionDtoList = repository.getPermissions()
|
||||
.stream()
|
||||
.map(per -> modelToDtoMapper.map(per, new NamespaceAndName(repository.getNamespace(), repository.getName())))
|
||||
.collect(Collectors.toList());
|
||||
return Response.ok(permissionDtoList).build();
|
||||
RepositoryPermissions.permissionRead(repository).check();
|
||||
return Response.ok(permissionCollectionToDtoMapper.map(repository)).build();
|
||||
}
|
||||
|
||||
|
||||
@@ -149,11 +150,12 @@ public class PermissionRootResource {
|
||||
@Consumes(VndMediaType.PERMISSION)
|
||||
@Path("{permission-name}")
|
||||
public Response update(@PathParam("namespace") String namespace,
|
||||
@PathParam("name") String name,
|
||||
@PathParam("permission-name") String permissionName,
|
||||
PermissionDto permission) throws Exception {
|
||||
@PathParam("name") String name,
|
||||
@PathParam("permission-name") String permissionName,
|
||||
PermissionDto permission) throws NotFoundException {
|
||||
log.info("try to update the permission with name: {}. the modified permission is: {}", permissionName, permission);
|
||||
Repository repository = load(namespace, name);
|
||||
RepositoryPermissions.permissionWrite(repository).check();
|
||||
Permission existingPermission = repository.getPermissions()
|
||||
.stream()
|
||||
.filter(perm -> StringUtils.isNotBlank(perm.getName()) && perm.getName().equals(permissionName))
|
||||
@@ -181,10 +183,11 @@ public class PermissionRootResource {
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Path("{permission-name}")
|
||||
public Response delete(@PathParam("namespace") String namespace,
|
||||
@PathParam("name") String name,
|
||||
@PathParam("permission-name") String permissionName) throws Exception {
|
||||
@PathParam("name") String name,
|
||||
@PathParam("permission-name") String permissionName) throws NotFoundException {
|
||||
log.info("try to delete the permission with name: {}.", permissionName);
|
||||
Repository repository = load(namespace, name);
|
||||
Repository repository = load(namespace, name);
|
||||
RepositoryPermissions.modify(repository).check();
|
||||
repository.getPermissions()
|
||||
.stream()
|
||||
.filter(perm -> StringUtils.isNotBlank(perm.getName()) && perm.getName().equals(permissionName))
|
||||
|
||||
@@ -2,12 +2,14 @@ package sonia.scm.api.v2.resources;
|
||||
|
||||
import de.otto.edison.hal.Links;
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.BeforeMapping;
|
||||
import org.mapstruct.Context;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import sonia.scm.repository.NamespaceAndName;
|
||||
import sonia.scm.repository.Permission;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryPermissions;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -21,21 +23,28 @@ public abstract class PermissionToPermissionDtoMapper {
|
||||
private ResourceLinks resourceLinks;
|
||||
|
||||
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
|
||||
public abstract PermissionDto map(Permission permission, @Context NamespaceAndName namespaceAndName);
|
||||
public abstract PermissionDto map(Permission permission, @Context Repository repository);
|
||||
|
||||
|
||||
@BeforeMapping
|
||||
void validatePermissions(@Context Repository repository) {
|
||||
RepositoryPermissions.permissionRead(repository).check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the self, update and delete links.
|
||||
*
|
||||
* @param target the mapped dto
|
||||
* @param namespaceAndName the repository namespace and name
|
||||
* @param target the mapped dto
|
||||
* @param repository the repository
|
||||
*/
|
||||
@AfterMapping
|
||||
void appendLinks(@MappingTarget PermissionDto target, @Context NamespaceAndName namespaceAndName) {
|
||||
void appendLinks(@MappingTarget PermissionDto target, @Context Repository repository) {
|
||||
Links.Builder linksBuilder = linkingTo()
|
||||
.self(resourceLinks.permission().self(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getName()));
|
||||
linksBuilder.single(link("update", resourceLinks.permission().update(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getName())));
|
||||
linksBuilder.single(link("delete", resourceLinks.permission().delete(namespaceAndName.getNamespace(), namespaceAndName.getName(), target.getName())));
|
||||
.self(resourceLinks.permission().self(repository.getNamespace(), repository.getName(), target.getName()));
|
||||
if (RepositoryPermissions.permissionWrite(repository).isPermitted()) {
|
||||
linksBuilder.single(link("update", resourceLinks.permission().update(repository.getNamespace(), repository.getName(), target.getName())));
|
||||
linksBuilder.single(link("delete", resourceLinks.permission().delete(repository.getNamespace(), repository.getName(), target.getName())));
|
||||
}
|
||||
target.add(linksBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,9 @@ import org.mapstruct.*;
|
||||
import sonia.scm.repository.Repository;
|
||||
|
||||
@Mapper
|
||||
public abstract class RepositoryDtoToRepositoryMapper {
|
||||
public abstract class RepositoryDtoToRepositoryMapper extends BaseDtoMapper {
|
||||
|
||||
@Mapping(target = "creationDate", ignore = true)
|
||||
@Mapping(target = "lastModified", ignore = true)
|
||||
@Mapping(target = "id", ignore = true)
|
||||
@Mapping(target = "publicReadable", ignore = true)
|
||||
@Mapping(target = "healthCheckFailures", ignore = true)
|
||||
|
||||
@@ -130,11 +130,17 @@ public class RepositoryResource {
|
||||
public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, @Valid RepositoryDto repositoryDto) throws NotFoundException, ConcurrentModificationException {
|
||||
return adapter.update(
|
||||
loadBy(namespace, name),
|
||||
existing -> dtoToRepositoryMapper.map(repositoryDto, existing.getId()),
|
||||
existing -> processUpdate(repositoryDto, existing),
|
||||
nameAndNamespaceStaysTheSame(namespace, name)
|
||||
);
|
||||
}
|
||||
|
||||
private Repository processUpdate(RepositoryDto repositoryDto, Repository existing) {
|
||||
Repository changedRepository = dtoToRepositoryMapper.map(repositoryDto, existing.getId());
|
||||
changedRepository.setPermissions(existing.getPermissions());
|
||||
return changedRepository;
|
||||
}
|
||||
|
||||
@Path("tags/")
|
||||
public TagRootResource tags() {
|
||||
return tagRootResource.get();
|
||||
@@ -178,6 +184,6 @@ public class RepositoryResource {
|
||||
}
|
||||
|
||||
private Predicate<Repository> nameAndNamespaceStaysTheSame(String namespace, String name) {
|
||||
return changed -> changed.getName().equals(name) && changed.getNamespace().equals(namespace);
|
||||
return changed -> name.equals(changed.getName()) && namespace.equals(changed.getNamespace());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +313,10 @@ class ResourceLinks {
|
||||
return permissionLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("permissions").parameters().method("getAll").parameters().href();
|
||||
}
|
||||
|
||||
String create(String repositoryNamespace, String repositoryName) {
|
||||
return permissionLinkBuilder.method("getRepositoryResource").parameters(repositoryNamespace, repositoryName).method("permissions").parameters().method("create").parameters().href();
|
||||
}
|
||||
|
||||
String self(String repositoryNamespace, String repositoryName, String permissionName) {
|
||||
return getLink(repositoryNamespace, repositoryName, permissionName, "get");
|
||||
}
|
||||
|
||||
@@ -9,19 +9,20 @@ import sonia.scm.user.User;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
import static sonia.scm.api.rest.resources.UserResource.DUMMY_PASSWORT;
|
||||
|
||||
// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection.
|
||||
@SuppressWarnings("squid:S3306")
|
||||
@Mapper
|
||||
public abstract class UserDtoToUserMapper {
|
||||
public abstract class UserDtoToUserMapper extends BaseDtoMapper {
|
||||
|
||||
@Inject
|
||||
private PasswordService passwordService;
|
||||
|
||||
@Mapping(source = "password", target = "password", qualifiedByName = "encrypt")
|
||||
@Mapping(target = "creationDate", ignore = true)
|
||||
@Mapping(target = "lastModified", ignore = true)
|
||||
public abstract User map(UserDto userDto, @Context String originalPassword);
|
||||
|
||||
@Named("encrypt")
|
||||
|
||||
@@ -203,9 +203,9 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
|
||||
boolean hasPermission = false;
|
||||
for (sonia.scm.repository.Permission permission : repositoryPermissions)
|
||||
{
|
||||
if (isUserPermitted(user, groups, permission))
|
||||
hasPermission = isUserPermitted(user, groups, permission);
|
||||
if (hasPermission)
|
||||
{
|
||||
|
||||
String perm = permission.getType().getPermissionPrefix().concat(repository.getId());
|
||||
if (logger.isTraceEnabled())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user