WorkspaceService extends Service { @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) public Response create(@ApiParam(value = "new workspace", required = true) @Required @Description("new workspace") NewWorkspace newWorkspace, @Context SecurityContext context) throws ConflictException, NotFoundException, ServerException, BadRequestException { requiredNotNull(newWorkspace, "New workspace"); requiredNotNull(newWorkspace.getAccountId(), "Account ID"); if (newWorkspace.getAttributes() != null) { validateAttributes(newWorkspace.getAttributes()); } if (newWorkspace.getName() == null || newWorkspace.getName().isEmpty()) { newWorkspace.setName(generateWorkspaceName()); } final Account account = accountDao.getById(newWorkspace.getAccountId()); if (!context.isUserInRole("system/admin")) { ensureCurrentUserOwnerOf(account); } if (account.getAttributes().containsKey(org.eclipse.che.api.account.server.Constants.RESOURCES_LOCKED_PROPERTY)) { newWorkspace.getAttributes().put(org.eclipse.che.api.account.server.Constants.RESOURCES_LOCKED_PROPERTY, "true"); } final Workspace workspace = new Workspace().withId(generate(Workspace.class.getSimpleName().toLowerCase(), Constants.ID_LENGTH)) .withName(newWorkspace.getName()) .withTemporary(false) .withAccountId(newWorkspace.getAccountId()) .withAttributes(newWorkspace.getAttributes()); workspaceDao.create(workspace); LOG.info("EVENT#workspace-created# WS#{}# WS-ID#{}# USER#{}#", newWorkspace.getName(), workspace.getId(), currentUser().getId()); return status(CREATED).entity(toDescriptor(workspace, context)).build(); } @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 shouldBeAbleToCreateFirstWorkspace() throws Exception { final Account testAccount = createAccount(); when(workspaceDao.getByAccount(testAccount.getId())).thenReturn(Collections.<Workspace>emptyList()); final NewWorkspace newWorkspace = newDTO(NewWorkspace.class).withName("new_workspace") .withAccountId(testAccount.getId()); final WorkspaceDescriptor descriptor = doPost(SERVICE_PATH, newWorkspace, CREATED); assertEquals(descriptor.getName(), newWorkspace.getName()); assertEquals(descriptor.getAccountId(), newWorkspace.getAccountId()); assertTrue(descriptor.getAttributes().isEmpty()); assertFalse(descriptor.isTemporary()); verify(workspaceDao).create(any(Workspace.class)); }
@Test public void shouldBeAbleToCreateMultiWorkspaces() throws Exception { final Account testAccount = createAccount(); when(workspaceDao.getByAccount(testAccount.getId())).thenReturn(singletonList(new Workspace())); final NewWorkspace newWorkspace = newDTO(NewWorkspace.class).withName("test_workspace") .withAccountId(testAccount.getId()); final WorkspaceDescriptor descriptor = doPost(SERVICE_PATH, newWorkspace, CREATED); assertEquals(descriptor.getName(), newWorkspace.getName()); assertEquals(descriptor.getAccountId(), newWorkspace.getAccountId()); verify(workspaceDao).create(any(Workspace.class)); }
@Test public void shouldBeAbleToCreateNewTemporaryWorkspace() throws Exception { final NewWorkspace newWorkspace = newDTO(NewWorkspace.class).withName("new_workspace") .withAccountId("fake_account_id"); createAccount(); final WorkspaceDescriptor descriptor = doPost(SERVICE_PATH + "/temp", newWorkspace, CREATED); assertTrue(descriptor.isTemporary()); assertEquals(descriptor.getName(), newWorkspace.getName()); assertEquals(descriptor.getAccountId(), newWorkspace.getAccountId()); verify(userDao, never()).create(any(User.class)); verify(profileDao, never()).create(any(Profile.class)); verify(workspaceDao).create(any(Workspace.class)); }
@Test public void shouldBeAbleToCreateNewTemporaryWorkspaceWhenUserDoesNotExist() throws Exception { when(securityContext.getUserPrincipal()).thenReturn(null); final NewWorkspace newWorkspace = newDTO(NewWorkspace.class).withName("new_workspace") .withAccountId("fake_account"); final WorkspaceDescriptor descriptor = doPost(SERVICE_PATH + "/temp", newWorkspace, CREATED); assertTrue(descriptor.isTemporary()); assertEquals(descriptor.getName(), newWorkspace.getName()); assertEquals(descriptor.getAccountId(), newWorkspace.getAccountId()); verify(userDao).create(any(User.class)); verify(profileDao).create(any(Profile.class)); verify(workspaceDao).create(any(Workspace.class)); }
@Test public void shouldBeAbleToAddWorkspaceMemberToNotEmptyWorkspaceForWorkspaceAdmin() throws Exception { final Workspace testWorkspace = createWorkspace(); when(memberDao.getWorkspaceMembers(testWorkspace.getId())).thenReturn(singletonList(new Member())); final NewMembership membership = newDTO(NewMembership.class).withRoles(singletonList("workspace/developer")) .withUserId("test_user_id"); prepareRole("workspace/admin"); final MemberDescriptor descriptor = doPost(SERVICE_PATH + "/" + testWorkspace.getId() + "/members", membership, CREATED); assertEquals(descriptor.getUserId(), membership.getUserId()); assertEquals(descriptor.getWorkspaceReference().getId(), testWorkspace.getId()); assertEquals(descriptor.getRoles(), membership.getRoles()); verify(memberDao).create(any(Member.class)); }
@Test public void shouldBeAbleToAddMemberToNotEmptyWorkspaceIfUserIsAccountOwner() throws Exception { final Workspace testWorkspace = createWorkspace(); final Account account = createAccount(); when(workspaceDao.getByAccount(account.getId())).thenReturn(singletonList(testWorkspace)); when(memberDao.getWorkspaceMembers(testWorkspace.getId())).thenReturn(singletonList(new Member())); final NewMembership membership = newDTO(NewMembership.class).withRoles(singletonList("workspace/developer")) .withUserId(testUser.getId()); prepareRole("account/owner"); final MemberDescriptor descriptor = doPost(SERVICE_PATH + "/" + testWorkspace.getId() + "/members", membership, CREATED); assertEquals(descriptor.getUserId(), membership.getUserId()); assertEquals(descriptor.getWorkspaceReference().getId(), testWorkspace.getId()); assertEquals(descriptor.getRoles(), membership.getRoles()); verify(memberDao).create(any(Member.class)); }
@Test public void shouldBeAbleToAddMemberToNotEmptyWorkspaceForAnyUserIfAllowAttributeIsTrue() throws Exception { final Workspace testWorkspace = createWorkspace(); when(memberDao.getWorkspaceMembers(testWorkspace.getId())).thenReturn(singletonList(new Member())); testWorkspace.getAttributes().put("allowAnyoneAddMember", "true"); final NewMembership membership = newDTO(NewMembership.class).withRoles(singletonList("workspace/developer")) .withUserId(testUser.getId()); final MemberDescriptor descriptor = doPost(SERVICE_PATH + "/" + testWorkspace.getId() + "/members", membership, CREATED); assertEquals(descriptor.getRoles(), membership.getRoles()); assertEquals(descriptor.getUserId(), membership.getUserId()); assertEquals(descriptor.getWorkspaceReference().getId(), testWorkspace.getId()); verify(memberDao).create(any(Member.class)); }