]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7838 WS api/permissions/groups returns group permissions
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Sat, 9 Jul 2016 22:46:43 +0000 (00:46 +0200)
committerStas Vilchik <vilchiks@gmail.com>
Tue, 12 Jul 2016 08:16:53 +0000 (10:16 +0200)
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionFinder.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/GroupsAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/TemplateGroupsAction.java
server/sonar-server/src/main/resources/org/sonar/server/permission/ws/groups-example.json
server/sonar-server/src/test/java/org/sonar/server/permission/ws/GroupsActionTest.java
server/sonar-server/src/test/resources/org/sonar/server/permission/ws/GroupsActionTest/groups.json
sonar-db/src/main/java/org/sonar/db/permission/PermissionQuery.java
sonar-ws/src/main/java/org/sonarqube/ws/client/permission/GroupsWsRequest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/permission/PermissionsService.java
sonar-ws/src/main/protobuf/ws-permissions.proto
sonar-ws/src/test/java/org/sonarqube/ws/client/permission/PermissionsServiceTest.java

index 05d3804e9a03a1b315f5385b5a300d81dc3a0add..c0020697358c13909344ad1c962d8b21a786c806 100644 (file)
  */
 package org.sonar.server.permission;
 
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import java.util.Collection;
+import com.google.common.collect.Ordering;
 import java.util.List;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import java.util.stream.Collectors;
 import org.sonar.api.security.DefaultGroups;
 import org.sonar.api.server.ServerSide;
-import org.sonar.api.utils.Paging;
-import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
-import org.sonar.db.component.ResourceDao;
-import org.sonar.db.component.ResourceDto;
-import org.sonar.db.component.ResourceQuery;
-import org.sonar.db.permission.GroupWithPermissionDto;
-import org.sonar.db.permission.OldPermissionQuery;
 import org.sonar.db.permission.PermissionDao;
-import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.db.permission.PermissionQuery;
+import org.sonar.db.user.GroupDao;
+import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.GroupRoleDto;
 
-import static com.google.common.collect.Lists.newArrayList;
-import static org.apache.commons.lang.StringUtils.containsIgnoreCase;
-import static org.sonar.api.utils.Paging.forPageIndex;
+import static java.util.Collections.emptyList;
 
 @ServerSide
 public class PermissionFinder {
 
   private final PermissionDao permissionDao;
-  private final ResourceDao resourceDao;
+  private final GroupDao groupDao;
 
   public PermissionFinder(DbClient dbClient) {
-    this.resourceDao = dbClient.resourceDao();
     this.permissionDao = dbClient.permissionDao();
+    this.groupDao = dbClient.groupDao();
   }
 
-  /**
-   * Paging for groups search is done in Java in order to correctly handle the 'Anyone' group
-   */
-  public List<GroupWithPermissionDto> findGroupsWithPermission(DbSession dbSession, OldPermissionQuery query) {
-    Long componentId = componentId(query.component());
-    return toGroupQueryResult(permissionDao.selectGroups(dbSession, query, componentId), query);
-  }
-
-  @Nullable
-  private Long componentId(@Nullable String componentKey) {
-    if (componentKey == null) {
-      return null;
-    } else {
-      ResourceDto resourceDto = resourceDao.selectResource(ResourceQuery.create().setKey(componentKey));
-      if (resourceDto == null) {
-        throw new NotFoundException(String.format("Project '%s' does not exist", componentKey));
-      }
-      return resourceDto.getId();
-    }
-  }
-
-  private static List<GroupWithPermissionDto> toGroupQueryResult(List<GroupWithPermissionDto> dtos, OldPermissionQuery query) {
-    addAnyoneGroup(dtos, query);
-    List<GroupWithPermissionDto> filteredDtos = filterMembership(dtos, query);
-
-    Paging paging = forPageIndex(query.pageIndex())
-      .withPageSize(query.pageSize())
-      .andTotal(filteredDtos.size());
-
-    return pagedGroups(filteredDtos, paging);
-  }
-
-  private static List<GroupWithPermissionDto> filterMembership(List<GroupWithPermissionDto> dtos, OldPermissionQuery query) {
-    return newArrayList(Iterables.filter(dtos, new GroupWithPermissionMatchQuery(query)));
-  }
+  public List<GroupDto> findGroups(DbSession dbSession, PermissionQuery.Builder dbQuery) {
+    List<String> orderedNames = permissionDao.selectGroupNamesByPermissionQuery(dbSession, dbQuery.build());
 
-  /**
-   * As the anyone group does not exists in db, it's not returned when it has not the permission.
-   * We have to manually add it at the begin of the list, if it matched the search text
-   */
-  private static void addAnyoneGroup(List<GroupWithPermissionDto> groups, OldPermissionQuery query) {
-    boolean hasAnyoneGroup = Iterables.any(groups, IsAnyoneGroup.INSTANCE);
-    if (!hasAnyoneGroup
-      && !GlobalPermissions.SYSTEM_ADMIN.equals(query.permission())
-      && (query.search() == null || containsIgnoreCase(DefaultGroups.ANYONE, query.search()))) {
-      groups.add(0, new GroupWithPermissionDto().setName(DefaultGroups.ANYONE));
+    List<GroupDto> groups = groupDao.selectByNames(dbSession, orderedNames);
+    if (orderedNames.contains(DefaultGroups.ANYONE)) {
+      groups.add(0, new GroupDto().setId(0L).setName(DefaultGroups.ANYONE));
     }
-  }
 
-  private static List<GroupWithPermissionDto> pagedGroups(Collection<GroupWithPermissionDto> dtos, Paging paging) {
-    List<GroupWithPermissionDto> groups = newArrayList();
-    int index = 0;
-    for (GroupWithPermissionDto dto : dtos) {
-      if (index >= paging.offset() && groups.size() < paging.pageSize()) {
-        groups.add(dto);
-      } else if (groups.size() >= paging.pageSize()) {
-        break;
-      }
-      index++;
-    }
-    return groups;
+    return Ordering.explicit(orderedNames).onResultOf(GroupDto::getName).immutableSortedCopy(groups);
   }
 
-  private static class GroupWithPermissionMatchQuery implements Predicate<GroupWithPermissionDto> {
-    private final OldPermissionQuery query;
-
-    public GroupWithPermissionMatchQuery(OldPermissionQuery query) {
-      this.query = query;
+  public List<GroupRoleDto> findGroupPermissions(DbSession dbSession, PermissionQuery.Builder dbQuery, List<GroupDto> groups) {
+    if (groups.isEmpty()) {
+      return emptyList();
     }
 
-    @Override
-    public boolean apply(@Nonnull GroupWithPermissionDto dto) {
-      if (OldPermissionQuery.IN.equals(query.membership())) {
-        return dto.getPermission() != null;
-      } else if (OldPermissionQuery.OUT.equals(query.membership())) {
-        return dto.getPermission() == null;
-      }
-      return true;
-    }
-  }
-
-  private enum IsAnyoneGroup implements Predicate<GroupWithPermissionDto> {
-    INSTANCE;
-
-    @Override
-    public boolean apply(@Nonnull GroupWithPermissionDto group) {
-      return group.getName().equals(DefaultGroups.ANYONE);
-    }
+    List<String> names = groups.stream().map(GroupDto::getName).collect(Collectors.toList());
+    return permissionDao.selectGroupPermissionsByQuery(dbSession, dbQuery
+      .setGroupNames(names)
+      .withPermissionOnly()
+      .build());
   }
 }
index 4346b4ae2bfcccda2feaac74a08a95d74f78ac44..7a1ec19c5b849bcfe1ac175f01955f708e1bfe3a 100644 (file)
 package org.sonar.server.permission.ws;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.TreeMultimap;
 import com.google.common.io.Resources;
 import java.util.List;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.server.ws.WebService.Param;
-import org.sonar.api.server.ws.WebService.SelectionMode;
+import org.sonar.api.utils.Paging;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.db.permission.GroupWithPermissionDto;
-import org.sonar.db.permission.OldPermissionQuery;
+import org.sonar.db.permission.PermissionQuery;
+import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.GroupRoleDto;
 import org.sonar.server.permission.PermissionFinder;
 import org.sonar.server.user.UserSession;
-import org.sonarqube.ws.Common;
 import org.sonarqube.ws.WsPermissions.Group;
 import org.sonarqube.ws.WsPermissions.WsGroupsResponse;
 import org.sonarqube.ws.client.permission.GroupsWsRequest;
 
-import static com.google.common.base.MoreObjects.firstNonNull;
+import static org.sonar.db.permission.PermissionQuery.DEFAULT_PAGE_SIZE;
+import static org.sonar.db.permission.PermissionQuery.RESULTS_MAX_SIZE;
+import static org.sonar.db.permission.PermissionQuery.SEARCH_QUERY_MIN_LENGTH;
 import static org.sonar.server.permission.PermissionPrivilegeChecker.checkProjectAdminUserByComponentDto;
-import static org.sonar.server.permission.ws.PermissionQueryParser.fromSelectionModeToMembership;
-import static org.sonar.server.permission.ws.PermissionRequestValidator.validateGlobalPermission;
-import static org.sonar.server.permission.ws.PermissionRequestValidator.validateProjectPermission;
+import static org.sonar.server.permission.ws.PermissionRequestValidator.validatePermission;
 import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createPermissionParameter;
 import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectParameters;
 import static org.sonar.server.permission.ws.WsProjectRef.newOptionalWsProjectRef;
@@ -70,18 +72,18 @@ public class GroupsAction implements PermissionsWsAction {
     WebService.NewAction action = context.createAction("groups")
       .setSince("5.2")
       .setInternal(true)
-      .setDescription(String.format("Lists the groups that have been explicitly granted the specified permission. <br />" +
-        "This service defaults to global permissions, but can be limited to project permissions by providing a project id or project key. <br />" +
-        "If the query parameter '%s' is specified, the '%s' parameter is forced to '%s'. <br />" +
-        "It requires administration permissions to access.",
-        Param.TEXT_QUERY, Param.SELECTED, SelectionMode.ALL.value()))
-      .addPagingParams(100)
-      .addSearchQuery("sonar", "names")
-      .addSelectionModeParam()
+      .setDescription("Lists the groups with their permissions.<br>" +
+        "This service defaults to global permissions, but can be limited to project permissions by providing project id or project key.<br> " +
+        "This service defaults to all groups, but can be limited to groups with a specific permission by providing the desired permission.<br>" +
+        "It requires administration permissions to access.")
+      .addPagingParams(DEFAULT_PAGE_SIZE, RESULTS_MAX_SIZE)
+      .addSearchQuery("sonar", "names").setDescription("Limit search to group names that contain the supplied string. Must have at least %d characters.<br/>" +
+        "When this parameter is not set, only groups having at least one permission are returned.", SEARCH_QUERY_MIN_LENGTH)
       .setResponseExample(Resources.getResource(getClass(), "groups-example.json"))
       .setHandler(this);
 
-    createPermissionParameter(action);
+    createPermissionParameter(action)
+      .setRequired(false);
     createProjectParameters(action);
   }
 
@@ -98,77 +100,67 @@ public class GroupsAction implements PermissionsWsAction {
       Optional<ComponentDto> project = dependenciesFinder.searchProject(dbSession, newOptionalWsProjectRef(request.getProjectId(), request.getProjectKey()));
       checkProjectAdminUserByComponentDto(userSession, project);
 
-      OldPermissionQuery permissionQuery = buildPermissionQuery(request, project);
-      Long projectIdIfPresent = project.isPresent() ? project.get().getId() : null;
-      int total = dbClient.permissionDao().countGroups(dbSession, permissionQuery.permission(), projectIdIfPresent);
-      List<GroupWithPermissionDto> groupsWithPermission = permissionFinder.findGroupsWithPermission(dbSession, permissionQuery);
-      return buildResponse(groupsWithPermission, request, total);
+      PermissionQuery.Builder dbQuery = buildPermissionQuery(request, project);
+      List<GroupDto> groups = permissionFinder.findGroups(dbSession, dbQuery);
+      int total = dbClient.permissionDao().countGroupsByPermissionQuery(dbSession, dbQuery.build());
+      List<GroupRoleDto> groupsWithPermission = permissionFinder.findGroupPermissions(dbSession, dbQuery, groups);
+      return buildResponse(groups, groupsWithPermission, Paging.forPageIndex(request.getPage()).withPageSize(request.getPageSize()).andTotal(total));
     } finally {
       dbClient.closeSession(dbSession);
     }
   }
 
   private static GroupsWsRequest toGroupsWsRequest(Request request) {
-    String permission = request.mandatoryParam(PARAM_PERMISSION);
-    String projectUuid = request.param(PARAM_PROJECT_ID);
-    String projectKey = request.param(PARAM_PROJECT_KEY);
-    if (newOptionalWsProjectRef(projectUuid, projectKey).isPresent()) {
-      validateProjectPermission(permission);
-    } else {
-      validateGlobalPermission(permission);
-    }
-
-    return new GroupsWsRequest()
-      .setPermission(permission)
-      .setProjectId(projectUuid)
-      .setProjectKey(projectKey)
+    GroupsWsRequest groupsRequest = new GroupsWsRequest()
+      .setPermission(request.param(PARAM_PERMISSION))
+      .setProjectId(request.param(PARAM_PROJECT_ID))
+      .setProjectKey(request.param(PARAM_PROJECT_KEY))
       .setPage(request.mandatoryParamAsInt(Param.PAGE))
       .setPageSize(request.mandatoryParamAsInt(Param.PAGE_SIZE))
-      .setQuery(request.param(Param.TEXT_QUERY))
-      .setSelected(request.mandatoryParam(Param.SELECTED));
+      .setQuery(request.param(Param.TEXT_QUERY));
+
+    Optional<WsProjectRef> wsProjectRef = newOptionalWsProjectRef(groupsRequest.getProjectId(), groupsRequest.getProjectKey());
+    validatePermission(groupsRequest.getPermission(), wsProjectRef);
+    return groupsRequest;
   }
 
-  private static OldPermissionQuery buildPermissionQuery(GroupsWsRequest request, Optional<ComponentDto> project) {
-    OldPermissionQuery.Builder permissionQuery = OldPermissionQuery.builder()
-      .permission(request.getPermission())
-      .pageIndex(request.getPage())
-      .pageSize(request.getPageSize())
-      .membership(fromSelectionModeToMembership(firstNonNull(request.getSelected(), SelectionMode.SELECTED.value())))
-      .search(request.getQuery());
+  private static PermissionQuery.Builder buildPermissionQuery(GroupsWsRequest request, Optional<ComponentDto> project) {
+    PermissionQuery.Builder permissionQuery = PermissionQuery.builder()
+      .setPermission(request.getPermission())
+      .setPageIndex(request.getPage())
+      .setPageSize(request.getPageSize())
+      .setSearchQuery(request.getQuery());
     if (project.isPresent()) {
-      permissionQuery.component(project.get().getKey());
+      permissionQuery.setComponentUuid(project.get().uuid());
     }
-
-    return permissionQuery.build();
+    if (request.getQuery() == null) {
+      permissionQuery.withPermissionOnly();
+    }
+    return permissionQuery;
   }
 
-  private static WsGroupsResponse buildResponse(List<GroupWithPermissionDto> groupsWithPermission, GroupsWsRequest permissionRequest, int total) {
-    WsGroupsResponse.Builder groupsResponse = WsGroupsResponse.newBuilder();
-    Group.Builder group = Group.newBuilder();
-    Common.Paging.Builder paging = Common.Paging.newBuilder();
-
-    for (GroupWithPermissionDto groupWithPermission : groupsWithPermission) {
-      group
-        .clear()
-        .setName(groupWithPermission.getName())
-        .setSelected(groupWithPermission.getPermission() != null);
-      // anyone group return with id = 0
-      if (groupWithPermission.getId() != 0) {
-        group.setId(String.valueOf(groupWithPermission.getId()));
+  private static WsGroupsResponse buildResponse(List<GroupDto> groups, List<GroupRoleDto> groupPermissions, Paging paging) {
+    Multimap<Long, String> permissionsByGroupId = TreeMultimap.create();
+    groupPermissions.forEach(groupPermission -> permissionsByGroupId.put(groupPermission.getGroupId(), groupPermission.getRole()));
+    WsGroupsResponse.Builder response = WsGroupsResponse.newBuilder();
+
+    groups.forEach(group -> {
+      Group.Builder wsGroup = response.addGroupsBuilder()
+        .setName(group.getName());
+      if (group.getId() != 0L) {
+        wsGroup.setId(String.valueOf(group.getId()));
       }
-      if (groupWithPermission.getDescription() != null) {
-        group.setDescription(groupWithPermission.getDescription());
+      if (group.getDescription() != null) {
+        wsGroup.setDescription(group.getDescription());
       }
+      wsGroup.addAllPermissions(permissionsByGroupId.get(group.getId()));
+    });
 
-      groupsResponse.addGroups(group);
-    }
-
-    groupsResponse.setPaging(
-      paging
-        .setPageIndex(permissionRequest.getPage())
-        .setPageSize(permissionRequest.getPageSize())
-        .setTotal(total));
+    response.getPagingBuilder()
+      .setPageIndex(paging.pageIndex())
+      .setPageSize(paging.pageSize())
+      .setTotal(paging.total());
 
-    return groupsResponse.build();
+    return response.build();
   }
 }
index 7f013d4597ef8169b30b8ed4f6be3b98fb55d5cc..ad29a5e25a23746b9b30d5964eed7b0c8ea46809 100644 (file)
@@ -31,16 +31,16 @@ import org.sonar.db.permission.GroupWithPermissionDto;
 import org.sonar.db.permission.OldPermissionQuery;
 import org.sonar.db.permission.template.PermissionTemplateDto;
 import org.sonar.server.user.UserSession;
-import org.sonarqube.ws.WsPermissions.Group;
-import org.sonarqube.ws.WsPermissions.WsGroupsResponse;
+import org.sonarqube.ws.WsPermissions.OldGroup;
+import org.sonarqube.ws.WsPermissions.WsTemplateGroupsResponse;
 
 import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser;
 import static org.sonar.server.permission.ws.PermissionQueryParser.fromSelectionModeToMembership;
 import static org.sonar.server.permission.ws.PermissionRequestValidator.validateProjectPermission;
-import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
 import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createProjectPermissionParameter;
 import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createTemplateParameters;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PERMISSION;
 
 public class TemplateGroupsAction implements PermissionsWsAction {
   private final DbClient dbClient;
@@ -82,7 +82,7 @@ public class TemplateGroupsAction implements PermissionsWsAction {
       PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateRef);
 
       OldPermissionQuery query = buildQuery(wsRequest, template);
-      WsGroupsResponse groupsResponse = buildResponse(dbSession, query, template);
+      WsTemplateGroupsResponse groupsResponse = buildResponse(dbSession, query, template);
 
       writeProtobuf(groupsResponse, wsRequest, wsResponse);
     } finally {
@@ -90,11 +90,11 @@ public class TemplateGroupsAction implements PermissionsWsAction {
     }
   }
 
-  private WsGroupsResponse buildResponse(DbSession dbSession, OldPermissionQuery query, PermissionTemplateDto template) {
+  private WsTemplateGroupsResponse buildResponse(DbSession dbSession, OldPermissionQuery query, PermissionTemplateDto template) {
     int total = dbClient.permissionTemplateDao().countGroups(dbSession, query, template.getId());
     List<GroupWithPermissionDto> groupsWithPermission = dbClient.permissionTemplateDao().selectGroups(dbSession, query, template.getId(), query.pageOffset(), query.pageSize());
 
-    WsGroupsResponse.Builder groupsResponse = WsGroupsResponse.newBuilder();
+    WsTemplateGroupsResponse.Builder groupsResponse = WsTemplateGroupsResponse.newBuilder();
 
     for (GroupWithPermissionDto groupWithPermission : groupsWithPermission) {
       groupsResponse.addGroups(groupDtoToGroupResponse(groupWithPermission));
@@ -123,8 +123,8 @@ public class TemplateGroupsAction implements PermissionsWsAction {
     return permissionQuery.build();
   }
 
-  private static Group groupDtoToGroupResponse(GroupWithPermissionDto groupDto) {
-    Group.Builder groupBuilder = Group.newBuilder();
+  private static OldGroup groupDtoToGroupResponse(GroupWithPermissionDto groupDto) {
+    OldGroup.Builder groupBuilder = OldGroup.newBuilder();
     groupBuilder
       .setName(groupDto.getName())
       .setSelected(groupDto.getPermission() != null);
index f6bef5229f2608a5a33742c686699d33f741db8a..4d85eb8b44a40dde6dde68515991001d4da71963 100644 (file)
@@ -1,25 +1,25 @@
 {
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 100,
+    "total": 3
+  },
   "groups": [
     {
       "name": "Anyone",
-      "selected": true
+      "permissions": []
     },
     {
       "id": "1",
       "name": "sonar-administrators",
       "description": "System administrators",
-      "selected": true
+      "permissions": []
     },
     {
       "id": "2",
       "name": "sonar-users",
       "description": "Any new users created will automatically join this group",
-      "selected": true
+      "permissions": []
     }
-  ],
-  "paging": {
-    "pageIndex": 1,
-    "pageSize": 100,
-    "total": 3
-  }
+  ]
 }
index 75aab28787930aeb8add07db2e21dd8ba86a2f21..c2e51e6291b2fd05299c1f89807ef339275d8254 100644 (file)
@@ -26,11 +26,7 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.security.DefaultGroups;
-import org.sonar.api.server.ws.WebService.Param;
-import org.sonar.api.server.ws.WebService.SelectionMode;
 import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
-import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
@@ -49,7 +45,10 @@ import org.sonar.server.usergroups.ws.UserGroupFinder;
 import org.sonar.server.ws.WsActionTester;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.api.server.ws.WebService.Param.SELECTED;
+import static org.sonar.api.server.ws.WebService.Param.PAGE;
+import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
+import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
+import static org.sonar.api.web.UserRole.ADMIN;
 import static org.sonar.api.web.UserRole.ISSUE_ADMIN;
 import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
 import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
@@ -60,7 +59,6 @@ import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_P
 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_ID;
 import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_PROJECT_KEY;
 
-
 public class GroupsActionTest {
 
   @Rule
@@ -69,6 +67,7 @@ public class GroupsActionTest {
   public UserSessionRule userSession = UserSessionRule.standalone();
   @Rule
   public DbTester db = DbTester.create(System2.INSTANCE);
+
   ComponentDbTester componentDb = new ComponentDbTester(db);
   ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");
 
@@ -97,6 +96,7 @@ public class GroupsActionTest {
     GroupDto group3 = insertGroup(new GroupDto().setName("group-3-name").setDescription("group-3-description"));
     insertGroupRole(new GroupRoleDto().setGroupId(group1.getId()).setRole(SCAN_EXECUTION));
     insertGroupRole(new GroupRoleDto().setGroupId(group2.getId()).setRole(SCAN_EXECUTION));
+    insertGroupRole(new GroupRoleDto().setGroupId(null).setRole(SCAN_EXECUTION));
     insertGroupRole(new GroupRoleDto().setGroupId(group3.getId()).setRole(SYSTEM_ADMIN));
   }
 
@@ -112,30 +112,18 @@ public class GroupsActionTest {
   @Test
   public void search_with_selection() {
     String result = ws.newRequest()
-      .setParam(PARAM_PERMISSION, GlobalPermissions.SCAN_EXECUTION)
-      .setParam(SELECTED, SelectionMode.ALL.value())
-      .execute().getInput();
-
-    assertThat(result).containsSequence(DefaultGroups.ANYONE, "group-1", "group-2", "group-3");
-  }
-
-  @Test
-  public void search_with_admin_does_not_return_anyone() {
-    String result = ws.newRequest()
-      .setParam(PARAM_PERMISSION, GlobalPermissions.SYSTEM_ADMIN)
-      .setParam(SELECTED, SelectionMode.ALL.value())
+      .setParam(PARAM_PERMISSION, SCAN_EXECUTION)
       .execute().getInput();
 
-    assertThat(result).containsSequence("group-1", "group-2", "group-3")
-      .doesNotContain(DefaultGroups.ANYONE);
+    assertThat(result).containsSequence(DefaultGroups.ANYONE, "group-1", "group-2");
   }
 
   @Test
   public void search_groups_with_pagination() {
     String result = ws.newRequest()
-      .setParam(PARAM_PERMISSION, "scan")
-      .setParam(Param.PAGE_SIZE, "1")
-      .setParam(Param.PAGE, "2")
+      .setParam(PARAM_PERMISSION, SCAN_EXECUTION)
+      .setParam(PAGE_SIZE, "1")
+      .setParam(PAGE, "3")
       .execute().getInput();
 
     assertThat(result).contains("group-2")
@@ -146,8 +134,8 @@ public class GroupsActionTest {
   @Test
   public void search_groups_with_query() {
     String result = ws.newRequest()
-      .setParam(PARAM_PERMISSION, "scan")
-      .setParam(Param.TEXT_QUERY, "group-")
+      .setParam(PARAM_PERMISSION, SCAN_EXECUTION)
+      .setParam(TEXT_QUERY, "group-")
       .execute().getInput();
 
     assertThat(result)
@@ -157,14 +145,71 @@ public class GroupsActionTest {
 
   @Test
   public void search_groups_with_project_permissions() {
-    dbClient.componentDao().insert(dbSession, newProjectDto("project-uuid").setKey("project-key"));
-    ComponentDto project = dbClient.componentDao().selectOrFailByUuid(dbSession, "project-uuid");
+    userSession.login().addProjectUuidPermissions(ADMIN, "project-uuid");
+
+    ComponentDto project = componentDb.insertComponent(newProjectDto("project-uuid"));
     GroupDto group = insertGroup(new GroupDto().setName("project-group-name"));
     insertGroupRole(new GroupRoleDto()
       .setGroupId(group.getId())
       .setRole(ISSUE_ADMIN)
       .setResourceId(project.getId()));
-    userSession.login().addProjectUuidPermissions(UserRole.ADMIN, "project-uuid");
+
+    ComponentDto anotherProject = componentDb.insertComponent(newProjectDto());
+    GroupDto anotherGroup = insertGroup(new GroupDto().setName("another-project-group-name"));
+    insertGroupRole(new GroupRoleDto()
+      .setGroupId(anotherGroup.getId())
+      .setRole(ISSUE_ADMIN)
+      .setResourceId(anotherProject.getId()));
+
+    GroupDto groupWithoutPermission = insertGroup(new GroupDto().setName("group-without-permission"));
+
+    String result = ws.newRequest()
+      .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
+      .setParam(PARAM_PROJECT_ID, "project-uuid")
+      .execute().getInput();
+
+    assertThat(result).contains(group.getName())
+      .doesNotContain(anotherGroup.getName())
+      .doesNotContain(groupWithoutPermission.getName());
+  }
+
+  @Test
+  public void return_only_for_groups_with_permission_when_no_search_query() {
+    userSession.login().setGlobalPermissions(SYSTEM_ADMIN);
+
+    ComponentDto project = componentDb.insertComponent(newProjectDto("project-uuid"));
+    GroupDto group = insertGroup(new GroupDto().setName("group-with-permission"));
+    insertGroupRole(new GroupRoleDto()
+      .setGroupId(group.getId())
+      .setRole(ISSUE_ADMIN)
+      .setResourceId(project.getId()));
+
+    GroupDto groupWithoutPermission = insertGroup(new GroupDto().setName("group-without-permission"));
+    GroupDto anotherGroup = insertGroup(new GroupDto().setName("another-group"));
+
+    String result = ws.newRequest()
+      .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
+      .setParam(PARAM_PROJECT_ID, "project-uuid")
+      .setParam(TEXT_QUERY, "group-with")
+      .execute().getInput();
+
+    assertThat(result).contains(group.getName())
+      .doesNotContain(groupWithoutPermission.getName())
+      .doesNotContain(anotherGroup.getName());
+  }
+
+  @Test
+  public void return_also_for_groups_without_permission_when_search_query() {
+    userSession.login().setGlobalPermissions(SYSTEM_ADMIN);
+
+    ComponentDto project = componentDb.insertComponent(newProjectDto("project-uuid"));
+    GroupDto group = insertGroup(new GroupDto().setName("project-group-name"));
+    insertGroupRole(new GroupRoleDto()
+      .setGroupId(group.getId())
+      .setRole(ISSUE_ADMIN)
+      .setResourceId(project.getId()));
+
+    GroupDto groupWithoutPermission = insertGroup(new GroupDto().setName("group-without-permission"));
 
     String result = ws.newRequest()
       .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
@@ -172,9 +217,7 @@ public class GroupsActionTest {
       .execute().getInput();
 
     assertThat(result).contains("project-group-name")
-      .doesNotContain("group-1")
-      .doesNotContain("group-2")
-      .doesNotContain("group-3");
+      .doesNotContain(groupWithoutPermission.getName());
   }
 
   @Test
@@ -202,7 +245,7 @@ public class GroupsActionTest {
     expectedException.expect(BadRequestException.class);
 
     ws.newRequest()
-      .setParam(PARAM_PERMISSION, UserRole.ISSUE_ADMIN)
+      .setParam(PARAM_PERMISSION, ISSUE_ADMIN)
       .execute();
   }
 
@@ -226,14 +269,6 @@ public class GroupsActionTest {
       .execute();
   }
 
-  @Test
-  public void fail_if_permission_is_not_specified() {
-    expectedException.expect(IllegalArgumentException.class);
-
-    ws.newRequest()
-      .execute();
-  }
-
   @Test
   public void fail_if_project_uuid_and_project_key_are_provided() {
     expectedException.expect(BadRequestException.class);
index f48cdd22d7b25a2149b2e14ea0b209366af48cb0..e67f7047034d1e43095db6a4182564ba7c1ade84 100644 (file)
@@ -1,19 +1,29 @@
 {
+  "paging": {
+    "pageIndex": 1,
+    "pageSize": 20,
+    "total": 3
+  },
   "groups": [
+    {
+      "name": "Anyone",
+      "permissions": [
+        "scan"
+      ]
+    },
     {
       "name": "group-1-name",
       "description": "group-1-description",
-      "selected": true
+      "permissions": [
+        "scan"
+      ]
     },
     {
       "name": "group-2-name",
       "description": "group-2-description",
-      "selected": true
+      "permissions": [
+        "scan"
+      ]
     }
-  ],
-  "paging": {
-    "pageIndex": 1,
-    "pageSize": 100,
-    "total": 2
-  }
+  ]
 }
index a7f6a042376fbed55c2325366c3b41a8cf2567d5..c47fff65b9c6b11bbd82d11cbeaadab893065d84 100644 (file)
@@ -134,6 +134,7 @@ public class PermissionQuery {
     }
 
     public Builder setPermission(@Nullable String permission) {
+      this.withPermissionOnly = permission != null;
       this.permission = permission;
       return this;
     }
index 2cf3f674856107603e39131f9801fdebbf28d4c9..fe18bc201559fb6ed1e675771d763e09209fc5b5 100644 (file)
@@ -22,8 +22,6 @@ package org.sonarqube.ws.client.permission;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
-import static java.util.Objects.requireNonNull;
-
 public class GroupsWsRequest {
   private String permission;
   private String projectId;
@@ -31,14 +29,14 @@ public class GroupsWsRequest {
   private Integer page;
   private Integer pageSize;
   private String query;
-  private String selected;
 
+  @CheckForNull
   public String getPermission() {
     return permission;
   }
 
-  public GroupsWsRequest setPermission(String permission) {
-    this.permission = requireNonNull(permission, "permission must not be null");
+  public GroupsWsRequest setPermission(@Nullable String permission) {
+    this.permission = permission;
     return this;
   }
 
@@ -91,13 +89,4 @@ public class GroupsWsRequest {
     this.query = query;
     return this;
   }
-
-  public String getSelected() {
-    return selected;
-  }
-
-  public GroupsWsRequest setSelected(String selected) {
-    this.selected = requireNonNull(selected, "selected must not be null");
-    return this;
-  }
 }
index db7965e791f77bc2664da2ae5e82c471181d96de..a0a53cf8427ade4f35e8c43ee947fba9709d1342 100644 (file)
@@ -58,7 +58,6 @@ public class PermissionsService extends BaseService {
       .setParam(PARAM_PROJECT_KEY, request.getProjectKey())
       .setParam("p", request.getPage())
       .setParam("ps", request.getPageSize())
-      .setParam("selected", request.getSelected())
       .setParam("q", request.getQuery());
     return call(get, WsPermissions.WsGroupsResponse.parser());
   }
index bbe40511eb4eaf5bffefd095c2873b3002bcdbf8..3f9a31372ff9fca472a3d31fec98d00ced955909 100644 (file)
@@ -39,12 +39,17 @@ message UsersWsResponse {
 }
 
 // WS api/permissions/groups for internal use only
-// and WS api/permissions/template_groups for internal use only
 message WsGroupsResponse {
   optional sonarqube.ws.commons.Paging paging = 1;
   repeated Group groups = 2;
 }
 
+// WS api/permissions/template_groups for internal use only
+message WsTemplateGroupsResponse {
+  optional sonarqube.ws.commons.Paging paging = 1;
+  repeated OldGroup groups = 2;
+}
+
 message WsSearchGlobalPermissionsResponse {
   repeated Permission permissions = 1;
 }
@@ -117,9 +122,16 @@ message User {
   repeated string permissions = 4;
 }
 
-message Group {
+message OldGroup {
   optional string id = 1;
   optional string name = 2;
   optional string description = 3;
   optional bool selected = 4;
 }
+
+message Group {
+  optional string id = 1;
+  optional string name = 2;
+  optional string description = 3;
+  repeated string permissions = 4;
+}
index f430c5dd5f8dc62b9ed52804eaebf0e27daf63f4..1b9fcb4ed95ba62574eae0046472cc7c0dfafbc8 100644 (file)
@@ -84,7 +84,6 @@ public class PermissionsServiceTest {
       .setProjectKey(PROJECT_KEY_VALUE)
       .setPage(PAGE_VALUE)
       .setPageSize(PAGE_SIZE_VALUE)
-      .setSelected(SELECTED_VALUE)
       .setQuery(QUERY_VALUE));
 
     assertThat(serviceTester.getGetParser()).isSameAs(WsPermissions.WsGroupsResponse.parser());
@@ -96,7 +95,6 @@ public class PermissionsServiceTest {
       .hasParam(PARAM_PROJECT_KEY, PROJECT_KEY_VALUE)
       .hasParam(PARAM_P, PAGE_VALUE)
       .hasParam(PARAM_PS, PAGE_SIZE_VALUE)
-      .hasParam(PARAM_SELECTED, SELECTED_VALUE)
       .hasParam(PARAM_Q, QUERY_VALUE)
       .andNoOtherParam();
   }