mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-14 01:15:44 +01:00
merge with branch 1.x
This commit is contained in:
@@ -137,6 +137,7 @@ import sonia.scm.schedule.QuartzScheduler;
|
||||
import sonia.scm.schedule.Scheduler;
|
||||
import sonia.scm.security.ConfigurableLoginAttemptHandler;
|
||||
import sonia.scm.security.LoginAttemptHandler;
|
||||
import sonia.scm.security.AuthorizationChangedEventProducer;
|
||||
import sonia.scm.web.UserAgentParser;
|
||||
|
||||
/**
|
||||
@@ -276,11 +277,14 @@ public class ScmServletModule extends JerseyServletModule
|
||||
|
||||
// bind security stuff
|
||||
bind(LoginAttemptHandler.class).to(ConfigurableLoginAttemptHandler.class);
|
||||
bind(AuthorizationChangedEventProducer.class);
|
||||
|
||||
bind(SecuritySystem.class).to(DefaultSecuritySystem.class);
|
||||
bind(AdministrationContext.class, DefaultAdministrationContext.class);
|
||||
|
||||
// bind cache
|
||||
bind(CacheManager.class, GuavaCacheManager.class);
|
||||
bind(org.apache.shiro.cache.CacheManager.class, GuavaCacheManager.class);
|
||||
|
||||
// bind dao
|
||||
bind(GroupDAO.class, XmlGroupDAO.class);
|
||||
|
||||
@@ -38,6 +38,10 @@ package sonia.scm.api.rest.resources;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Lists;
|
||||
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 sonia.scm.api.rest.Permission;
|
||||
import sonia.scm.security.AssignedPermission;
|
||||
@@ -114,13 +118,7 @@ public abstract class AbstractPermissionResource
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Adds a new permission to the user or group managed by the resource.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 add successful</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Adds a new permission to the user or group managed by the resource.
|
||||
*
|
||||
* @param uriInfo uri informations
|
||||
* @param permission permission to add
|
||||
@@ -128,6 +126,13 @@ public abstract class AbstractPermissionResource
|
||||
* @return web response
|
||||
*/
|
||||
@POST
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 201, condition = "creates", additionalHeaders = {
|
||||
@ResponseHeader(name = "Location", description = "uri to new create permission")
|
||||
}),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response add(@Context UriInfo uriInfo, Permission permission)
|
||||
{
|
||||
@@ -139,15 +144,7 @@ public abstract class AbstractPermissionResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a permission from the user or group managed by the resource.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 delete successful</li>
|
||||
* <li>400 bad request, permission id does not belong to the user or group</li>
|
||||
* <li>404 not found, no permission with the specified id available</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Deletes a permission from the user or group managed by the resource.
|
||||
*
|
||||
* @param id id of the permission
|
||||
*
|
||||
@@ -155,6 +152,13 @@ public abstract class AbstractPermissionResource
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, permission id does not belong to the user or group"),
|
||||
@ResponseCode(code = 404, condition = "not found, no permission with the specified id available"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
public Response delete(@PathParam("id") String id)
|
||||
{
|
||||
StoredAssignedPermission sap = getPermission(id);
|
||||
@@ -165,16 +169,7 @@ public abstract class AbstractPermissionResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified permission on the user or group managed by the
|
||||
* resource.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>204 update successful</li>
|
||||
* <li>400 bad request, permission id does not belong to the user or group</li>
|
||||
* <li>404 not found, no permission with the specified id available</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Updates the specified permission on the user or group managed by the resource.
|
||||
*
|
||||
* @param id id of the permission
|
||||
* @param permission updated permission
|
||||
@@ -183,6 +178,13 @@ public abstract class AbstractPermissionResource
|
||||
*/
|
||||
@PUT
|
||||
@Path("{id}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, permission id does not belong to the user or group"),
|
||||
@ResponseCode(code = 404, condition = "not found, no permission with the specified id available"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response update(@PathParam("id") String id, Permission permission)
|
||||
{
|
||||
@@ -197,16 +199,7 @@ public abstract class AbstractPermissionResource
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the {@link Permission} with the specified id.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>400 bad request, permission id does not belong to the user or group</li>
|
||||
* <li>404 not found, no permission with the specified id available</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
*
|
||||
* Returns the {@link Permission} with the specified id.
|
||||
*
|
||||
* @param id id of the {@link Permission}
|
||||
*
|
||||
@@ -214,6 +207,12 @@ public abstract class AbstractPermissionResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, permission id does not belong to the user or group"),
|
||||
@ResponseCode(code = 404, condition = "not found, no permission with the specified id available"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Permission get(@PathParam("id") String id)
|
||||
{
|
||||
@@ -223,17 +222,15 @@ public abstract class AbstractPermissionResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all permissions of the user or group managed by the resource.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all permissions of the user or group managed by the resource.
|
||||
*
|
||||
* @return all permissions of the user or group
|
||||
*/
|
||||
@GET
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public List<Permission> getAll()
|
||||
{
|
||||
|
||||
@@ -39,7 +39,10 @@ import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.List;
|
||||
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
@@ -47,8 +50,6 @@ import org.apache.shiro.authc.DisabledAccountException;
|
||||
import org.apache.shiro.authc.ExcessiveAttemptsException;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import org.codehaus.enunciate.jaxrs.TypeHint;
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -59,6 +60,11 @@ import sonia.scm.api.rest.RestActionResult;
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.security.Tokens;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -81,12 +87,12 @@ import sonia.scm.security.AccessTokenCookieIssuer;
|
||||
import sonia.scm.security.Scope;
|
||||
|
||||
/**
|
||||
*
|
||||
* Authentication related RESTful Web Service endpoint.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
@Path("auth")
|
||||
@ExternallyManagedLifecycle
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public class AuthenticationResource
|
||||
{
|
||||
@@ -128,15 +134,8 @@ public class AuthenticationResource
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Authenticate a user and return the state of the application.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>400 bad request, required parameter is missing.</li>
|
||||
* <li>401 unauthorized, the specified username or password is wrong</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
*
|
||||
* Authenticate a user and return the state of the application.
|
||||
*
|
||||
* @param request current http request
|
||||
* @param response current http response
|
||||
* @param grantType grant type, currently only password is supported
|
||||
@@ -150,6 +149,12 @@ public class AuthenticationResource
|
||||
@POST
|
||||
@Path("access_token")
|
||||
@TypeHint(ScmState.class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, required parameter is missing"),
|
||||
@ResponseCode(code = 401, condition = "unauthorized, the specified username or password is wrong"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response authenticate(
|
||||
@Context HttpServletRequest request,
|
||||
@Context HttpServletResponse response,
|
||||
@@ -238,13 +243,7 @@ public class AuthenticationResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout the current user. Returns the current state of the application,
|
||||
* if public access is enabled.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Logout the current user. Returns the current state of the application, if public access is enabled.
|
||||
*
|
||||
* @param request the current http request
|
||||
* @param response the current http response
|
||||
@@ -254,6 +253,10 @@ public class AuthenticationResource
|
||||
@GET
|
||||
@Path("logout")
|
||||
@TypeHint(ScmState.class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response logout(@Context HttpServletRequest request, @Context HttpServletResponse response)
|
||||
{
|
||||
Subject subject = SecurityUtils.getSubject();
|
||||
@@ -280,16 +283,8 @@ public class AuthenticationResource
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This method is an alias of the
|
||||
* {@link #getState(javax.servlet.http.HttpServletRequest)} method.
|
||||
* The only difference between the methods,
|
||||
* is that this one could not be used with basic authentication.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>401 unauthorized, user is not authenticated and public access is disabled.</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* This method is an alias of the {@link #getState(HttpServletRequest)} method.
|
||||
* The only difference between the methods, is that this one could not be used with basic authentication.
|
||||
*
|
||||
* @param request the current http request
|
||||
*
|
||||
@@ -298,19 +293,18 @@ public class AuthenticationResource
|
||||
@GET
|
||||
@Path("state")
|
||||
@TypeHint(ScmState.class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 401, condition = "unauthorized, user is not authenticated and public access is disabled"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response getCurrentState(@Context HttpServletRequest request)
|
||||
{
|
||||
return getState(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current state of the application.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>401 unauthorized, user is not authenticated and public access is disabled.</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns the current state of the application.
|
||||
*
|
||||
* @param request the current http request
|
||||
*
|
||||
@@ -318,6 +312,11 @@ public class AuthenticationResource
|
||||
*/
|
||||
@GET
|
||||
@TypeHint(ScmState.class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 401, condition = "unauthorized, user is not authenticated and public access is disabled"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
public Response getState(@Context HttpServletRequest request)
|
||||
{
|
||||
Response response;
|
||||
|
||||
@@ -36,14 +36,14 @@ package sonia.scm.api.rest.resources;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.credential.PasswordService;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import org.codehaus.enunciate.jaxrs.TypeHint;
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -68,10 +68,10 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
*
|
||||
* Resource to change the password of the authenticated user.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@ExternallyManagedLifecycle
|
||||
@Path("action/change-password")
|
||||
public class ChangePasswordResource
|
||||
{
|
||||
@@ -100,14 +100,7 @@ public class ChangePasswordResource
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Changes the password of the current user.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>400 bad request, the old password is not correct</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Changes the password of the current user.
|
||||
*
|
||||
* @param oldPassword old password of the current user
|
||||
* @param newPassword new password for the current user
|
||||
@@ -119,6 +112,11 @@ public class ChangePasswordResource
|
||||
*/
|
||||
@POST
|
||||
@TypeHint(RestActionResult.class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, the old password is not correct"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response changePassword(@FormParam("old-password") String oldPassword,
|
||||
@FormParam("new-password") String newPassword)
|
||||
|
||||
@@ -35,6 +35,8 @@ package sonia.scm.api.rest.resources;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
|
||||
@@ -60,12 +62,7 @@ public class CipherResource
|
||||
|
||||
/**
|
||||
* Encrypts the request body and returns an encrypted string. This method can
|
||||
* only executed with administration privileges.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* only executed with administration privileges.
|
||||
*
|
||||
* @param value value to encrypt
|
||||
*
|
||||
@@ -73,6 +70,10 @@ public class CipherResource
|
||||
*/
|
||||
@POST
|
||||
@Path("encrypt")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String encrypt(String value)
|
||||
{
|
||||
|
||||
@@ -41,8 +41,6 @@ import com.google.inject.Singleton;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import sonia.scm.config.ScmConfiguration;
|
||||
import sonia.scm.security.Role;
|
||||
import sonia.scm.security.ScmSecurityException;
|
||||
@@ -66,7 +64,6 @@ import javax.ws.rs.core.UriInfo;
|
||||
*/
|
||||
@Singleton
|
||||
@Path("config")
|
||||
@ExternallyManagedLifecycle
|
||||
public class ConfigurationResource
|
||||
{
|
||||
|
||||
|
||||
@@ -37,12 +37,13 @@ package sonia.scm.api.rest.resources;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
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.codehaus.enunciate.jaxrs.TypeHint;
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupException;
|
||||
import sonia.scm.group.GroupManager;
|
||||
@@ -70,12 +71,12 @@ import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* RESTful Web Service Resource to manage groups and their members.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Path("groups")
|
||||
@Singleton
|
||||
@ExternallyManagedLifecycle
|
||||
public class GroupResource
|
||||
extends AbstractManagerResource<Group, GroupException>
|
||||
{
|
||||
@@ -102,15 +103,7 @@ public class GroupResource
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates a new group.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 create success</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Creates a new group. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param uriInfo current uri informations
|
||||
* @param group the group to be created
|
||||
@@ -118,6 +111,14 @@ public class GroupResource
|
||||
* @return
|
||||
*/
|
||||
@POST
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 201, condition = "create success", additionalHeaders = {
|
||||
@ResponseHeader(name = "Location", description = "uri to the created group")
|
||||
}),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Override
|
||||
public Response create(@Context UriInfo uriInfo, Group group)
|
||||
@@ -126,15 +127,7 @@ public class GroupResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a group.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 delete success</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Deletes a group. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param name the name of the group to delete.
|
||||
*
|
||||
@@ -142,6 +135,12 @@ public class GroupResource
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "delete success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Override
|
||||
public Response delete(@PathParam("id") String name)
|
||||
{
|
||||
@@ -149,15 +148,7 @@ public class GroupResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the given group.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 update successful</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Modifies the given group. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param uriInfo current uri informations
|
||||
* @param name name of the group to be modified
|
||||
@@ -167,6 +158,12 @@ public class GroupResource
|
||||
*/
|
||||
@PUT
|
||||
@Path("{id}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "update success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Override
|
||||
public Response update(@Context UriInfo uriInfo,
|
||||
@@ -178,16 +175,7 @@ public class GroupResource
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a group.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>404 not found, no group with the specified id/name available</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Fetches a group by its name or id. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param request the current request
|
||||
* @param id the id/name of the group
|
||||
@@ -197,6 +185,12 @@ public class GroupResource
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@TypeHint(Group.class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Override
|
||||
public Response get(@Context Request request, @PathParam("id") String id)
|
||||
@@ -216,15 +210,7 @@ public class GroupResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all groups.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all groups. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param request the current request
|
||||
* @param start the start value for paging
|
||||
@@ -237,6 +223,11 @@ public class GroupResource
|
||||
@GET
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@TypeHint(Group[].class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Override
|
||||
public Response getAll(@Context Request request, @DefaultValue("0")
|
||||
@QueryParam("start") int start, @DefaultValue("-1")
|
||||
@@ -249,14 +240,6 @@ public class GroupResource
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param items
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected GenericEntity<Collection<Group>> createGenericEntity(
|
||||
Collection<Group> items)
|
||||
@@ -267,26 +250,12 @@ public class GroupResource
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param group
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected String getId(Group group)
|
||||
{
|
||||
return group.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected String getPathPart()
|
||||
{
|
||||
|
||||
@@ -34,11 +34,11 @@ package sonia.scm.api.rest.resources;
|
||||
//~--- non-JDK imports --------------------------------------------------------
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import sonia.scm.security.KeyGenerator;
|
||||
import sonia.scm.security.Role;
|
||||
|
||||
@@ -56,7 +56,6 @@ import javax.ws.rs.core.MediaType;
|
||||
* @since 1.41
|
||||
*/
|
||||
@Path("security/key")
|
||||
@ExternallyManagedLifecycle
|
||||
public class KeyResource
|
||||
{
|
||||
|
||||
@@ -75,17 +74,15 @@ public class KeyResource
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Generates a unique key. This method can only executed with administration
|
||||
* privileges.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Generates a unique key. <strong>Note:</strong> This method can only executed with administration privileges.
|
||||
*
|
||||
* @return unique key
|
||||
*/
|
||||
@GET
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String generateKey()
|
||||
{
|
||||
|
||||
@@ -39,8 +39,6 @@ import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -55,6 +53,9 @@ import sonia.scm.plugin.PluginManager;
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import com.sun.jersey.multipart.FormDataParam;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
import com.webcohesion.enunciate.metadata.rs.TypeHint;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -75,12 +76,12 @@ import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
/**
|
||||
*
|
||||
* RESTful Web Service Endpoint to manage plugins.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
@Path("plugins")
|
||||
@ExternallyManagedLifecycle
|
||||
public class PluginResource
|
||||
{
|
||||
|
||||
@@ -107,21 +108,21 @@ public class PluginResource
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Installs a plugin from a package.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>412 precondition failed</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Installs a plugin from a package.
|
||||
*
|
||||
* @param uploadedInputStream
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
@POST
|
||||
@Path("install-package")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 412, condition = "precondition failed"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response install(
|
||||
@@ -153,35 +154,30 @@ public class PluginResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a plugin.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Installs a plugin.
|
||||
*
|
||||
* @param id id of the plugin to be installed
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@POST
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Path("install/{id}")
|
||||
public Response install(@PathParam("id") String id)
|
||||
{
|
||||
pluginManager.install(id);
|
||||
|
||||
// TODO should return 204 no content
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs a plugin from a package. This method is a workaround for ExtJS
|
||||
* file upload, which requires text/html as content-type.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>412 precondition failed</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* file upload, which requires text/html as content-type.
|
||||
*
|
||||
* @param uploadedInputStream
|
||||
* @return
|
||||
@@ -190,6 +186,11 @@ public class PluginResource
|
||||
*/
|
||||
@POST
|
||||
@Path("install-package.html")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 412, condition = "precondition failed"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
public Response installFromUI(
|
||||
@@ -200,60 +201,62 @@ public class PluginResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstalls a plugin.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Uninstalls a plugin.
|
||||
*
|
||||
* @param id id of the plugin to be uninstalled
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@POST
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Path("uninstall/{id}")
|
||||
public Response uninstall(@PathParam("id") String id)
|
||||
{
|
||||
pluginManager.uninstall(id);
|
||||
|
||||
// TODO should return 204 content
|
||||
// consider to do a uninstall with a delete
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a plugin.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Updates a plugin.
|
||||
*
|
||||
* @param id id of the plugin to be updated
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@POST
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Path("update/{id}")
|
||||
public Response update(@PathParam("id") String id)
|
||||
{
|
||||
pluginManager.update(id);
|
||||
|
||||
// TODO should return 204 content
|
||||
// consider to do an update with a put
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns all plugins.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all plugins.
|
||||
*
|
||||
* @return all plugins
|
||||
*/
|
||||
@GET
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Collection<PluginInformation> getAll()
|
||||
{
|
||||
@@ -261,17 +264,16 @@ public class PluginResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all available plugins.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all available plugins.
|
||||
*
|
||||
* @return all available plugins
|
||||
*/
|
||||
@GET
|
||||
@Path("available")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Collection<PluginInformation> getAvailable()
|
||||
{
|
||||
@@ -279,17 +281,16 @@ public class PluginResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all plugins which are available for update.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all plugins which are available for update.
|
||||
*
|
||||
* @return all plugins which are available for update
|
||||
*/
|
||||
@GET
|
||||
@Path("updates")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Collection<PluginInformation> getAvailableUpdates()
|
||||
{
|
||||
@@ -297,17 +298,16 @@ public class PluginResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all installed plugins.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all installed plugins.
|
||||
*
|
||||
* @return all installed plugins
|
||||
*/
|
||||
@GET
|
||||
@Path("installed")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Collection<PluginInformation> getInstalled()
|
||||
{
|
||||
@@ -315,17 +315,16 @@ public class PluginResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all plugins for the overview.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all plugins for the overview.
|
||||
*
|
||||
* @return all plugins for the overview
|
||||
*/
|
||||
@GET
|
||||
@Path("overview")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Collection<PluginInformation> getOverview()
|
||||
{
|
||||
|
||||
@@ -43,9 +43,6 @@ import com.google.inject.Inject;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
|
||||
import org.codehaus.enunciate.jaxrs.TypeHint;
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -74,6 +71,10 @@ import static com.google.common.base.Preconditions.*;
|
||||
|
||||
import com.sun.jersey.api.client.ClientResponse.Status;
|
||||
import com.sun.jersey.multipart.FormDataParam;
|
||||
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 java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -111,7 +112,6 @@ import javax.xml.bind.annotation.XmlRootElement;
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Path("import/repositories")
|
||||
@ExternallyManagedLifecycle
|
||||
public class RepositoryImportResource
|
||||
{
|
||||
|
||||
@@ -142,17 +142,8 @@ public class RepositoryImportResource
|
||||
/**
|
||||
* Imports a repository type specific bundle. The bundle file is uploaded to
|
||||
* the server which is running scm-manager. After the upload has finished, the
|
||||
* bundle file is passed to the {@link UnbundleCommandBuilder}. This method
|
||||
* requires admin privileges.<br />
|
||||
*
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 created</li>
|
||||
* <li>400 bad request, the import bundle feature is not supported by this
|
||||
* type of repositories or the parameters are not valid.</li>
|
||||
* <li>500 internal server error</li>
|
||||
* <li>409 conflict, a repository with the name already exists.</li>
|
||||
* </ul>
|
||||
* bundle file is passed to the {@link UnbundleCommandBuilder}. <strong>Note:</strong> This method
|
||||
* requires admin privileges.
|
||||
*
|
||||
* @param uriInfo uri info
|
||||
* @param type repository type
|
||||
@@ -160,12 +151,23 @@ public class RepositoryImportResource
|
||||
* @param inputStream input bundle
|
||||
* @param compressed true if the bundle is gzip compressed
|
||||
*
|
||||
* @return empty response with location header which points to the imported
|
||||
* repository
|
||||
* @return empty response with location header which points to the imported repository
|
||||
* @since 1.43
|
||||
*/
|
||||
@POST
|
||||
@Path("{type}/bundle")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 201, condition = "created", additionalHeaders = {
|
||||
@ResponseHeader(name = "Location", description = "uri to the imported repository")
|
||||
}),
|
||||
@ResponseCode(
|
||||
code = 400,
|
||||
condition = "bad request, the import bundle feature is not supported by this type of repositories or the parameters are not valid"
|
||||
),
|
||||
@ResponseCode(code = 409, condition = "conflict, a repository with the name already exists"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
public Response importFromBundle(@Context UriInfo uriInfo,
|
||||
@PathParam("type") String type, @FormDataParam("name") String name,
|
||||
@@ -182,18 +184,8 @@ public class RepositoryImportResource
|
||||
* This method works exactly like
|
||||
* {@link #importFromBundle(UriInfo, String, String, InputStream)}, but this
|
||||
* method returns an html content-type. The method exists only for a
|
||||
* workaround of the javascript ui extjs. This method requires admin
|
||||
* privileges.<br />
|
||||
*
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 created</li>
|
||||
* <li>400 bad request, the import bundle feature is not supported by this
|
||||
* type of repositories or the parameters are not valid.</li>
|
||||
* <li>500 internal server error</li>
|
||||
* <li>409 conflict, a repository with the name already exists.</li>
|
||||
* </ul>
|
||||
*
|
||||
* workaround of the javascript ui extjs. <strong>Note:</strong> This method requires admin
|
||||
* privileges.
|
||||
*
|
||||
* @param type repository type
|
||||
* @param name name of the repository
|
||||
@@ -206,6 +198,16 @@ public class RepositoryImportResource
|
||||
*/
|
||||
@POST
|
||||
@Path("{type}/bundle.html")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(
|
||||
code = 400,
|
||||
condition = "bad request, the import bundle feature is not supported by this type of repositories or the parameters are not valid"
|
||||
),
|
||||
@ResponseCode(code = 409, condition = "conflict, a repository with the name already exists"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(RestActionUploadResult.class)
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
public Response importFromBundleUI(@PathParam("type") String type,
|
||||
@@ -234,16 +236,7 @@ public class RepositoryImportResource
|
||||
* Imports a external repository which is accessible via url. The method can
|
||||
* only be used, if the repository type supports the {@link Command#PULL}. The
|
||||
* method will return a location header with the url to the imported
|
||||
* repository. This method requires admin privileges.<br />
|
||||
*
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 created</li>
|
||||
* <li>400 bad request, the import by url feature is not supported by this
|
||||
* type of repositories or the parameters are not valid.</li>
|
||||
* <li>409 conflict, a repository with the name already exists.</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* repository. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param uriInfo uri info
|
||||
* @param type repository type
|
||||
@@ -255,6 +248,18 @@ public class RepositoryImportResource
|
||||
*/
|
||||
@POST
|
||||
@Path("{type}/url")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 201, condition = "created", additionalHeaders = {
|
||||
@ResponseHeader(name = "Location", description = "uri to the imported repository")
|
||||
}),
|
||||
@ResponseCode(
|
||||
code = 400,
|
||||
condition = "bad request, the import feature is not supported by this type of repositories or the parameters are not valid"
|
||||
),
|
||||
@ResponseCode(code = 409, condition = "conflict, a repository with the name already exists"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response importFromUrl(@Context UriInfo uriInfo,
|
||||
@PathParam("type") String type, UrlImportRequest request)
|
||||
@@ -298,15 +303,7 @@ public class RepositoryImportResource
|
||||
|
||||
/**
|
||||
* Imports repositories of the given type from the configured repository
|
||||
* directory. This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 ok, successful</li>
|
||||
* <li>400 bad request, the import feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* directory. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param type repository type
|
||||
*
|
||||
@@ -314,6 +311,14 @@ public class RepositoryImportResource
|
||||
*/
|
||||
@POST
|
||||
@Path("{type}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(
|
||||
code = 400,
|
||||
condition = "bad request, the import feature is not supported by this type of repositories"
|
||||
),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(Repository[].class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response importRepositories(@PathParam("type") String type)
|
||||
@@ -333,19 +338,19 @@ public class RepositoryImportResource
|
||||
|
||||
/**
|
||||
* Imports repositories of all supported types from the configured repository
|
||||
* directories. This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 ok, successful</li>
|
||||
* <li>400 bad request, the import feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* directories. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @return imported repositories
|
||||
*/
|
||||
@POST
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(
|
||||
code = 400,
|
||||
condition = "bad request, the import feature is not supported by this type of repositories"
|
||||
),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(Repository[].class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response importRepositories()
|
||||
@@ -371,15 +376,7 @@ public class RepositoryImportResource
|
||||
/**
|
||||
* Imports repositories of the given type from the configured repository
|
||||
* directory. Returns a list of successfully imported directories and a list
|
||||
* of failed directories. This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 ok, successful</li>
|
||||
* <li>400 bad request, the import feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* of failed directories. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param type repository type
|
||||
*
|
||||
@@ -388,6 +385,14 @@ public class RepositoryImportResource
|
||||
*/
|
||||
@POST
|
||||
@Path("{type}/directory")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(
|
||||
code = 400,
|
||||
condition = "bad request, the import feature is not supported by this type of repositories"
|
||||
),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(ImportResult.class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response importRepositoriesFromDirectory(
|
||||
@@ -456,22 +461,20 @@ public class RepositoryImportResource
|
||||
|
||||
/**
|
||||
* Returns a list of repository types, which support the directory import
|
||||
* feature.
|
||||
*
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 ok, successful</li>
|
||||
* <li>400 bad request, the import feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* feature. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @return list of repository types
|
||||
*/
|
||||
@GET
|
||||
@TypeHint(Type[].class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(
|
||||
code = 400,
|
||||
condition = "bad request, the import feature is not supported by this type of repositories"
|
||||
),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response getImportableTypes()
|
||||
{
|
||||
|
||||
@@ -38,12 +38,13 @@ package sonia.scm.api.rest.resources;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
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.codehaus.enunciate.jaxrs.TypeHint;
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -103,14 +104,13 @@ import javax.ws.rs.core.UriInfo;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Repository related RESTful Web Service Endpoint.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
@Path("repositories")
|
||||
@ExternallyManagedLifecycle
|
||||
public class RepositoryResource
|
||||
extends AbstractManagerResource<Repository, RepositoryException>
|
||||
public class RepositoryResource extends AbstractManagerResource<Repository, RepositoryException>
|
||||
{
|
||||
|
||||
/** Field description */
|
||||
@@ -147,22 +147,22 @@ public class RepositoryResource
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates a new repository.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 create success</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Creates a new repository.<strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param uriInfo current uri informations
|
||||
* @param repository the repository to be created
|
||||
*
|
||||
* @return
|
||||
* @return empty response with location header to the new repository
|
||||
*/
|
||||
@POST
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 201, condition = "success", additionalHeaders = {
|
||||
@ResponseHeader(name = "Location", description = "uri to the new created repository")
|
||||
}),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Override
|
||||
public Response create(@Context UriInfo uriInfo, Repository repository)
|
||||
@@ -171,19 +171,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a repository.<br />
|
||||
* This method requires owner privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 delete success</li>
|
||||
* <li>403 forbidden, the current user has no owner privileges</li>
|
||||
* <li>
|
||||
* 412 forbidden, the repository is not archived,
|
||||
* this error occurs only with enabled repository archive.
|
||||
* </li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Deletes a repository. <strong>Note:</strong> This method requires owner privileges.
|
||||
*
|
||||
* @param id the id of the repository to delete.
|
||||
*
|
||||
@@ -191,6 +179,17 @@ public class RepositoryResource
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "delete success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no owner privileges"),
|
||||
@ResponseCode(code = 404, condition = "could not find repository"),
|
||||
@ResponseCode(
|
||||
code = 412,
|
||||
condition = "precondition failed, the repository is not archived, this error occurs only with enabled repository archive"
|
||||
),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Override
|
||||
public Response delete(@PathParam("id") String id)
|
||||
{
|
||||
@@ -232,20 +231,20 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Re run repository health checks.<br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 re run success</li>
|
||||
* <li>403 forbidden, the current user has no owner privileges</li>
|
||||
* <li>404 could not find repository</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Re run repository health checks.
|
||||
*
|
||||
* @param id id of the repository
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@POST
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "re run success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no owner privileges"),
|
||||
@ResponseCode(code = 404, condition = "could not find repository"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Path("{id}/healthcheck")
|
||||
public Response runHealthChecks(@PathParam("id") String id)
|
||||
{
|
||||
@@ -254,6 +253,7 @@ public class RepositoryResource
|
||||
try
|
||||
{
|
||||
healthChecker.check(id);
|
||||
// TODO should return 204 instead of 200
|
||||
response = Response.ok().build();
|
||||
}
|
||||
catch (RepositoryNotFoundException ex)
|
||||
@@ -271,15 +271,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the given repository.<br />
|
||||
* This method requires owner privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 update successful</li>
|
||||
* <li>403 forbidden, the current user has no owner privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Modifies the given repository. <strong>Note:</strong> This method requires owner privileges.
|
||||
*
|
||||
* @param uriInfo current uri informations
|
||||
* @param id id of the repository to be modified
|
||||
@@ -289,10 +281,16 @@ public class RepositoryResource
|
||||
*/
|
||||
@PUT
|
||||
@Path("{id}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "update successful"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no owner privileges"),
|
||||
@ResponseCode(code = 404, condition = "could not find repository"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Override
|
||||
public Response update(@Context UriInfo uriInfo, @PathParam("id") String id,
|
||||
Repository repository)
|
||||
public Response update(@Context UriInfo uriInfo, @PathParam("id") String id, Repository repository)
|
||||
{
|
||||
return super.update(uriInfo, id, repository);
|
||||
}
|
||||
@@ -300,14 +298,7 @@ public class RepositoryResource
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the {@link Repository} with the specified id.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>404 not found, no repository with the specified id available</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns the {@link Repository} with the specified id.
|
||||
*
|
||||
* @param request the current request
|
||||
* @param id the id/name of the user
|
||||
@@ -317,6 +308,11 @@ public class RepositoryResource
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 404, condition = "not found, no repository with the specified id available"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(Repository.class)
|
||||
@Override
|
||||
public Response get(@Context Request request, @PathParam("id") String id)
|
||||
@@ -325,13 +321,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all repositories.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all repositories.
|
||||
*
|
||||
* @param request the current request
|
||||
* @param start the start value for paging
|
||||
@@ -343,6 +333,10 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(Repository[].class)
|
||||
@Override
|
||||
public Response getAll(@Context Request request, @DefaultValue("0")
|
||||
@@ -355,16 +349,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a annotate/blame view for the given path.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>400 bad request, the blame feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>404 not found, if the repository or the path could not be found</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns a annotate/blame view for the given path.
|
||||
*
|
||||
* @param id the id of the repository
|
||||
* @param revision the revision of the file
|
||||
@@ -377,6 +362,12 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{id}/blame")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, the blame feature is not supported by this type of repositories."),
|
||||
@ResponseCode(code = 404, condition = "not found, the repository or the path could not be found"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(BlameResult.class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response getBlame(@PathParam("id") String id,
|
||||
@@ -430,16 +421,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all {@link Branches} of a repository.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>400 bad request, the content feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>404 not found, if the repository or the path could not be found</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all {@link Branches} of a repository.
|
||||
*
|
||||
* @param id the id of the repository
|
||||
*
|
||||
@@ -452,6 +434,14 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{id}/branches")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, the branch feature is not supported by this type of repositories."),
|
||||
@ResponseCode(code = 404, condition = "not found, the repository could not be found"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(Branches.class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response getBranches(@PathParam("id") String id)
|
||||
throws RepositoryException, IOException
|
||||
{
|
||||
@@ -490,16 +480,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of folders and files for the given folder.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>400 bad request, the browse feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>404 not found, if the repository or the path could not be found</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns a list of folders and files for the given folder.
|
||||
*
|
||||
* @param id the id of the repository
|
||||
* @param revision the revision of the file
|
||||
@@ -515,6 +496,12 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{id}/browse")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, the browse feature is not supported by this type of repositories."),
|
||||
@ResponseCode(code = 404, condition = "not found, the repository or the path could not be found"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(BrowserResult.class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
//J-
|
||||
@@ -581,15 +568,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Repository} with the specified type and name.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>404 not found,
|
||||
* no repository with the specified type and name available</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns the {@link Repository} with the specified type and name.
|
||||
*
|
||||
* @param type the type of the repository
|
||||
* @param name the name of the repository
|
||||
@@ -598,8 +577,13 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{type: [a-z]+}/{name: .*}")
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 404, condition = "not found, no repository with the specified type and name available"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(Repository.class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response getByTypeAndName(@PathParam("type") String type,
|
||||
@PathParam("name") String name)
|
||||
{
|
||||
@@ -621,17 +605,7 @@ public class RepositoryResource
|
||||
|
||||
/**
|
||||
* Returns the {@link Changeset} from the given repository
|
||||
* with the specified revision.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>400 bad request, the changeset feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>404 not found, if the repository or
|
||||
* the revision could not be found</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* with the specified revision.
|
||||
*
|
||||
* @param id the id of the repository
|
||||
* @param revision the revision of the changeset
|
||||
@@ -643,6 +617,14 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{id}/changeset/{revision}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, the changeset feature is not supported by this type of repositories."),
|
||||
@ResponseCode(code = 404, condition = "not found, the repository or the revision could not be found"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(Changeset.class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response getChangeset(@PathParam("id") String id,
|
||||
@PathParam("revision") String revision)
|
||||
throws IOException, RepositoryException
|
||||
@@ -691,16 +673,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of {@link Changeset} for the given repository.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>400 bad request, the changeset feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>404 not found, if the repository or the path could not be found</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns a list of {@link Changeset} for the given repository.
|
||||
*
|
||||
* @param id the id of the repository
|
||||
* @param path path of a file
|
||||
@@ -716,6 +689,12 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{id}/changesets")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, the changeset feature is not supported by this type of repositories."),
|
||||
@ResponseCode(code = 404, condition = "not found, the repository or the path could not be found"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(ChangesetPagingResult.class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
//J-
|
||||
@@ -784,16 +763,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of a file.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>400 bad request, the content feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>404 not found, if the repository or the path could not be found</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns the content of a file.
|
||||
*
|
||||
* @param id the id of the repository
|
||||
* @param revision the revision of the file
|
||||
@@ -803,6 +773,12 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{id}/content")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, the content feature is not supported by this type of repositories."),
|
||||
@ResponseCode(code = 404, condition = "not found, the repository or the path could not be found"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(StreamingOutput.class)
|
||||
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
|
||||
public Response getContent(@PathParam("id") String id,
|
||||
@@ -855,16 +831,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the modifications of a {@link Changeset}.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>400 bad request, the content feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>404 not found, if the repository or the path could not be found</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns the modifications of a {@link Changeset}.
|
||||
*
|
||||
* @param id the id of the repository
|
||||
* @param revision the revision of the file
|
||||
@@ -878,6 +845,12 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{id}/diff")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, the diff feature is not supported by this type of repositories."),
|
||||
@ResponseCode(code = 404, condition = "not found, the repository or the path could not be found"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(DiffStreamingOutput.class)
|
||||
@Produces(MediaType.APPLICATION_OCTET_STREAM)
|
||||
public Response getDiff(@PathParam("id") String id,
|
||||
@@ -943,16 +916,7 @@ public class RepositoryResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all {@link Tags} of a repository.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>400 bad request, the content feature is not
|
||||
* supported by this type of repositories.</li>
|
||||
* <li>404 not found, if the repository or the path could not be found</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all {@link Tags} of a repository.
|
||||
*
|
||||
* @param id the id of the repository
|
||||
*
|
||||
@@ -965,6 +929,14 @@ public class RepositoryResource
|
||||
*/
|
||||
@GET
|
||||
@Path("{id}/tags")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 400, condition = "bad request, the tag feature is not supported by this type of repositories."),
|
||||
@ResponseCode(code = 404, condition = "not found, the repository could not be found"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(Tags.class)
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public Response getTags(@PathParam("id") String id)
|
||||
throws RepositoryException, IOException
|
||||
{
|
||||
|
||||
@@ -41,8 +41,6 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryManager;
|
||||
import sonia.scm.repository.RepositoryTypePredicate;
|
||||
@@ -74,7 +72,6 @@ import javax.ws.rs.core.MediaType;
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@ExternallyManagedLifecycle
|
||||
@Path("help/repository-root/{type}.html")
|
||||
public class RepositoryRootResource
|
||||
{
|
||||
|
||||
@@ -40,8 +40,8 @@ import com.github.legman.Subscribe;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
import com.webcohesion.enunciate.metadata.rs.ResponseCode;
|
||||
import com.webcohesion.enunciate.metadata.rs.StatusCodes;
|
||||
|
||||
import sonia.scm.cache.Cache;
|
||||
import sonia.scm.cache.CacheManager;
|
||||
@@ -64,12 +64,13 @@ import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
/**
|
||||
*
|
||||
* RESTful Web Service Resource to search users and groups. This endpoint can be used to implement typeahead input
|
||||
* fields for permissions.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
@Path("search")
|
||||
@ExternallyManagedLifecycle
|
||||
public class SearchResource
|
||||
{
|
||||
|
||||
@@ -140,12 +141,7 @@ public class SearchResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of groups found by the given search string.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns a list of groups found by the given search string.
|
||||
*
|
||||
* @param queryString the search string
|
||||
*
|
||||
@@ -153,6 +149,10 @@ public class SearchResource
|
||||
*/
|
||||
@GET
|
||||
@Path("groups")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public SearchResults searchGroups(@QueryParam("query") String queryString)
|
||||
{
|
||||
@@ -176,12 +176,7 @@ public class SearchResource
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of users found by the given search string.<br />
|
||||
* <br />
|
||||
* <ul>
|
||||
* <li>200 success</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns a list of users found by the given search string.
|
||||
*
|
||||
* @param queryString the search string
|
||||
*
|
||||
@@ -189,6 +184,10 @@ public class SearchResource
|
||||
*/
|
||||
@GET
|
||||
@Path("users")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
public SearchResults searchUsers(@QueryParam("query") String queryString)
|
||||
{
|
||||
|
||||
@@ -45,14 +45,13 @@ import sonia.scm.security.SecuritySystem;
|
||||
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
/**
|
||||
*
|
||||
* Resource for managing system security permissions.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Path("security/permission")
|
||||
@ExternallyManagedLifecycle
|
||||
public class SecuritySystemResource
|
||||
{
|
||||
|
||||
@@ -74,31 +73,28 @@ public class SecuritySystemResource
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns group permission sub resource.
|
||||
*
|
||||
* @param group name of group
|
||||
*
|
||||
* @param group
|
||||
*
|
||||
* @return
|
||||
* @return sub resource
|
||||
*/
|
||||
@Path("group/{group}")
|
||||
public GroupPermissionResource getGroupSubResource(
|
||||
@PathParam("group") String group)
|
||||
public GroupPermissionResource getGroupSubResource(@PathParam("group") String group)
|
||||
{
|
||||
return new GroupPermissionResource(system, group);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
* Returns user permission sub resource.
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
* @param user name of user
|
||||
*
|
||||
* @return
|
||||
* @return sub resource
|
||||
*/
|
||||
@Path("user/{user}")
|
||||
public UserPermissionResource getUserSubResource(
|
||||
@PathParam("user") String user)
|
||||
public UserPermissionResource getUserSubResource(@PathParam("user") String user)
|
||||
{
|
||||
return new UserPermissionResource(system, user);
|
||||
}
|
||||
@@ -106,5 +102,5 @@ public class SecuritySystemResource
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
private SecuritySystem system;
|
||||
private final SecuritySystem system;
|
||||
}
|
||||
|
||||
@@ -42,8 +42,6 @@ import com.google.inject.Inject;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import sonia.scm.SCMContextProvider;
|
||||
import sonia.scm.ServletContainerDetector;
|
||||
import sonia.scm.Type;
|
||||
@@ -79,7 +77,6 @@ import sonia.scm.store.ConfigurationStoreFactory;
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Path("support")
|
||||
@ExternallyManagedLifecycle
|
||||
public class SupportResource
|
||||
{
|
||||
|
||||
|
||||
@@ -37,13 +37,14 @@ package sonia.scm.api.rest.resources;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
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.authc.credential.PasswordService;
|
||||
|
||||
import org.codehaus.enunciate.jaxrs.TypeHint;
|
||||
import org.codehaus.enunciate.modules.jersey.ExternallyManagedLifecycle;
|
||||
|
||||
import sonia.scm.security.Role;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserException;
|
||||
@@ -73,12 +74,12 @@ import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
/**
|
||||
*
|
||||
* RESTful Web Service Resource to manage users.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
@Path("users")
|
||||
@ExternallyManagedLifecycle
|
||||
public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
{
|
||||
|
||||
@@ -107,15 +108,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates a new user.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 create success</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Creates a new user. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param uriInfo current uri informations
|
||||
* @param user the user to be created
|
||||
@@ -123,6 +116,14 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
* @return
|
||||
*/
|
||||
@POST
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 201, condition = "create success", additionalHeaders = {
|
||||
@ResponseHeader(name = "Location", description = "uri to the created group")
|
||||
}),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Override
|
||||
public Response create(@Context UriInfo uriInfo, User user)
|
||||
@@ -131,15 +132,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a user.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 delete success</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Deletes a user. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param name the name of the user to delete.
|
||||
*
|
||||
@@ -147,6 +140,12 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
*/
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "delete success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Override
|
||||
public Response delete(@PathParam("id") String name)
|
||||
{
|
||||
@@ -154,15 +153,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the given user.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>201 update successful</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Modifies the given user. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param uriInfo current uri informations
|
||||
* @param name name of the user to be modified
|
||||
@@ -172,6 +163,12 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
*/
|
||||
@PUT
|
||||
@Path("{id}")
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 204, condition = "update success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@TypeHint(TypeHint.NO_CONTENT.class)
|
||||
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Override
|
||||
public Response update(@Context UriInfo uriInfo,
|
||||
@@ -183,16 +180,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a user.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>404 not found, no user with the specified id/name available</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns a user. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param request the current request
|
||||
* @param id the id/name of the user
|
||||
@@ -202,6 +190,12 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@TypeHint(User.class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 404, condition = "not found, no group with the specified id/name available"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Override
|
||||
public Response get(@Context Request request, @PathParam("id") String id)
|
||||
@@ -221,15 +215,7 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all users.<br />
|
||||
* This method requires admin privileges.<br />
|
||||
* <br />
|
||||
* Status codes:
|
||||
* <ul>
|
||||
* <li>200 get successful</li>
|
||||
* <li>403 forbidden, the current user has no admin privileges</li>
|
||||
* <li>500 internal server error</li>
|
||||
* </ul>
|
||||
* Returns all users. <strong>Note:</strong> This method requires admin privileges.
|
||||
*
|
||||
* @param request the current request
|
||||
* @param start the start value for paging
|
||||
@@ -241,6 +227,11 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
*/
|
||||
@GET
|
||||
@TypeHint(User[].class)
|
||||
@StatusCodes({
|
||||
@ResponseCode(code = 200, condition = "success"),
|
||||
@ResponseCode(code = 403, condition = "forbidden, the current user has no admin privileges"),
|
||||
@ResponseCode(code = 500, condition = "internal server error")
|
||||
})
|
||||
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
|
||||
@Override
|
||||
public Response getAll(@Context Request request, @DefaultValue("0")
|
||||
@@ -254,14 +245,6 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param items
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected GenericEntity<Collection<User>> createGenericEntity(
|
||||
Collection<User> items)
|
||||
@@ -270,24 +253,12 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
*/
|
||||
@Override
|
||||
protected void preCreate(User user)
|
||||
{
|
||||
encryptPassword(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected void preUpate(User user)
|
||||
{
|
||||
@@ -304,14 +275,6 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param users
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected Collection<User> prepareForReturn(Collection<User> users)
|
||||
{
|
||||
@@ -326,14 +289,6 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected User prepareForReturn(User user)
|
||||
{
|
||||
@@ -342,42 +297,18 @@ public class UserResource extends AbstractManagerResource<User, UserException>
|
||||
return user;
|
||||
}
|
||||
|
||||
//~--- get methods ----------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected String getId(User user)
|
||||
{
|
||||
return user.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected String getPathPart()
|
||||
{
|
||||
return PATH_PART;
|
||||
}
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param user
|
||||
*/
|
||||
private void encryptPassword(User user)
|
||||
{
|
||||
String password = user.getPassword();
|
||||
|
||||
@@ -63,8 +63,7 @@ public class GuavaCache<K, V>
|
||||
/**
|
||||
* the logger for GuavaCache
|
||||
*/
|
||||
private static final Logger logger =
|
||||
LoggerFactory.getLogger(GuavaCache.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(GuavaCache.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
@@ -89,8 +88,7 @@ public class GuavaCache<K, V>
|
||||
@SuppressWarnings("unchecked")
|
||||
public GuavaCache(GuavaCacheConfiguration configuration, String name)
|
||||
{
|
||||
this(GuavaCaches.create(configuration, name),
|
||||
configuration.getCopyStrategy(), name);
|
||||
this(GuavaCaches.create(configuration, name), configuration.getCopyStrategy(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +115,7 @@ public class GuavaCache<K, V>
|
||||
this.copyStrategy = CopyStrategy.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//~--- methods --------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,8 @@ import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* Guava based implementation of {@link CacheManager} and {@link org.apache.shiro.cache.CacheManager}.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
*/
|
||||
@Singleton
|
||||
@@ -57,7 +58,7 @@ public class GuavaCacheManager
|
||||
implements CacheManager, org.apache.shiro.cache.CacheManager
|
||||
{
|
||||
|
||||
/**
|
||||
/**
|
||||
* the logger for GuavaCacheManager
|
||||
*/
|
||||
private static final Logger logger =
|
||||
|
||||
@@ -104,15 +104,18 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
|
||||
* @param keyGenerator
|
||||
* @param repositoryDAO
|
||||
* @param handlerSet
|
||||
* @param repositoryMatcher
|
||||
*/
|
||||
@Inject
|
||||
public DefaultRepositoryManager(ScmConfiguration configuration,
|
||||
SCMContextProvider contextProvider, KeyGenerator keyGenerator,
|
||||
RepositoryDAO repositoryDAO, Set<RepositoryHandler> handlerSet)
|
||||
RepositoryDAO repositoryDAO, Set<RepositoryHandler> handlerSet,
|
||||
RepositoryMatcher repositoryMatcher)
|
||||
{
|
||||
this.configuration = configuration;
|
||||
this.keyGenerator = keyGenerator;
|
||||
this.repositoryDAO = repositoryDAO;
|
||||
this.repositoryMatcher = repositoryMatcher;
|
||||
|
||||
//J-
|
||||
ThreadFactory factory = new ThreadFactoryBuilder()
|
||||
@@ -558,7 +561,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
|
||||
|
||||
for (Repository r : repositories)
|
||||
{
|
||||
if (type.equals(r.getType()) && isNameMatching(r, uri))
|
||||
if (repositoryMatcher.matches(r, type, uri))
|
||||
{
|
||||
check.check(r);
|
||||
repository = r.clone();
|
||||
@@ -715,30 +718,6 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
* @param repository
|
||||
* @param path
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private boolean isNameMatching(Repository repository, String path)
|
||||
{
|
||||
boolean result = false;
|
||||
String name = repository.getName();
|
||||
|
||||
if (path.startsWith(name))
|
||||
{
|
||||
String sub = path.substring(name.length());
|
||||
|
||||
result = Util.isEmpty(sub) || sub.startsWith(HttpUtil.SEPARATOR_PATH);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//~--- fields ---------------------------------------------------------------
|
||||
|
||||
/** Field description */
|
||||
@@ -758,4 +737,7 @@ public class DefaultRepositoryManager extends AbstractRepositoryManager
|
||||
|
||||
/** Field description */
|
||||
private final Set<Type> types;
|
||||
|
||||
/** Field description */
|
||||
private RepositoryMatcher repositoryMatcher;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright (c) 2010, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package sonia.scm.repository;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.util.HttpUtil;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
/**
|
||||
* RepositoryMatcher is able to check if a repository matches the requested path.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.54
|
||||
*/
|
||||
public final class RepositoryMatcher {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RepositoryMatcher.class);
|
||||
|
||||
private static final RepositoryPathMatcher DEFAULT_PATH_MATCHER = new DefaultRepositoryPathMatcher();
|
||||
|
||||
private final Map<String, RepositoryPathMatcher> pathMatchers;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param pathMatchers injected set of {@link RepositoryPathMatcher}.
|
||||
*/
|
||||
@Inject
|
||||
public RepositoryMatcher(Set<RepositoryPathMatcher> pathMatchers) {
|
||||
this.pathMatchers = Maps.newHashMap();
|
||||
for ( RepositoryPathMatcher pathMatcher : pathMatchers ) {
|
||||
LOG.info("register custom repository path matcher for type {}", pathMatcher.getType());
|
||||
this.pathMatchers.put(pathMatcher.getType(), pathMatcher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} is the repository matches the type and the name matches the requested path.
|
||||
*
|
||||
* @param repository repository
|
||||
* @param type type of repository
|
||||
* @param path requested path without context and without type information
|
||||
*
|
||||
* @return {@code true} is the repository matches
|
||||
*/
|
||||
public boolean matches(Repository repository, String type, String path) {
|
||||
return type.equals(repository.getType()) && isPathMatching(repository, path);
|
||||
}
|
||||
|
||||
private boolean isPathMatching(Repository repository, String path) {
|
||||
return getPathMatcherForType(repository.getType()).isPathMatching(repository, path);
|
||||
}
|
||||
|
||||
private RepositoryPathMatcher getPathMatcherForType(String type) {
|
||||
RepositoryPathMatcher pathMatcher = pathMatchers.get(type);
|
||||
if (pathMatcher == null) {
|
||||
pathMatcher = DEFAULT_PATH_MATCHER;
|
||||
}
|
||||
return pathMatcher;
|
||||
}
|
||||
|
||||
private static class DefaultRepositoryPathMatcher implements RepositoryPathMatcher {
|
||||
|
||||
@Override
|
||||
public boolean isPathMatching(Repository repository, String path) {
|
||||
String name = repository.getName();
|
||||
|
||||
if (path.startsWith(name)) {
|
||||
String sub = path.substring(name.length());
|
||||
|
||||
return Util.isEmpty(sub) || sub.startsWith(HttpUtil.SEPARATOR_PATH);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "any";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
/**
|
||||
* Copyright (c) 2014, Sebastian Sdorra
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of SCM-Manager; nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* http://bitbucket.org/sdorra/scm-manager
|
||||
*
|
||||
*/
|
||||
package sonia.scm.security;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sonia.scm.EagerSingleton;
|
||||
import sonia.scm.ModificationHandlerEvent;
|
||||
import sonia.scm.event.HandlerEvent;
|
||||
import sonia.scm.event.ScmEventBus;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupEvent;
|
||||
import sonia.scm.group.GroupModificationEvent;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryEvent;
|
||||
import sonia.scm.repository.RepositoryModificationEvent;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserEvent;
|
||||
import sonia.scm.user.UserModificationEvent;
|
||||
|
||||
/**
|
||||
* Receives all kinds of events, which affects authorization relevant data and fires an
|
||||
* {@link AuthorizationChangedEvent} if authorization data has changed.
|
||||
*
|
||||
* @author Sebastian Sdorra
|
||||
* @since 1.52
|
||||
*/
|
||||
@EagerSingleton
|
||||
public class AuthorizationChangedEventProducer {
|
||||
|
||||
/**
|
||||
* the logger for AuthorizationChangedEventProducer
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthorizationChangedEventProducer.class);
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
*/
|
||||
public AuthorizationChangedEventProducer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the cache of a user which was modified. The cache entries for the user will be invalidated for the
|
||||
* following reasons:
|
||||
* <ul>
|
||||
* <li>Admin or Active flag was modified.</li>
|
||||
* <li>New user created, for the case of old cache values</li>
|
||||
* <li>User deleted</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param event user event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onEvent(UserEvent event) {
|
||||
if (event.getEventType().isPost()) {
|
||||
if (isModificationEvent(event)) {
|
||||
handleUserModificationEvent((UserModificationEvent) event);
|
||||
} else {
|
||||
handleUserEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isModificationEvent(HandlerEvent<?> event) {
|
||||
return event instanceof ModificationHandlerEvent;
|
||||
}
|
||||
|
||||
private void handleUserEvent(UserEvent event) {
|
||||
String username = event.getItem().getName();
|
||||
logger.debug(
|
||||
"fire authorization changed event for user {}, because of user {} event", username, event.getEventType()
|
||||
);
|
||||
fireEventForUser(username);
|
||||
}
|
||||
|
||||
private void handleUserModificationEvent(UserModificationEvent event) {
|
||||
String username = event.getItem().getId();
|
||||
User beforeModification = event.getItemBeforeModification();
|
||||
if (isAuthorizationDataModified(event.getItem(), beforeModification)) {
|
||||
logger.debug(
|
||||
"fire authorization changed event for user {}, because of a authorization relevant field has changed",
|
||||
username
|
||||
);
|
||||
fireEventForUser(username);
|
||||
} else {
|
||||
logger.debug(
|
||||
"authorization changed event for user {} is not fired, because no authorization relevant field has changed",
|
||||
username
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthorizationDataModified(User user, User beforeModification) {
|
||||
return user.isAdmin() != beforeModification.isAdmin() || user.isActive() != beforeModification.isActive();
|
||||
}
|
||||
|
||||
private void fireEventForUser(String username) {
|
||||
sendEvent(AuthorizationChangedEvent.createForUser(username));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the whole cache, if a repository has changed. The cache get cleared for one of the following reasons:
|
||||
* <ul>
|
||||
* <li>New repository created</li>
|
||||
* <li>Repository was removed</li>
|
||||
* <li>Archived, Public readable or permission field of the repository was modified</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param event repository event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onEvent(RepositoryEvent event) {
|
||||
if (event.getEventType().isPost()) {
|
||||
if (isModificationEvent(event)) {
|
||||
handleRepositoryModificationEvent((RepositoryModificationEvent) event);
|
||||
} else {
|
||||
handleRepositoryEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRepositoryModificationEvent(RepositoryModificationEvent event) {
|
||||
Repository repository = event.getItem();
|
||||
if (isAuthorizationDataModified(repository, event.getItemBeforeModification())) {
|
||||
logger.debug(
|
||||
"fire authorization changed event, because a relevant field of repository {} has changed", repository.getName()
|
||||
);
|
||||
fireEventForEveryUser();
|
||||
} else {
|
||||
logger.debug(
|
||||
"authorization changed event is not fired, because non relevant field of repository {} has changed",
|
||||
repository.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthorizationDataModified(Repository repository, Repository beforeModification) {
|
||||
return repository.isArchived() != beforeModification.isArchived()
|
||||
|| repository.isPublicReadable() != beforeModification.isPublicReadable()
|
||||
|| ! repository.getPermissions().equals(beforeModification.getPermissions());
|
||||
}
|
||||
|
||||
private void fireEventForEveryUser() {
|
||||
sendEvent(AuthorizationChangedEvent.createForEveryUser());
|
||||
}
|
||||
|
||||
private void handleRepositoryEvent(RepositoryEvent event){
|
||||
logger.debug(
|
||||
"fire authorization changed event, because of received {} event for repository {}",
|
||||
event.getEventType(), event.getItem().getName()
|
||||
);
|
||||
fireEventForEveryUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the whole cache if a group permission has changed and invalidates the cached entries of a user, if a
|
||||
* user permission has changed.
|
||||
*
|
||||
* @param event permission event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onEvent(StoredAssignedPermissionEvent event) {
|
||||
if (event.getEventType().isPost()) {
|
||||
StoredAssignedPermission permission = event.getPermission();
|
||||
if (permission.isGroupPermission()) {
|
||||
handleGroupPermissionChange(permission);
|
||||
} else {
|
||||
handleUserPermissionChange(permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleGroupPermissionChange(StoredAssignedPermission permission) {
|
||||
logger.debug(
|
||||
"fire authorization changed event, because global group permission {} has changed",
|
||||
permission.getId()
|
||||
);
|
||||
fireEventForEveryUser();
|
||||
}
|
||||
|
||||
private void handleUserPermissionChange(StoredAssignedPermission permission) {
|
||||
logger.debug(
|
||||
"fire authorization changed event for user {}, because permission {} has changed",
|
||||
permission.getName(), permission.getId()
|
||||
);
|
||||
fireEventForUser(permission.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the whole cache, if a group has changed. The cache get cleared for one of the following reasons:
|
||||
* <ul>
|
||||
* <li>New group created</li>
|
||||
* <li>Group was removed</li>
|
||||
* <li>Group members was modified</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param event group event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onEvent(GroupEvent event) {
|
||||
if (event.getEventType().isPost()) {
|
||||
if (isModificationEvent(event)) {
|
||||
handleGroupModificationEvent((GroupModificationEvent) event);
|
||||
} else {
|
||||
handleGroupEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleGroupModificationEvent(GroupModificationEvent event) {
|
||||
Group group = event.getItem();
|
||||
if (isAuthorizationDataModified(group, event.getItemBeforeModification())) {
|
||||
logger.debug("fire authorization changed event, because group {} has changed", group.getId());
|
||||
fireEventForEveryUser();
|
||||
} else {
|
||||
logger.debug(
|
||||
"authorization changed event is not fired, because non relevant field of group {} has changed",
|
||||
group.getId()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthorizationDataModified(Group group, Group beforeModification) {
|
||||
return !group.getMembers().equals(beforeModification.getMembers());
|
||||
}
|
||||
|
||||
private void handleGroupEvent(GroupEvent event){
|
||||
logger.debug(
|
||||
"fire authorization changed event, because of received group event {} for group {}",
|
||||
event.getEventType(),
|
||||
event.getItem().getId()
|
||||
);
|
||||
fireEventForEveryUser();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void sendEvent(AuthorizationChangedEvent event) {
|
||||
ScmEventBus.getInstance().post(event);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -55,24 +55,17 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import sonia.scm.cache.Cache;
|
||||
import sonia.scm.cache.CacheManager;
|
||||
import sonia.scm.group.GroupEvent;
|
||||
import sonia.scm.group.GroupNames;
|
||||
import sonia.scm.plugin.Extension;
|
||||
import sonia.scm.repository.Repository;
|
||||
import sonia.scm.repository.RepositoryDAO;
|
||||
import sonia.scm.repository.RepositoryEvent;
|
||||
import sonia.scm.user.User;
|
||||
import sonia.scm.user.UserEvent;
|
||||
import sonia.scm.util.Util;
|
||||
|
||||
//~--- JDK imports ------------------------------------------------------------
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import sonia.scm.group.Group;
|
||||
import sonia.scm.group.GroupModificationEvent;
|
||||
import sonia.scm.repository.RepositoryModificationEvent;
|
||||
import sonia.scm.user.UserModificationEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -99,7 +92,7 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
|
||||
LoggerFactory.getLogger(DefaultAuthorizationCollector.class);
|
||||
|
||||
//~--- constructors ---------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Constructs ...
|
||||
*
|
||||
@@ -144,187 +137,14 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
|
||||
return authorizationInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the cache of a user which was modified. The cache entries for the user will be invalidated for the
|
||||
* following reasons:
|
||||
* <ul>
|
||||
* <li>Admin or Active flag was modified.</li>
|
||||
* <li>New user created, for the case of old cache values</li>
|
||||
* <li>User deleted</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param event user event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onEvent(UserEvent event)
|
||||
{
|
||||
if (event.getEventType().isPost())
|
||||
{
|
||||
User user = event.getItem();
|
||||
String username = user.getId();
|
||||
if (event instanceof UserModificationEvent)
|
||||
{
|
||||
User beforeModification = ((UserModificationEvent) event).getItemBeforeModification();
|
||||
if (shouldCacheBeCleared(user, beforeModification))
|
||||
{
|
||||
logger.debug("invalidate cache of user {}, because of a permission relevant field has changed", username);
|
||||
invalidateUserCache(username);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("cache of user {} is not invalidated, because no permission relevant field has changed", username);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("invalidate cache of user {}, because of user {} event", username, event.getEventType());
|
||||
invalidateUserCache(username);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldCacheBeCleared(User user, User beforeModification)
|
||||
{
|
||||
return user.isAdmin() != beforeModification.isAdmin() || user.isActive() != beforeModification.isActive();
|
||||
}
|
||||
|
||||
private void invalidateUserCache(final String username)
|
||||
{
|
||||
cache.removeAll((CacheKey item) -> username.equalsIgnoreCase(item.username));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the whole cache, if a repository has changed. The cache get cleared for one of the following reasons:
|
||||
* <ul>
|
||||
* <li>New repository created</li>
|
||||
* <li>Repository was removed</li>
|
||||
* <li>Archived, Public readable or permission field of the repository was modified</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param event repository event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onEvent(RepositoryEvent event)
|
||||
{
|
||||
if (event.getEventType().isPost())
|
||||
{
|
||||
Repository repository = event.getItem();
|
||||
|
||||
if (event instanceof RepositoryModificationEvent)
|
||||
{
|
||||
Repository beforeModification = ((RepositoryModificationEvent) event).getItemBeforeModification();
|
||||
if (shouldCacheBeCleared(repository, beforeModification))
|
||||
{
|
||||
logger.debug("clear cache, because a relevant field of repository {} has changed", repository.getName());
|
||||
cache.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug(
|
||||
"cache is not invalidated, because non relevant field of repository {} has changed",
|
||||
repository.getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("clear cache, received {} event of repository {}", event.getEventType(), repository.getName());
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldCacheBeCleared(Repository repository, Repository beforeModification)
|
||||
{
|
||||
return repository.isArchived() != beforeModification.isArchived()
|
||||
|| repository.isPublicReadable() != beforeModification.isPublicReadable()
|
||||
|| ! repository.getPermissions().equals(beforeModification.getPermissions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the whole cache if a group permission has changed and invalidates the cached entries of a user, if a
|
||||
* user permission has changed.
|
||||
*
|
||||
*
|
||||
* @param event permission event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onEvent(StoredAssignedPermissionEvent event)
|
||||
{
|
||||
if (event.getEventType().isPost())
|
||||
{
|
||||
StoredAssignedPermission permission = event.getPermission();
|
||||
if (permission.isGroupPermission())
|
||||
{
|
||||
logger.debug("clear cache, because global group permission {} has changed", permission.getId());
|
||||
cache.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug(
|
||||
"clear cache of user {}, because permission {} has changed",
|
||||
permission.getName(), event.getPermission().getId()
|
||||
);
|
||||
invalidateUserCache(permission.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates the whole cache, if a group has changed. The cache get cleared for one of the following reasons:
|
||||
* <ul>
|
||||
* <li>New group created</li>
|
||||
* <li>Group was removed</li>
|
||||
* <li>Group members was modified</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param event group event
|
||||
*/
|
||||
@Subscribe
|
||||
public void onEvent(GroupEvent event)
|
||||
{
|
||||
if (event.getEventType().isPost())
|
||||
{
|
||||
Group group = event.getItem();
|
||||
if (event instanceof GroupModificationEvent)
|
||||
{
|
||||
Group beforeModification = ((GroupModificationEvent) event).getItemBeforeModification();
|
||||
if (shouldCacheBeCleared(group, beforeModification))
|
||||
{
|
||||
logger.debug("clear cache, because group {} has changed", group.getId());
|
||||
cache.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug(
|
||||
"cache is not invalidated, because non relevant field of group {} has changed",
|
||||
group.getId()
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.debug("clear cache, received group event {} for group {}", event.getEventType(), group.getId());
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldCacheBeCleared(Group group, Group beforeModification)
|
||||
{
|
||||
return !group.getMembers().equals(beforeModification.getMembers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method description
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param principals
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
AuthorizationInfo collect(PrincipalCollection principals)
|
||||
public AuthorizationInfo collect(PrincipalCollection principals)
|
||||
{
|
||||
Preconditions.checkNotNull(principals, "principals parameter is required");
|
||||
|
||||
@@ -456,6 +276,25 @@ public class DefaultAuthorizationCollector implements AuthorizationCollector
|
||||
|| ((!perm.isGroupPermission()) && user.getName().equals(perm.getName()));
|
||||
//J+
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void invalidateCache(AuthorizationChangedEvent event) {
|
||||
if (event.isEveryUserAffected()) {
|
||||
invalidateUserCache(event.getNameOfAffectedUser());
|
||||
} else {
|
||||
invalidateCache();
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidateUserCache(final String username) {
|
||||
logger.info("invalidate cache for user {}, because of a received authorization event", username);
|
||||
cache.removeAll((CacheKey item) -> username.equalsIgnoreCase(item.username));
|
||||
}
|
||||
|
||||
private void invalidateCache() {
|
||||
logger.info("invalidate cache, because of a received authorization event");
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
//~--- inner classes --------------------------------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user