mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-08 06:25:45 +01:00
Merge branch 2.0.0-m3 into feature/global_config_v2_endpoint
This commit is contained in:
@@ -53,13 +53,9 @@ public interface HandlerBase<T extends TypedObject, E extends Exception>
|
|||||||
/**
|
/**
|
||||||
* Persists a new object.
|
* Persists a new object.
|
||||||
*
|
*
|
||||||
*
|
* @return The persisted object.
|
||||||
* @param object to store
|
|
||||||
*
|
|
||||||
* @throws E
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
*/
|
||||||
public void create(T object) throws E, IOException;
|
public T create(T object) throws E;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a persistent object.
|
* Removes a persistent object.
|
||||||
@@ -70,7 +66,7 @@ public interface HandlerBase<T extends TypedObject, E extends Exception>
|
|||||||
* @throws E
|
* @throws E
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void delete(T object) throws E, IOException;
|
public void delete(T object) throws E;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies a persistent object.
|
* Modifies a persistent object.
|
||||||
@@ -81,5 +77,5 @@ public interface HandlerBase<T extends TypedObject, E extends Exception>
|
|||||||
* @throws E
|
* @throws E
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void modify(T object) throws E, IOException;
|
public void modify(T object) throws E;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
package sonia.scm;
|
package sonia.scm;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
@@ -56,9 +55,8 @@ public interface Manager<T extends ModelObject, E extends Exception>
|
|||||||
* @param object to refresh
|
* @param object to refresh
|
||||||
*
|
*
|
||||||
* @throws E
|
* @throws E
|
||||||
* @throws IOException
|
|
||||||
*/
|
*/
|
||||||
void refresh(T object) throws E, IOException;
|
void refresh(T object) throws E;
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ package sonia.scm;
|
|||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
@@ -78,16 +77,16 @@ public class ManagerDecorator<T extends ModelObject, E extends Exception>
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void create(T object) throws E, IOException
|
public T create(T object) throws E
|
||||||
{
|
{
|
||||||
decorated.create(object);
|
return decorated.create(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void delete(T object) throws E, IOException
|
public void delete(T object) throws E
|
||||||
{
|
{
|
||||||
decorated.delete(object);
|
decorated.delete(object);
|
||||||
}
|
}
|
||||||
@@ -105,7 +104,7 @@ public class ManagerDecorator<T extends ModelObject, E extends Exception>
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void modify(T object) throws E, IOException
|
public void modify(T object) throws E
|
||||||
{
|
{
|
||||||
decorated.modify(object);
|
decorated.modify(object);
|
||||||
}
|
}
|
||||||
@@ -114,7 +113,7 @@ public class ManagerDecorator<T extends ModelObject, E extends Exception>
|
|||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void refresh(T object) throws E, IOException
|
public void refresh(T object) throws E
|
||||||
{
|
{
|
||||||
decorated.refresh(object);
|
decorated.refresh(object);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,5 +53,11 @@ public interface ModelObject
|
|||||||
*
|
*
|
||||||
* @return unique id
|
* @return unique id
|
||||||
*/
|
*/
|
||||||
public String getId();
|
String getId();
|
||||||
|
|
||||||
|
void setLastModified(Long timestamp);
|
||||||
|
|
||||||
|
Long getCreationDate();
|
||||||
|
|
||||||
|
void setCreationDate(Long timestamp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,15 +42,9 @@ package sonia.scm.group;
|
|||||||
public class GroupAlreadyExistsException extends GroupException
|
public class GroupAlreadyExistsException extends GroupException
|
||||||
{
|
{
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = 4042878550219750430L;
|
private static final long serialVersionUID = 4042878550219750430L;
|
||||||
|
|
||||||
/**
|
public GroupAlreadyExistsException(Group group) {
|
||||||
* Constructs a new instance.
|
super(group.getName() + " group already exists");
|
||||||
*
|
|
||||||
* @param message exception message
|
|
||||||
*/
|
|
||||||
public GroupAlreadyExistsException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,39 +52,7 @@ public class GroupNotFoundException extends GroupException
|
|||||||
* Constructs a new GroupNotFoundException.
|
* Constructs a new GroupNotFoundException.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public GroupNotFoundException() {}
|
public GroupNotFoundException(Group group) {
|
||||||
|
super("group " + group.getName() + " does not exist");
|
||||||
/**
|
|
||||||
* Constructs a new GroupNotFoundException.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param message message for the exception
|
|
||||||
*/
|
|
||||||
public GroupNotFoundException(String message)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new GroupNotFoundException.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param throwable root cause
|
|
||||||
*/
|
|
||||||
public GroupNotFoundException(Throwable throwable)
|
|
||||||
{
|
|
||||||
super(throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new GroupNotFoundException.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param message message for the exception
|
|
||||||
* @param throwable root cause
|
|
||||||
*/
|
|
||||||
public GroupNotFoundException(String message, Throwable throwable)
|
|
||||||
{
|
|
||||||
super(message, throwable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,23 +38,20 @@ package sonia.scm.repository;
|
|||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import com.google.common.io.Resources;
|
import com.google.common.io.Resources;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import sonia.scm.ConfigurationException;
|
import sonia.scm.ConfigurationException;
|
||||||
import sonia.scm.io.CommandResult;
|
import sonia.scm.io.CommandResult;
|
||||||
import sonia.scm.io.ExtendedCommand;
|
import sonia.scm.io.ExtendedCommand;
|
||||||
import sonia.scm.io.FileSystem;
|
import sonia.scm.io.FileSystem;
|
||||||
|
import sonia.scm.store.ConfigurationStoreFactory;
|
||||||
import sonia.scm.util.IOUtil;
|
import sonia.scm.util.IOUtil;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import sonia.scm.store.ConfigurationStoreFactory;
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -108,8 +105,8 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
|
|||||||
* @throws RepositoryException
|
* @throws RepositoryException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void create(Repository repository)
|
public Repository create(Repository repository)
|
||||||
throws RepositoryException, IOException
|
throws RepositoryException
|
||||||
{
|
{
|
||||||
File directory = getDirectory(repository);
|
File directory = getDirectory(repository);
|
||||||
|
|
||||||
@@ -125,6 +122,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
|
|||||||
fileSystem.create(directory);
|
fileSystem.create(directory);
|
||||||
create(repository, directory);
|
create(repository, directory);
|
||||||
postCreate(repository, directory);
|
postCreate(repository, directory);
|
||||||
|
return repository;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -137,11 +135,16 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
|
|||||||
directory);
|
directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
fileSystem.destroy(directory);
|
try {
|
||||||
|
fileSystem.destroy(directory);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("could not delete directory after failed repository creation: {}", directory, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Throwables.propagateIfPossible(ex, RepositoryException.class,
|
Throwables.propagateIfPossible(ex, RepositoryException.class);
|
||||||
IOException.class);
|
// This point will never be reached
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,14 +176,17 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
|
|||||||
* @throws RepositoryException
|
* @throws RepositoryException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void delete(Repository repository)
|
public void delete(Repository repository) throws RepositoryException
|
||||||
throws RepositoryException, IOException
|
|
||||||
{
|
{
|
||||||
File directory = getDirectory(repository);
|
File directory = getDirectory(repository);
|
||||||
|
|
||||||
if (directory.exists())
|
if (directory.exists())
|
||||||
{
|
{
|
||||||
fileSystem.destroy(directory);
|
try {
|
||||||
|
fileSystem.destroy(directory);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RepositoryException("could not delete repository", e);
|
||||||
|
}
|
||||||
cleanupEmptyDirectories(config.getRepositoryDirectory(),
|
cleanupEmptyDirectories(config.getRepositoryDirectory(),
|
||||||
directory.getParentFile());
|
directory.getParentFile());
|
||||||
}
|
}
|
||||||
@@ -232,8 +238,7 @@ public abstract class AbstractSimpleRepositoryHandler<C extends SimpleRepository
|
|||||||
* @throws RepositoryException
|
* @throws RepositoryException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void modify(Repository repository)
|
public void modify(Repository repository) throws RepositoryException
|
||||||
throws RepositoryException, IOException
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// nothing todo
|
// nothing todo
|
||||||
|
|||||||
@@ -37,23 +37,17 @@ import com.github.sdorra.ssp.PermissionObject;
|
|||||||
import com.github.sdorra.ssp.StaticPermissions;
|
import com.github.sdorra.ssp.StaticPermissions;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import sonia.scm.BasicPropertiesAware;
|
import sonia.scm.BasicPropertiesAware;
|
||||||
import sonia.scm.ModelObject;
|
import sonia.scm.ModelObject;
|
||||||
import sonia.scm.util.HttpUtil;
|
import sonia.scm.util.HttpUtil;
|
||||||
import sonia.scm.util.Util;
|
import sonia.scm.util.Util;
|
||||||
import sonia.scm.util.ValidationUtil;
|
import sonia.scm.util.ValidationUtil;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.*;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Source code repository.
|
* Source code repository.
|
||||||
*
|
*
|
||||||
@@ -207,6 +201,10 @@ public class Repository extends BasicPropertiesAware implements ModelObject, Per
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getNamespace() {
|
||||||
|
return namespace;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the access permissions of the {@link Repository}.
|
* Returns the access permissions of the {@link Repository}.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -38,13 +38,12 @@ package sonia.scm.repository;
|
|||||||
import sonia.scm.Type;
|
import sonia.scm.Type;
|
||||||
import sonia.scm.TypeManager;
|
import sonia.scm.TypeManager;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The central class for managing {@link Repository} objects.
|
* The central class for managing {@link Repository} objects.
|
||||||
@@ -149,4 +148,11 @@ public interface RepositoryManager
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public RepositoryHandler getHandler(String type);
|
public RepositoryHandler getHandler(String type);
|
||||||
|
|
||||||
|
default Optional<Repository> getByNamespace(String namespace, String name) {
|
||||||
|
return getAll()
|
||||||
|
.stream()
|
||||||
|
.filter(r -> r.getName().equals(name) && r.getNamespace().equals(namespace))
|
||||||
|
.findFirst();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,13 +38,11 @@ package sonia.scm.repository;
|
|||||||
import sonia.scm.ManagerDecorator;
|
import sonia.scm.ManagerDecorator;
|
||||||
import sonia.scm.Type;
|
import sonia.scm.Type;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decorator for {@link RepositoryManager}.
|
* Decorator for {@link RepositoryManager}.
|
||||||
@@ -92,19 +90,10 @@ public class RepositoryManagerDecorator
|
|||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param type
|
|
||||||
* @param name
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public Repository get(String type, String name)
|
public Repository get(String namespace, String name)
|
||||||
{
|
{
|
||||||
return decorated.get(type, name);
|
return decorated.get(namespace, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -52,17 +52,11 @@ public class RepositoryNotFoundException extends RepositoryException
|
|||||||
* error detail message.
|
* error detail message.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public RepositoryNotFoundException() {}
|
public RepositoryNotFoundException(Repository repository) {
|
||||||
|
super("repository " + repository.getName() + "/" + repository.getNamespace() + " does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public RepositoryNotFoundException(String repositoryId) {
|
||||||
* Constructs a new {@link RepositoryNotFoundException} with the specified
|
super("repository with id " + repositoryId + " does not exist");
|
||||||
* error detail message.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param message error detail message
|
|
||||||
*/
|
|
||||||
public RepositoryNotFoundException(String message)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,37 +37,26 @@ package sonia.scm.repository.api;
|
|||||||
|
|
||||||
import com.github.legman.ReferenceType;
|
import com.github.legman.ReferenceType;
|
||||||
import com.github.legman.Subscribe;
|
import com.github.legman.Subscribe;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import sonia.scm.HandlerEventType;
|
import sonia.scm.HandlerEventType;
|
||||||
import sonia.scm.cache.Cache;
|
import sonia.scm.cache.Cache;
|
||||||
import sonia.scm.cache.CacheManager;
|
import sonia.scm.cache.CacheManager;
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
import sonia.scm.repository.PostReceiveRepositoryHookEvent;
|
import sonia.scm.event.ScmEventBus;
|
||||||
import sonia.scm.repository.PreProcessorUtil;
|
import sonia.scm.repository.*;
|
||||||
import sonia.scm.repository.Repository;
|
|
||||||
import sonia.scm.repository.RepositoryCacheKeyPredicate;
|
|
||||||
import sonia.scm.repository.RepositoryEvent;
|
|
||||||
import sonia.scm.repository.RepositoryManager;
|
|
||||||
import sonia.scm.repository.RepositoryNotFoundException;
|
|
||||||
import sonia.scm.repository.RepositoryPermissions;
|
|
||||||
import sonia.scm.repository.spi.RepositoryServiceProvider;
|
import sonia.scm.repository.spi.RepositoryServiceProvider;
|
||||||
import sonia.scm.repository.spi.RepositoryServiceResolver;
|
import sonia.scm.repository.spi.RepositoryServiceResolver;
|
||||||
import sonia.scm.security.ScmSecurityException;
|
import sonia.scm.security.ScmSecurityException;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import sonia.scm.event.ScmEventBus;
|
|
||||||
import sonia.scm.repository.ClearRepositoryCacheEvent;
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link RepositoryServiceFactory} is the entrypoint of the repository api.
|
* The {@link RepositoryServiceFactory} is the entrypoint of the repository api.
|
||||||
@@ -179,8 +168,7 @@ public final class RepositoryServiceFactory
|
|||||||
|
|
||||||
if (repository == null)
|
if (repository == null)
|
||||||
{
|
{
|
||||||
throw new RepositoryNotFoundException(
|
throw new RepositoryNotFoundException(repositoryId);
|
||||||
"could not find a repository with id ".concat(repositoryId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return create(repository);
|
return create(repository);
|
||||||
|
|||||||
@@ -30,12 +30,10 @@ package sonia.scm.security;
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import org.apache.shiro.authc.AuthenticationException;
|
import org.apache.shiro.authc.AuthenticationException;
|
||||||
import org.apache.shiro.authc.AuthenticationInfo;
|
import org.apache.shiro.authc.AuthenticationInfo;
|
||||||
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
||||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||||
|
|
||||||
import sonia.scm.group.Group;
|
import sonia.scm.group.Group;
|
||||||
import sonia.scm.group.GroupException;
|
import sonia.scm.group.GroupException;
|
||||||
import sonia.scm.group.GroupManager;
|
import sonia.scm.group.GroupManager;
|
||||||
@@ -46,9 +44,6 @@ import sonia.scm.user.UserException;
|
|||||||
import sonia.scm.user.UserManager;
|
import sonia.scm.user.UserManager;
|
||||||
import sonia.scm.web.security.AdministrationContext;
|
import sonia.scm.web.security.AdministrationContext;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -134,7 +129,7 @@ public final class SyncingRealmHelper {
|
|||||||
groupManager.create(group);
|
groupManager.create(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (GroupException | IOException ex) {
|
catch (GroupException ex) {
|
||||||
throw new AuthenticationException("could not store group", ex);
|
throw new AuthenticationException("could not store group", ex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -155,7 +150,7 @@ public final class SyncingRealmHelper {
|
|||||||
userManager.create(user);
|
userManager.create(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (UserException | IOException ex) {
|
catch (UserException ex) {
|
||||||
throw new AuthenticationException("could not store user", ex);
|
throw new AuthenticationException("could not store user", ex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -41,19 +41,11 @@ package sonia.scm.user;
|
|||||||
public class UserAlreadyExistsException extends UserException
|
public class UserAlreadyExistsException extends UserException
|
||||||
{
|
{
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private static final long serialVersionUID = 9182294539718090814L;
|
private static final long serialVersionUID = 9182294539718090814L;
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
//~--- constructors ---------------------------------------------------------
|
||||||
|
|
||||||
/**
|
public UserAlreadyExistsException(User user) {
|
||||||
* Constructs a new instance.
|
super(user.getName() + " user already exists");
|
||||||
*
|
|
||||||
* @param message message of exception
|
|
||||||
* @since 1.5
|
|
||||||
*/
|
|
||||||
public UserAlreadyExistsException(String message)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,39 +51,7 @@ public class UserNotFoundException extends UserException
|
|||||||
* Constructs a new UserNotFoundException.
|
* Constructs a new UserNotFoundException.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public UserNotFoundException() {}
|
public UserNotFoundException(User user) {
|
||||||
|
super("user " + user.getName() + " does not exist");
|
||||||
/**
|
|
||||||
* Constructs a new UserNotFoundException.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param message message for the exception
|
|
||||||
*/
|
|
||||||
public UserNotFoundException(String message)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new UserNotFoundException.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param throwable root cause
|
|
||||||
*/
|
|
||||||
public UserNotFoundException(Throwable throwable)
|
|
||||||
{
|
|
||||||
super(throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new UserNotFoundException.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param message message for the exception
|
|
||||||
* @param throwable root cause
|
|
||||||
*/
|
|
||||||
public UserNotFoundException(String message, Throwable throwable)
|
|
||||||
{
|
|
||||||
super(message, throwable);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ public class VndMediaType {
|
|||||||
|
|
||||||
public static final String USER = PREFIX + "user" + SUFFIX;
|
public static final String USER = PREFIX + "user" + SUFFIX;
|
||||||
public static final String GROUP = PREFIX + "group" + SUFFIX;
|
public static final String GROUP = PREFIX + "group" + SUFFIX;
|
||||||
|
public static final String REPOSITORY = PREFIX + "repository" + SUFFIX;
|
||||||
public static final String USER_COLLECTION = PREFIX + "userCollection" + SUFFIX;
|
public static final String USER_COLLECTION = PREFIX + "userCollection" + SUFFIX;
|
||||||
public static final String GROUP_COLLECTION = PREFIX + "groupCollection" + SUFFIX;
|
public static final String GROUP_COLLECTION = PREFIX + "groupCollection" + SUFFIX;
|
||||||
|
public static final String REPOSITORY_COLLECTION = PREFIX + "repositoryCollection" + SUFFIX;
|
||||||
|
|
||||||
public static final String GLOBAL_CONFIG = PREFIX + "global_config" + SUFFIX;
|
public static final String GLOBAL_CONFIG = PREFIX + "global_config" + SUFFIX;
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ public class ManagerTest {
|
|||||||
public Collection getAll(Comparator comparator, int start, int limit) { return null; }
|
public Collection getAll(Comparator comparator, int start, int limit) { return null; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create(TypedObject object) {}
|
public TypedObject create(TypedObject object) { return null; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(TypedObject object) {}
|
public void delete(TypedObject object) {}
|
||||||
|
|||||||
68
scm-webapp/src/main/java/sonia/scm/ManagerDaoAdapter.java
Normal file
68
scm-webapp/src/main/java/sonia/scm/ManagerDaoAdapter.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package sonia.scm;
|
||||||
|
|
||||||
|
import com.github.sdorra.ssp.PermissionCheck;
|
||||||
|
import sonia.scm.util.AssertUtil;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ManagerDaoAdapter<T extends ModelObject, E extends Exception> {
|
||||||
|
|
||||||
|
private final GenericDAO<T> dao;
|
||||||
|
private final Function<T, E> notFoundException;
|
||||||
|
private final Function<T, E> alreadyExistsException;
|
||||||
|
|
||||||
|
public ManagerDaoAdapter(GenericDAO<T> dao, Function<T, E> notFoundException, Function<T, E> alreadyExistsException) {
|
||||||
|
this.dao = dao;
|
||||||
|
this.notFoundException = notFoundException;
|
||||||
|
this.alreadyExistsException = alreadyExistsException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void modify(T object, Function<T, PermissionCheck> permissionCheck, AroundHandler<T, E> beforeUpdate, AroundHandler<T, E> afterUpdate) throws E {
|
||||||
|
T notModified = dao.get(object.getId());
|
||||||
|
if (notModified != null) {
|
||||||
|
permissionCheck.apply(notModified).check();
|
||||||
|
AssertUtil.assertIsValid(object);
|
||||||
|
|
||||||
|
beforeUpdate.handle(notModified);
|
||||||
|
|
||||||
|
object.setLastModified(System.currentTimeMillis());
|
||||||
|
object.setCreationDate(notModified.getCreationDate());
|
||||||
|
|
||||||
|
dao.modify(object);
|
||||||
|
|
||||||
|
afterUpdate.handle(notModified);
|
||||||
|
} else {
|
||||||
|
throw notFoundException.apply(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public T create(T newObject, Supplier<PermissionCheck> permissionCheck, AroundHandler<T, E> beforeCreate, AroundHandler<T, E> afterCreate) throws E {
|
||||||
|
permissionCheck.get().check();
|
||||||
|
AssertUtil.assertIsValid(newObject);
|
||||||
|
if (dao.contains(newObject)) {
|
||||||
|
throw alreadyExistsException.apply(newObject);
|
||||||
|
}
|
||||||
|
newObject.setCreationDate(System.currentTimeMillis());
|
||||||
|
beforeCreate.handle(newObject);
|
||||||
|
dao.add(newObject);
|
||||||
|
afterCreate.handle(newObject);
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(T toDelete, Supplier<PermissionCheck> permissionCheck, AroundHandler<T, E> beforeDelete, AroundHandler<T, E> afterDelete) throws E {
|
||||||
|
permissionCheck.get().check();
|
||||||
|
if (dao.contains(toDelete)) {
|
||||||
|
beforeDelete.handle(toDelete);
|
||||||
|
dao.delete(toDelete);
|
||||||
|
afterDelete.handle(toDelete);
|
||||||
|
} else {
|
||||||
|
throw notFoundException.apply(toDelete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface AroundHandler<T extends ModelObject, E extends Exception> {
|
||||||
|
void handle(T notModified) throws E;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package sonia.scm.api.rest;
|
||||||
|
|
||||||
|
import sonia.scm.repository.RepositoryAlreadyExistsException;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
import javax.ws.rs.ext.ExceptionMapper;
|
||||||
|
import javax.ws.rs.ext.Provider;
|
||||||
|
|
||||||
|
@Provider
|
||||||
|
public class RepositoryAlreadyExistsExceptionMapper implements ExceptionMapper<RepositoryAlreadyExistsException> {
|
||||||
|
@Override
|
||||||
|
public Response toResponse(RepositoryAlreadyExistsException exception) {
|
||||||
|
return Response.status(Status.CONFLICT).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,13 +48,13 @@ import sonia.scm.util.AssertUtil;
|
|||||||
import sonia.scm.util.HttpUtil;
|
import sonia.scm.util.HttpUtil;
|
||||||
import sonia.scm.util.Util;
|
import sonia.scm.util.Util;
|
||||||
|
|
||||||
import javax.ws.rs.core.CacheControl;
|
import javax.ws.rs.core.*;
|
||||||
import javax.ws.rs.core.EntityTag;
|
|
||||||
import javax.ws.rs.core.GenericEntity;
|
|
||||||
import javax.ws.rs.core.Request;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import java.beans.BeanInfo;
|
||||||
|
import java.beans.IntrospectionException;
|
||||||
|
import java.beans.Introspector;
|
||||||
|
import java.beans.PropertyDescriptor;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -76,17 +76,15 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
|||||||
private static final Logger logger =
|
private static final Logger logger =
|
||||||
LoggerFactory.getLogger(AbstractManagerResource.class);
|
LoggerFactory.getLogger(AbstractManagerResource.class);
|
||||||
|
|
||||||
//~--- constructors ---------------------------------------------------------
|
protected final Manager<T, E> manager;
|
||||||
|
private final Class<T> type;
|
||||||
|
|
||||||
/**
|
protected int cacheMaxAge = 0;
|
||||||
* Constructs ...
|
protected boolean disableCache = false;
|
||||||
*
|
|
||||||
*
|
public AbstractManagerResource(Manager<T, E> manager, Class<T> type) {
|
||||||
* @param manager
|
|
||||||
*/
|
|
||||||
public AbstractManagerResource(Manager<T, E> manager)
|
|
||||||
{
|
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
@@ -526,45 +524,25 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
|||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param sortby
|
|
||||||
* @param desc
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Comparator<T> createComparator(String sortby, boolean desc)
|
private Comparator<T> createComparator(String sortBy, boolean desc)
|
||||||
{
|
{
|
||||||
|
checkSortByField(sortBy);
|
||||||
Comparator comparator;
|
Comparator comparator;
|
||||||
|
|
||||||
if (desc)
|
if (desc)
|
||||||
{
|
{
|
||||||
comparator = new BeanReverseComparator(sortby);
|
comparator = new BeanReverseComparator(sortBy);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
comparator = new BeanComparator(sortby);
|
comparator = new BeanComparator(sortBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
return comparator;
|
return comparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private Collection<T> fetchItems(String sortBy, boolean desc, int start,
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param sortby
|
|
||||||
* @param desc
|
|
||||||
* @param start
|
|
||||||
* @param limit
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Collection<T> fetchItems(String sortby, boolean desc, int start,
|
|
||||||
int limit)
|
int limit)
|
||||||
{
|
{
|
||||||
AssertUtil.assertPositive(start);
|
AssertUtil.assertPositive(start);
|
||||||
@@ -573,18 +551,18 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
|||||||
|
|
||||||
if (limit > 0)
|
if (limit > 0)
|
||||||
{
|
{
|
||||||
if (Util.isEmpty(sortby))
|
if (Util.isEmpty(sortBy))
|
||||||
{
|
{
|
||||||
|
|
||||||
// replace with something useful
|
// replace with something useful
|
||||||
sortby = "id";
|
sortBy = "id";
|
||||||
}
|
}
|
||||||
|
|
||||||
items = manager.getAll(createComparator(sortby, desc), start, limit);
|
items = manager.getAll(createComparator(sortBy, desc), start, limit);
|
||||||
}
|
}
|
||||||
else if (Util.isNotEmpty(sortby))
|
else if (Util.isNotEmpty(sortBy))
|
||||||
{
|
{
|
||||||
items = manager.getAll(createComparator(sortby, desc));
|
items = manager.getAll(createComparator(sortBy, desc));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -594,17 +572,32 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PageResult<T> fetchPage(String sortby, boolean desc, int pageNumber,
|
// We have to handle IntrospectionException here, because it's a checked exception
|
||||||
|
// It shouldn't occur really - so creating a new unchecked exception would be over-engineered here
|
||||||
|
@SuppressWarnings("squid:S00112")
|
||||||
|
private void checkSortByField(String sortBy) {
|
||||||
|
try {
|
||||||
|
BeanInfo info = Introspector.getBeanInfo(type);
|
||||||
|
PropertyDescriptor[] pds = info.getPropertyDescriptors();
|
||||||
|
if (Arrays.stream(pds).noneMatch(p -> p.getName().equals(sortBy))) {
|
||||||
|
throw new IllegalArgumentException("sortBy");
|
||||||
|
}
|
||||||
|
} catch (IntrospectionException e) {
|
||||||
|
throw new RuntimeException("error introspecting model type " + type.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PageResult<T> fetchPage(String sortBy, boolean desc, int pageNumber,
|
||||||
int pageSize) {
|
int pageSize) {
|
||||||
AssertUtil.assertPositive(pageNumber);
|
AssertUtil.assertPositive(pageNumber);
|
||||||
AssertUtil.assertPositive(pageSize);
|
AssertUtil.assertPositive(pageSize);
|
||||||
|
|
||||||
if (Util.isEmpty(sortby)) {
|
if (Util.isEmpty(sortBy)) {
|
||||||
// replace with something useful
|
// replace with something useful
|
||||||
sortby = "id";
|
sortBy = "id";
|
||||||
}
|
}
|
||||||
|
|
||||||
return manager.getPage(createComparator(sortby, desc), pageNumber, pageSize);
|
return manager.getPage(createComparator(sortBy, desc), pageNumber, pageSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
@@ -676,16 +669,4 @@ public abstract class AbstractManagerResource<T extends ModelObject,
|
|||||||
return super.compare(o1, o2) * -1;
|
return super.compare(o1, o2) * -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
protected int cacheMaxAge = 0;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
protected boolean disableCache = false;
|
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
protected Manager<T, E> manager;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,34 +41,17 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
|||||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
||||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||||
|
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
|
||||||
import sonia.scm.group.Group;
|
import sonia.scm.group.Group;
|
||||||
import sonia.scm.group.GroupException;
|
import sonia.scm.group.GroupException;
|
||||||
import sonia.scm.group.GroupManager;
|
import sonia.scm.group.GroupManager;
|
||||||
import sonia.scm.security.Role;
|
import sonia.scm.security.Role;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.*;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.DefaultValue;
|
|
||||||
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.QueryParam;
|
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.GenericEntity;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Request;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RESTful Web Service Resource to manage groups and their members.
|
* RESTful Web Service Resource to manage groups and their members.
|
||||||
@@ -97,7 +80,7 @@ public class GroupResource
|
|||||||
@Inject
|
@Inject
|
||||||
public GroupResource(GroupManager groupManager)
|
public GroupResource(GroupManager groupManager)
|
||||||
{
|
{
|
||||||
super(groupManager);
|
super(groupManager, Group.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
|
|||||||
@@ -40,24 +40,17 @@ import com.google.common.base.Strings;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||||
|
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
||||||
|
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||||
|
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import sonia.scm.NotSupportedFeatuerException;
|
import sonia.scm.NotSupportedFeatuerException;
|
||||||
import sonia.scm.Type;
|
import sonia.scm.Type;
|
||||||
import sonia.scm.api.rest.RestActionUploadResult;
|
import sonia.scm.api.rest.RestActionUploadResult;
|
||||||
import sonia.scm.repository.AdvancedImportHandler;
|
import sonia.scm.repository.*;
|
||||||
import sonia.scm.repository.ImportHandler;
|
|
||||||
import sonia.scm.repository.ImportResult;
|
|
||||||
import sonia.scm.repository.Repository;
|
|
||||||
import sonia.scm.repository.RepositoryAlreadyExistsException;
|
|
||||||
import sonia.scm.repository.RepositoryException;
|
|
||||||
import sonia.scm.repository.RepositoryHandler;
|
|
||||||
import sonia.scm.repository.RepositoryManager;
|
|
||||||
import sonia.scm.repository.RepositoryType;
|
|
||||||
import sonia.scm.repository.api.Command;
|
import sonia.scm.repository.api.Command;
|
||||||
import sonia.scm.repository.api.RepositoryService;
|
import sonia.scm.repository.api.RepositoryService;
|
||||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
import sonia.scm.repository.api.RepositoryServiceFactory;
|
||||||
@@ -65,45 +58,24 @@ import sonia.scm.repository.api.UnbundleCommandBuilder;
|
|||||||
import sonia.scm.security.Role;
|
import sonia.scm.security.Role;
|
||||||
import sonia.scm.util.IOUtil;
|
import sonia.scm.util.IOUtil;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.*;
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.*;
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
import javax.xml.bind.annotation.XmlRootElement;
|
||||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
|
||||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
|
||||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import javax.ws.rs.DefaultValue;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import javax.ws.rs.FormParam;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
import javax.ws.rs.POST;
|
|
||||||
import javax.ws.rs.Path;
|
|
||||||
import javax.ws.rs.PathParam;
|
|
||||||
import javax.ws.rs.Produces;
|
|
||||||
import javax.ws.rs.QueryParam;
|
|
||||||
import javax.ws.rs.WebApplicationException;
|
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.GenericEntity;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
|
||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
|
||||||
import javax.xml.bind.annotation.XmlRootElement;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rest resource for importing repositories.
|
* Rest resource for importing repositories.
|
||||||
@@ -564,10 +536,6 @@ public class RepositoryImportResource
|
|||||||
{
|
{
|
||||||
handleGenericCreationFailure(ex, type, name);
|
handleGenericCreationFailure(ex, type, name);
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
handleGenericCreationFailure(ex, type, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return repository;
|
return repository;
|
||||||
}
|
}
|
||||||
@@ -716,10 +684,6 @@ public class RepositoryImportResource
|
|||||||
{
|
{
|
||||||
manager.delete(repository);
|
manager.delete(repository);
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
logger.error("can not delete repository", e);
|
|
||||||
}
|
|
||||||
catch (RepositoryException e)
|
catch (RepositoryException e)
|
||||||
{
|
{
|
||||||
logger.error("can not delete repository", e);
|
logger.error("can not delete repository", e);
|
||||||
|
|||||||
@@ -46,52 +46,16 @@ import org.apache.shiro.SecurityUtils;
|
|||||||
import org.apache.shiro.authz.AuthorizationException;
|
import org.apache.shiro.authz.AuthorizationException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.repository.*;
|
||||||
import sonia.scm.repository.BlameResult;
|
import sonia.scm.repository.api.*;
|
||||||
import sonia.scm.repository.Branches;
|
|
||||||
import sonia.scm.repository.BrowserResult;
|
|
||||||
import sonia.scm.repository.Changeset;
|
|
||||||
import sonia.scm.repository.ChangesetPagingResult;
|
|
||||||
import sonia.scm.repository.HealthChecker;
|
|
||||||
import sonia.scm.repository.Permission;
|
|
||||||
import sonia.scm.repository.Repository;
|
|
||||||
import sonia.scm.repository.RepositoryException;
|
|
||||||
import sonia.scm.repository.RepositoryIsNotArchivedException;
|
|
||||||
import sonia.scm.repository.RepositoryManager;
|
|
||||||
import sonia.scm.repository.RepositoryNotFoundException;
|
|
||||||
import sonia.scm.repository.Tags;
|
|
||||||
import sonia.scm.repository.api.BlameCommandBuilder;
|
|
||||||
import sonia.scm.repository.api.BrowseCommandBuilder;
|
|
||||||
import sonia.scm.repository.api.CatCommandBuilder;
|
|
||||||
import sonia.scm.repository.api.CommandNotSupportedException;
|
|
||||||
import sonia.scm.repository.api.DiffCommandBuilder;
|
|
||||||
import sonia.scm.repository.api.DiffFormat;
|
|
||||||
import sonia.scm.repository.api.LogCommandBuilder;
|
|
||||||
import sonia.scm.repository.api.RepositoryService;
|
|
||||||
import sonia.scm.repository.api.RepositoryServiceFactory;
|
|
||||||
import sonia.scm.util.AssertUtil;
|
import sonia.scm.util.AssertUtil;
|
||||||
import sonia.scm.util.HttpUtil;
|
import sonia.scm.util.HttpUtil;
|
||||||
import sonia.scm.util.IOUtil;
|
import sonia.scm.util.IOUtil;
|
||||||
import sonia.scm.util.Util;
|
import sonia.scm.util.Util;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.DELETE;
|
import javax.ws.rs.core.*;
|
||||||
import javax.ws.rs.DefaultValue;
|
|
||||||
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.QueryParam;
|
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.GenericEntity;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Request;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
import javax.ws.rs.core.StreamingOutput;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -120,19 +84,15 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
|
|||||||
/**
|
/**
|
||||||
* Constructs ...
|
* Constructs ...
|
||||||
*
|
*
|
||||||
*
|
* @param repositoryManager
|
||||||
* @param configuration
|
|
||||||
* @param repositoryManager
|
|
||||||
* @param servicefactory
|
* @param servicefactory
|
||||||
* @param healthChecker
|
* @param healthChecker
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
public RepositoryResource(ScmConfiguration configuration,
|
public RepositoryResource(RepositoryManager repositoryManager,
|
||||||
RepositoryManager repositoryManager,
|
|
||||||
RepositoryServiceFactory servicefactory, HealthChecker healthChecker)
|
RepositoryServiceFactory servicefactory, HealthChecker healthChecker)
|
||||||
{
|
{
|
||||||
super(repositoryManager);
|
super(repositoryManager, Repository.class);
|
||||||
this.configuration = configuration;
|
|
||||||
this.repositoryManager = repositoryManager;
|
this.repositoryManager = repositoryManager;
|
||||||
this.servicefactory = servicefactory;
|
this.servicefactory = servicefactory;
|
||||||
this.healthChecker = healthChecker;
|
this.healthChecker = healthChecker;
|
||||||
@@ -210,9 +170,9 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
|
|||||||
logger.warn("delete not allowed", ex);
|
logger.warn("delete not allowed", ex);
|
||||||
response = Response.status(Response.Status.FORBIDDEN).build();
|
response = Response.status(Response.Status.FORBIDDEN).build();
|
||||||
}
|
}
|
||||||
catch (RepositoryException | IOException ex)
|
catch (RepositoryException ex)
|
||||||
{
|
{
|
||||||
logger.error("error during create", ex);
|
logger.error("error during delete", ex);
|
||||||
response = createErrorResponse(ex);
|
response = createErrorResponse(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1103,9 +1063,6 @@ public class RepositoryResource extends AbstractManagerResource<Repository, Repo
|
|||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final ScmConfiguration configuration;
|
|
||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private final HealthChecker healthChecker;
|
private final HealthChecker healthChecker;
|
||||||
|
|
||||||
|
|||||||
@@ -41,10 +41,8 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
|||||||
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
import com.webcohesion.enunciate.metadata.rs.ResponseHeader;
|
||||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||||
|
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.apache.shiro.authc.credential.PasswordService;
|
import org.apache.shiro.authc.credential.PasswordService;
|
||||||
|
|
||||||
import sonia.scm.security.Role;
|
import sonia.scm.security.Role;
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
import sonia.scm.user.UserException;
|
import sonia.scm.user.UserException;
|
||||||
@@ -52,26 +50,11 @@ import sonia.scm.user.UserManager;
|
|||||||
import sonia.scm.util.AssertUtil;
|
import sonia.scm.util.AssertUtil;
|
||||||
import sonia.scm.util.Util;
|
import sonia.scm.util.Util;
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.*;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.DefaultValue;
|
|
||||||
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.QueryParam;
|
|
||||||
import javax.ws.rs.core.Context;
|
|
||||||
import javax.ws.rs.core.GenericEntity;
|
|
||||||
import javax.ws.rs.core.MediaType;
|
|
||||||
import javax.ws.rs.core.Request;
|
|
||||||
import javax.ws.rs.core.Response;
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RESTful Web Service Resource to manage users.
|
* RESTful Web Service Resource to manage users.
|
||||||
@@ -101,7 +84,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
|||||||
@Inject
|
@Inject
|
||||||
public UserResource(UserManager userManager, PasswordService passwordService)
|
public UserResource(UserManager userManager, PasswordService passwordService)
|
||||||
{
|
{
|
||||||
super(userManager);
|
super(userManager, User.class);
|
||||||
this.passwordService = passwordService;
|
this.passwordService = passwordService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import java.time.Instant;
|
|||||||
abstract class BaseMapper<T extends ModelObject, D extends HalRepresentation> {
|
abstract class BaseMapper<T extends ModelObject, D extends HalRepresentation> {
|
||||||
|
|
||||||
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
|
@Mapping(target = "attributes", ignore = true) // We do not map HAL attributes
|
||||||
public abstract D map(T user);
|
public abstract D map(T modelObject);
|
||||||
|
|
||||||
Instant mapTime(Long epochMilli) {
|
Instant mapTime(Long epochMilli) {
|
||||||
return epochMilli == null? null: Instant.ofEpochMilli(epochMilli);
|
return epochMilli == null? null: Instant.ofEpochMilli(epochMilli);
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.ws.rs.DefaultValue;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
public class BranchCollectionResource {
|
||||||
|
@GET
|
||||||
|
@Path("")
|
||||||
|
public Response getAll(@DefaultValue("0") @QueryParam("page") int page,
|
||||||
|
@DefaultValue("10") @QueryParam("pageSize") int pageSize,
|
||||||
|
@QueryParam("sortBy") String sortBy,
|
||||||
|
@DefaultValue("false") @QueryParam("desc") boolean desc) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
|
||||||
|
public class BranchRootResource {
|
||||||
|
|
||||||
|
private final Provider<BranchCollectionResource> branchCollectionResource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public BranchRootResource(Provider<BranchCollectionResource> branchCollectionResource) {
|
||||||
|
this.branchCollectionResource = branchCollectionResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("")
|
||||||
|
public BranchCollectionResource getBranchCollectionResource() {
|
||||||
|
return branchCollectionResource.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.ws.rs.DefaultValue;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
public class ChangesetCollectionResource {
|
||||||
|
@GET
|
||||||
|
@Path("")
|
||||||
|
public Response getAll(@DefaultValue("0") @QueryParam("page") int page,
|
||||||
|
@DefaultValue("10") @QueryParam("pageSize") int pageSize,
|
||||||
|
@QueryParam("sortBy") String sortBy,
|
||||||
|
@DefaultValue("false") @QueryParam("desc") boolean desc) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
|
||||||
|
public class ChangesetRootResource {
|
||||||
|
|
||||||
|
private final Provider<ChangesetCollectionResource> changesetCollectionResource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ChangesetRootResource(Provider<ChangesetCollectionResource> changesetCollectionResource) {
|
||||||
|
this.changesetCollectionResource = changesetCollectionResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("")
|
||||||
|
public ChangesetCollectionResource getChangesetCollectionResource() {
|
||||||
|
return changesetCollectionResource.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,6 @@ import sonia.scm.api.rest.resources.AbstractManagerResource;
|
|||||||
|
|
||||||
import javax.ws.rs.core.GenericEntity;
|
import javax.ws.rs.core.GenericEntity;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -17,50 +16,23 @@ import java.util.function.Supplier;
|
|||||||
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
|
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapter from resource http endpoints to managers.
|
* Adapter from resource http endpoints to managers, for Collection resources (e.g. {@code /users}).
|
||||||
*
|
*
|
||||||
* Provides common CRUD operations and DTO to Model Object mapping to keep Resources more DRY.
|
* Provides common CRUD operations and DTO to Model Object mapping to keep Resources more DRY.
|
||||||
*
|
*
|
||||||
* @param <MODEL_OBJECT> The type of the model object, eg. {@link sonia.scm.user.User}.
|
* @param <MODEL_OBJECT> The type of the model object, eg. {@link sonia.scm.user.User}.
|
||||||
* @param <DTO> The corresponding transport object, eg. {@link UserDto}.
|
* @param <DTO> The corresponding transport object, eg. {@link UserDto}.
|
||||||
* @param <EXCEPTION> The exception type for the model object, eg. {@link sonia.scm.user.UserException}.
|
* @param <EXCEPTION> The exception type for the model object, eg. {@link sonia.scm.user.UserException}.
|
||||||
|
*
|
||||||
|
* @see SingleResourceManagerAdapter
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right?
|
@SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right?
|
||||||
class ResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
class CollectionResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
||||||
DTO extends HalRepresentation,
|
DTO extends HalRepresentation,
|
||||||
EXCEPTION extends Exception> extends AbstractManagerResource<MODEL_OBJECT, EXCEPTION> {
|
EXCEPTION extends Exception> extends AbstractManagerResource<MODEL_OBJECT, EXCEPTION> {
|
||||||
|
|
||||||
ResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager) {
|
CollectionResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager, Class<MODEL_OBJECT> type) {
|
||||||
super(manager);
|
super(manager, type);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the model object for the given id, transforms it to a dto and returns a corresponding http response.
|
|
||||||
* This handles all corner cases, eg. no matching object for the id or missing privileges.
|
|
||||||
*/
|
|
||||||
Response get(String id, Function<MODEL_OBJECT, DTO> mapToDto) {
|
|
||||||
MODEL_OBJECT modelObject = manager.get(id);
|
|
||||||
if (modelObject == null) {
|
|
||||||
return Response.status(Response.Status.NOT_FOUND).build();
|
|
||||||
}
|
|
||||||
DTO dto = mapToDto.apply(modelObject);
|
|
||||||
return Response.ok(dto).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the model object for the given id according to the given function and returns a corresponding http response.
|
|
||||||
* This handles all corner cases, eg. no matching object for the id or missing privileges.
|
|
||||||
*/
|
|
||||||
public Response update(String id, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges) {
|
|
||||||
MODEL_OBJECT existingModelObject = manager.get(id);
|
|
||||||
if (existingModelObject == null) {
|
|
||||||
return Response.status(Response.Status.NOT_FOUND).build();
|
|
||||||
}
|
|
||||||
MODEL_OBJECT changedModelObject = applyChanges.apply(existingModelObject);
|
|
||||||
if (!id.equals(changedModelObject.getId())) {
|
|
||||||
return Response.status(BAD_REQUEST).entity("illegal change of id").build();
|
|
||||||
}
|
|
||||||
return update(id, changedModelObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,13 +48,13 @@ class ResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
|||||||
* Creates a model object for the given dto and returns a corresponding http response.
|
* Creates a model object for the given dto and returns a corresponding http response.
|
||||||
* This handles all corner cases, eg. no conflicts or missing privileges.
|
* This handles all corner cases, eg. no conflicts or missing privileges.
|
||||||
*/
|
*/
|
||||||
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) throws IOException, EXCEPTION {
|
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) throws EXCEPTION {
|
||||||
if (dto == null) {
|
if (dto == null) {
|
||||||
return Response.status(BAD_REQUEST).build();
|
return Response.status(BAD_REQUEST).build();
|
||||||
}
|
}
|
||||||
MODEL_OBJECT modelObject = modelObjectSupplier.get();
|
MODEL_OBJECT modelObject = modelObjectSupplier.get();
|
||||||
manager.create(modelObject);
|
MODEL_OBJECT created = manager.create(modelObject);
|
||||||
return Response.created(URI.create(uriCreator.apply(modelObject))).build();
|
return Response.created(URI.create(uriCreator.apply(created))).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -19,23 +19,24 @@ public class GroupCollectionResource {
|
|||||||
private final GroupCollectionToDtoMapper groupCollectionToDtoMapper;
|
private final GroupCollectionToDtoMapper groupCollectionToDtoMapper;
|
||||||
private final ResourceLinks resourceLinks;
|
private final ResourceLinks resourceLinks;
|
||||||
|
|
||||||
private final ResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
|
private final IdResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public GroupCollectionResource(GroupManager manager, GroupDtoToGroupMapper dtoToGroupMapper, GroupCollectionToDtoMapper groupCollectionToDtoMapper, ResourceLinks resourceLinks) {
|
public GroupCollectionResource(GroupManager manager, GroupDtoToGroupMapper dtoToGroupMapper, GroupCollectionToDtoMapper groupCollectionToDtoMapper, ResourceLinks resourceLinks) {
|
||||||
this.dtoToGroupMapper = dtoToGroupMapper;
|
this.dtoToGroupMapper = dtoToGroupMapper;
|
||||||
this.groupCollectionToDtoMapper = groupCollectionToDtoMapper;
|
this.groupCollectionToDtoMapper = groupCollectionToDtoMapper;
|
||||||
this.resourceLinks = resourceLinks;
|
this.resourceLinks = resourceLinks;
|
||||||
this.adapter = new ResourceManagerAdapter<>(manager);
|
this.adapter = new IdResourceManagerAdapter<>(manager, Group.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all groups for a given page number with a given page size (default page size is {@value DEFAULT_PAGE_SIZE}).
|
* Returns all groups for a given page number with a given page size (default page size is {@value DEFAULT_PAGE_SIZE}).
|
||||||
*
|
*
|
||||||
* <strong>Note:</strong> This method requires "group" privilege.
|
* <strong>Note:</strong> This method requires "group" privilege.
|
||||||
* @param page the number of the requested page
|
*
|
||||||
|
* @param page the number of the requested page
|
||||||
* @param pageSize the page size (default page size is {@value DEFAULT_PAGE_SIZE})
|
* @param pageSize the page size (default page size is {@value DEFAULT_PAGE_SIZE})
|
||||||
* @param sortBy sort parameter
|
* @param sortBy sort parameter (if empty - undefined sorting)
|
||||||
* @param desc sort direction desc or aesc
|
* @param desc sort direction desc or aesc
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@@ -44,6 +45,7 @@ public class GroupCollectionResource {
|
|||||||
@TypeHint(GroupDto[].class)
|
@TypeHint(GroupDto[].class)
|
||||||
@StatusCodes({
|
@StatusCodes({
|
||||||
@ResponseCode(code = 200, condition = "success"),
|
@ResponseCode(code = 200, condition = "success"),
|
||||||
|
@ResponseCode(code = 400, condition = "\"sortBy\" field unknown"),
|
||||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||||
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"group\" privilege"),
|
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"group\" privilege"),
|
||||||
@ResponseCode(code = 500, condition = "internal server error")
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
|
|||||||
@@ -9,27 +9,21 @@ import sonia.scm.group.GroupManager;
|
|||||||
import sonia.scm.web.VndMediaType;
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
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 javax.ws.rs.core.Response;
|
||||||
|
|
||||||
public class GroupResource {
|
public class GroupResource {
|
||||||
|
|
||||||
private final GroupToGroupDtoMapper groupToGroupDtoMapper;
|
private final GroupToGroupDtoMapper groupToGroupDtoMapper;
|
||||||
private final GroupDtoToGroupMapper dtoToGroupMapper;
|
private final GroupDtoToGroupMapper dtoToGroupMapper;
|
||||||
private final ResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
|
private final IdResourceManagerAdapter<Group, GroupDto, GroupException> adapter;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public GroupResource(GroupManager manager, GroupToGroupDtoMapper groupToGroupDtoMapper,
|
public GroupResource(GroupManager manager, GroupToGroupDtoMapper groupToGroupDtoMapper,
|
||||||
GroupDtoToGroupMapper groupDtoToGroupMapper) {
|
GroupDtoToGroupMapper groupDtoToGroupMapper) {
|
||||||
this.groupToGroupDtoMapper = groupToGroupDtoMapper;
|
this.groupToGroupDtoMapper = groupToGroupDtoMapper;
|
||||||
this.dtoToGroupMapper = groupDtoToGroupMapper;
|
this.dtoToGroupMapper = groupDtoToGroupMapper;
|
||||||
this.adapter = new ResourceManagerAdapter<>(manager);
|
this.adapter = new IdResourceManagerAdapter<>(manager, Group.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter @Setter
|
||||||
|
public class HealthCheckFailureDto {
|
||||||
|
private String description;
|
||||||
|
private String summary;
|
||||||
|
private String url;
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
|
import sonia.scm.Manager;
|
||||||
|
import sonia.scm.ModelObject;
|
||||||
|
import sonia.scm.PageResult;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Facade for {@link SingleResourceManagerAdapter} and {@link CollectionResourceManagerAdapter}
|
||||||
|
* for model objects handled by a single id.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right?
|
||||||
|
class IdResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
||||||
|
DTO extends HalRepresentation,
|
||||||
|
EXCEPTION extends Exception> {
|
||||||
|
|
||||||
|
private final Manager<MODEL_OBJECT, EXCEPTION> manager;
|
||||||
|
|
||||||
|
private final SingleResourceManagerAdapter<MODEL_OBJECT, DTO, EXCEPTION> singleAdapter;
|
||||||
|
private final CollectionResourceManagerAdapter<MODEL_OBJECT, DTO, EXCEPTION> collectionAdapter;
|
||||||
|
|
||||||
|
IdResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager, Class<MODEL_OBJECT> type) {
|
||||||
|
this.manager = manager;
|
||||||
|
singleAdapter = new SingleResourceManagerAdapter<>(manager, type);
|
||||||
|
collectionAdapter = new CollectionResourceManagerAdapter<>(manager, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response get(String id, Function<MODEL_OBJECT, DTO> mapToDto) {
|
||||||
|
return singleAdapter.get(loadBy(id), mapToDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response update(String id, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges) {
|
||||||
|
return singleAdapter.update(
|
||||||
|
loadBy(id),
|
||||||
|
applyChanges,
|
||||||
|
idStaysTheSame(id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response getAll(int page, int pageSize, String sortBy, boolean desc, Function<PageResult<MODEL_OBJECT>, CollectionDto> mapToDto) {
|
||||||
|
return collectionAdapter.getAll(page, pageSize, sortBy, desc, mapToDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response create(DTO dto, Supplier<MODEL_OBJECT> modelObjectSupplier, Function<MODEL_OBJECT, String> uriCreator) throws IOException, EXCEPTION {
|
||||||
|
return collectionAdapter.create(dto, modelObjectSupplier, uriCreator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response delete(String id) {
|
||||||
|
return singleAdapter.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Supplier<Optional<MODEL_OBJECT>> loadBy(String id) {
|
||||||
|
return () -> Optional.ofNullable(manager.get(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Predicate<MODEL_OBJECT> idStaysTheSame(String id) {
|
||||||
|
return changed -> changed.getId().equals(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,9 @@ public class MapperModule extends AbstractModule {
|
|||||||
bind(ScmConfigurationToGlobalConfigDtoMapper.class).to(Mappers.getMapper(ScmConfigurationToGlobalConfigDtoMapper.class).getClass());
|
bind(ScmConfigurationToGlobalConfigDtoMapper.class).to(Mappers.getMapper(ScmConfigurationToGlobalConfigDtoMapper.class).getClass());
|
||||||
bind(GlobalConfigDtoToScmConfigurationMapper.class).to(Mappers.getMapper(GlobalConfigDtoToScmConfigurationMapper.class).getClass());
|
bind(GlobalConfigDtoToScmConfigurationMapper.class).to(Mappers.getMapper(GlobalConfigDtoToScmConfigurationMapper.class).getClass());
|
||||||
|
|
||||||
|
bind(RepositoryToRepositoryDtoMapper.class).to(Mappers.getMapper(RepositoryToRepositoryDtoMapper.class).getClass());
|
||||||
|
bind(RepositoryDtoToRepositoryMapper.class).to(Mappers.getMapper(RepositoryDtoToRepositoryMapper.class).getClass());
|
||||||
|
|
||||||
bind(UriInfoStore.class).in(ServletScopes.REQUEST);
|
bind(UriInfoStore.class).in(ServletScopes.REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.ws.rs.DefaultValue;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
public class PermissionCollectionResource {
|
||||||
|
@GET
|
||||||
|
@Path("")
|
||||||
|
public Response getAll(@DefaultValue("0") @QueryParam("page") int page,
|
||||||
|
@DefaultValue("10") @QueryParam("pageSize") int pageSize,
|
||||||
|
@QueryParam("sortBy") String sortBy,
|
||||||
|
@DefaultValue("false") @QueryParam("desc") boolean desc) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
|
||||||
|
public class PermissionRootResource {
|
||||||
|
|
||||||
|
private final Provider<PermissionCollectionResource> permissionCollectionResource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public PermissionRootResource(Provider<PermissionCollectionResource> permissionCollectionResource) {
|
||||||
|
this.permissionCollectionResource = permissionCollectionResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("")
|
||||||
|
public PermissionCollectionResource getPermissionCollectionResource() {
|
||||||
|
return permissionCollectionResource.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.webcohesion.enunciate.metadata.rs.*;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.RepositoryException;
|
||||||
|
import sonia.scm.repository.RepositoryManager;
|
||||||
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
public class RepositoryCollectionResource {
|
||||||
|
|
||||||
|
private static final int DEFAULT_PAGE_SIZE = 10;
|
||||||
|
|
||||||
|
private final CollectionResourceManagerAdapter<Repository, RepositoryDto, RepositoryException> adapter;
|
||||||
|
private final RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper;
|
||||||
|
private final RepositoryDtoToRepositoryMapper dtoToRepositoryMapper;
|
||||||
|
private final ResourceLinks resourceLinks;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public RepositoryCollectionResource(RepositoryManager manager, RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper, RepositoryDtoToRepositoryMapper dtoToRepositoryMapper, ResourceLinks resourceLinks) {
|
||||||
|
this.adapter = new CollectionResourceManagerAdapter<>(manager, Repository.class);
|
||||||
|
this.repositoryCollectionToDtoMapper = repositoryCollectionToDtoMapper;
|
||||||
|
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
|
||||||
|
this.resourceLinks = resourceLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all repositories for a given page number with a given page size (default page size is {@value DEFAULT_PAGE_SIZE}).
|
||||||
|
*
|
||||||
|
* <strong>Note:</strong> This method requires "repository" privilege.
|
||||||
|
*
|
||||||
|
* @param page the number of the requested page
|
||||||
|
* @param pageSize the page size (default page size is {@value DEFAULT_PAGE_SIZE})
|
||||||
|
* @param sortBy sort parameter (if empty - undefined sorting)
|
||||||
|
* @param desc sort direction desc or asc
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("")
|
||||||
|
@Produces(VndMediaType.REPOSITORY_COLLECTION)
|
||||||
|
@TypeHint(RepositoryDto[].class)
|
||||||
|
@StatusCodes({
|
||||||
|
@ResponseCode(code = 200, condition = "success"),
|
||||||
|
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||||
|
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"repository\" privilege"),
|
||||||
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
|
})
|
||||||
|
public Response getAll(@DefaultValue("0") @QueryParam("page") int page,
|
||||||
|
@DefaultValue("" + DEFAULT_PAGE_SIZE) @QueryParam("pageSize") int pageSize,
|
||||||
|
@QueryParam("sortBy") String sortBy,
|
||||||
|
@DefaultValue("false") @QueryParam("desc") boolean desc) {
|
||||||
|
return adapter.getAll(page, pageSize, sortBy, desc,
|
||||||
|
pageResult -> repositoryCollectionToDtoMapper.map(page, pageSize, pageResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new repository.
|
||||||
|
*
|
||||||
|
* <strong>Note:</strong> This method requires "repository" privilege. The namespace of the given repository will
|
||||||
|
* be ignored and set by the configured namespace strategy.
|
||||||
|
*
|
||||||
|
* @param repositoryDto The repository to be created.
|
||||||
|
* @return A response with the link to the new repository (if created successfully).
|
||||||
|
*/
|
||||||
|
@POST
|
||||||
|
@Path("")
|
||||||
|
@Consumes(VndMediaType.REPOSITORY)
|
||||||
|
@StatusCodes({
|
||||||
|
@ResponseCode(code = 201, condition = "create success"),
|
||||||
|
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||||
|
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"repository\" privilege"),
|
||||||
|
@ResponseCode(code = 409, condition = "conflict, a repository with this name already exists"),
|
||||||
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
|
})
|
||||||
|
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||||
|
@ResponseHeaders(@ResponseHeader(name = "Location", description = "uri to the created repository"))
|
||||||
|
public Response create(RepositoryDto repositoryDto) throws RepositoryException {
|
||||||
|
return adapter.create(repositoryDto,
|
||||||
|
() -> dtoToRepositoryMapper.map(repositoryDto, null),
|
||||||
|
repository -> resourceLinks.repository().self(repository.getNamespace(), repository.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.RepositoryPermissions;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
// Mapstruct does not support parameterized (i.e. non-default) constructors. Thus, we need to use field injection.
|
||||||
|
@SuppressWarnings("squid:S3306")
|
||||||
|
public class RepositoryCollectionToDtoMapper extends BasicCollectionToDtoMapper<Repository, RepositoryDto> {
|
||||||
|
|
||||||
|
private final ResourceLinks resourceLinks;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public RepositoryCollectionToDtoMapper(RepositoryToRepositoryDtoMapper repositoryToDtoMapper, ResourceLinks resourceLinks) {
|
||||||
|
super("repositories", repositoryToDtoMapper);
|
||||||
|
this.resourceLinks = resourceLinks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String createCreateLink() {
|
||||||
|
return resourceLinks.repositoryCollection().create();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
String createSelfLink() {
|
||||||
|
return resourceLinks.repositoryCollection().self();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean isCreatePermitted() {
|
||||||
|
return RepositoryPermissions.create().isPermitted();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||||
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
|
import de.otto.edison.hal.Links;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Getter @Setter
|
||||||
|
public class RepositoryDto extends HalRepresentation {
|
||||||
|
|
||||||
|
private String contact;
|
||||||
|
private Instant creationDate;
|
||||||
|
private String description;
|
||||||
|
private List<HealthCheckFailureDto> healthCheckFailures;
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
private Instant lastModified;
|
||||||
|
private String namespace;
|
||||||
|
private String name;
|
||||||
|
private boolean archived = false;
|
||||||
|
private String type;
|
||||||
|
protected Map<String, String> properties;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("squid:S1185") // We want to have this method available in this package
|
||||||
|
protected HalRepresentation add(Links links) {
|
||||||
|
return super.add(links);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import org.mapstruct.*;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public abstract class RepositoryDtoToRepositoryMapper {
|
||||||
|
|
||||||
|
@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)
|
||||||
|
@Mapping(target = "permissions", ignore = true)
|
||||||
|
public abstract Repository map(RepositoryDto repositoryDto, @Context String id);
|
||||||
|
|
||||||
|
@AfterMapping
|
||||||
|
void updateId(@MappingTarget Repository repository, @Context String id) {
|
||||||
|
repository.setId(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
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 sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.RepositoryException;
|
||||||
|
import sonia.scm.repository.RepositoryManager;
|
||||||
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.ws.rs.*;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class RepositoryResource {
|
||||||
|
|
||||||
|
private final RepositoryToRepositoryDtoMapper repositoryToDtoMapper;
|
||||||
|
private final RepositoryDtoToRepositoryMapper dtoToRepositoryMapper;
|
||||||
|
|
||||||
|
private final RepositoryManager manager;
|
||||||
|
private final SingleResourceManagerAdapter<Repository, RepositoryDto, RepositoryException> adapter;
|
||||||
|
private final Provider<TagRootResource> tagRootResource;
|
||||||
|
private final Provider<BranchRootResource> branchRootResource;
|
||||||
|
private final Provider<ChangesetRootResource> changesetRootResource;
|
||||||
|
private final Provider<SourceRootResource> sourceRootResource;
|
||||||
|
private final Provider<PermissionRootResource> permissionRootResource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public RepositoryResource(
|
||||||
|
RepositoryToRepositoryDtoMapper repositoryToDtoMapper,
|
||||||
|
RepositoryDtoToRepositoryMapper dtoToRepositoryMapper, RepositoryManager manager,
|
||||||
|
Provider<TagRootResource> tagRootResource,
|
||||||
|
Provider<BranchRootResource> branchRootResource,
|
||||||
|
Provider<ChangesetRootResource> changesetRootResource,
|
||||||
|
Provider<SourceRootResource> sourceRootResource, Provider<PermissionRootResource> permissionRootResource) {
|
||||||
|
this.dtoToRepositoryMapper = dtoToRepositoryMapper;
|
||||||
|
this.manager = manager;
|
||||||
|
this.repositoryToDtoMapper = repositoryToDtoMapper;
|
||||||
|
this.adapter = new SingleResourceManagerAdapter<>(manager, Repository.class);
|
||||||
|
this.tagRootResource = tagRootResource;
|
||||||
|
this.branchRootResource = branchRootResource;
|
||||||
|
this.changesetRootResource = changesetRootResource;
|
||||||
|
this.sourceRootResource = sourceRootResource;
|
||||||
|
this.permissionRootResource = permissionRootResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a repository.
|
||||||
|
*
|
||||||
|
* <strong>Note:</strong> This method requires "repository" privilege.
|
||||||
|
*
|
||||||
|
* @param namespace the namespace of the repository
|
||||||
|
* @param name the name of the repository
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@GET
|
||||||
|
@Path("")
|
||||||
|
@Produces(VndMediaType.REPOSITORY)
|
||||||
|
@TypeHint(RepositoryDto.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 repository"),
|
||||||
|
@ResponseCode(code = 404, condition = "not found, no repository with the specified name available in the namespace"),
|
||||||
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
|
})
|
||||||
|
public Response get(@PathParam("namespace") String namespace, @PathParam("name") String name) {
|
||||||
|
return adapter.get(loadBy(namespace, name), repositoryToDtoMapper::map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a repository.
|
||||||
|
*
|
||||||
|
* <strong>Note:</strong> This method requires "repository" privilege.
|
||||||
|
*
|
||||||
|
* @param namespace the namespace of the repository to delete
|
||||||
|
* @param name the name of the repository to delete
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@DELETE
|
||||||
|
@Path("")
|
||||||
|
@StatusCodes({
|
||||||
|
@ResponseCode(code = 204, condition = "delete success or nothing to delete"),
|
||||||
|
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||||
|
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"repository\" privilege"),
|
||||||
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
|
})
|
||||||
|
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||||
|
public Response delete(@PathParam("namespace") String namespace, @PathParam("name") String name) {
|
||||||
|
return adapter.delete(loadBy(namespace, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies the given repository.
|
||||||
|
*
|
||||||
|
* <strong>Note:</strong> This method requires "repository" privilege.
|
||||||
|
*
|
||||||
|
* @param namespace the namespace of the repository to be modified
|
||||||
|
* @param name the name of the repository to be modified
|
||||||
|
* @param repositoryDto repository object to modify
|
||||||
|
*/
|
||||||
|
@PUT
|
||||||
|
@Path("")
|
||||||
|
@Consumes(VndMediaType.REPOSITORY)
|
||||||
|
@StatusCodes({
|
||||||
|
@ResponseCode(code = 204, condition = "update success"),
|
||||||
|
@ResponseCode(code = 400, condition = "Invalid body, e.g. illegal change of namespace or name"),
|
||||||
|
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||||
|
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"repository\" privilege"),
|
||||||
|
@ResponseCode(code = 404, condition = "not found, no repository with the specified namespace and name available"),
|
||||||
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
|
})
|
||||||
|
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||||
|
public Response update(@PathParam("namespace") String namespace, @PathParam("name") String name, RepositoryDto repositoryDto) {
|
||||||
|
return adapter.update(
|
||||||
|
loadBy(namespace, name),
|
||||||
|
existing -> dtoToRepositoryMapper.map(repositoryDto, existing.getId()),
|
||||||
|
nameAndNamespaceStaysTheSame(namespace, name)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("tags/")
|
||||||
|
public TagRootResource tags() {
|
||||||
|
return tagRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("branches/")
|
||||||
|
public BranchRootResource branches() {
|
||||||
|
return branchRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("changesets/")
|
||||||
|
public ChangesetRootResource changesets() {
|
||||||
|
return changesetRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("sources/")
|
||||||
|
public SourceRootResource sources() {
|
||||||
|
return sourceRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("permissions/")
|
||||||
|
public PermissionRootResource permissions() {
|
||||||
|
return permissionRootResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Supplier<Optional<Repository>> loadBy(String namespace, String name) {
|
||||||
|
return () -> manager.getByNamespace(namespace, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Predicate<Repository> nameAndNamespaceStaysTheSame(String namespace, String name) {
|
||||||
|
return changed -> changed.getName().equals(name) && changed.getNamespace().equals(namespace);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RESTful Web Service Resource to manage repositories.
|
||||||
|
*/
|
||||||
|
@Path(RepositoryRootResource.REPOSITORIES_PATH_V2)
|
||||||
|
public class RepositoryRootResource {
|
||||||
|
static final String REPOSITORIES_PATH_V2 = "v2/repositories/";
|
||||||
|
|
||||||
|
private final Provider<RepositoryResource> repositoryResource;
|
||||||
|
private final Provider<RepositoryCollectionResource> repositoryCollectionResource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public RepositoryRootResource(Provider<RepositoryResource> repositoryResource, Provider<RepositoryCollectionResource> repositoryCollectionResource) {
|
||||||
|
this.repositoryResource = repositoryResource;
|
||||||
|
this.repositoryCollectionResource = repositoryCollectionResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("{namespace}/{name}")
|
||||||
|
public RepositoryResource getRepositoryResource() {
|
||||||
|
return repositoryResource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("")
|
||||||
|
public RepositoryCollectionResource getRepositoryCollectionResource() {
|
||||||
|
return repositoryCollectionResource.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import de.otto.edison.hal.Links;
|
||||||
|
import org.mapstruct.AfterMapping;
|
||||||
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
|
import sonia.scm.repository.HealthCheckFailure;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.RepositoryPermissions;
|
||||||
|
|
||||||
|
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 RepositoryToRepositoryDtoMapper extends BaseMapper<Repository, RepositoryDto> {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ResourceLinks resourceLinks;
|
||||||
|
|
||||||
|
abstract HealthCheckFailureDto toDto(HealthCheckFailure failure);
|
||||||
|
|
||||||
|
@AfterMapping
|
||||||
|
void appendLinks(Repository repository, @MappingTarget RepositoryDto target) {
|
||||||
|
Links.Builder linksBuilder = linkingTo().self(resourceLinks.repository().self(target.getNamespace(), target.getName()));
|
||||||
|
if (RepositoryPermissions.delete(repository).isPermitted()) {
|
||||||
|
linksBuilder.single(link("delete", resourceLinks.repository().delete(target.getNamespace(), target.getName())));
|
||||||
|
}
|
||||||
|
if (RepositoryPermissions.modify(repository).isPermitted()) {
|
||||||
|
linksBuilder.single(link("update", resourceLinks.repository().update(target.getNamespace(), target.getName())));
|
||||||
|
linksBuilder.single(link("permissions", resourceLinks.permissionCollection().self(target.getNamespace(), target.getName())));
|
||||||
|
}
|
||||||
|
linksBuilder.single(link("tags", resourceLinks.tagCollection().self(target.getNamespace(), target.getName())));
|
||||||
|
linksBuilder.single(link("branches", resourceLinks.branchCollection().self(target.getNamespace(), target.getName())));
|
||||||
|
linksBuilder.single(link("changesets", resourceLinks.changesetCollection().self(target.getNamespace(), target.getName())));
|
||||||
|
linksBuilder.single(link("sources", resourceLinks.sourceCollection().self(target.getNamespace(), target.getName())));
|
||||||
|
target.add(linksBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,7 +20,7 @@ class ResourceLinks {
|
|||||||
static class GroupLinks {
|
static class GroupLinks {
|
||||||
private final LinkBuilder groupLinkBuilder;
|
private final LinkBuilder groupLinkBuilder;
|
||||||
|
|
||||||
private GroupLinks(UriInfo uriInfo) {
|
GroupLinks(UriInfo uriInfo) {
|
||||||
groupLinkBuilder = new LinkBuilder(uriInfo, GroupRootResource.class, GroupResource.class);
|
groupLinkBuilder = new LinkBuilder(uriInfo, GroupRootResource.class, GroupResource.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class ResourceLinks {
|
|||||||
static class GroupCollectionLinks {
|
static class GroupCollectionLinks {
|
||||||
private final LinkBuilder collectionLinkBuilder;
|
private final LinkBuilder collectionLinkBuilder;
|
||||||
|
|
||||||
private GroupCollectionLinks(UriInfo uriInfo) {
|
GroupCollectionLinks(UriInfo uriInfo) {
|
||||||
collectionLinkBuilder = new LinkBuilder(uriInfo, GroupRootResource.class, GroupCollectionResource.class);
|
collectionLinkBuilder = new LinkBuilder(uriInfo, GroupRootResource.class, GroupCollectionResource.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ class ResourceLinks {
|
|||||||
static class UserLinks {
|
static class UserLinks {
|
||||||
private final LinkBuilder userLinkBuilder;
|
private final LinkBuilder userLinkBuilder;
|
||||||
|
|
||||||
private UserLinks(UriInfo uriInfo) {
|
UserLinks(UriInfo uriInfo) {
|
||||||
userLinkBuilder = new LinkBuilder(uriInfo, UserRootResource.class, UserResource.class);
|
userLinkBuilder = new LinkBuilder(uriInfo, UserRootResource.class, UserResource.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ class ResourceLinks {
|
|||||||
static class UserCollectionLinks {
|
static class UserCollectionLinks {
|
||||||
private final LinkBuilder collectionLinkBuilder;
|
private final LinkBuilder collectionLinkBuilder;
|
||||||
|
|
||||||
private UserCollectionLinks(UriInfo uriInfo) {
|
UserCollectionLinks(UriInfo uriInfo) {
|
||||||
collectionLinkBuilder = new LinkBuilder(uriInfo, UserRootResource.class, UserCollectionResource.class);
|
collectionLinkBuilder = new LinkBuilder(uriInfo, UserRootResource.class, UserCollectionResource.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ class ResourceLinks {
|
|||||||
static class GlobalConfigLinks {
|
static class GlobalConfigLinks {
|
||||||
private final LinkBuilder globalConfigLinkBuilder;
|
private final LinkBuilder globalConfigLinkBuilder;
|
||||||
|
|
||||||
private GlobalConfigLinks(UriInfo uriInfo) {
|
GlobalConfigLinks(UriInfo uriInfo) {
|
||||||
globalConfigLinkBuilder = new LinkBuilder(uriInfo, GlobalConfigResource.class);
|
globalConfigLinkBuilder = new LinkBuilder(uriInfo, GlobalConfigResource.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,4 +120,128 @@ class ResourceLinks {
|
|||||||
return globalConfigLinkBuilder.method("update").parameters().href();
|
return globalConfigLinkBuilder.method("update").parameters().href();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RepositoryLinks repository() {
|
||||||
|
return new RepositoryLinks(uriInfoStore.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RepositoryLinks {
|
||||||
|
private final LinkBuilder repositoryLinkBuilder;
|
||||||
|
|
||||||
|
RepositoryLinks(UriInfo uriInfo) {
|
||||||
|
repositoryLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
String self(String namespace, String name) {
|
||||||
|
return repositoryLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("get").parameters().href();
|
||||||
|
}
|
||||||
|
|
||||||
|
String delete(String namespace, String name) {
|
||||||
|
return repositoryLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("delete").parameters().href();
|
||||||
|
}
|
||||||
|
|
||||||
|
String update(String namespace, String name) {
|
||||||
|
return repositoryLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("update").parameters().href();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RepositoryCollectionLinks repositoryCollection() {
|
||||||
|
return new RepositoryCollectionLinks(uriInfoStore.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RepositoryCollectionLinks {
|
||||||
|
private final LinkBuilder collectionLinkBuilder;
|
||||||
|
|
||||||
|
RepositoryCollectionLinks(UriInfo uriInfo) {
|
||||||
|
collectionLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryCollectionResource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
String self() {
|
||||||
|
return collectionLinkBuilder.method("getRepositoryCollectionResource").parameters().method("getAll").parameters().href();
|
||||||
|
}
|
||||||
|
|
||||||
|
String create() {
|
||||||
|
return collectionLinkBuilder.method("getRepositoryCollectionResource").parameters().method("create").parameters().href();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TagCollectionLinks tagCollection() {
|
||||||
|
return new TagCollectionLinks(uriInfoStore.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TagCollectionLinks {
|
||||||
|
private final LinkBuilder tagLinkBuilder;
|
||||||
|
|
||||||
|
TagCollectionLinks(UriInfo uriInfo) {
|
||||||
|
tagLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, TagRootResource.class, TagCollectionResource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
String self(String namespace, String name) {
|
||||||
|
return tagLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("tags").parameters().method("getTagCollectionResource").parameters().method("getAll").parameters().href();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BranchCollectionLinks branchCollection() {
|
||||||
|
return new BranchCollectionLinks(uriInfoStore.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BranchCollectionLinks {
|
||||||
|
private final LinkBuilder branchLinkBuilder;
|
||||||
|
|
||||||
|
BranchCollectionLinks(UriInfo uriInfo) {
|
||||||
|
branchLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, BranchRootResource.class, BranchCollectionResource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
String self(String namespace, String name) {
|
||||||
|
return branchLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("branches").parameters().method("getBranchCollectionResource").parameters().method("getAll").parameters().href();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChangesetCollectionLinks changesetCollection() {
|
||||||
|
return new ChangesetCollectionLinks(uriInfoStore.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ChangesetCollectionLinks {
|
||||||
|
private final LinkBuilder changesetLinkBuilder;
|
||||||
|
|
||||||
|
ChangesetCollectionLinks(UriInfo uriInfo) {
|
||||||
|
changesetLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, ChangesetRootResource.class, ChangesetCollectionResource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
String self(String namespace, String name) {
|
||||||
|
return changesetLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("changesets").parameters().method("getChangesetCollectionResource").parameters().method("getAll").parameters().href();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceCollectionLinks sourceCollection() {
|
||||||
|
return new SourceCollectionLinks(uriInfoStore.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SourceCollectionLinks {
|
||||||
|
private final LinkBuilder sourceLinkBuilder;
|
||||||
|
|
||||||
|
SourceCollectionLinks(UriInfo uriInfo) {
|
||||||
|
sourceLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, SourceRootResource.class, SourceCollectionResource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
String self(String namespace, String name) {
|
||||||
|
return sourceLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("sources").parameters().method("getSourceCollectionResource").parameters().method("getAll").parameters().href();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PermissionCollectionLinks permissionCollection() {
|
||||||
|
return new PermissionCollectionLinks(uriInfoStore.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PermissionCollectionLinks {
|
||||||
|
private final LinkBuilder permissionLinkBuilder;
|
||||||
|
|
||||||
|
PermissionCollectionLinks(UriInfo uriInfo) {
|
||||||
|
permissionLinkBuilder = new LinkBuilder(uriInfo, RepositoryRootResource.class, RepositoryResource.class, PermissionRootResource.class, PermissionCollectionResource.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
String self(String namespace, String name) {
|
||||||
|
return permissionLinkBuilder.method("getRepositoryResource").parameters(namespace, name).method("permissions").parameters().method("getPermissionCollectionResource").parameters().method("getAll").parameters().href();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import de.otto.edison.hal.HalRepresentation;
|
||||||
|
import sonia.scm.Manager;
|
||||||
|
import sonia.scm.ModelObject;
|
||||||
|
import sonia.scm.api.rest.resources.AbstractManagerResource;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.GenericEntity;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter from resource http endpoints to managers, for Single resources (e.g. {@code /user/name}).
|
||||||
|
*
|
||||||
|
* Provides common CRUD operations and DTO to Model Object mapping to keep Resources more DRY.
|
||||||
|
*
|
||||||
|
* @param <MODEL_OBJECT> The type of the model object, eg. {@link sonia.scm.user.User}.
|
||||||
|
* @param <DTO> The corresponding transport object, eg. {@link UserDto}.
|
||||||
|
* @param <EXCEPTION> The exception type for the model object, eg. {@link sonia.scm.user.UserException}.
|
||||||
|
*
|
||||||
|
* @see CollectionResourceManagerAdapter
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("squid:S00119") // "MODEL_OBJECT" is much more meaningful than "M", right?
|
||||||
|
class SingleResourceManagerAdapter<MODEL_OBJECT extends ModelObject,
|
||||||
|
DTO extends HalRepresentation,
|
||||||
|
EXCEPTION extends Exception> extends AbstractManagerResource<MODEL_OBJECT, EXCEPTION> {
|
||||||
|
|
||||||
|
SingleResourceManagerAdapter(Manager<MODEL_OBJECT, EXCEPTION> manager, Class<MODEL_OBJECT> type) {
|
||||||
|
super(manager, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the model object for the given id, transforms it to a dto and returns a corresponding http response.
|
||||||
|
* This handles all corner cases, eg. no matching object for the id or missing privileges.
|
||||||
|
*/
|
||||||
|
Response get(Supplier<Optional<MODEL_OBJECT>> reader, Function<MODEL_OBJECT, DTO> mapToDto) {
|
||||||
|
return reader.get()
|
||||||
|
.map(mapToDto)
|
||||||
|
.map(Response::ok)
|
||||||
|
.map(Response.ResponseBuilder::build)
|
||||||
|
.orElse(Response.status(Response.Status.NOT_FOUND).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the model object for the given id according to the given function and returns a corresponding http response.
|
||||||
|
* This handles all corner cases, eg. no matching object for the id or missing privileges.
|
||||||
|
*/
|
||||||
|
public Response update(Supplier<Optional<MODEL_OBJECT>> reader, Function<MODEL_OBJECT, MODEL_OBJECT> applyChanges, Predicate<MODEL_OBJECT> hasSameKey) {
|
||||||
|
Optional<MODEL_OBJECT> existingModelObject = reader.get();
|
||||||
|
if (!existingModelObject.isPresent()) {
|
||||||
|
return Response.status(Response.Status.NOT_FOUND).build();
|
||||||
|
}
|
||||||
|
MODEL_OBJECT changedModelObject = applyChanges.apply(existingModelObject.get());
|
||||||
|
if (!hasSameKey.test(changedModelObject)) {
|
||||||
|
return Response.status(BAD_REQUEST).entity("illegal change of id").build();
|
||||||
|
}
|
||||||
|
return update(getId(existingModelObject.get()), changedModelObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response delete(Supplier<Optional<MODEL_OBJECT>> reader) {
|
||||||
|
return reader.get()
|
||||||
|
.map(MODEL_OBJECT::getId)
|
||||||
|
.map(this::delete)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected GenericEntity<Collection<MODEL_OBJECT>> createGenericEntity(Collection<MODEL_OBJECT> modelObjects) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getId(MODEL_OBJECT item) {
|
||||||
|
return item.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPathPart() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.ws.rs.DefaultValue;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
public class SourceCollectionResource {
|
||||||
|
@GET
|
||||||
|
@Path("")
|
||||||
|
public Response getAll(@DefaultValue("0") @QueryParam("page") int page,
|
||||||
|
@DefaultValue("10") @QueryParam("pageSize") int pageSize,
|
||||||
|
@QueryParam("sortBy") String sortBy,
|
||||||
|
@DefaultValue("false") @QueryParam("desc") boolean desc) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
|
||||||
|
public class SourceRootResource {
|
||||||
|
|
||||||
|
private final Provider<SourceCollectionResource> sourceCollectionResource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public SourceRootResource(Provider<SourceCollectionResource> sourceCollectionResource) {
|
||||||
|
this.sourceCollectionResource = sourceCollectionResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("")
|
||||||
|
public SourceCollectionResource getSourceCollectionResource() {
|
||||||
|
return sourceCollectionResource.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.ws.rs.DefaultValue;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
public class TagCollectionResource {
|
||||||
|
@GET
|
||||||
|
@Path("")
|
||||||
|
public Response getAll(@DefaultValue("0") @QueryParam("page") int page,
|
||||||
|
@DefaultValue("10") @QueryParam("pageSize") int pageSize,
|
||||||
|
@QueryParam("sortBy") String sortBy,
|
||||||
|
@DefaultValue("false") @QueryParam("desc") boolean desc) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
|
||||||
|
public class TagRootResource {
|
||||||
|
|
||||||
|
private final Provider<TagCollectionResource> tagCollectionResource;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public TagRootResource(Provider<TagCollectionResource> tagCollectionResource) {
|
||||||
|
this.tagCollectionResource = tagCollectionResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("")
|
||||||
|
public TagCollectionResource getTagCollectionResource() {
|
||||||
|
return tagCollectionResource.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,14 +18,14 @@ public class UserCollectionResource {
|
|||||||
private final UserCollectionToDtoMapper userCollectionToDtoMapper;
|
private final UserCollectionToDtoMapper userCollectionToDtoMapper;
|
||||||
private final ResourceLinks resourceLinks;
|
private final ResourceLinks resourceLinks;
|
||||||
|
|
||||||
private final ResourceManagerAdapter<User, UserDto, UserException> adapter;
|
private final IdResourceManagerAdapter<User, UserDto, UserException> adapter;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public UserCollectionResource(UserManager manager, UserDtoToUserMapper dtoToUserMapper,
|
public UserCollectionResource(UserManager manager, UserDtoToUserMapper dtoToUserMapper,
|
||||||
UserCollectionToDtoMapper userCollectionToDtoMapper, ResourceLinks resourceLinks) {
|
UserCollectionToDtoMapper userCollectionToDtoMapper, ResourceLinks resourceLinks) {
|
||||||
this.dtoToUserMapper = dtoToUserMapper;
|
this.dtoToUserMapper = dtoToUserMapper;
|
||||||
this.userCollectionToDtoMapper = userCollectionToDtoMapper;
|
this.userCollectionToDtoMapper = userCollectionToDtoMapper;
|
||||||
this.adapter = new ResourceManagerAdapter<>(manager);
|
this.adapter = new IdResourceManagerAdapter<>(manager, User.class);
|
||||||
this.resourceLinks = resourceLinks;
|
this.resourceLinks = resourceLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,9 +33,10 @@ public class UserCollectionResource {
|
|||||||
* Returns all users for a given page number with a given page size (default page size is {@value DEFAULT_PAGE_SIZE}).
|
* Returns all users for a given page number with a given page size (default page size is {@value DEFAULT_PAGE_SIZE}).
|
||||||
*
|
*
|
||||||
* <strong>Note:</strong> This method requires "user" privilege.
|
* <strong>Note:</strong> This method requires "user" privilege.
|
||||||
* @param page the number of the requested page
|
*
|
||||||
|
* @param page the number of the requested page
|
||||||
* @param pageSize the page size (default page size is {@value DEFAULT_PAGE_SIZE})
|
* @param pageSize the page size (default page size is {@value DEFAULT_PAGE_SIZE})
|
||||||
* @param sortBy sort parameter
|
* @param sortBy sort parameter (if empty - undefined sorting)
|
||||||
* @param desc sort direction desc or asc
|
* @param desc sort direction desc or asc
|
||||||
*/
|
*/
|
||||||
@GET
|
@GET
|
||||||
@@ -44,6 +45,7 @@ public class UserCollectionResource {
|
|||||||
@TypeHint(UserDto[].class)
|
@TypeHint(UserDto[].class)
|
||||||
@StatusCodes({
|
@StatusCodes({
|
||||||
@ResponseCode(code = 200, condition = "success"),
|
@ResponseCode(code = 200, condition = "success"),
|
||||||
|
@ResponseCode(code = 400, condition = "\"sortBy\" field unknown"),
|
||||||
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
@ResponseCode(code = 401, condition = "not authenticated / invalid credentials"),
|
||||||
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"user\" privilege"),
|
@ResponseCode(code = 403, condition = "not authorized, the current user does not have the \"user\" privilege"),
|
||||||
@ResponseCode(code = 500, condition = "internal server error")
|
@ResponseCode(code = 500, condition = "internal server error")
|
||||||
|
|||||||
@@ -9,13 +9,7 @@ import sonia.scm.user.UserManager;
|
|||||||
import sonia.scm.web.VndMediaType;
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.*;
|
||||||
import javax.ws.rs.DELETE;
|
|
||||||
import javax.ws.rs.GET;
|
|
||||||
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 javax.ws.rs.core.Response;
|
||||||
|
|
||||||
public class UserResource {
|
public class UserResource {
|
||||||
@@ -23,13 +17,13 @@ public class UserResource {
|
|||||||
private final UserDtoToUserMapper dtoToUserMapper;
|
private final UserDtoToUserMapper dtoToUserMapper;
|
||||||
private final UserToUserDtoMapper userToDtoMapper;
|
private final UserToUserDtoMapper userToDtoMapper;
|
||||||
|
|
||||||
private final ResourceManagerAdapter<User, UserDto, UserException> adapter;
|
private final IdResourceManagerAdapter<User, UserDto, UserException> adapter;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public UserResource(UserDtoToUserMapper dtoToUserMapper, UserToUserDtoMapper userToDtoMapper, UserManager manager) {
|
public UserResource(UserDtoToUserMapper dtoToUserMapper, UserToUserDtoMapper userToDtoMapper, UserManager manager) {
|
||||||
this.dtoToUserMapper = dtoToUserMapper;
|
this.dtoToUserMapper = dtoToUserMapper;
|
||||||
this.userToDtoMapper = userToDtoMapper;
|
this.userToDtoMapper = userToDtoMapper;
|
||||||
this.adapter = new ResourceManagerAdapter<>(manager);
|
this.adapter = new IdResourceManagerAdapter<>(manager, User.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import com.google.inject.Singleton;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.HandlerEventType;
|
import sonia.scm.HandlerEventType;
|
||||||
|
import sonia.scm.ManagerDaoAdapter;
|
||||||
import sonia.scm.SCMContextProvider;
|
import sonia.scm.SCMContextProvider;
|
||||||
import sonia.scm.TransformFilter;
|
import sonia.scm.TransformFilter;
|
||||||
import sonia.scm.search.SearchRequest;
|
import sonia.scm.search.SearchRequest;
|
||||||
@@ -79,6 +80,10 @@ public class DefaultGroupManager extends AbstractGroupManager
|
|||||||
public DefaultGroupManager(GroupDAO groupDAO)
|
public DefaultGroupManager(GroupDAO groupDAO)
|
||||||
{
|
{
|
||||||
this.groupDAO = groupDAO;
|
this.groupDAO = groupDAO;
|
||||||
|
this.managerDaoAdapter = new ManagerDaoAdapter<>(
|
||||||
|
groupDAO,
|
||||||
|
GroupNotFoundException::new,
|
||||||
|
GroupAlreadyExistsException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
@@ -96,78 +101,34 @@ public class DefaultGroupManager extends AbstractGroupManager
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param group
|
|
||||||
*
|
|
||||||
* @throws GroupException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void create(Group group) throws GroupException, IOException
|
public Group create(Group group) throws GroupException {
|
||||||
{
|
|
||||||
String type = group.getType();
|
String type = group.getType();
|
||||||
|
if (Util.isEmpty(type)) {
|
||||||
if (Util.isEmpty(type))
|
|
||||||
{
|
|
||||||
group.setType(groupDAO.getType());
|
group.setType(groupDAO.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
String name = group.getName();
|
logger.info("create group {} of type {}", group.getName(), group.getType());
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("create group {} of type {}", name,
|
|
||||||
group.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
GroupPermissions.create().check();
|
|
||||||
|
|
||||||
if (groupDAO.contains(name))
|
|
||||||
{
|
|
||||||
throw new GroupAlreadyExistsException(name.concat(" group already exists"));
|
|
||||||
}
|
|
||||||
|
|
||||||
removeDuplicateMembers(group);
|
removeDuplicateMembers(group);
|
||||||
group.setCreationDate(System.currentTimeMillis());
|
|
||||||
fireEvent(HandlerEventType.BEFORE_CREATE, group);
|
return managerDaoAdapter.create(
|
||||||
groupDAO.add(group);
|
group,
|
||||||
fireEvent(HandlerEventType.CREATE, group);
|
GroupPermissions::create,
|
||||||
|
newGroup -> fireEvent(HandlerEventType.BEFORE_CREATE, newGroup),
|
||||||
|
newGroup -> fireEvent(HandlerEventType.CREATE, newGroup)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param group
|
|
||||||
*
|
|
||||||
* @throws GroupException
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(Group group) throws GroupException, IOException
|
public void delete(Group group) throws GroupException {
|
||||||
{
|
logger.info("delete group {} of type {}", group.getName(), group.getType());
|
||||||
if (logger.isInfoEnabled())
|
managerDaoAdapter.delete(
|
||||||
{
|
group,
|
||||||
logger.info("delete group {} of type {}", group.getName(),
|
() -> GroupPermissions.delete(group.getName()),
|
||||||
group.getType());
|
toDelete -> fireEvent(HandlerEventType.BEFORE_DELETE, toDelete),
|
||||||
}
|
toDelete -> fireEvent(HandlerEventType.DELETE, toDelete)
|
||||||
|
);
|
||||||
String name = group.getName();
|
|
||||||
GroupPermissions.delete().check(name);
|
|
||||||
|
|
||||||
if (groupDAO.contains(name))
|
|
||||||
{
|
|
||||||
fireEvent(HandlerEventType.BEFORE_DELETE, group);
|
|
||||||
groupDAO.delete(group);
|
|
||||||
fireEvent(HandlerEventType.DELETE, group);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new GroupNotFoundException("user does not exists");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -189,31 +150,18 @@ public class DefaultGroupManager extends AbstractGroupManager
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void modify(Group group) throws GroupException, IOException
|
public void modify(Group group) throws GroupException {
|
||||||
{
|
logger.info("modify group {} of type {}", group.getName(), group.getType());
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
|
||||||
logger.info("modify group {} of type {}", group.getName(),
|
|
||||||
group.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = group.getName();
|
managerDaoAdapter.modify(
|
||||||
GroupPermissions.modify().check(name);
|
group,
|
||||||
|
GroupPermissions::modify,
|
||||||
Group notModified = groupDAO.get(name);
|
notModified -> {
|
||||||
if (notModified != null)
|
removeDuplicateMembers(group);
|
||||||
{
|
fireEvent(HandlerEventType.BEFORE_MODIFY, group, notModified);
|
||||||
removeDuplicateMembers(group);
|
},
|
||||||
fireEvent(HandlerEventType.BEFORE_MODIFY, group, notModified);
|
notModified -> fireEvent(HandlerEventType.MODIFY, group, notModified)
|
||||||
group.setLastModified(System.currentTimeMillis());
|
);
|
||||||
group.setCreationDate(notModified.getCreationDate());
|
|
||||||
groupDAO.modify(group);
|
|
||||||
fireEvent(HandlerEventType.MODIFY, group, notModified);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new GroupNotFoundException("group does not exists");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -226,7 +174,7 @@ public class DefaultGroupManager extends AbstractGroupManager
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void refresh(Group group) throws GroupException, IOException
|
public void refresh(Group group) throws GroupException
|
||||||
{
|
{
|
||||||
String name = group.getName();
|
String name = group.getName();
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
@@ -239,7 +187,7 @@ public class DefaultGroupManager extends AbstractGroupManager
|
|||||||
|
|
||||||
if (fresh == null)
|
if (fresh == null)
|
||||||
{
|
{
|
||||||
throw new GroupNotFoundException("group does not exists");
|
throw new GroupNotFoundException(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
fresh.copyProperties(group);
|
fresh.copyProperties(group);
|
||||||
@@ -452,4 +400,5 @@ public class DefaultGroupManager extends AbstractGroupManager
|
|||||||
|
|
||||||
/** Field description */
|
/** Field description */
|
||||||
private GroupDAO groupDAO;
|
private GroupDAO groupDAO;
|
||||||
|
private final ManagerDaoAdapter<Group, GroupException> managerDaoAdapter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,29 +42,14 @@ import com.google.inject.Singleton;
|
|||||||
import org.apache.shiro.concurrent.SubjectAwareExecutorService;
|
import org.apache.shiro.concurrent.SubjectAwareExecutorService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.ArgumentIsInvalidException;
|
import sonia.scm.*;
|
||||||
import sonia.scm.ConfigurationException;
|
|
||||||
import sonia.scm.HandlerEventType;
|
|
||||||
import sonia.scm.SCMContextProvider;
|
|
||||||
import sonia.scm.Type;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
import sonia.scm.security.KeyGenerator;
|
import sonia.scm.security.KeyGenerator;
|
||||||
import sonia.scm.util.AssertUtil;
|
import sonia.scm.util.*;
|
||||||
import sonia.scm.util.CollectionAppender;
|
|
||||||
import sonia.scm.util.HttpUtil;
|
|
||||||
import sonia.scm.util.IOUtil;
|
|
||||||
import sonia.scm.util.Util;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
@@ -90,6 +75,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
|||||||
private final Set<Type> types;
|
private final Set<Type> types;
|
||||||
private RepositoryMatcher repositoryMatcher;
|
private RepositoryMatcher repositoryMatcher;
|
||||||
private NamespaceStrategy namespaceStrategy;
|
private NamespaceStrategy namespaceStrategy;
|
||||||
|
private final ManagerDaoAdapter<Repository, RepositoryException> managerDaoAdapter;
|
||||||
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -116,6 +102,10 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
|||||||
for (RepositoryHandler handler : handlerSet) {
|
for (RepositoryHandler handler : handlerSet) {
|
||||||
addHandler(contextProvider, handler);
|
addHandler(contextProvider, handler);
|
||||||
}
|
}
|
||||||
|
managerDaoAdapter = new ManagerDaoAdapter<>(
|
||||||
|
repositoryDAO,
|
||||||
|
RepositoryNotFoundException::new,
|
||||||
|
RepositoryAlreadyExistsException::create);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -128,89 +118,47 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Method description
|
public Repository create(Repository repository) throws RepositoryException {
|
||||||
*
|
return create(repository, true);
|
||||||
*
|
}
|
||||||
* @param repository
|
|
||||||
* @param initRepository
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
|
||||||
public void create(Repository repository, boolean initRepository)
|
|
||||||
throws RepositoryException, IOException {
|
|
||||||
logger.info("create repository {} of type {}", repository.getName(),
|
|
||||||
repository.getType());
|
|
||||||
|
|
||||||
RepositoryPermissions.create().check();
|
|
||||||
AssertUtil.assertIsValid(repository);
|
|
||||||
|
|
||||||
if (repositoryDAO.contains(repository)) {
|
|
||||||
throw RepositoryAlreadyExistsException.create(repository);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public Repository create(Repository repository, boolean initRepository) throws RepositoryException {
|
||||||
repository.setId(keyGenerator.createKey());
|
repository.setId(keyGenerator.createKey());
|
||||||
repository.setCreationDate(System.currentTimeMillis());
|
|
||||||
repository.setNamespace(namespaceStrategy.getNamespace());
|
repository.setNamespace(namespaceStrategy.getNamespace());
|
||||||
|
|
||||||
if (initRepository) {
|
logger.info("create repository {} of type {} in namespace {}", repository.getName(), repository.getType(), repository.getNamespace());
|
||||||
getHandler(repository).create(repository);
|
|
||||||
}
|
|
||||||
|
|
||||||
fireEvent(HandlerEventType.BEFORE_CREATE, repository);
|
return managerDaoAdapter.create(
|
||||||
repositoryDAO.add(repository);
|
repository,
|
||||||
fireEvent(HandlerEventType.CREATE, repository);
|
RepositoryPermissions::create,
|
||||||
|
newRepository -> {
|
||||||
|
if (initRepository) {
|
||||||
|
getHandler(newRepository).create(newRepository);
|
||||||
|
}
|
||||||
|
fireEvent(HandlerEventType.BEFORE_CREATE, newRepository);
|
||||||
|
},
|
||||||
|
newRepository -> fireEvent(HandlerEventType.CREATE, newRepository)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param repository
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void create(Repository repository)
|
public void delete(Repository repository) throws RepositoryException {
|
||||||
throws RepositoryException, IOException {
|
logger.info("delete repository {} of type {}", repository.getName(), repository.getType());
|
||||||
create(repository, true);
|
managerDaoAdapter.delete(
|
||||||
|
repository,
|
||||||
|
() -> RepositoryPermissions.delete(repository),
|
||||||
|
this::preDelete,
|
||||||
|
toDelete -> fireEvent(HandlerEventType.DELETE, toDelete)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void preDelete(Repository toDelete) throws RepositoryException {
|
||||||
* Method description
|
if (configuration.isEnableRepositoryArchive() && !toDelete.isArchived()) {
|
||||||
*
|
throw new RepositoryIsNotArchivedException("Repository could not deleted, because it is not archived.");
|
||||||
*
|
|
||||||
* @param repository
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void delete(Repository repository)
|
|
||||||
throws RepositoryException, IOException {
|
|
||||||
if (logger.isInfoEnabled()) {
|
|
||||||
logger.info("delete repository {} of type {}", repository.getName(),
|
|
||||||
repository.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
RepositoryPermissions.delete(repository).check();
|
|
||||||
|
|
||||||
if (configuration.isEnableRepositoryArchive() && !repository.isArchived()) {
|
|
||||||
throw new RepositoryIsNotArchivedException(
|
|
||||||
"Repository could not deleted, because it is not archived.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (repositoryDAO.contains(repository)) {
|
|
||||||
fireEvent(HandlerEventType.BEFORE_DELETE, repository);
|
|
||||||
getHandler(repository).delete(repository);
|
|
||||||
repositoryDAO.delete(repository);
|
|
||||||
fireEvent(HandlerEventType.DELETE, repository);
|
|
||||||
} else {
|
|
||||||
throw new RepositoryNotFoundException(
|
|
||||||
"repository ".concat(repository.getName()).concat(" not found"));
|
|
||||||
}
|
}
|
||||||
|
fireEvent(HandlerEventType.BEFORE_DELETE, toDelete);
|
||||||
|
getHandler(toDelete).delete(toDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -248,29 +196,18 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
|||||||
* @throws RepositoryException
|
* @throws RepositoryException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void modify(Repository repository)
|
public void modify(Repository repository) throws RepositoryException {
|
||||||
throws RepositoryException, IOException {
|
logger.info("modify repository {} of type {}", repository.getName(), repository.getType());
|
||||||
if (logger.isInfoEnabled()) {
|
|
||||||
logger.info("modify repository {} of type {}", repository.getName(),
|
|
||||||
repository.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
AssertUtil.assertIsValid(repository);
|
managerDaoAdapter.modify(
|
||||||
|
repository,
|
||||||
Repository oldRepository = repositoryDAO.get(repository.getType(),
|
RepositoryPermissions::modify,
|
||||||
repository.getName());
|
notModified -> {
|
||||||
|
fireEvent(HandlerEventType.BEFORE_MODIFY, repository, notModified);
|
||||||
if (oldRepository != null) {
|
getHandler(repository).modify(repository);
|
||||||
RepositoryPermissions.modify(oldRepository).check();
|
},
|
||||||
fireEvent(HandlerEventType.BEFORE_MODIFY, repository, oldRepository);
|
notModified -> fireEvent(HandlerEventType.MODIFY, repository, notModified)
|
||||||
repository.setLastModified(System.currentTimeMillis());
|
);
|
||||||
getHandler(repository).modify(repository);
|
|
||||||
repositoryDAO.modify(repository);
|
|
||||||
fireEvent(HandlerEventType.MODIFY, repository, oldRepository);
|
|
||||||
} else {
|
|
||||||
throw new RepositoryNotFoundException(
|
|
||||||
"repository ".concat(repository.getName()).concat(" not found"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -284,7 +221,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void refresh(Repository repository)
|
public void refresh(Repository repository)
|
||||||
throws RepositoryException, IOException {
|
throws RepositoryException {
|
||||||
AssertUtil.assertIsNotNull(repository);
|
AssertUtil.assertIsNotNull(repository);
|
||||||
RepositoryPermissions.read(repository).check();
|
RepositoryPermissions.read(repository).check();
|
||||||
|
|
||||||
@@ -294,8 +231,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
|||||||
if (fresh != null) {
|
if (fresh != null) {
|
||||||
fresh.copyProperties(repository);
|
fresh.copyProperties(repository);
|
||||||
} else {
|
} else {
|
||||||
throw new RepositoryNotFoundException(
|
throw new RepositoryNotFoundException(repository);
|
||||||
"repository ".concat(repository.getName()).concat(" not found"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,5 +572,4 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager {
|
|||||||
|
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,8 @@ package sonia.scm.repository;
|
|||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import sonia.scm.EagerSingleton;
|
import sonia.scm.EagerSingleton;
|
||||||
import sonia.scm.plugin.Extension;
|
import sonia.scm.plugin.Extension;
|
||||||
import sonia.scm.web.security.AdministrationContext;
|
import sonia.scm.web.security.AdministrationContext;
|
||||||
@@ -46,8 +44,6 @@ import sonia.scm.web.security.PrivilegedAction;
|
|||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Sebastian Sdorra
|
* @author Sebastian Sdorra
|
||||||
@@ -154,7 +150,7 @@ public final class LastModifiedUpdateListener
|
|||||||
{
|
{
|
||||||
repositoryManager.modify(dbr);
|
repositoryManager.modify(dbr);
|
||||||
}
|
}
|
||||||
catch (RepositoryException | IOException ex)
|
catch (RepositoryException ex)
|
||||||
{
|
{
|
||||||
logger.error("could not modify repository", ex);
|
logger.error("could not modify repository", ex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,11 @@ import com.google.inject.Singleton;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.HandlerEventType;
|
import sonia.scm.HandlerEventType;
|
||||||
|
import sonia.scm.ManagerDaoAdapter;
|
||||||
import sonia.scm.SCMContextProvider;
|
import sonia.scm.SCMContextProvider;
|
||||||
import sonia.scm.TransformFilter;
|
import sonia.scm.TransformFilter;
|
||||||
import sonia.scm.search.SearchRequest;
|
import sonia.scm.search.SearchRequest;
|
||||||
import sonia.scm.search.SearchUtil;
|
import sonia.scm.search.SearchUtil;
|
||||||
import sonia.scm.util.AssertUtil;
|
|
||||||
import sonia.scm.util.CollectionAppender;
|
import sonia.scm.util.CollectionAppender;
|
||||||
import sonia.scm.util.IOUtil;
|
import sonia.scm.util.IOUtil;
|
||||||
import sonia.scm.util.Util;
|
import sonia.scm.util.Util;
|
||||||
@@ -55,11 +55,7 @@ import javax.xml.bind.JAXBException;
|
|||||||
import javax.xml.bind.Unmarshaller;
|
import javax.xml.bind.Unmarshaller;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
//~--- JDK imports ------------------------------------------------------------
|
//~--- JDK imports ------------------------------------------------------------
|
||||||
|
|
||||||
@@ -96,6 +92,10 @@ public class DefaultUserManager extends AbstractUserManager
|
|||||||
public DefaultUserManager(UserDAO userDAO)
|
public DefaultUserManager(UserDAO userDAO)
|
||||||
{
|
{
|
||||||
this.userDAO = userDAO;
|
this.userDAO = userDAO;
|
||||||
|
this.managerDaoAdapter = new ManagerDaoAdapter<>(
|
||||||
|
userDAO,
|
||||||
|
UserNotFoundException::new,
|
||||||
|
UserAlreadyExistsException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- methods --------------------------------------------------------------
|
//~--- methods --------------------------------------------------------------
|
||||||
@@ -137,64 +137,31 @@ public class DefaultUserManager extends AbstractUserManager
|
|||||||
* @throws UserException
|
* @throws UserException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void create(User user) throws UserException, IOException
|
public User create(User user) throws UserException {
|
||||||
{
|
|
||||||
String type = user.getType();
|
String type = user.getType();
|
||||||
|
if (Util.isEmpty(type)) {
|
||||||
if (Util.isEmpty(type))
|
|
||||||
{
|
|
||||||
user.setType(userDAO.getType());
|
user.setType(userDAO.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
logger.info("create user {} of type {}", user.getName(), user.getType());
|
||||||
{
|
|
||||||
logger.info("create user {} of type {}", user.getName(), user.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
UserPermissions.create().check();
|
return managerDaoAdapter.create(
|
||||||
|
user,
|
||||||
if (userDAO.contains(user.getName()))
|
UserPermissions::create,
|
||||||
{
|
newUser -> fireEvent(HandlerEventType.BEFORE_CREATE, newUser),
|
||||||
throw new UserAlreadyExistsException(user.getName().concat(" user already exists"));
|
newUser -> fireEvent(HandlerEventType.CREATE, newUser)
|
||||||
}
|
);
|
||||||
|
|
||||||
AssertUtil.assertIsValid(user);
|
|
||||||
user.setCreationDate(System.currentTimeMillis());
|
|
||||||
fireEvent(HandlerEventType.BEFORE_CREATE, user);
|
|
||||||
userDAO.add(user);
|
|
||||||
fireEvent(HandlerEventType.CREATE, user);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method description
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param user
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws UserException
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(User user) throws UserException, IOException
|
public void delete(User user) throws UserException {
|
||||||
{
|
logger.info("delete user {} of type {}", user.getName(), user.getType());
|
||||||
if (logger.isInfoEnabled())
|
managerDaoAdapter.delete(
|
||||||
{
|
user,
|
||||||
logger.info("delete user {} of type {}", user.getName(), user.getType());
|
() -> UserPermissions.delete(user.getName()),
|
||||||
}
|
toDelete -> fireEvent(HandlerEventType.BEFORE_DELETE, toDelete),
|
||||||
|
toDelete -> fireEvent(HandlerEventType.DELETE, toDelete)
|
||||||
String name = user.getName();
|
);
|
||||||
UserPermissions.delete(name).check();
|
|
||||||
|
|
||||||
if (userDAO.contains(name))
|
|
||||||
{
|
|
||||||
fireEvent(HandlerEventType.BEFORE_DELETE, user);
|
|
||||||
userDAO.delete(user);
|
|
||||||
fireEvent(HandlerEventType.DELETE, user);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new UserNotFoundException("user does not exists");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,29 +191,15 @@ public class DefaultUserManager extends AbstractUserManager
|
|||||||
* @throws UserException
|
* @throws UserException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void modify(User user) throws UserException, IOException
|
public void modify(User user) throws UserException
|
||||||
{
|
{
|
||||||
String name = user.getName();
|
logger.info("modify user {} of type {}", user.getName(), user.getType());
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
{
|
managerDaoAdapter.modify(
|
||||||
logger.info("modify user {} of type {}", user.getName(), user.getType());
|
user,
|
||||||
}
|
UserPermissions::modify,
|
||||||
|
notModified -> fireEvent(HandlerEventType.BEFORE_MODIFY, user, notModified),
|
||||||
UserPermissions.modify(user).check();
|
notModified -> fireEvent(HandlerEventType.MODIFY, user, notModified));
|
||||||
User notModified = userDAO.get(name);
|
|
||||||
if (notModified != null)
|
|
||||||
{
|
|
||||||
AssertUtil.assertIsValid(user);
|
|
||||||
fireEvent(HandlerEventType.BEFORE_MODIFY, user, notModified);
|
|
||||||
user.setLastModified(System.currentTimeMillis());
|
|
||||||
user.setCreationDate(notModified.getCreationDate());
|
|
||||||
userDAO.modify(user);
|
|
||||||
fireEvent(HandlerEventType.MODIFY, user, notModified);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new UserNotFoundException("user does not exists");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -259,7 +212,7 @@ public class DefaultUserManager extends AbstractUserManager
|
|||||||
* @throws UserException
|
* @throws UserException
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void refresh(User user) throws UserException, IOException
|
public void refresh(User user) throws UserException
|
||||||
{
|
{
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
{
|
{
|
||||||
@@ -271,7 +224,7 @@ public class DefaultUserManager extends AbstractUserManager
|
|||||||
|
|
||||||
if (fresh == null)
|
if (fresh == null)
|
||||||
{
|
{
|
||||||
throw new UserNotFoundException("user does not exists");
|
throw new UserNotFoundException(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
fresh.copyProperties(user);
|
fresh.copyProperties(user);
|
||||||
@@ -496,6 +449,6 @@ public class DefaultUserManager extends AbstractUserManager
|
|||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
/** Field description */
|
|
||||||
private final UserDAO userDAO;
|
private final UserDAO userDAO;
|
||||||
|
private final ManagerDaoAdapter<User, UserException> managerDaoAdapter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
package sonia.scm.api.rest.resources;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
import sonia.scm.Manager;
|
||||||
|
import sonia.scm.ModelObject;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.GenericEntity;
|
||||||
|
import javax.ws.rs.core.Request;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class AbstractManagerResourceTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Manager<Simple, Exception> manager;
|
||||||
|
@Mock
|
||||||
|
private Request request;
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<Comparator<Simple>> comparatorCaptor;
|
||||||
|
|
||||||
|
private AbstractManagerResource<Simple, Exception> abstractManagerResource;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void captureComparator() {
|
||||||
|
when(manager.getAll(comparatorCaptor.capture(), eq(0), eq(1))).thenReturn(emptyList());
|
||||||
|
abstractManagerResource = new SimpleManagerResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptDefaultSortByParameter() {
|
||||||
|
abstractManagerResource.getAll(request, 0, 1, null, true);
|
||||||
|
|
||||||
|
Comparator<Simple> comparator = comparatorCaptor.getValue();
|
||||||
|
assertTrue(comparator.compare(new Simple("1", null), new Simple("2", null)) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldAcceptValidSortByParameter() {
|
||||||
|
abstractManagerResource.getAll(request, 0, 1, "data", true);
|
||||||
|
|
||||||
|
Comparator<Simple> comparator = comparatorCaptor.getValue();
|
||||||
|
assertTrue(comparator.compare(new Simple("", "1"), new Simple("", "2")) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void shouldFailForIllegalSortByParameter() {
|
||||||
|
abstractManagerResource.getAll(request, 0, 1, "x", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class SimpleManagerResource extends AbstractManagerResource<Simple, Exception> {
|
||||||
|
|
||||||
|
{
|
||||||
|
disableCache = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SimpleManagerResource() {
|
||||||
|
super(AbstractManagerResourceTest.this.manager, Simple.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected GenericEntity<Collection<Simple>> createGenericEntity(Collection<Simple> items) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getId(Simple item) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getPathPart() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Simple implements ModelObject {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String data;
|
||||||
|
|
||||||
|
Simple(String id, String data) {
|
||||||
|
this.id = id;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLastModified(Long timestamp) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getCreationDate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCreationDate(Long timestamp) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getLastModified() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean isValid() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,9 +10,7 @@ import org.jboss.resteasy.mock.MockHttpResponse;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Answers;
|
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
import sonia.scm.web.VndMediaType;
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
@@ -40,8 +38,9 @@ public class GlobalConfigResourceTest {
|
|||||||
|
|
||||||
private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
|
private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
private final URI baseUri = URI.create("/");
|
||||||
private ResourceLinks resourceLinks;
|
@SuppressWarnings("unused") // Is injected
|
||||||
|
private ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private GlobalConfigDtoToScmConfigurationMapperImpl dtoToConfigMapper;
|
private GlobalConfigDtoToScmConfigurationMapperImpl dtoToConfigMapper;
|
||||||
@@ -49,11 +48,9 @@ public class GlobalConfigResourceTest {
|
|||||||
private ScmConfigurationToGlobalConfigDtoMapperImpl configToDtoMapper;
|
private ScmConfigurationToGlobalConfigDtoMapperImpl configToDtoMapper;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void prepareEnvironment() throws IOException {
|
public void prepareEnvironment() {
|
||||||
initMocks(this);
|
initMocks(this);
|
||||||
|
|
||||||
ResourceLinksMock.initMock(resourceLinks, URI.create("/"));
|
|
||||||
|
|
||||||
GlobalConfigResource globalConfigResource = new GlobalConfigResource(dtoToConfigMapper,
|
GlobalConfigResource globalConfigResource = new GlobalConfigResource(dtoToConfigMapper,
|
||||||
configToDtoMapper, createConfiguration());
|
configToDtoMapper, createConfiguration());
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import org.jboss.resteasy.mock.MockHttpResponse;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Answers;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
@@ -28,9 +27,7 @@ import java.net.URL;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
@@ -49,8 +46,7 @@ public class GroupRootResourceTest {
|
|||||||
|
|
||||||
private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
|
private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/"));
|
||||||
private ResourceLinks resourceLinks;
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private GroupManager groupManager;
|
private GroupManager groupManager;
|
||||||
@@ -64,15 +60,13 @@ public class GroupRootResourceTest {
|
|||||||
@Before
|
@Before
|
||||||
public void prepareEnvironment() throws IOException, GroupException {
|
public void prepareEnvironment() throws IOException, GroupException {
|
||||||
initMocks(this);
|
initMocks(this);
|
||||||
doNothing().when(groupManager).create(groupCaptor.capture());
|
when(groupManager.create(groupCaptor.capture())).thenAnswer(invocation -> invocation.getArguments()[0]);
|
||||||
doNothing().when(groupManager).modify(groupCaptor.capture());
|
doNothing().when(groupManager).modify(groupCaptor.capture());
|
||||||
|
|
||||||
Group group = createDummyGroup();
|
Group group = createDummyGroup();
|
||||||
when(groupManager.getPage(any(), eq(0), eq(10))).thenReturn(new PageResult<>(singletonList(group), 1));
|
when(groupManager.getPage(any(), eq(0), eq(10))).thenReturn(new PageResult<>(singletonList(group), 1));
|
||||||
when(groupManager.get("admin")).thenReturn(group);
|
when(groupManager.get("admin")).thenReturn(group);
|
||||||
|
|
||||||
ResourceLinksMock.initMock(resourceLinks, URI.create("/"));
|
|
||||||
|
|
||||||
GroupCollectionToDtoMapper groupCollectionToDtoMapper = new GroupCollectionToDtoMapper(groupToDtoMapper, resourceLinks);
|
GroupCollectionToDtoMapper groupCollectionToDtoMapper = new GroupCollectionToDtoMapper(groupToDtoMapper, resourceLinks);
|
||||||
GroupCollectionResource groupCollectionResource = new GroupCollectionResource(groupManager, dtoToGroupMapper, groupCollectionToDtoMapper, resourceLinks);
|
GroupCollectionResource groupCollectionResource = new GroupCollectionResource(groupManager, dtoToGroupMapper, groupCollectionToDtoMapper, resourceLinks);
|
||||||
GroupResource groupResource = new GroupResource(groupManager, groupToDtoMapper, dtoToGroupMapper);
|
GroupResource groupResource = new GroupResource(groupManager, groupToDtoMapper, dtoToGroupMapper);
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ import org.apache.shiro.util.ThreadState;
|
|||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Answers;
|
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
|
||||||
import sonia.scm.group.Group;
|
import sonia.scm.group.Group;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@@ -24,8 +22,9 @@ import static org.mockito.MockitoAnnotations.initMocks;
|
|||||||
|
|
||||||
public class GroupToGroupDtoMapperTest {
|
public class GroupToGroupDtoMapperTest {
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
private final URI baseUri = URI.create("http://example.com/base/");
|
||||||
private ResourceLinks resourceLinks;
|
@SuppressWarnings("unused") // Is injected
|
||||||
|
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private GroupToGroupDtoMapperImpl mapper;
|
private GroupToGroupDtoMapperImpl mapper;
|
||||||
@@ -38,12 +37,8 @@ public class GroupToGroupDtoMapperTest {
|
|||||||
@Before
|
@Before
|
||||||
public void init() throws URISyntaxException {
|
public void init() throws URISyntaxException {
|
||||||
initMocks(this);
|
initMocks(this);
|
||||||
URI baseUri = new URI("http://example.com/base/");
|
|
||||||
expectedBaseUri = baseUri.resolve(GroupRootResource.GROUPS_PATH_V2 + "/");
|
expectedBaseUri = baseUri.resolve(GroupRootResource.GROUPS_PATH_V2 + "/");
|
||||||
subjectThreadState.bind();
|
subjectThreadState.bind();
|
||||||
|
|
||||||
ResourceLinksMock.initMock(resourceLinks, baseUri);
|
|
||||||
|
|
||||||
ThreadContext.bind(subject);
|
ThreadContext.bind(subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.google.inject.binder.AnnotatedBindingBuilder;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public class MapperModuleTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldBindToClassesWithDefaultConstructorOnly() {
|
||||||
|
AnnotatedBindingBuilder binding = mock(AnnotatedBindingBuilder.class);
|
||||||
|
ArgumentCaptor<Class> captor = ArgumentCaptor.forClass(Class.class);
|
||||||
|
when(binding.to(captor.capture())).thenReturn(null);
|
||||||
|
new MapperModule() {
|
||||||
|
@Override
|
||||||
|
protected <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
}.configure();
|
||||||
|
captor.getAllValues().forEach(this::verifyClassCanBeInstantiated);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T verifyClassCanBeInstantiated(Class<T> c) {
|
||||||
|
try {
|
||||||
|
return c.getConstructor().newInstance();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.github.sdorra.shiro.ShiroRule;
|
||||||
|
import com.github.sdorra.shiro.SubjectAware;
|
||||||
|
import com.google.common.io.Resources;
|
||||||
|
import org.jboss.resteasy.core.Dispatcher;
|
||||||
|
import org.jboss.resteasy.mock.MockDispatcherFactory;
|
||||||
|
import org.jboss.resteasy.mock.MockHttpRequest;
|
||||||
|
import org.jboss.resteasy.mock.MockHttpResponse;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import sonia.scm.PageResult;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
import sonia.scm.repository.RepositoryException;
|
||||||
|
import sonia.scm.repository.RepositoryManager;
|
||||||
|
import sonia.scm.web.VndMediaType;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static java.util.Optional.empty;
|
||||||
|
import static java.util.Optional.of;
|
||||||
|
import static javax.servlet.http.HttpServletResponse.*;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyObject;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
|
|
||||||
|
@SubjectAware(
|
||||||
|
username = "trillian",
|
||||||
|
password = "secret",
|
||||||
|
configuration = "classpath:sonia/scm/repository/shiro.ini"
|
||||||
|
)
|
||||||
|
public class RepositoryRootResourceTest {
|
||||||
|
|
||||||
|
private final Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ShiroRule shiro = new ShiroRule();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RepositoryManager repositoryManager;
|
||||||
|
|
||||||
|
private final URI baseUri = URI.create("/");
|
||||||
|
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private RepositoryToRepositoryDtoMapperImpl repositoryToDtoMapper;
|
||||||
|
@InjectMocks
|
||||||
|
private RepositoryDtoToRepositoryMapperImpl dtoToRepositoryMapper;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void prepareEnvironment() {
|
||||||
|
initMocks(this);
|
||||||
|
RepositoryResource repositoryResource = new RepositoryResource(repositoryToDtoMapper, dtoToRepositoryMapper, repositoryManager, null, null, null, null, null);
|
||||||
|
RepositoryCollectionToDtoMapper repositoryCollectionToDtoMapper = new RepositoryCollectionToDtoMapper(repositoryToDtoMapper, resourceLinks);
|
||||||
|
RepositoryCollectionResource repositoryCollectionResource = new RepositoryCollectionResource(repositoryManager, repositoryCollectionToDtoMapper, dtoToRepositoryMapper, resourceLinks);
|
||||||
|
RepositoryRootResource repositoryRootResource = new RepositoryRootResource(MockProvider.of(repositoryResource), MockProvider.of(repositoryCollectionResource));
|
||||||
|
dispatcher.getRegistry().addSingletonResource(repositoryRootResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFailForNotExistingRepository() throws URISyntaxException {
|
||||||
|
when(repositoryManager.getByNamespace(anyString(), anyString())).thenReturn(empty());
|
||||||
|
mockRepository("space", "repo");
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/other");
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertEquals(SC_NOT_FOUND, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFindExistingRepository() throws URISyntaxException {
|
||||||
|
mockRepository("space", "repo");
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo");
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertEquals(SC_OK, response.getStatus());
|
||||||
|
assertTrue(response.getContentAsString().contains("\"name\":\"repo\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMapProperties() throws URISyntaxException {
|
||||||
|
Repository repository = mockRepository("space", "repo");
|
||||||
|
repository.setProperty("testKey", "testValue");
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo");
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertTrue(response.getContentAsString().contains("\"testKey\":\"testValue\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldGetAll() throws URISyntaxException {
|
||||||
|
PageResult<Repository> singletonPageResult = createSingletonPageResult(mockRepository("space", "repo"));
|
||||||
|
when(repositoryManager.getPage(any(), eq(0), eq(10))).thenReturn(singletonPageResult);
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest.get("/" + RepositoryRootResource.REPOSITORIES_PATH_V2);
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertEquals(SC_OK, response.getStatus());
|
||||||
|
assertTrue(response.getContentAsString().contains("\"name\":\"repo\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleUpdateForNotExistingRepository() throws URISyntaxException, IOException {
|
||||||
|
URL url = Resources.getResource("sonia/scm/api/v2/repository-test-update.json");
|
||||||
|
byte[] repository = Resources.toByteArray(url);
|
||||||
|
when(repositoryManager.getByNamespace(anyString(), anyString())).thenReturn(empty());
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest
|
||||||
|
.put("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo")
|
||||||
|
.contentType(VndMediaType.REPOSITORY)
|
||||||
|
.content(repository);
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertEquals(SC_NOT_FOUND, response.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleUpdateForExistingRepository() throws Exception {
|
||||||
|
mockRepository("space", "repo");
|
||||||
|
|
||||||
|
URL url = Resources.getResource("sonia/scm/api/v2/repository-test-update.json");
|
||||||
|
byte[] repository = Resources.toByteArray(url);
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest
|
||||||
|
.put("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo")
|
||||||
|
.contentType(VndMediaType.REPOSITORY)
|
||||||
|
.content(repository);
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertEquals(SC_NO_CONTENT, response.getStatus());
|
||||||
|
verify(repositoryManager).modify(anyObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleUpdateForExistingRepositoryForChangedNamespace() throws Exception {
|
||||||
|
mockRepository("wrong", "repo");
|
||||||
|
|
||||||
|
URL url = Resources.getResource("sonia/scm/api/v2/repository-test-update.json");
|
||||||
|
byte[] repository = Resources.toByteArray(url);
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest
|
||||||
|
.put("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "wrong/repo")
|
||||||
|
.contentType(VndMediaType.REPOSITORY)
|
||||||
|
.content(repository);
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertEquals(SC_BAD_REQUEST, response.getStatus());
|
||||||
|
verify(repositoryManager, never()).modify(anyObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldHandleDeleteForExistingRepository() throws Exception {
|
||||||
|
mockRepository("space", "repo");
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest.delete("/" + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo");
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertEquals(SC_NO_CONTENT, response.getStatus());
|
||||||
|
verify(repositoryManager).delete(anyObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateNewRepositoryInCorrectNamespace() throws URISyntaxException, IOException, RepositoryException {
|
||||||
|
when(repositoryManager.create(any())).thenAnswer(invocation -> {
|
||||||
|
Repository repository = (Repository) invocation.getArguments()[0];
|
||||||
|
repository.setNamespace("otherspace");
|
||||||
|
return repository;
|
||||||
|
});
|
||||||
|
|
||||||
|
URL url = Resources.getResource("sonia/scm/api/v2/repository-test-update.json");
|
||||||
|
byte[] repositoryJson = Resources.toByteArray(url);
|
||||||
|
|
||||||
|
MockHttpRequest request = MockHttpRequest
|
||||||
|
.post("/" + RepositoryRootResource.REPOSITORIES_PATH_V2)
|
||||||
|
.contentType(VndMediaType.REPOSITORY)
|
||||||
|
.content(repositoryJson);
|
||||||
|
MockHttpResponse response = new MockHttpResponse();
|
||||||
|
|
||||||
|
dispatcher.invoke(request, response);
|
||||||
|
|
||||||
|
assertEquals(HttpServletResponse.SC_CREATED, response.getStatus());
|
||||||
|
assertEquals("/v2/repositories/otherspace/repo", response.getOutputHeaders().get("Location").get(0).toString());
|
||||||
|
verify(repositoryManager).create(any(Repository.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageResult<Repository> createSingletonPageResult(Repository repository) {
|
||||||
|
return new PageResult<>(singletonList(repository), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Repository mockRepository(String namespace, String name) {
|
||||||
|
Repository repository = new Repository();
|
||||||
|
repository.setNamespace(namespace);
|
||||||
|
repository.setName(name);
|
||||||
|
String id = namespace + "-" + name;
|
||||||
|
repository.setId(id);
|
||||||
|
when(repositoryManager.getByNamespace(namespace, name)).thenReturn(of(repository));
|
||||||
|
when(repositoryManager.get(id)).thenReturn(repository);
|
||||||
|
return repository;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import com.github.sdorra.shiro.ShiroRule;
|
||||||
|
import com.github.sdorra.shiro.SubjectAware;
|
||||||
|
import org.apache.shiro.util.ThreadContext;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import sonia.scm.repository.HealthCheckFailure;
|
||||||
|
import sonia.scm.repository.Permission;
|
||||||
|
import sonia.scm.repository.PermissionType;
|
||||||
|
import sonia.scm.repository.Repository;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import static java.util.Collections.singletonList;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
|
|
||||||
|
@SubjectAware(
|
||||||
|
username = "trillian",
|
||||||
|
password = "secret",
|
||||||
|
configuration = "classpath:sonia/scm/repository/shiro.ini"
|
||||||
|
)
|
||||||
|
public class RepositoryToRepositoryDtoMapperTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ShiroRule rule = new ShiroRule();
|
||||||
|
|
||||||
|
private final URI baseUri = URI.create("http://example.com/base/");
|
||||||
|
@SuppressWarnings("unused") // Is injected
|
||||||
|
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private RepositoryToRepositoryDtoMapperImpl mapper;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
initMocks(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanup() {
|
||||||
|
ThreadContext.unbindSubject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMapSimpleProperties() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals("testspace", dto.getNamespace());
|
||||||
|
assertEquals("test", dto.getName());
|
||||||
|
assertEquals("description", dto.getDescription());
|
||||||
|
assertEquals("git", dto.getType());
|
||||||
|
assertEquals("none@example.com", dto.getContact());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMapPropertiesProperty() {
|
||||||
|
Repository repository = createTestRepository();
|
||||||
|
repository.setProperty("testKey", "testValue");
|
||||||
|
|
||||||
|
RepositoryDto dto = mapper.map(repository);
|
||||||
|
|
||||||
|
assertEquals("testValue", dto.getProperties().get("testKey"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SubjectAware(username = "unpriv")
|
||||||
|
public void shouldCreateLinksForUnprivilegedUser() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals(
|
||||||
|
"http://example.com/base/v2/repositories/testspace/test",
|
||||||
|
dto.getLinks().getLinkBy("self").get().getHref());
|
||||||
|
assertFalse(dto.getLinks().getLinkBy("update").isPresent());
|
||||||
|
assertFalse(dto.getLinks().getLinkBy("delete").isPresent());
|
||||||
|
assertFalse(dto.getLinks().getLinkBy("permissions").isPresent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateDeleteLink() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals(
|
||||||
|
"http://example.com/base/v2/repositories/testspace/test",
|
||||||
|
dto.getLinks().getLinkBy("delete").get().getHref());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateUpdateLink() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals(
|
||||||
|
"http://example.com/base/v2/repositories/testspace/test",
|
||||||
|
dto.getLinks().getLinkBy("update").get().getHref());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldMapHealthCheck() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals(1, dto.getHealthCheckFailures().size());
|
||||||
|
assertEquals("summary", dto.getHealthCheckFailures().get(0).getSummary());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateTagsLink() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals(
|
||||||
|
"http://example.com/base/v2/repositories/testspace/test/tags/",
|
||||||
|
dto.getLinks().getLinkBy("tags").get().getHref());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateBranchesLink() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals(
|
||||||
|
"http://example.com/base/v2/repositories/testspace/test/branches/",
|
||||||
|
dto.getLinks().getLinkBy("branches").get().getHref());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateChangesetsLink() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals(
|
||||||
|
"http://example.com/base/v2/repositories/testspace/test/changesets/",
|
||||||
|
dto.getLinks().getLinkBy("changesets").get().getHref());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateSourcesLink() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals(
|
||||||
|
"http://example.com/base/v2/repositories/testspace/test/sources/",
|
||||||
|
dto.getLinks().getLinkBy("sources").get().getHref());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreatePermissionsLink() {
|
||||||
|
RepositoryDto dto = mapper.map(createTestRepository());
|
||||||
|
assertEquals(
|
||||||
|
"http://example.com/base/v2/repositories/testspace/test/permissions/",
|
||||||
|
dto.getLinks().getLinkBy("permissions").get().getHref());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Repository createTestRepository() {
|
||||||
|
Repository repository = new Repository();
|
||||||
|
repository.setNamespace("testspace");
|
||||||
|
repository.setName("test");
|
||||||
|
repository.setDescription("description");
|
||||||
|
repository.setType("git");
|
||||||
|
repository.setContact("none@example.com");
|
||||||
|
repository.setId("1");
|
||||||
|
repository.setCreationDate(System.currentTimeMillis());
|
||||||
|
repository.setHealthCheckFailures(singletonList(new HealthCheckFailure("1", "summary", "url", "failure")));
|
||||||
|
repository.setPermissions(singletonList(new Permission("permission", PermissionType.READ)));
|
||||||
|
|
||||||
|
return repository;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +1,30 @@
|
|||||||
package sonia.scm.api.v2.resources;
|
package sonia.scm.api.v2.resources;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static sonia.scm.api.v2.resources.GlobalConfigResource.GLOBAL_CONFIG_PATH_V2;
|
|
||||||
import static sonia.scm.api.v2.resources.GroupRootResource.GROUPS_PATH_V2;
|
|
||||||
import static sonia.scm.api.v2.resources.UserRootResource.USERS_PATH_V2;
|
|
||||||
|
|
||||||
public class ResourceLinksMock {
|
public class ResourceLinksMock {
|
||||||
public static void initMock(ResourceLinks resourceLinks, URI baseUri) {
|
public static ResourceLinks createMock(URI baseUri) {
|
||||||
when(resourceLinks.user().self(anyString())).thenAnswer(invocation -> baseUri + USERS_PATH_V2 + invocation.getArguments()[0]);
|
ResourceLinks resourceLinks = mock(ResourceLinks.class);
|
||||||
when(resourceLinks.user().update(anyString())).thenAnswer(invocation -> baseUri + USERS_PATH_V2 + invocation.getArguments()[0]);
|
|
||||||
when(resourceLinks.user().delete(anyString())).thenAnswer(invocation -> baseUri + USERS_PATH_V2 + invocation.getArguments()[0]);
|
|
||||||
|
|
||||||
when(resourceLinks.userCollection().self()).thenAnswer(invocation -> baseUri + USERS_PATH_V2);
|
UriInfo uriInfo = mock(UriInfo.class);
|
||||||
when(resourceLinks.userCollection().create()).thenAnswer(invocation -> baseUri + USERS_PATH_V2);
|
when(uriInfo.getBaseUri()).thenReturn(baseUri);
|
||||||
|
|
||||||
when(resourceLinks.group().self(anyString())).thenAnswer(invocation -> baseUri + GROUPS_PATH_V2 + invocation.getArguments()[0]);
|
when(resourceLinks.user()).thenReturn(new ResourceLinks.UserLinks(uriInfo));
|
||||||
when(resourceLinks.group().update(anyString())).thenAnswer(invocation -> baseUri + GROUPS_PATH_V2 + invocation.getArguments()[0]);
|
when(resourceLinks.userCollection()).thenReturn(new ResourceLinks.UserCollectionLinks(uriInfo));
|
||||||
when(resourceLinks.group().delete(anyString())).thenAnswer(invocation -> baseUri + GROUPS_PATH_V2 + invocation.getArguments()[0]);
|
when(resourceLinks.group()).thenReturn(new ResourceLinks.GroupLinks(uriInfo));
|
||||||
|
when(resourceLinks.groupCollection()).thenReturn(new ResourceLinks.GroupCollectionLinks(uriInfo));
|
||||||
when(resourceLinks.groupCollection().self()).thenAnswer(invocation -> baseUri + GROUPS_PATH_V2);
|
when(resourceLinks.repository()).thenReturn(new ResourceLinks.RepositoryLinks(uriInfo));
|
||||||
when(resourceLinks.groupCollection().create()).thenAnswer(invocation -> baseUri + GROUPS_PATH_V2);
|
when(resourceLinks.repositoryCollection()).thenReturn(new ResourceLinks.RepositoryCollectionLinks(uriInfo));
|
||||||
|
when(resourceLinks.tagCollection()).thenReturn(new ResourceLinks.TagCollectionLinks(uriInfo));
|
||||||
when(resourceLinks.globalConfig().self()).thenAnswer(invocation -> baseUri + GLOBAL_CONFIG_PATH_V2);
|
when(resourceLinks.branchCollection()).thenReturn(new ResourceLinks.BranchCollectionLinks(uriInfo));
|
||||||
when(resourceLinks.globalConfig().update()).thenAnswer(invocation -> baseUri + GLOBAL_CONFIG_PATH_V2);
|
when(resourceLinks.changesetCollection()).thenReturn(new ResourceLinks.ChangesetCollectionLinks(uriInfo));
|
||||||
|
when(resourceLinks.sourceCollection()).thenReturn(new ResourceLinks.SourceCollectionLinks(uriInfo));
|
||||||
|
when(resourceLinks.permissionCollection()).thenReturn(new ResourceLinks.PermissionCollectionLinks(uriInfo));
|
||||||
|
when(resourceLinks.globalConfig()).thenReturn(new ResourceLinks.GlobalConfigLinks(uriInfo));
|
||||||
|
return resourceLinks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,54 @@ public class ResourceLinksTest {
|
|||||||
assertEquals(BASE_URL + GroupRootResource.GROUPS_PATH_V2, url);
|
assertEquals(BASE_URL + GroupRootResource.GROUPS_PATH_V2, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateCorrectRepositorySelfUrl() {
|
||||||
|
String url = resourceLinks.repository().self("space", "repo");
|
||||||
|
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateCorrectRepositoryDeleteUrl() {
|
||||||
|
String url = resourceLinks.repository().delete("space", "repo");
|
||||||
|
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateCorrectRepositoryUpdateUrl() {
|
||||||
|
String url = resourceLinks.repository().update("space", "repo");
|
||||||
|
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateCorrectTagCollectionUrl() {
|
||||||
|
String url = resourceLinks.tagCollection().self("space", "repo");
|
||||||
|
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/tags/", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateCorrectBranchCollectionUrl() {
|
||||||
|
String url = resourceLinks.branchCollection().self("space", "repo");
|
||||||
|
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/branches/", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateCorrectChangesetCollectionUrl() {
|
||||||
|
String url = resourceLinks.changesetCollection().self("space", "repo");
|
||||||
|
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/changesets/", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateCorrectSourceCollectionUrl() {
|
||||||
|
String url = resourceLinks.sourceCollection().self("space", "repo");
|
||||||
|
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/sources/", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldCreateCorrectPermissionCollectionUrl() {
|
||||||
|
String url = resourceLinks.sourceCollection().self("space", "repo");
|
||||||
|
assertEquals(BASE_URL + RepositoryRootResource.REPOSITORIES_PATH_V2 + "space/repo/sources/", url);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldCreateCorrectGlobalConfigSelfUrl() {
|
public void shouldCreateCorrectGlobalConfigSelfUrl() {
|
||||||
String url = resourceLinks.globalConfig().self();
|
String url = resourceLinks.globalConfig().self();
|
||||||
|
|||||||
@@ -6,14 +6,11 @@ import org.apache.shiro.util.ThreadContext;
|
|||||||
import org.apache.shiro.util.ThreadState;
|
import org.apache.shiro.util.ThreadState;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Answers;
|
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
import sonia.scm.security.Role;
|
import sonia.scm.security.Role;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
@@ -24,8 +21,9 @@ import static sonia.scm.api.v2.resources.GlobalConfigResourceTest.createConfigur
|
|||||||
|
|
||||||
public class ScmConfigurationToGlobalConfigDtoMapperTest {
|
public class ScmConfigurationToGlobalConfigDtoMapperTest {
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
private URI baseUri = URI.create("http://example.com/base/");
|
||||||
private ResourceLinks resourceLinks;
|
@SuppressWarnings("unused") // Is injected
|
||||||
|
private ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private ScmConfigurationToGlobalConfigDtoMapperImpl mapper;
|
private ScmConfigurationToGlobalConfigDtoMapperImpl mapper;
|
||||||
@@ -36,12 +34,10 @@ public class ScmConfigurationToGlobalConfigDtoMapperTest {
|
|||||||
private URI expectedBaseUri;
|
private URI expectedBaseUri;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() throws URISyntaxException {
|
public void init() {
|
||||||
initMocks(this);
|
initMocks(this);
|
||||||
URI baseUri = new URI("http://example.com/base/");
|
|
||||||
expectedBaseUri = baseUri.resolve(GlobalConfigResource.GLOBAL_CONFIG_PATH_V2);
|
expectedBaseUri = baseUri.resolve(GlobalConfigResource.GLOBAL_CONFIG_PATH_V2);
|
||||||
subjectThreadState.bind();
|
subjectThreadState.bind();
|
||||||
ResourceLinksMock.initMock(resourceLinks, baseUri);
|
|
||||||
ThreadContext.bind(subject);
|
ThreadContext.bind(subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import org.apache.shiro.util.ThreadContext;
|
|||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Answers;
|
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import sonia.scm.PageResult;
|
import sonia.scm.PageResult;
|
||||||
@@ -19,17 +18,15 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static java.util.stream.Collectors.toList;
|
import static java.util.stream.Collectors.toList;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.MockitoAnnotations.initMocks;
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
import static sonia.scm.PageResult.createPage;
|
import static sonia.scm.PageResult.createPage;
|
||||||
|
|
||||||
public class UserCollectionToDtoMapperTest {
|
public class UserCollectionToDtoMapperTest {
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
private final URI baseUri = URI.create("http://example.com/base/");
|
||||||
private ResourceLinks resourceLinks;
|
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||||
@Mock
|
@Mock
|
||||||
private UserToUserDtoMapper userToDtoMapper;
|
private UserToUserDtoMapper userToDtoMapper;
|
||||||
@Mock
|
@Mock
|
||||||
@@ -45,9 +42,7 @@ public class UserCollectionToDtoMapperTest {
|
|||||||
@Before
|
@Before
|
||||||
public void init() throws URISyntaxException {
|
public void init() throws URISyntaxException {
|
||||||
initMocks(this);
|
initMocks(this);
|
||||||
URI baseUri = new URI("http://example.com/base/");
|
|
||||||
expectedBaseUri = baseUri.resolve(UserRootResource.USERS_PATH_V2 + "/");
|
expectedBaseUri = baseUri.resolve(UserRootResource.USERS_PATH_V2 + "/");
|
||||||
ResourceLinksMock.initMock(resourceLinks, baseUri);
|
|
||||||
subjectThreadState.bind();
|
subjectThreadState.bind();
|
||||||
ThreadContext.bind(subject);
|
ThreadContext.bind(subject);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import org.jboss.resteasy.mock.MockHttpResponse;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Answers;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
@@ -28,15 +27,10 @@ import java.net.URISyntaxException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
import static org.mockito.MockitoAnnotations.initMocks;
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
|
|
||||||
@SubjectAware(
|
@SubjectAware(
|
||||||
@@ -51,8 +45,7 @@ public class UserRootResourceTest {
|
|||||||
|
|
||||||
private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
|
private Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(URI.create("/"));
|
||||||
private ResourceLinks resourceLinks;
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private PasswordService passwordService;
|
private PasswordService passwordService;
|
||||||
@@ -66,15 +59,13 @@ public class UserRootResourceTest {
|
|||||||
private ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
|
private ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void prepareEnvironment() throws IOException, UserException {
|
public void prepareEnvironment() throws UserException {
|
||||||
initMocks(this);
|
initMocks(this);
|
||||||
User dummyUser = createDummyUser("Neo");
|
User dummyUser = createDummyUser("Neo");
|
||||||
doNothing().when(userManager).create(userCaptor.capture());
|
when(userManager.create(userCaptor.capture())).thenAnswer(invocation -> invocation.getArguments()[0]);
|
||||||
doNothing().when(userManager).modify(userCaptor.capture());
|
doNothing().when(userManager).modify(userCaptor.capture());
|
||||||
doNothing().when(userManager).delete(userCaptor.capture());
|
doNothing().when(userManager).delete(userCaptor.capture());
|
||||||
|
|
||||||
ResourceLinksMock.initMock(resourceLinks, URI.create("/"));
|
|
||||||
|
|
||||||
UserCollectionToDtoMapper userCollectionToDtoMapper = new UserCollectionToDtoMapper(userToDtoMapper, resourceLinks);
|
UserCollectionToDtoMapper userCollectionToDtoMapper = new UserCollectionToDtoMapper(userToDtoMapper, resourceLinks);
|
||||||
UserCollectionResource userCollectionResource = new UserCollectionResource(userManager, dtoToUserMapper,
|
UserCollectionResource userCollectionResource = new UserCollectionResource(userManager, dtoToUserMapper,
|
||||||
userCollectionToDtoMapper, resourceLinks);
|
userCollectionToDtoMapper, resourceLinks);
|
||||||
|
|||||||
@@ -7,14 +7,11 @@ import org.apache.shiro.util.ThreadState;
|
|||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Answers;
|
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
|
||||||
import sonia.scm.api.rest.resources.UserResource;
|
import sonia.scm.api.rest.resources.UserResource;
|
||||||
import sonia.scm.user.User;
|
import sonia.scm.user.User;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -25,8 +22,9 @@ import static org.mockito.MockitoAnnotations.initMocks;
|
|||||||
|
|
||||||
public class UserToUserDtoMapperTest {
|
public class UserToUserDtoMapperTest {
|
||||||
|
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
private final URI baseUri = URI.create("http://example.com/base/");
|
||||||
private ResourceLinks resourceLinks;
|
@SuppressWarnings("unused") // Is injected
|
||||||
|
private final ResourceLinks resourceLinks = ResourceLinksMock.createMock(baseUri);
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private UserToUserDtoMapperImpl mapper;
|
private UserToUserDtoMapperImpl mapper;
|
||||||
@@ -37,12 +35,10 @@ public class UserToUserDtoMapperTest {
|
|||||||
private URI expectedBaseUri;
|
private URI expectedBaseUri;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void init() throws URISyntaxException {
|
public void init() {
|
||||||
initMocks(this);
|
initMocks(this);
|
||||||
URI baseUri = new URI("http://example.com/base/");
|
|
||||||
expectedBaseUri = baseUri.resolve(UserRootResource.USERS_PATH_V2 + "/");
|
expectedBaseUri = baseUri.resolve(UserRootResource.USERS_PATH_V2 + "/");
|
||||||
subjectThreadState.bind();
|
subjectThreadState.bind();
|
||||||
ResourceLinksMock.initMock(resourceLinks, baseUri);
|
|
||||||
ThreadContext.bind(subject);
|
ThreadContext.bind(subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,10 +41,7 @@ import org.junit.Rule;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.ExpectedException;
|
import org.junit.rules.ExpectedException;
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import sonia.scm.HandlerEventType;
|
import sonia.scm.*;
|
||||||
import sonia.scm.Manager;
|
|
||||||
import sonia.scm.ManagerTestBase;
|
|
||||||
import sonia.scm.Type;
|
|
||||||
import sonia.scm.config.ScmConfiguration;
|
import sonia.scm.config.ScmConfiguration;
|
||||||
import sonia.scm.event.ScmEventBus;
|
import sonia.scm.event.ScmEventBus;
|
||||||
import sonia.scm.repository.api.HookContext;
|
import sonia.scm.repository.api.HookContext;
|
||||||
@@ -57,24 +54,10 @@ import sonia.scm.security.KeyGenerator;
|
|||||||
import sonia.scm.store.ConfigurationStoreFactory;
|
import sonia.scm.store.ConfigurationStoreFactory;
|
||||||
import sonia.scm.store.JAXBConfigurationStoreFactory;
|
import sonia.scm.store.JAXBConfigurationStoreFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.hamcrest.Matchers.hasProperty;
|
import static org.junit.Assert.*;
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertNotSame;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertSame;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -98,14 +81,13 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
@Rule
|
@Rule
|
||||||
public ExpectedException thrown = ExpectedException.none();
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
private ScmConfiguration configuration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#create(sonia.scm.repository.Repository)}.
|
* Tests {@link RepositoryManager#create(TypedObject)}.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCreate() throws RepositoryException, IOException {
|
public void testCreate() throws RepositoryException {
|
||||||
Repository heartOfGold = createTestRepository();
|
Repository heartOfGold = createTestRepository();
|
||||||
Repository dbRepo = manager.get(heartOfGold.getId());
|
Repository dbRepo = manager.get(heartOfGold.getId());
|
||||||
|
|
||||||
@@ -114,88 +96,68 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#create(sonia.scm.repository.Repository)} without the required permissions.
|
* Tests {@link RepositoryManager#create(TypedObject)} without the required permissions.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@SubjectAware(
|
@SubjectAware(
|
||||||
username = "unpriv"
|
username = "unpriv"
|
||||||
)
|
)
|
||||||
@Test(expected = UnauthorizedException.class)
|
@Test(expected = UnauthorizedException.class)
|
||||||
public void testCreateWithoutPrivileges() throws RepositoryException, IOException {
|
public void testCreateWithoutPrivileges() throws RepositoryException {
|
||||||
createTestRepository();
|
createTestRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#create(sonia.scm.repository.Repository)} with a already existing repository.
|
* Tests {@link RepositoryManager#create(TypedObject)} with a already existing repository.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test(expected = RepositoryAlreadyExistsException.class)
|
@Test(expected = RepositoryAlreadyExistsException.class)
|
||||||
public void testCreateExisting() throws RepositoryException, IOException {
|
public void testCreateExisting() throws RepositoryException {
|
||||||
createTestRepository();
|
createTestRepository();
|
||||||
createTestRepository();
|
createTestRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#delete(sonia.scm.repository.Repository)}.
|
* Tests {@link RepositoryManager#delete(TypedObject)}.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testDelete() throws RepositoryException, IOException {
|
public void testDelete() throws RepositoryException {
|
||||||
delete(manager, createTestRepository());
|
delete(manager, createTestRepository());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#delete(sonia.scm.repository.Repository)} without the required permissions.
|
* Tests {@link RepositoryManager#delete(TypedObject)} without the required permissions.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@SubjectAware(
|
@SubjectAware(
|
||||||
username = "unpriv"
|
username = "unpriv"
|
||||||
)
|
)
|
||||||
@Test(expected = UnauthorizedException.class)
|
@Test(expected = UnauthorizedException.class)
|
||||||
public void testDeleteWithoutPrivileges() throws RepositoryException, IOException {
|
public void testDeleteWithoutPrivileges() throws RepositoryException {
|
||||||
delete(manager, createTestRepository());
|
delete(manager, createTestRepository());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#delete(sonia.scm.repository.Repository)} with a non archived repository and with
|
* Tests {@link RepositoryManager#delete(TypedObject)} with a non archived repository and with
|
||||||
* enabled archive mode.
|
* enabled archive mode.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test(expected = RepositoryIsNotArchivedException.class)
|
@Test(expected = RepositoryIsNotArchivedException.class)
|
||||||
public void testDeleteNonArchived() throws RepositoryException, IOException {
|
public void testDeleteNonArchived() throws RepositoryException {
|
||||||
delete(createRepositoryManager(true), createTestRepository());
|
configuration.setEnableRepositoryArchive(true);
|
||||||
|
delete(manager, createTestRepository());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#delete(sonia.scm.repository.Repository)} with a non existing repository.
|
* Tests {@link RepositoryManager#delete(TypedObject)} with a non existing repository.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test(expected = RepositoryNotFoundException.class)
|
@Test(expected = RepositoryNotFoundException.class)
|
||||||
public void testDeleteNotFound() throws RepositoryException, IOException {
|
public void testDeleteNotFound() throws RepositoryException {
|
||||||
manager.delete(createRepositoryWithId());
|
manager.delete(createRepositoryWithId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#delete(sonia.scm.repository.Repository)} with enabled archive mode.
|
* Tests {@link RepositoryManager#delete(TypedObject)} with enabled archive mode.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteWithEnabledArchive()
|
public void testDeleteWithEnabledArchive()
|
||||||
throws RepositoryException, IOException {
|
throws RepositoryException {
|
||||||
Repository repository = createTestRepository();
|
Repository repository = createTestRepository();
|
||||||
|
|
||||||
repository.setArchived(true);
|
repository.setArchived(true);
|
||||||
@@ -206,12 +168,9 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#get(java.lang.String)} .
|
* Tests {@link RepositoryManager#get(java.lang.String)} .
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGet() throws RepositoryException, IOException {
|
public void testGet() throws RepositoryException {
|
||||||
Repository heartOfGold = createTestRepository();
|
Repository heartOfGold = createTestRepository();
|
||||||
String id = heartOfGold.getId();
|
String id = heartOfGold.getId();
|
||||||
String description = heartOfGold.getDescription();
|
String description = heartOfGold.getDescription();
|
||||||
@@ -227,15 +186,12 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#get(java.lang.String)} without required privileges.
|
* Tests {@link RepositoryManager#get(java.lang.String)} without required privileges.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@SubjectAware(
|
@SubjectAware(
|
||||||
username = "crato"
|
username = "crato"
|
||||||
)
|
)
|
||||||
public void testGetWithoutRequiredPrivileges() throws RepositoryException, IOException {
|
public void testGetWithoutRequiredPrivileges() throws RepositoryException {
|
||||||
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
|
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
|
||||||
manager.create(heartOfGold);
|
manager.create(heartOfGold);
|
||||||
|
|
||||||
@@ -245,12 +201,9 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#getAll()}.
|
* Tests {@link RepositoryManager#getAll()}.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGetAll() throws RepositoryException, IOException {
|
public void testGetAll() throws RepositoryException {
|
||||||
Repository heartOfGold = createTestRepository();
|
Repository heartOfGold = createTestRepository();
|
||||||
Repository happyVerticalPeopleTransporter = createSecondTestRepository();
|
Repository happyVerticalPeopleTransporter = createSecondTestRepository();
|
||||||
boolean foundHeart = false;
|
boolean foundHeart = false;
|
||||||
@@ -287,14 +240,11 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#getAll()} with permission for 2 of 3 repositories.
|
* Tests {@link RepositoryManager#getAll()} with permission for 2 of 3 repositories.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@SubjectAware(username = "dent")
|
@SubjectAware(username = "dent")
|
||||||
public void testGetAllWithPermissions() throws RepositoryException, IOException {
|
public void testGetAllWithPermissions() throws RepositoryException {
|
||||||
// mock key generator
|
// mock key generator
|
||||||
KeyGenerator keyGenerator = mock(KeyGenerator.class);
|
KeyGenerator keyGenerator = mock(KeyGenerator.class);
|
||||||
Stack<String> keys = new Stack<>();
|
Stack<String> keys = new Stack<>();
|
||||||
@@ -336,12 +286,9 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests repository manager events.
|
* Tests repository manager events.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testEvents() throws RepositoryException, IOException {
|
public void testEvents() throws RepositoryException {
|
||||||
RepositoryManager repoManager = createRepositoryManager(false);
|
RepositoryManager repoManager = createRepositoryManager(false);
|
||||||
repoManager.init(contextProvider);
|
repoManager.init(contextProvider);
|
||||||
TestListener listener = new TestListener();
|
TestListener listener = new TestListener();
|
||||||
@@ -372,13 +319,10 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#modify(sonia.scm.repository.Repository)}.
|
* Tests {@link RepositoryManager#modify(TypedObject)}.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testModify() throws RepositoryException, IOException {
|
public void testModify() throws RepositoryException {
|
||||||
Repository heartOfGold = createTestRepository();
|
Repository heartOfGold = createTestRepository();
|
||||||
|
|
||||||
heartOfGold.setDescription("prototype ship");
|
heartOfGold.setDescription("prototype ship");
|
||||||
@@ -391,15 +335,12 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#modify(sonia.scm.repository.Repository)} without
|
* Tests {@link RepositoryManager#modify(TypedObject)} without
|
||||||
* the required permissions.
|
* the required permissions.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@SubjectAware(username = "crato")
|
@SubjectAware(username = "crato")
|
||||||
public void testModifyWithoutRequiredPermissions() throws RepositoryException, IOException {
|
public void testModifyWithoutRequiredPermissions() throws RepositoryException {
|
||||||
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
|
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
|
||||||
manager.create(heartOfGold);
|
manager.create(heartOfGold);
|
||||||
heartOfGold.setDescription("prototype ship");
|
heartOfGold.setDescription("prototype ship");
|
||||||
@@ -409,25 +350,19 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#modify(sonia.scm.repository.Repository)} with a non
|
* Tests {@link RepositoryManager#modify(TypedObject)} with a non
|
||||||
* existing repository.
|
* existing repository.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test(expected = RepositoryNotFoundException.class)
|
@Test(expected = RepositoryNotFoundException.class)
|
||||||
public void testModifyNotFound() throws RepositoryException, IOException {
|
public void testModifyNotFound() throws RepositoryException {
|
||||||
manager.modify(createRepositoryWithId());
|
manager.modify(createRepositoryWithId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#refresh(sonia.scm.repository.Repository)}.
|
* Tests {@link RepositoryManager#refresh(ModelObject)}.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testRefresh() throws RepositoryException, IOException {
|
public void testRefresh() throws RepositoryException {
|
||||||
Repository heartOfGold = createTestRepository();
|
Repository heartOfGold = createTestRepository();
|
||||||
String description = heartOfGold.getDescription();
|
String description = heartOfGold.getDescription();
|
||||||
|
|
||||||
@@ -437,15 +372,12 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#refresh(sonia.scm.repository.Repository)} without
|
* Tests {@link RepositoryManager#refresh(ModelObject)} without
|
||||||
* required permissions.
|
* required permissions.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@SubjectAware(username = "crato")
|
@SubjectAware(username = "crato")
|
||||||
public void testRefreshWithoutRequiredPermissions() throws RepositoryException, IOException {
|
public void testRefreshWithoutRequiredPermissions() throws RepositoryException {
|
||||||
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
|
Repository heartOfGold = RepositoryTestData.createHeartOfGold();
|
||||||
manager.create(heartOfGold);
|
manager.create(heartOfGold);
|
||||||
heartOfGold.setDescription("prototype ship");
|
heartOfGold.setDescription("prototype ship");
|
||||||
@@ -455,25 +387,19 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#refresh(sonia.scm.repository.Repository)} with a non existing
|
* Tests {@link RepositoryManager#refresh(ModelObject)} with a non existing
|
||||||
* repository.
|
* repository.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test(expected = RepositoryNotFoundException.class)
|
@Test(expected = RepositoryNotFoundException.class)
|
||||||
public void testRefreshNotFound() throws RepositoryException, IOException {
|
public void testRefreshNotFound() throws RepositoryException {
|
||||||
manager.refresh(createRepositoryWithId());
|
manager.refresh(createRepositoryWithId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests repository hooks.
|
* Tests repository hooks.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testRepositoryHook() throws RepositoryException, IOException {
|
public void testRepositoryHook() throws RepositoryException {
|
||||||
CountingReceiveHook hook = new CountingReceiveHook();
|
CountingReceiveHook hook = new CountingReceiveHook();
|
||||||
RepositoryManager repoManager = createRepositoryManager(false);
|
RepositoryManager repoManager = createRepositoryManager(false);
|
||||||
|
|
||||||
@@ -494,12 +420,9 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link RepositoryManager#getFromTypeAndUri(String, String)}.
|
* Tests {@link RepositoryManager#getFromTypeAndUri(String, String)}.
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
* @throws RepositoryException
|
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void getRepositoryFromRequestUriTest() throws RepositoryException, IOException {
|
public void getRepositoryFromRequestUriTest() throws RepositoryException {
|
||||||
RepositoryManager m = createManager();
|
RepositoryManager m = createManager();
|
||||||
m.init(contextProvider);
|
m.init(contextProvider);
|
||||||
|
|
||||||
@@ -546,7 +469,7 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
|
|
||||||
XmlRepositoryDAO repositoryDAO = new XmlRepositoryDAO(factory);
|
XmlRepositoryDAO repositoryDAO = new XmlRepositoryDAO(factory);
|
||||||
|
|
||||||
ScmConfiguration configuration = new ScmConfiguration();
|
this.configuration = new ScmConfiguration();
|
||||||
|
|
||||||
NamespaceStrategy namespaceStrategy = new DefaultNamespaceStrategy();
|
NamespaceStrategy namespaceStrategy = new DefaultNamespaceStrategy();
|
||||||
|
|
||||||
@@ -557,7 +480,7 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createRepository(RepositoryManager m, Repository repository)
|
private void createRepository(RepositoryManager m, Repository repository)
|
||||||
throws RepositoryException, IOException {
|
throws RepositoryException {
|
||||||
m.create(repository);
|
m.create(repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,7 +507,7 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
return new RepositoryMatcher(Collections.<RepositoryPathMatcher>emptySet());
|
return new RepositoryMatcher(Collections.<RepositoryPathMatcher>emptySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Repository createRepository(Repository repository) throws RepositoryException, IOException {
|
private Repository createRepository(Repository repository) throws RepositoryException {
|
||||||
manager.create(repository);
|
manager.create(repository);
|
||||||
assertNotNull(repository.getId());
|
assertNotNull(repository.getId());
|
||||||
assertNotNull(manager.get(repository.getId()));
|
assertNotNull(manager.get(repository.getId()));
|
||||||
@@ -599,17 +522,17 @@ public class DefaultRepositoryManagerTest extends ManagerTestBase<Repository, Re
|
|||||||
return repository;
|
return repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Repository createSecondTestRepository() throws RepositoryException, IOException {
|
private Repository createSecondTestRepository() throws RepositoryException {
|
||||||
return createRepository(
|
return createRepository(
|
||||||
RepositoryTestData.createHappyVerticalPeopleTransporter());
|
RepositoryTestData.createHappyVerticalPeopleTransporter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Repository createTestRepository() throws RepositoryException, IOException {
|
private Repository createTestRepository() throws RepositoryException {
|
||||||
return createRepository(RepositoryTestData.createHeartOfGold());
|
return createRepository(RepositoryTestData.createHeartOfGold());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void delete(Manager<Repository, RepositoryException> manager, Repository repository)
|
private void delete(Manager<Repository, RepositoryException> manager, Repository repository)
|
||||||
throws RepositoryException, IOException {
|
throws RepositoryException {
|
||||||
|
|
||||||
String id = repository.getId();
|
String id = repository.getId();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"contact": "none@example.com",
|
||||||
|
"description": "Test repository",
|
||||||
|
"namespace": "space",
|
||||||
|
"name": "repo",
|
||||||
|
"archived": false,
|
||||||
|
"type": "git"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user