WorkspaceService extends Service { MemberDescriptor toDescriptor(Member member, Workspace workspace, SecurityContext context) { final UriBuilder serviceUriBuilder = getServiceContext().getServiceUriBuilder(); final UriBuilder baseUriBuilder = getServiceContext().getBaseUriBuilder(); final List<Link> links = new LinkedList<>(); if (context.isUserInRole("account/owner") || context.isUserInRole("workspace/admin") || context.isUserInRole("workspace/developer")) { links.add(LinksHelper.createLink(HttpMethod.GET, serviceUriBuilder.clone() .path(getClass(), "getMembers") .build(workspace.getId()) .toString(), null, APPLICATION_JSON, Constants.LINK_REL_GET_WORKSPACE_MEMBERS)); } if (context.isUserInRole("account/owner") || context.isUserInRole("workspace/admin")) { links.add(LinksHelper.createLink(HttpMethod.DELETE, serviceUriBuilder.clone() .path(getClass(), "removeMember") .build(workspace.getId(), member.getUserId()) .toString(), null, null, Constants.LINK_REL_REMOVE_WORKSPACE_MEMBER)); } links.add(LinksHelper.createLink(HttpMethod.GET, baseUriBuilder.clone() .path(UserService.class) .path(UserService.class, "getById") .build(member.getUserId()) .toString(), null, APPLICATION_JSON, LINK_REL_GET_USER_BY_ID)); final Link wsLink = LinksHelper.createLink(HttpMethod.GET, serviceUriBuilder.clone() .path(getClass(), "getById") .build(workspace.getId()) .toString(), null, APPLICATION_JSON, Constants.LINK_REL_GET_WORKSPACE_BY_ID); final Link projectsLink = LinksHelper.createLink(HttpMethod.GET, getServiceContext().getBaseUriBuilder().clone() .path("/project/{ws-id}") .build(member.getWorkspaceId()) .toString(), null, APPLICATION_JSON, "get projects"); final WorkspaceReference wsRef = DtoFactory.getInstance().createDto(WorkspaceReference.class) .withId(workspace.getId()) .withName(workspace.getName()) .withTemporary(workspace.isTemporary()) .withLinks(asList(wsLink, projectsLink)); return DtoFactory.getInstance().createDto(MemberDescriptor.class) .withUserId(member.getUserId()) .withWorkspaceReference(wsRef) .withRoles(member.getRoles()) .withLinks(links); } @Inject  WorkspaceService(WorkspaceDao workspaceDao,
                            UserDao userDao,
                            MemberDao memberDao,
                            AccountDao accountDao,
                            UserProfileDao profileDao,
                            PreferenceDao preferenceDao
                           ); @ApiOperation(value = "Create a new workspace", notes = "User and system/admin can create a new persistent workspace. To create a new workspace, a user needs " + "a valid account. Workspace attributes are optional and used as a storage for any workspace specific information", response = WorkspaceDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 201, message = "CREATED"), @ApiResponse(code = 403, message = "You have no access to create more workspaces"), @ApiResponse(code = 404, message = "NOT FOUND"), @ApiResponse(code = 409, message = "You can create workspace associated only with your own account"), @ApiResponse(code = 500, message = "INTERNAL SERVER ERROR")}) @POST @GenerateLink(rel = Constants.LINK_REL_CREATE_WORKSPACE) @RolesAllowed({"user", "system/admin"}) @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) Response create(@ApiParam(value = "new workspace", required = true)
                           @Required
                           @Description("new workspace")
                           NewWorkspace newWorkspace,
                           @Context SecurityContext context); @ApiOperation(value = "Create a temporary workspace", notes = "A temporary workspace is destroyed after certain time of inactivity. It has the same functionality as" + "a persistent workspace. Temporary workspace name is automatically generated when it is system created," + "otherwise a name can be passed in JSON params", response = WorkspaceDescriptor.class ) @ApiResponses(value = { @ApiResponse(code = 201, message = "CREATED"), @ApiResponse(code = 403, message = "You have no access to create more workspaces"), @ApiResponse(code = 404, message = "NOT FOUND"), @ApiResponse(code = 409, message = "You can create workspace associated only to your own account"), @ApiResponse(code = 500, message = "INTERNAL SERVER ERROR") }) @POST @Path("/temp") @GenerateLink(rel = Constants.LINK_REL_CREATE_TEMP_WORKSPACE) @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) Response createTemporary(@ApiParam(value = "New Temporary workspace", required = true)
                                    @Required
                                    @Description("New temporary workspace")
                                    NewWorkspace newWorkspace,
                                    @Context SecurityContext context); @ApiOperation(value = "Get workspace by ID", response = WorkspaceDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 404, message = "Workspace with specified ID does not exist"), @ApiResponse(code = 403, message = "Access to requested workspace is forbidden"), @ApiResponse(code = 500, message = "Server error")}) @GET @Path("/{id}") @Produces(APPLICATION_JSON) WorkspaceDescriptor getById(@ApiParam(value = "Workspace ID")
                                       @Description("Workspace ID")
                                       @PathParam("id")
                                       String id,
                                       @Context SecurityContext context); @ApiOperation(value = "Gets workspace by name", response = WorkspaceDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 404, message = "Workspace with specified name doesn't exist"), @ApiResponse(code = 403, message = "Access to requested workspace is forbidden"), @ApiResponse(code = 500, message = "Server error")}) @GET @GenerateLink(rel = Constants.LINK_REL_GET_WORKSPACE_BY_NAME) @Produces(APPLICATION_JSON) WorkspaceDescriptor getByName(@ApiParam(value = "Name of workspace", required = true)
                                         @Required
                                         @Description("Name of workspace")
                                         @QueryParam("name")
                                         String name,
                                         @Context SecurityContext context); @ApiOperation(value = "Update workspace", notes = "Update an existing workspace. A JSON with updated properties is sent." + "The entire WorkspaceDexcriptor should be sent in the payload, not only updates. " + "Roles allowed: accoubnt/owner, workspace/admin, system/admin", response = WorkspaceDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "Workspace updated"), @ApiResponse(code = 404, message = "Not found"), @ApiResponse(code = 403, message = "Access to required workspace is forbidden"), @ApiResponse(code = 500, message = "Internal server error")}) @POST @Path("/{id}") @RolesAllowed({"account/owner", "workspace/admin", "system/admin"}) @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) WorkspaceDescriptor update(@ApiParam("Workspace ID") @PathParam("id") String id,
                                      @ApiParam(value = "Workspace update", required = true) WorkspaceUpdate update,
                                      @Context SecurityContext context); @ApiOperation(value = "Get workspace by Account ID", notes = "Search for a workspace by its Account ID which is added as query parameter. " + "Roles allowed: user, system/admin, system/manager", response = WorkspaceDescriptor.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 403, message = "User is not authorized to call this operation"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/find/account") @GenerateLink(rel = Constants.LINK_REL_GET_WORKSPACES_BY_ACCOUNT) @RolesAllowed({"user", "system/admin", "system/manager"}) @Produces(APPLICATION_JSON) List<WorkspaceDescriptor> getWorkspacesByAccount(@ApiParam(value = "Account ID", required = true)
                                                            @Required
                                                            @QueryParam("id")
                                                            String accountId,
                                                            @Context SecurityContext context); @ApiOperation(value = "Get membership of a current user", notes = "Get workspaces, membership and roles of a currently logged in user", response = MemberDescriptor.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/all") @GenerateLink(rel = Constants.LINK_REL_GET_CURRENT_USER_WORKSPACES) @RolesAllowed({"user", "temp_user"}) @Produces(APPLICATION_JSON) List<MemberDescriptor> getMembershipsOfCurrentUser(@Context SecurityContext context); @ApiOperation(value = "Get memberships by user ID", notes = "Search for a workspace by User ID which is added to URL as query parameter. JSON with workspace details and user roles is returned." + "Only system/admin or system/manager can access this method", response = MemberDescriptor.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to call this action"), @ApiResponse(code = 404, message = "Not Foound"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/find") @GenerateLink(rel = Constants.LINK_REL_GET_CONCRETE_USER_WORKSPACES) @RolesAllowed({"system/admin", "system/manager"}) @Produces(APPLICATION_JSON) List<MemberDescriptor> getMembershipsOfSpecificUser(@ApiParam(value = "User ID", required = true)
                                                               @Required
                                                               @QueryParam("userid")
                                                               String userId,
                                                               @Context SecurityContext context); @ApiOperation(value = "Get workspace members by workspace ID", notes = "Get all workspace members and their roles in a specified workspace. A JSON with members and their roles is returned. " + "Roles allowed: workspace/admin, workspace/developer, account/owner, system/admin, system/manager", response = MemberDescriptor.class, responseContainer = "List") @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/{id}/members") @RolesAllowed({"workspace/admin", "workspace/developer", "account/owner", "system/admin", "system/manager"}) @Produces(APPLICATION_JSON) List<MemberDescriptor> getMembers(@ApiParam(value = "Workspace ID")
                                             @PathParam("id")
                                             String wsId,
                                             @Context SecurityContext context); @ApiOperation(value = "Get user membership in a specified workspace", notes = "Returns membership of a user with roles. Roles allowed: workspace/stakeholder, workspace/developer, " + "workspace/admin", response = MemberDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK"), @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 500, message = "Internal Server Error")}) @GET @Path("/{id}/membership") @RolesAllowed({"workspace/stakeholder", "workspace/developer", "workspace/admin"}) @Produces(APPLICATION_JSON) MemberDescriptor getMembershipOfCurrentUser(@ApiParam(value = "Workspace ID")
                                                       @PathParam("id")
                                                       String wsId,
                                                       @Context SecurityContext context); @ApiOperation(value = "Delete workspace attribute", notes = "Deletes attributes of a specified workspace. Roles allowed: account/owner, workspace/admin, system/admin") @ApiResponses(value = { @ApiResponse(code = 204, message = "No Content"), @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 409, message = "Invalid attribute name"), @ApiResponse(code = 500, message = "Internal Server Error")}) @DELETE @Path("/{id}/attribute") @RolesAllowed({"account/owner", "workspace/admin", "system/admin"}) void removeAttribute(@ApiParam(value = "Workspace ID")
                                @PathParam("id")
                                String wsId,
                                @ApiParam(value = "Attribute name", required = true)
                                @Required
                                @QueryParam("name")
                                String attributeName,
                                @Context SecurityContext context); @ApiOperation(value = "Create new workspace member", notes = "Add a new member into a workspace with a set of specified roles. A new member should be a registered " + "user. One or both roles can be assigned. Rolles allowed: account/owner, workspace/admin", response = MemberDescriptor.class) @ApiResponses(value = { @ApiResponse(code = 201, message = "OK"), @ApiResponse(code = 403, message = "User not authorized to perform this operation"), @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 409, message = "No user ID and/or role specified")}) @POST @Path("/{id}/members") @RolesAllowed({"user", "temp_user"}) @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) Response addMember(@ApiParam("Workspace ID") @PathParam("id") String wsId,
                              @ApiParam(value = "New membership", required = true) NewMembership newMembership,
                              @Context SecurityContext context); @ApiOperation(value = "Remove user from workspace", notes = "Remove a user from a workspace by User ID. Roles allowed: account/owner, workspace/admin, workspace/developer." + "User who has only workspace/developer role can remove only his own memberships.") @ApiResponses(value = { @ApiResponse(code = 204, message = "No Content"), @ApiResponse(code = 403, message = "User not authorized to perform this operation"), @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 409, message = "Cannot remove workspace/admin"), @ApiResponse(code = 500, message = "Internal Server Error")}) @DELETE @Path("/{id}/members/{userid}") @RolesAllowed({"account/owner", "workspace/admin", "workspace/developer"}) void removeMember(@ApiParam(value = "Workspace ID")
                             @PathParam("id")
                             String wsId,
                             @ApiParam(value = "User ID")
                             @PathParam("userid")
                             String userId,
                             @Context SecurityContext context); @ApiOperation(value = "Delete a workspace", notes = "Delete a workspace by its ID. Roles allowed: account/owner, workspace/admin, system/admin") @ApiResponses(value = { @ApiResponse(code = 204, message = "No Content"), @ApiResponse(code = 404, message = "Not Found"), @ApiResponse(code = 409, message = "Failed to remove workspace member"), @ApiResponse(code = 500, message = "Internal Server Error")}) @DELETE @Path("/{id}") @RolesAllowed({"account/owner", "workspace/admin", "system/admin"}) void remove(@ApiParam(value = "Workspace ID")
                       @PathParam("id")
                       String wsId);  }
@Test public void testWorkspaceDescriptorLinksForUser() throws NotFoundException, ServerException { final Workspace testWorkspace = createWorkspace(); when(securityContext.isUserInRole("user")).thenReturn(true); final Set<String> expectedRels = new HashSet<>(asList(Constants.LINK_REL_GET_CURRENT_USER_WORKSPACES, Constants.LINK_REL_GET_CURRENT_USER_MEMBERSHIP, "get projects")); assertEquals(asRels(service.toDescriptor(testWorkspace, securityContext).getLinks()), expectedRels); }
@Test public void testWorkspaceDescriptorLinksForWorkspaceDeveloper() throws NotFoundException, ServerException { final Workspace testWorkspace = createWorkspace(); prepareRole("workspace/developer"); final Set<String> expectedRels = new HashSet<>(asList(Constants.LINK_REL_GET_WORKSPACE_BY_NAME, Constants.LINK_REL_GET_WORKSPACE_BY_ID, Constants.LINK_REL_GET_WORKSPACE_MEMBERS, Constants.LINK_REL_GET_CURRENT_USER_WORKSPACES, Constants.LINK_REL_GET_CURRENT_USER_MEMBERSHIP, "get projects")); assertEquals(asRels(service.toDescriptor(testWorkspace, securityContext).getLinks()), expectedRels); }
@Test public void testWorkspaceDescriptorLinksForWorkspaceAdmin() throws NotFoundException, ServerException { final Workspace testWorkspace = createWorkspace(); prepareRole("workspace/admin"); final Set<String> expectedRels = new HashSet<>(asList(Constants.LINK_REL_GET_WORKSPACE_BY_NAME, Constants.LINK_REL_GET_WORKSPACE_BY_ID, Constants.LINK_REL_GET_WORKSPACE_MEMBERS, Constants.LINK_REL_REMOVE_WORKSPACE, Constants.LINK_REL_GET_CURRENT_USER_WORKSPACES, Constants.LINK_REL_GET_CURRENT_USER_MEMBERSHIP, "get projects")); assertEquals(asRels(service.toDescriptor(testWorkspace, securityContext).getLinks()), expectedRels); }
@Test public void testWorkspaceDescriptorLinksForSystemManager() throws NotFoundException, ServerException { final Workspace testWorkspace = createWorkspace(); prepareRole("system/manager"); final Set<String> expectedRels = new HashSet<>(asList(Constants.LINK_REL_GET_WORKSPACE_BY_NAME, Constants.LINK_REL_GET_WORKSPACE_BY_ID, Constants.LINK_REL_GET_WORKSPACE_MEMBERS)); assertEquals(asRels(service.toDescriptor(testWorkspace, securityContext).getLinks()), expectedRels); }
@Test public void testWorkspaceDescriptorLinksForSystemAdmin() throws NotFoundException, ServerException { final Workspace testWorkspace = createWorkspace(); prepareRole("system/admin"); final Set<String> expectedRels = new HashSet<>(asList(Constants.LINK_REL_GET_WORKSPACE_BY_NAME, Constants.LINK_REL_GET_WORKSPACE_BY_ID, Constants.LINK_REL_GET_WORKSPACE_MEMBERS, Constants.LINK_REL_REMOVE_WORKSPACE)); assertEquals(asRels(service.toDescriptor(testWorkspace, securityContext).getLinks()), expectedRels); }
@Test public void testMemberDescriptorLinksForWorkspaceDeveloper() throws NotFoundException, ServerException { final Workspace testWorkspace = createWorkspace(); final Member testMember = new Member().withUserId(testUser.getId()) .withWorkspaceId(testWorkspace.getId()); prepareRole("workspace/developer"); final Set<String> expectedRels = new HashSet<>(asList(Constants.LINK_REL_GET_WORKSPACE_MEMBERS, LINK_REL_GET_USER_BY_ID)); assertEquals(asRels(service.toDescriptor(testMember, testWorkspace, securityContext).getLinks()), expectedRels); }
@Test public void testMemberDescriptorLinksForWorkspaceAdmin() throws NotFoundException, ServerException { final Workspace testWorkspace = createWorkspace(); final Member testMember = new Member().withUserId(testUser.getId()) .withWorkspaceId(testWorkspace.getId()); prepareRole("workspace/admin"); final Set<String> expectedRels = new HashSet<>(asList(Constants.LINK_REL_GET_WORKSPACE_MEMBERS, LINK_REL_GET_USER_BY_ID, Constants.LINK_REL_REMOVE_WORKSPACE_MEMBER)); assertEquals(asRels(service.toDescriptor(testMember, testWorkspace, securityContext).getLinks()), expectedRels); }