From 9ff0d1863c71368818013f718acf2f8dc1cd3c9c Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Wed, 10 May 2017 08:56:43 +0200 Subject: [PATCH] improve rest api documentation of Repository, RepositoryImport, Search, SecuritySystem and User resource --- .../resources/AbstractPermissionResource.java | 83 +++-- .../api/rest/resources/PluginResource.java | 1 + .../resources/RepositoryImportResource.java | 152 +++++----- .../rest/resources/RepositoryResource.java | 287 ++++++++---------- .../api/rest/resources/SearchResource.java | 32 +- .../resources/SecuritySystemResource.java | 24 +- .../scm/api/rest/resources/UserResource.java | 153 +++------- 7 files changed, 322 insertions(+), 410 deletions(-) diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java index 29384ba020..e9e63d16d8 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AbstractPermissionResource.java @@ -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.
- *
- * Status codes: - * + * 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.
- *
- * Status codes: - * + * 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.
- *
- * Status codes: - * + * 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.
- *
- * Status codes: - * - * + * 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.
- *
- * Status codes: - * + * 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 getAll() { diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java index 0fd7518795..54c9369a57 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/PluginResource.java @@ -111,6 +111,7 @@ public class PluginResource * Installs a plugin from a package. * * @param uploadedInputStream + * * @return * * @throws IOException diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java index 4232ecda9d..9382f58c5c 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryImportResource.java @@ -71,6 +71,9 @@ 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; @@ -139,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.
- * - * Status codes: - * + * bundle file is passed to the {@link UnbundleCommandBuilder}. Note: This method + * requires admin privileges. * * @param uriInfo uri info * @param type repository type @@ -157,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, @@ -179,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.
- * - * Status codes: - * - * + * workaround of the javascript ui extjs. Note: This method requires admin + * privileges. * * @param type repository type * @param name name of the repository @@ -203,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, @@ -231,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.
- * - * Status codes: - * + * repository. Note: This method requires admin privileges. * * @param uriInfo uri info * @param type repository type @@ -252,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) @@ -295,15 +303,7 @@ public class RepositoryImportResource /** * Imports repositories of the given type from the configured repository - * directory. This method requires admin privileges.
- *
- * Status codes: - * + * directory. Note: This method requires admin privileges. * * @param type repository type * @@ -311,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) @@ -330,19 +338,19 @@ public class RepositoryImportResource /** * Imports repositories of all supported types from the configured repository - * directories. This method requires admin privileges.
- *
- * Status codes: - * + * directories. Note: 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() @@ -368,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.
- *
- * Status codes: - * + * of failed directories. Note: This method requires admin privileges. * * @param type repository type * @@ -385,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( @@ -453,22 +461,20 @@ public class RepositoryImportResource /** * Returns a list of repository types, which support the directory import - * feature. - * - * This method requires admin privileges.
- *
- * Status codes: - * + * feature. Note: 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() { diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java index be0a2ec603..16168aefc7 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/RepositoryResource.java @@ -39,6 +39,9 @@ import com.google.common.base.Strings; import com.google.common.io.Closeables; 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; @@ -104,13 +107,13 @@ import javax.ws.rs.core.StreamingOutput; import javax.ws.rs.core.UriInfo; /** - * + * Repository related RESTful Web Service Endpoint. + * * @author Sebastian Sdorra */ @Singleton @Path("repositories") -public class RepositoryResource - extends AbstractManagerResource +public class RepositoryResource extends AbstractManagerResource { /** Field description */ @@ -147,22 +150,22 @@ public class RepositoryResource //~--- methods -------------------------------------------------------------- /** - * Creates a new repository.
- * This method requires admin privileges.
- *
- * Status codes: - *
    - *
  • 201 create success
  • - *
  • 403 forbidden, the current user has no admin privileges
  • - *
  • 500 internal server error
  • - *
+ * Creates a new repository.Note: 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 +174,7 @@ public class RepositoryResource } /** - * Deletes a repository.
- * This method requires owner privileges.
- *
- * Status codes: - *
    - *
  • 201 delete success
  • - *
  • 403 forbidden, the current user has no owner privileges
  • - *
  • - * 412 forbidden, the repository is not archived, - * this error occurs only with enabled repository archive. - *
  • - *
  • 500 internal server error
  • - *
+ * Deletes a repository. Note: This method requires owner privileges. * * @param id the id of the repository to delete. * @@ -191,6 +182,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 +234,20 @@ public class RepositoryResource } /** - * Re run repository health checks.
- * Status codes: - *
    - *
  • 201 re run success
  • - *
  • 403 forbidden, the current user has no owner privileges
  • - *
  • 404 could not find repository
  • - *
  • 500 internal server error
  • - *
+ * 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 +256,7 @@ public class RepositoryResource try { healthChecker.check(id); + // TODO should return 204 instead of 200 response = Response.ok().build(); } catch (RepositoryNotFoundException ex) @@ -276,15 +279,7 @@ public class RepositoryResource } /** - * Modifies the given repository.
- * This method requires owner privileges.
- *
- * Status codes: - *
    - *
  • 201 update successful
  • - *
  • 403 forbidden, the current user has no owner privileges
  • - *
  • 500 internal server error
  • - *
+ * Modifies the given repository. Note: This method requires owner privileges. * * @param uriInfo current uri informations * @param id id of the repository to be modified @@ -294,10 +289,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); } @@ -305,14 +306,7 @@ public class RepositoryResource //~--- get methods ---------------------------------------------------------- /** - * Returns the {@link Repository} with the specified id.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 404 not found, no repository with the specified id available
  • - *
  • 500 internal server error
  • - *
+ * Returns the {@link Repository} with the specified id. * * @param request the current request * @param id the id/name of the user @@ -322,6 +316,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) @@ -330,13 +329,7 @@ public class RepositoryResource } /** - * Returns all repositories.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 500 internal server error
  • - *
+ * Returns all repositories. * * @param request the current request * @param start the start value for paging @@ -348,6 +341,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") @@ -360,16 +357,7 @@ public class RepositoryResource } /** - * Returns a annotate/blame view for the given path.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 400 bad request, the blame feature is not - * supported by this type of repositories.
  • - *
  • 404 not found, if the repository or the path could not be found
  • - *
  • 500 internal server error
  • - *
+ * Returns a annotate/blame view for the given path. * * @param id the id of the repository * @param revision the revision of the file @@ -382,6 +370,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, @@ -435,16 +429,7 @@ public class RepositoryResource } /** - * Returns all {@link Branches} of a repository.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 400 bad request, the content feature is not - * supported by this type of repositories.
  • - *
  • 404 not found, if the repository or the path could not be found
  • - *
  • 500 internal server error
  • - *
+ * Returns all {@link Branches} of a repository. * * @param id the id of the repository * @@ -457,6 +442,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 { @@ -495,16 +488,7 @@ public class RepositoryResource } /** - * Returns a list of folders and files for the given folder.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 400 bad request, the browse feature is not - * supported by this type of repositories.
  • - *
  • 404 not found, if the repository or the path could not be found
  • - *
  • 500 internal server error
  • - *
+ * 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 @@ -520,6 +504,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- @@ -586,15 +576,7 @@ public class RepositoryResource } /** - * Returns the {@link Repository} with the specified type and name.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 404 not found, - * no repository with the specified type and name available
  • - *
  • 500 internal server error
  • - *
+ * Returns the {@link Repository} with the specified type and name. * * @param type the type of the repository * @param name the name of the repository @@ -603,8 +585,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) { @@ -626,17 +613,7 @@ public class RepositoryResource /** * Returns the {@link Changeset} from the given repository - * with the specified revision.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 400 bad request, the changeset feature is not - * supported by this type of repositories.
  • - *
  • 404 not found, if the repository or - * the revision could not be found
  • - *
  • 500 internal server error
  • - *
+ * with the specified revision. * * @param id the id of the repository * @param revision the revision of the changeset @@ -648,6 +625,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 @@ -700,16 +685,7 @@ public class RepositoryResource } /** - * Returns a list of {@link Changeset} for the given repository.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 400 bad request, the changeset feature is not - * supported by this type of repositories.
  • - *
  • 404 not found, if the repository or the path could not be found
  • - *
  • 500 internal server error
  • - *
+ * Returns a list of {@link Changeset} for the given repository. * * @param id the id of the repository * @param path path of a file @@ -725,6 +701,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- @@ -793,16 +775,7 @@ public class RepositoryResource } /** - * Returns the content of a file.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 400 bad request, the content feature is not - * supported by this type of repositories.
  • - *
  • 404 not found, if the repository or the path could not be found
  • - *
  • 500 internal server error
  • - *
+ * Returns the content of a file. * * @param id the id of the repository * @param revision the revision of the file @@ -812,14 +785,20 @@ 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, @QueryParam("revision") String revision, @QueryParam("path") String path) { - Response response = null; - StreamingOutput output = null; - RepositoryService service = null; + Response response; + StreamingOutput output; + RepositoryService service; try { @@ -864,16 +843,7 @@ public class RepositoryResource } /** - * Returns the modifications of a {@link Changeset}.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 400 bad request, the content feature is not - * supported by this type of repositories.
  • - *
  • 404 not found, if the repository or the path could not be found
  • - *
  • 500 internal server error
  • - *
+ * Returns the modifications of a {@link Changeset}. * * @param id the id of the repository * @param revision the revision of the file @@ -887,6 +857,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, @@ -903,8 +879,8 @@ public class RepositoryResource */ HttpUtil.checkForCRLFInjection(revision); - RepositoryService service = null; - Response response = null; + RepositoryService service; + Response response; try { @@ -952,16 +928,7 @@ public class RepositoryResource } /** - * Returns all {@link Tags} of a repository.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 400 bad request, the content feature is not - * supported by this type of repositories.
  • - *
  • 404 not found, if the repository or the path could not be found
  • - *
  • 500 internal server error
  • - *
+ * Returns all {@link Tags} of a repository. * * @param id the id of the repository * @@ -974,6 +941,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 { diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SearchResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SearchResource.java index 3b4606682a..3c7c9b8785 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SearchResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SearchResource.java @@ -38,6 +38,8 @@ package sonia.scm.api.rest.resources; import com.google.common.base.Function; import com.google.inject.Inject; import com.google.inject.Singleton; +import com.webcohesion.enunciate.metadata.rs.ResponseCode; +import com.webcohesion.enunciate.metadata.rs.StatusCodes; import sonia.scm.HandlerEvent; import sonia.scm.cache.Cache; @@ -61,7 +63,9 @@ 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 @@ -138,12 +142,7 @@ public class SearchResource implements UserListener, GroupListener } /** - * Returns a list of groups found by the given search string.
- *
- *
    - *
  • 200 success
  • - *
  • 500 internal server error
  • - *
+ * Returns a list of groups found by the given search string. * * @param queryString the search string * @@ -151,6 +150,10 @@ public class SearchResource implements UserListener, GroupListener */ @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) { @@ -174,12 +177,7 @@ public class SearchResource implements UserListener, GroupListener } /** - * Returns a list of users found by the given search string.
- *
- *
    - *
  • 200 success
  • - *
  • 500 internal server error
  • - *
+ * Returns a list of users found by the given search string. * * @param queryString the search string * @@ -187,6 +185,10 @@ public class SearchResource implements UserListener, GroupListener */ @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) { @@ -208,8 +210,8 @@ public class SearchResource implements UserListener, GroupListener //~--- fields --------------------------------------------------------------- /** Field description */ - private SearchHandler groupSearchHandler; + private final SearchHandler groupSearchHandler; /** Field description */ - private SearchHandler userSearchHandler; + private final SearchHandler userSearchHandler; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SecuritySystemResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SecuritySystemResource.java index d97b21110b..f9e95232db 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SecuritySystemResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/SecuritySystemResource.java @@ -47,7 +47,8 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; /** - * + * Resource for managing system security permissions. + * * @author Sebastian Sdorra */ @Path("security/permission") @@ -72,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); } @@ -104,5 +102,5 @@ public class SecuritySystemResource //~--- fields --------------------------------------------------------------- /** Field description */ - private SecuritySystem system; + private final SecuritySystem system; } diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserResource.java index e76d185ed2..ed384071b1 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/UserResource.java @@ -37,6 +37,9 @@ 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; @@ -71,7 +74,8 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; /** - * + * RESTful Web Service Resource to manage users. + * * @author Sebastian Sdorra */ @Singleton @@ -96,8 +100,7 @@ public class UserResource extends AbstractManagerResource * @param securityContextProvider */ @Inject - public UserResource(UserManager userManager, - EncryptionHandler encryptionHandler) + public UserResource(UserManager userManager, EncryptionHandler encryptionHandler) { super(userManager); this.encryptionHandler = encryptionHandler; @@ -106,15 +109,7 @@ public class UserResource extends AbstractManagerResource //~--- methods -------------------------------------------------------------- /** - * Creates a new user.
- * This method requires admin privileges.
- *
- * Status codes: - *
    - *
  • 201 create success
  • - *
  • 403 forbidden, the current user has no admin privileges
  • - *
  • 500 internal server error
  • - *
+ * Creates a new user. Note: This method requires admin privileges. * * @param uriInfo current uri informations * @param user the user to be created @@ -122,6 +117,14 @@ public class UserResource extends AbstractManagerResource * @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) @@ -130,15 +133,7 @@ public class UserResource extends AbstractManagerResource } /** - * Deletes a user.
- * This method requires admin privileges.
- *
- * Status codes: - *
    - *
  • 201 delete success
  • - *
  • 403 forbidden, the current user has no admin privileges
  • - *
  • 500 internal server error
  • - *
+ * Deletes a user. Note: This method requires admin privileges. * * @param name the name of the user to delete. * @@ -146,6 +141,12 @@ public class UserResource extends AbstractManagerResource */ @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) { @@ -153,15 +154,7 @@ public class UserResource extends AbstractManagerResource } /** - * Modifies the given user.
- * This method requires admin privileges.
- *
- * Status codes: - *
    - *
  • 201 update successful
  • - *
  • 403 forbidden, the current user has no admin privileges
  • - *
  • 500 internal server error
  • - *
+ * Modifies the given user. Note: This method requires admin privileges. * * @param uriInfo current uri informations * @param name name of the user to be modified @@ -171,6 +164,12 @@ public class UserResource extends AbstractManagerResource */ @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, @@ -182,16 +181,7 @@ public class UserResource extends AbstractManagerResource //~--- get methods ---------------------------------------------------------- /** - * Returns a user.
- * This method requires admin privileges.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 403 forbidden, the current user has no admin privileges
  • - *
  • 404 not found, no user with the specified id/name available
  • - *
  • 500 internal server error
  • - *
+ * Returns a user. Note: This method requires admin privileges. * * @param request the current request * @param id the id/name of the user @@ -201,6 +191,12 @@ public class UserResource extends AbstractManagerResource @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) @@ -220,15 +216,7 @@ public class UserResource extends AbstractManagerResource } /** - * Returns all users.
- * This method requires admin privileges.
- *
- * Status codes: - *
    - *
  • 200 get successful
  • - *
  • 403 forbidden, the current user has no admin privileges
  • - *
  • 500 internal server error
  • - *
+ * Returns all users. Note: This method requires admin privileges. * * @param request the current request * @param start the start value for paging @@ -240,6 +228,11 @@ public class UserResource extends AbstractManagerResource */ @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") @@ -253,14 +246,6 @@ public class UserResource extends AbstractManagerResource //~--- methods -------------------------------------------------------------- - /** - * Method description - * - * - * @param items - * - * @return - */ @Override protected GenericEntity> createGenericEntity( Collection items) @@ -269,24 +254,12 @@ public class UserResource extends AbstractManagerResource ; } - /** - * Method description - * - * - * @param user - */ @Override protected void preCreate(User user) { encryptPassword(user); } - - /** - * Method description - * - * - * @param user - */ + @Override protected void preUpate(User user) { @@ -303,14 +276,6 @@ public class UserResource extends AbstractManagerResource } } - /** - * Method description - * - * - * @param users - * - * @return - */ @Override protected Collection prepareForReturn(Collection users) { @@ -325,14 +290,6 @@ public class UserResource extends AbstractManagerResource return users; } - /** - * Method description - * - * - * @param user - * - * @return - */ @Override protected User prepareForReturn(User user) { @@ -341,42 +298,18 @@ public class UserResource extends AbstractManagerResource 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();