ProjectService extends Service { @ApiOperation(value = "Import resource", notes = "Import resource. JSON with a designated importer and project location is sent. It is possible to import from " + "VCS or ZIP", response = ImportResponse.class) @ApiResponses(value = { @ApiResponse(code = 200, message = ""), @ApiResponse(code = 401, message = "User not authorized to call this operation"), @ApiResponse(code = 403, message = "Forbidden operation"), @ApiResponse(code = 409, message = "Resource already exists"), @ApiResponse(code = 500, message = "Unsupported source type")}) @POST @Path("/import/{path:.*}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public ImportResponse importProject(@ApiParam(value = "Workspace ID", required = true) @PathParam("ws-id") String workspace, @ApiParam(value = "Path in the project", required = true) @PathParam("path") String path, @ApiParam(value = "Force rewrite existing project", allowableValues = "true,false") @QueryParam("force") boolean force, ImportProject importProject) throws ConflictException, ForbiddenException, UnauthorizedException, IOException, ServerException, NotFoundException, BadRequestException { requiredNotNull(workspace, "Workspace id"); requiredNotNull(path, "Project path"); requiredNotNull(importProject, "Project descriptor"); final ImportSourceDescriptor projectSource = importProject.getSource().getProject(); final ProjectImporter importer = importers.getImporter(projectSource.getType()); if (importer == null) { throw new ServerException(String.format("Unable import sources project from '%s'. Sources type '%s' is not supported.", projectSource.getLocation(), projectSource.getType())); } final LineConsumerFactory outputOutputConsumerFactory = () -> new ProjectImportOutputWSLineConsumer(path, workspace, 300); long creationDate = System.currentTimeMillis(); boolean folderExistedBeforeCommand = virtualEntryExists(workspace, path); VirtualFileEntry virtualFile = getVirtualFile(workspace, path, force); FolderEntry baseProjectFolder = null; try { baseProjectFolder = (FolderEntry)virtualFile; importer.importSources(baseProjectFolder, projectSource.getLocation(), projectSource.getParameters(), outputOutputConsumerFactory); return configureProject(importProject, baseProjectFolder, workspace, creationDate); } catch (Exception e) { handleImportException(e, folderExistedBeforeCommand, baseProjectFolder ); throw e; } }  @ApiOperation(value = "Get list of projects in root folder", response = ProjectReference.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 500, message = "Server error")}) @GenerateLink(rel = Constants.LINK_REL_GET_PROJECTS) @GET @Produces(MediaType.APPLICATION_JSON) List<ProjectReference> getProjects(@ApiParam("ID of workspace to get projects") @PathParam("ws-id") String workspace); @ApiOperation(value = "Get project by ID of workspace and project's path", response = ProjectDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 404, message = "Project with specified path doesn't exist in workspace"), @ApiResponse(code = 403, message = "Access to requested project is forbidden"), @ApiResponse(code = 500, message = "Server error")}) @GET @Path("/{path:.*}") @Produces(MediaType.APPLICATION_JSON) ProjectDescriptor getProject(@ApiParam(value = "ID of workspace to get projects", required = true)
                                        @PathParam("ws-id") String workspace,
                                        @ApiParam(value = "Path to requested project", required = true)
                                        @PathParam("path") String path); @ApiOperation(value = "Creates a new project", response = ProjectDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "Operation is forbidden"), @ApiResponse(code = 409, message = "Project with specified name already exist in workspace"), @ApiResponse(code = 500, message = "Server error")}) @POST @GenerateLink(rel = Constants.LINK_REL_CREATE_PROJECT) @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) ProjectDescriptor createProject(@ApiParam(value = "ID of workspace to create project", required = true)
                                           @PathParam("ws-id") String workspace,
                                           @ApiParam(value = "Name for new project", required = true)
                                           @Required
                                           @Description("project name")
                                           @QueryParam("name") String name,
                                           @ApiParam(value = "New project", required = true)
                                           @Description("descriptor of project") NewProject newProject); @ApiOperation(value = "Get project modules", notes = "Get project modules. Roles allowed: system/admin, system/manager.", response = ProjectDescriptor.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/modules/{path:.*}") @Produces(MediaType.APPLICATION_JSON) List<ProjectDescriptor> getModules(@ApiParam(value = "Workspace ID", required = true)
                                              @PathParam("ws-id") String workspace,
                                              @ApiParam(value = "Path to a project", required = true)
                                              @PathParam("path") String path); @ApiOperation(value = "Create a new module", notes = "Create a new module in a specified project", response = ProjectDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "Module already exists"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Path("/{path:.*}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) ProjectDescriptor createModule(@ApiParam(value = "Workspace ID", required = true)
                                          @PathParam("ws-id") String workspace,
                                          @ApiParam(value = "Path to a target directory", required = true)
                                          @PathParam("path") String parentPath,
                                          @ApiParam(value = "New module name", required = true)
                                          @QueryParam("path") String path,
                                          NewProject newProject); @ApiOperation(value = "Updates existing project", response = ProjectDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 404, message = "Project with specified path doesn't exist in workspace"), @ApiResponse(code = 403, message = "Operation is forbidden"), @ApiResponse(code = 409, message = "Update operation causes conflicts"), @ApiResponse(code = 500, message = "Server error")}) @PUT @Path("/{path:.*}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) ProjectDescriptor updateProject(@ApiParam(value = "ID of workspace", required = true)
                                           @PathParam("ws-id") String workspace,
                                           @ApiParam(value = "Path to updated project", required = true)
                                           @PathParam("path") String path,
                                           ProjectUpdate update); @ApiOperation(value = "Make sure the folder is supposed to be project of a certain type", response = Map.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 404, message = "Project with specified path doesn't exist in workspace"), @ApiResponse(code = 403, message = "Access to requested project is forbidden"), @ApiResponse(code = 500, message = "Server error")}) @GET @Path("/estimate/{path:.*}") @Produces(MediaType.APPLICATION_JSON) Map<String, List<String>> estimateProject(@ApiParam(value = "ID of workspace to estimate projects", required = true)
                                                     @PathParam("ws-id") String workspace,
                                                     @ApiParam(value = "Path to requested project", required = true)
                                                     @PathParam("path") String path,
                                                     @ApiParam(value = "Project Type ID to estimate against", required = true)
                                                     @QueryParam("type") String projectType); @GET @Path("/resolve/{path:.*}") @Produces(MediaType.APPLICATION_JSON) List<SourceEstimation> resolveSources(@ApiParam(value = "ID of workspace to estimate projects", required = true)
                                                 @PathParam("ws-id") String workspace,
                                                 @ApiParam(value = "Path to requested project", required = true)
                                                 @PathParam("path") String path); @ApiOperation(value = "Create file", notes = "Create a new file in a project. If file type isn't specified the server will resolve its type") @ApiResponses(value = { @ApiResponse(code = 201, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "File already exists"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Consumes({MediaType.MEDIA_TYPE_WILDCARD}) @Produces({MediaType.APPLICATION_JSON}) @Path("/file/{parent:.*}") Response createFile(@ApiParam(value = "Workspace ID", required = true)
                               @PathParam("ws-id") String workspace,
                               @ApiParam(value = "Path to a target directory", required = true)
                               @PathParam("parent") String parentPath,
                               @ApiParam(value = "New file name", required = true)
                               @QueryParam("name") String fileName,
                               @ApiParam(value = "New file content type")
                               @HeaderParam("content-type") MediaType contentType,
                               InputStream content); @ApiOperation(value = "Create a folder", notes = "Create a folder is a specified project") @ApiResponses(value = { @ApiResponse(code = 201, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "File already exists"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Produces({MediaType.APPLICATION_JSON}) @Path("/folder/{path:.*}") Response createFolder(@ApiParam(value = "Workspace ID", required = true)
                                 @PathParam("ws-id") String workspace,
                                 @ApiParam(value = "Path to a new folder destination", required = true)
                                 @PathParam("path") String path); @ApiOperation(value = "Upload a file", notes = "Upload a new file") @ApiResponses(value = { @ApiResponse(code = 201, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "File already exists"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Consumes({MediaType.MULTIPART_FORM_DATA}) @Produces({MediaType.TEXT_HTML}) @Path("/uploadfile/{parent:.*}") Response uploadFile(@ApiParam(value = "Workspace ID", required = true)
                               @PathParam("ws-id") String workspace,
                               @ApiParam(value = "Destination path", required = true)
                               @PathParam("parent") String parentPath,
                               Iterator<FileItem> formData); @ApiOperation(value = "Upload zip folder", notes = "Upload folder from local zip", response = Response.class) @ApiResponses(value = { @ApiResponse(code = 200, message = ""), @ApiResponse(code = 401, message = "User not authorized to call this operation"), @ApiResponse(code = 403, message = "Forbidden operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "Resource already exists"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Consumes({MediaType.MULTIPART_FORM_DATA}) @Produces(MediaType.APPLICATION_JSON) @Path("/upload/zipfolder/{path:.*}") Response uploadFolderFromZip(@ApiParam(value = "Workspace ID", required = true)
                                        @PathParam("ws-id") String workspace,
                                        @ApiParam(value = "Path in the project", required = true)
                                        @PathParam("path") String path,
                                        Iterator<FileItem> formData); @ApiOperation(value = "Get file content", notes = "Get file content by its name") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/file/{path:.*}") Response getFile(@ApiParam(value = "Workspace ID", required = true)
                            @PathParam("ws-id") String workspace,
                            @ApiParam(value = "Path to a file", required = true)
                            @PathParam("path") String path); @ApiOperation(value = "Update file", notes = "Update an existing file with new content") @ApiResponses(value = { @ApiResponse(code = 200, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @PUT @Consumes({MediaType.MEDIA_TYPE_WILDCARD}) @Path("/file/{path:.*}") Response updateFile(@ApiParam(value = "Workspace ID", required = true)
                               @PathParam("ws-id") String workspace,
                               @ApiParam(value = "Full path to a file", required = true)
                               @PathParam("path") String path,
                               @ApiParam(value = "Media Type")
                               @HeaderParam("content-type") MediaType contentType,
                               InputStream content); @ApiOperation(value = "Delete a resource", notes = "Delete resources. If you want to delete a single project, specify project name. If a folder or file needs to " + "be deleted a path to the requested resource needs to be specified") @ApiResponses(value = { @ApiResponse(code = 204, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @DELETE @Path("/{path:.*}") void delete(@ApiParam(value = "Workspace ID", required = true)
                       @PathParam("ws-id") String workspace,
                       @ApiParam(value = "Path to a resource to be deleted", required = true)
                       @PathParam("path") String path,
                       @QueryParam("module") String modulePath); @ApiOperation(value = "Copy resource", notes = "Copy resource to a new location which is specified in a query parameter. " + "It is possible to specify new files name in a JSON. " + "All paths start with /{project-name}") @ApiResponses({@ApiResponse(code = 201, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "Resource already exists"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Path("/copy/{path:.*}") @Consumes(MediaType.APPLICATION_JSON) Response copy(@ApiParam("Workspace ID") @PathParam("ws-id") String workspace,
                         @ApiParam("Path to a resource") @PathParam("path") String path,
                         @ApiParam(value = "Path to a new location", required = true) @QueryParam("to") String newParent,
                         CopyOptions copyOptions); @ApiOperation(value = "Move resource", notes = "Move resource to a new location which is specified in a query parameter. " + "It is possible to change new file name in a new location. File name is passed in a JSON. " + "All paths start with /{project-name}") @ApiResponses({@ApiResponse(code = 201, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "Resource already exists"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Path("/move/{path:.*}") @Consumes(MediaType.APPLICATION_JSON) Response move(@ApiParam("Workspace ID") @PathParam("ws-id") String workspace,
                         @ApiParam("Path to a resource to be moved") @PathParam("path") String path,
                         @ApiParam("Path to a new location") @QueryParam("to") String newParent,
                         MoveOptions moveOptions); @ApiOperation(value = "Rename resource", notes = "Rename resources. It can be project, module, folder or file") @ApiResponses(value = { @ApiResponse(code = 201, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "Resource already exists"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Path("/rename/{path:.*}") Response rename(@ApiParam(value = "Workspace ID", required = true)
                           @PathParam("ws-id") String workspace,
                           @ApiParam(value = "Path to resource to be renamed", required = true)
                           @PathParam("path") String path,
                           @ApiParam(value = "New name", required = true)
                           @QueryParam("name") String newName,
                           @ApiParam(value = "New media type")
                           @QueryParam("mediaType") String newMediaType); @ApiOperation(value = "Import resource", notes = "Import resource. JSON with a designated importer and project location is sent. It is possible to import from " + "VCS or ZIP", response = ImportResponse.class) @ApiResponses(value = { @ApiResponse(code = 200, message = ""), @ApiResponse(code = 401, message = "User not authorized to call this operation"), @ApiResponse(code = 403, message = "Forbidden operation"), @ApiResponse(code = 409, message = "Resource already exists"), @ApiResponse(code = 500, message = "Unsupported source type")}) @POST @Path("/import/{path:.*}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) ImportResponse importProject(@ApiParam(value = "Workspace ID", required = true)
                                        @PathParam("ws-id") String workspace,
                                        @ApiParam(value = "Path in the project", required = true)
                                        @PathParam("path") String path,
                                        @ApiParam(value = "Force rewrite existing project", allowableValues = "true,false")
                                        @QueryParam("force") boolean force,
                                        ImportProject importProject); @ApiOperation(value = "Upload zip project", notes = "Upload project from local zip", response = ImportResponse.class) @ApiResponses(value = { @ApiResponse(code = 200, message = ""), @ApiResponse(code = 401, message = "User not authorized to call this operation"), @ApiResponse(code = 403, message = "Forbidden operation"), @ApiResponse(code = 409, message = "Resource already exists"), @ApiResponse(code = 500, message = "Unsupported source type")}) @POST @Consumes({MediaType.MULTIPART_FORM_DATA}) @Produces(MediaType.APPLICATION_JSON) @Path("/upload/zipproject/{path:.*}") ImportResponse uploadProjectFromZip(@ApiParam(value = "Workspace ID", required = true)
                                               @PathParam("ws-id") String workspace,
                                               @ApiParam(value = "Path in the project", required = true)
                                               @PathParam("path") String path,
                                               @ApiParam(value = "Force rewrite existing project", allowableValues = "true,false")
                                               @QueryParam("force") boolean force,
                                               Iterator<FileItem> formData); @ApiOperation(value = "Import zip", notes = "Import resources as zip") @ApiResponses(value = { @ApiResponse(code = 201, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "Resource already exists"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Path("/import/{path:.*}") @Consumes(ExtMediaType.APPLICATION_ZIP) Response importZip(@ApiParam(value = "Workspace ID", required = true)
                              @PathParam("ws-id") String workspace,
                              @ApiParam(value = "Path to a location (where import to?)")
                              @PathParam("path") String path,
                              InputStream zip,
                              @DefaultValue("false") @QueryParam("skipFirstLevel") Boolean skipFirstLevel); @ApiOperation(value = "Download ZIP", notes = "Export resource as zip. It can be an entire project or folder") @ApiResponses(value = { @ApiResponse(code = 201, message = ""), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/export/{path:.*}") @Produces(ExtMediaType.APPLICATION_ZIP) ContentStream exportZip(@ApiParam(value = "Workspace ID", required = true)
                                   @PathParam("ws-id") String workspace,
                                   @ApiParam(value = "Path to resource to be imported")
                                   @PathParam("path") String path); @POST @Path("/export/{path:.*}") @Consumes(MediaType.TEXT_PLAIN) @Produces(ExtMediaType.APPLICATION_ZIP) Response exportDiffZip(@PathParam("ws-id") String workspace, @PathParam("path") String path, InputStream in); @POST @Path("/export/{path:.*}") @Consumes(MediaType.TEXT_PLAIN) @Produces(MediaType.MULTIPART_FORM_DATA) Response exportDiffZipMultipart(@PathParam("ws-id") String workspace, @PathParam("path") String path, InputStream in); @GET @Path("/export/file/{path:.*}") @Produces(MediaType.APPLICATION_JSON) Response exportFile(@ApiParam(value = "Workspace ID", required = true)
                               @PathParam("ws-id") String workspace,
                               @ApiParam(value = "Path to resource to be imported")
                               @PathParam("path") String path); @ApiOperation(value = "Get project children items", notes = "Request all children items for a project, such as files and folders", response = ItemReference.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/children/{parent:.*}") @Produces(MediaType.APPLICATION_JSON) List<ItemReference> getChildren(@ApiParam(value = "Workspace ID", required = true)
                                           @PathParam("ws-id") String workspace,
                                           @ApiParam(value = "Path to a project", required = true)
                                           @PathParam("parent") String path); @ApiOperation(value = "Get project tree", notes = "Get project tree. Depth is specified in a query parameter", response = TreeElement.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/tree/{parent:.*}") @Produces(MediaType.APPLICATION_JSON) TreeElement getTree(@ApiParam(value = "Workspace ID", required = true)
                               @PathParam("ws-id") String workspace,
                               @ApiParam(value = "Path to resource. Can be project or its folders", required = true)
                               @PathParam("parent") String path,
                               @ApiParam(value = "Tree depth. This parameter can be dropped. If not specified ?depth=1 is used by default")
                               @DefaultValue("1") @QueryParam("depth") int depth,
                               @ApiParam(value = "include children files (in addition to children folders). This parameter can be dropped. If not specified ?includeFiles=false is used by default")
    						   @DefaultValue("false") @QueryParam("includeFiles") boolean includeFiles); @ApiOperation(value = "Get file or folder", response = ItemReference.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/item/{path:.*}") @Produces(MediaType.APPLICATION_JSON) ItemReference getItem(@ApiParam(value = "Workspace ID", required = true)
                                 @PathParam("ws-id") String workspace,
                                 @ApiParam(value = "Path to resource. Can be project or its folders", required = true)
                                 @PathParam("path") String path); @ApiOperation(value = "Search for resources", notes = "Search for resources applying a number of search filters as query parameters", response = ItemReference.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 409, message = "Conflict error"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/search/{path:.*}") @Produces(MediaType.APPLICATION_JSON) List<ItemReference> search(@ApiParam(value = "Workspace ID", required = true)
                                      @PathParam("ws-id") String workspace,
                                      @ApiParam(value = "Path to resource, i.e. where to search?", required = true)
                                      @PathParam("path") String path,
                                      @ApiParam(value = "Resource name")
                                      @QueryParam("name") String name,
                                      @ApiParam(value = "Media type")
                                      @QueryParam("mediatype") String mediatype,
                                      @ApiParam(value = "Search keywords")
                                      @QueryParam("text") String text,
                                      @ApiParam(value = "Maximum items to display. If this parameter is dropped, there are no limits")
                                      @QueryParam("maxItems") @DefaultValue("-1") int maxItems,
                                      @ApiParam(value = "Skip count")
                                      @QueryParam("skipCount") int skipCount); @ApiOperation(value = "Get user permissions in a project", notes = "Get permissions for a user in a specified project, such as read, write, build, " + "run etc. ID of a user is set in a query parameter of a request URL. Roles allowed: workspace/admin", response = AccessControlEntry.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/permissions/{path:.*}") @Produces(MediaType.APPLICATION_JSON) @RolesAllowed("workspace/admin") List<AccessControlEntry> getPermissions(@ApiParam(value = "Workspace ID", required = true)
                                                   @PathParam("ws-id") String wsId,
                                                   @ApiParam(value = "Path to a project", required = true)
                                                   @PathParam("path") String path,
                                                   @ApiParam(value = "User ID", required = true)
                                                   @QueryParam("userid") Set<String> users); @ApiOperation(value = "Set project visibility", notes = "Set project visibility. Projects can be private or public") @ApiResponses(value = { @ApiResponse(code = 204, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Path("/switch_visibility/{path:.*}") void switchVisibility(@ApiParam(value = "Workspace ID", required = true)
                                 @PathParam("ws-id") String wsId,
                                 @ApiParam(value = "Path to a project", required = true)
                                 @PathParam("path") String path,
                                 @ApiParam(value = "Visibility type", required = true, allowableValues = "public,private")
                                 @QueryParam("visibility") String visibility); @ApiOperation(value = "Set permissions for a user in a project", notes = "Set permissions for a user in a specified project, such as read, write, build, " + "run etc. ID of a user is set in a query parameter of a request URL.", response = AccessControlEntry.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 204, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @POST @Path("/permissions/{path:.*}") @Consumes(MediaType.APPLICATION_JSON) @RolesAllowed("workspace/admin") List<AccessControlEntry> setPermissions(@ApiParam(value = "Workspace ID", required = true)
                                                   @PathParam("ws-id") String wsId,
                                                   @ApiParam(value = "Path to a project", required = true)
                                                   @PathParam("path") String path,
                                                   @ApiParam(value = "Permissions", required = true)
                                                   List<AccessControlEntry> acl); @ApiOperation(value = "Get available project-scoped runner environments", notes = "Get available project-scoped runner environments.", response = RunnerEnvironmentTree.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this operation"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/runner_environments/{path:.*}") @Produces(MediaType.APPLICATION_JSON) RunnerEnvironmentTree getRunnerEnvironments(@ApiParam(value = "Workspace ID", required = true)
                                                       @PathParam("ws-id") String workspace,
                                                       @ApiParam(value = "Path to a project", required = true)
                                                       @PathParam("path") String path);  }
@Test public void testImportProject() throws Exception { }