]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7106 WS api/permissions/bulk_apply_template bulk apply permission template
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Thu, 17 Mar 2016 17:17:38 +0000 (18:17 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 18 Mar 2016 08:03:33 +0000 (09:03 +0100)
server/sonar-server/src/main/java/org/sonar/server/permission/PermissionService.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWsModule.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/template/BulkApplyTemplateAction.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/BulkApplyTemplateActionTest.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/component/ComponentQuery.java
sonar-db/src/main/resources/org/sonar/db/component/ComponentMapper.xml
sonar-db/src/test/java/org/sonar/db/component/ComponentDaoTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/permission/BulkApplyTemplateWsRequest.java [new file with mode: 0644]

index e0698ee5d69a86b32ecd6e608a53df5a9edb9ea4..882e16aa5681ff9320ac351d058d361f5d8229ac 100644 (file)
@@ -85,20 +85,25 @@ public class PermissionService {
   public void applyPermissionTemplate(ApplyPermissionTemplateQuery query) {
     DbSession dbSession = dbClient.openSession(false);
     try {
-      if (query.getComponentKeys().size() == 1) {
-        checkProjectAdminUserByComponentKey(userSession, query.getComponentKeys().get(0));
-      } else {
-        checkGlobalAdminUser(userSession);
-      }
-
-      for (String componentKey : query.getComponentKeys()) {
-        ComponentDto component = componentFinder.getByKey(dbSession, componentKey);
-        permissionRepository.applyPermissionTemplate(dbSession, query.getTemplateUuid(), component.getId());
-      }
-      dbSession.commit();
+      applyPermissionTemplate(dbSession, query);
     } finally {
       dbClient.closeSession(dbSession);
     }
+  }
+
+  public void applyPermissionTemplate(DbSession dbSession, ApplyPermissionTemplateQuery query) {
+    if (query.getComponentKeys().size() == 1) {
+      checkProjectAdminUserByComponentKey(userSession, query.getComponentKeys().get(0));
+    } else {
+      checkGlobalAdminUser(userSession);
+    }
+
+    // TODO apply permission templates in on query instead of on on each project
+    for (String componentKey : query.getComponentKeys()) {
+      ComponentDto component = componentFinder.getByKey(dbSession, componentKey);
+      permissionRepository.applyPermissionTemplate(dbSession, query.getTemplateUuid(), component.getId());
+    }
+    dbSession.commit();
 
     indexProjectPermissions();
   }
index ea98a083d1fe19176c0508d7f8092b26ea9e34a6..1f30fd0875f2060a604142804f113c975f5badb7 100644 (file)
@@ -23,6 +23,7 @@ import org.sonar.core.platform.Module;
 import org.sonar.server.permission.ws.template.AddGroupToTemplateAction;
 import org.sonar.server.permission.ws.template.AddUserToTemplateAction;
 import org.sonar.server.permission.ws.template.ApplyTemplateAction;
+import org.sonar.server.permission.ws.template.BulkApplyTemplateAction;
 import org.sonar.server.permission.ws.template.CreateTemplateAction;
 import org.sonar.server.permission.ws.template.DefaultPermissionTemplateFinder;
 import org.sonar.server.permission.ws.template.RemoveGroupFromTemplateAction;
@@ -58,6 +59,7 @@ public class PermissionsWsModule extends Module {
       SearchTemplatesAction.class,
       TemplateUsersAction.class,
       TemplateGroupsAction.class,
+      BulkApplyTemplateAction.class,
       // utility classes
       PermissionChangeBuilder.class,
       SearchProjectPermissionsDataLoader.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/template/BulkApplyTemplateAction.java b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/template/BulkApplyTemplateAction.java
new file mode 100644 (file)
index 0000000..702bf50
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission.ws.template;
+
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.sonar.api.i18n.I18n;
+import org.sonar.api.resources.ResourceTypes;
+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.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentDtoFunctions;
+import org.sonar.db.component.ComponentQuery;
+import org.sonar.db.permission.PermissionTemplateDto;
+import org.sonar.server.permission.ApplyPermissionTemplateQuery;
+import org.sonar.server.permission.PermissionService;
+import org.sonar.server.permission.ws.PermissionDependenciesFinder;
+import org.sonar.server.permission.ws.PermissionsWsAction;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.client.permission.BulkApplyTemplateWsRequest;
+
+import static org.sonar.server.component.ResourceTypeFunctions.RESOURCE_TYPE_TO_QUALIFIER;
+import static org.sonar.server.permission.ws.PermissionsWsParametersBuilder.createTemplateParameters;
+import static org.sonar.server.permission.ws.WsTemplateRef.newTemplateRef;
+import static org.sonar.server.ws.WsParameterBuilder.QualifierParameterContext.newQualifierParameterContext;
+import static org.sonar.server.ws.WsParameterBuilder.createRootQualifierParameter;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_QUALIFIER;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME;
+
+public class BulkApplyTemplateAction implements PermissionsWsAction {
+  private final DbClient dbClient;
+  private final PermissionService permissionService;
+  private final PermissionDependenciesFinder finder;
+  private final UserSession userSession;
+  private final I18n i18n;
+  private final ResourceTypes resourceTypes;
+
+  public BulkApplyTemplateAction(DbClient dbClient, PermissionService permissionService, PermissionDependenciesFinder finder, UserSession userSession, I18n i18n,
+    ResourceTypes resourceTypes) {
+    this.dbClient = dbClient;
+    this.permissionService = permissionService;
+    this.finder = finder;
+    this.userSession = userSession;
+    this.i18n = i18n;
+    this.resourceTypes = resourceTypes;
+  }
+
+  @Override
+  public void define(WebService.NewController context) {
+    WebService.NewAction action = context.createAction("bulk_apply_template")
+      .setDescription("Apply a permission template to several projects.<br />" +
+        "The template id or name must be provided.<br />" +
+        "It requires administration permissions to access.")
+      .setPost(true)
+      .setSince("5.5")
+      .setHandler(this);
+
+    action.createParam(Param.TEXT_QUERY)
+      .setDescription("Limit search to: <ul>" +
+        "<li>project names that contain the supplied string</li>" +
+        "<li>project keys that are exactly the same as the supplied string</li>" +
+        "</ul>")
+      .setExampleValue("apac");
+    createRootQualifierParameter(action, newQualifierParameterContext(userSession, i18n, resourceTypes));
+    createTemplateParameters(action);
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    doHandle(toBulkApplyTemplateWsRequest(request));
+    response.noContent();
+  }
+
+  private void doHandle(BulkApplyTemplateWsRequest request) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      PermissionTemplateDto template = finder.getTemplate(dbSession, newTemplateRef(request.getTemplateId(), request.getTemplateName()));
+      ComponentQuery componentQuery = ComponentQuery.builder()
+        .setNameOrKeyQuery(request.getQuery())
+        .setQualifiers(qualifiers(request.getQualifier()))
+        .build();
+      List<ComponentDto> rootComponents = dbClient.componentDao().selectByQuery(dbSession, componentQuery, 0, Integer.MAX_VALUE);
+      if (rootComponents.isEmpty()) {
+        return;
+      }
+
+      ApplyPermissionTemplateQuery query = ApplyPermissionTemplateQuery.create(
+        template.getUuid(),
+        Lists.transform(rootComponents, ComponentDtoFunctions.toKey()));
+      permissionService.applyPermissionTemplate(dbSession, query);
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private String[] qualifiers(@Nullable String qualifier) {
+    return qualifier == null
+      ? Collections2.transform(resourceTypes.getRoots(), RESOURCE_TYPE_TO_QUALIFIER).toArray(new String[resourceTypes.getRoots().size()])
+      : new String[] {qualifier};
+  }
+
+  private static BulkApplyTemplateWsRequest toBulkApplyTemplateWsRequest(Request request) {
+    return new BulkApplyTemplateWsRequest()
+      .setTemplateId(request.param(PARAM_TEMPLATE_ID))
+      .setTemplateName(request.param(PARAM_TEMPLATE_NAME))
+      .setQualifier(request.param(PARAM_QUALIFIER))
+      .setQuery(request.param(Param.TEXT_QUERY));
+  }
+}
index 4d0cefca1e03335673d0efed52fc1050b8988466..aaf3b6d3308112cb250e577e54a09b6b0e6157d4 100644 (file)
@@ -29,6 +29,6 @@ public class PermissionsWsModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new PermissionsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(28);
+    assertThat(container.size()).isEqualTo(2 + 27);
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/BulkApplyTemplateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/template/BulkApplyTemplateActionTest.java
new file mode 100644 (file)
index 0000000..629c32a
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.permission.ws.template;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+import java.util.List;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.server.ws.WebService.Param;
+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;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ResourceTypesRule;
+import org.sonar.db.permission.GroupWithPermissionDto;
+import org.sonar.db.permission.PermissionQuery;
+import org.sonar.db.permission.PermissionRepository;
+import org.sonar.db.permission.PermissionTemplateDto;
+import org.sonar.db.permission.UserWithPermissionDto;
+import org.sonar.db.user.GroupDbTester;
+import org.sonar.db.user.GroupDto;
+import org.sonar.db.user.GroupRoleDto;
+import org.sonar.db.user.UserDbTester;
+import org.sonar.db.user.UserDto;
+import org.sonar.db.user.UserRoleDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.i18n.I18nRule;
+import org.sonar.server.issue.index.IssueAuthorizationIndexer;
+import org.sonar.server.permission.PermissionService;
+import org.sonar.server.permission.ws.PermissionDependenciesFinder;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.usergroups.ws.UserGroupFinder;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.sonar.db.component.ComponentTesting.newDeveloper;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.db.component.ComponentTesting.newView;
+import static org.sonar.db.permission.PermissionTemplateTesting.newPermissionTemplateDto;
+import static org.sonar.db.user.GroupMembershipQuery.IN;
+import static org.sonar.db.user.GroupTesting.newGroupDto;
+import static org.sonar.db.user.UserTesting.newUserDto;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_QUALIFIER;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_ID;
+import static org.sonarqube.ws.client.permission.PermissionsWsParameters.PARAM_TEMPLATE_NAME;
+
+public class BulkApplyTemplateActionTest {
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone().login("login").setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+  ComponentDbTester componentDb = new ComponentDbTester(db);
+  UserDbTester userDb = new UserDbTester(db);
+  GroupDbTester groupDb = new GroupDbTester(db);
+  DbClient dbClient = db.getDbClient();
+  DbSession dbSession = db.getSession();
+
+  ResourceTypesRule resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT, Qualifiers.VIEW, "DEV");
+  I18nRule i18n = new I18nRule();
+  WsActionTester ws;
+
+  UserDto user1;
+  UserDto user2;
+  GroupDto group1;
+  GroupDto group2;
+  PermissionTemplateDto template1;
+  PermissionTemplateDto template2;
+  IssueAuthorizationIndexer issueAuthorizationIndexer = mock(IssueAuthorizationIndexer.class);
+
+  @Before
+  public void setUp() {
+    PermissionRepository repository = new PermissionRepository(dbClient, new Settings());
+    ComponentFinder componentFinder = new ComponentFinder(dbClient);
+    PermissionService permissionService = new PermissionService(dbClient, repository, issueAuthorizationIndexer, userSession, componentFinder);
+    PermissionDependenciesFinder permissionDependenciesFinder = new PermissionDependenciesFinder(dbClient, componentFinder, new UserGroupFinder(dbClient), resourceTypes);
+
+    BulkApplyTemplateAction underTest = new BulkApplyTemplateAction(dbClient, permissionService, permissionDependenciesFinder, userSession, i18n, resourceTypes);
+    ws = new WsActionTester(underTest);
+
+    user1 = userDb.insertUser(newUserDto().setLogin("user-login-1"));
+    user2 = userDb.insertUser(newUserDto().setLogin("user-login-2"));
+    group1 = groupDb.insertGroup(newGroupDto().setName("group-name-1"));
+    group2 = groupDb.insertGroup(newGroupDto().setName("group-name-2"));
+
+    // template 1
+    template1 = insertTemplate(newPermissionTemplateDto().setUuid("permission-template-uuid-1"));
+    addUserToTemplate(user1, template1, UserRole.CODEVIEWER);
+    addUserToTemplate(user2, template1, UserRole.ISSUE_ADMIN);
+    addGroupToTemplate(group1, template1, UserRole.ADMIN);
+    addGroupToTemplate(group2, template1, UserRole.USER);
+    // template 2
+    template2 = insertTemplate(newPermissionTemplateDto().setUuid("permission-template-uuid-2"));
+    addUserToTemplate(user1, template2, UserRole.USER);
+    addUserToTemplate(user2, template2, UserRole.USER);
+    addGroupToTemplate(group1, template2, UserRole.USER);
+    addGroupToTemplate(group2, template2, UserRole.USER);
+
+    commit();
+  }
+
+  @Test
+  public void bulk_apply_template_by_template_uuid() {
+    ComponentDto project = componentDb.insertComponent(newProjectDto());
+    ComponentDto view = componentDb.insertComponent(newView());
+    ComponentDto developer = componentDb.insertComponent(newDeveloper("developer-name"));
+    addUserPermissionToProject(user1, developer, UserRole.ADMIN);
+    addUserPermissionToProject(user2, developer, UserRole.ADMIN);
+    addGroupPermissionToProject(group1, developer, UserRole.ADMIN);
+    addGroupPermissionToProject(group2, developer, UserRole.ADMIN);
+    db.commit();
+
+    call(ws.newRequest().setParam(PARAM_TEMPLATE_ID, template1.getUuid()));
+
+    assertTemplate1AppliedToProject(project);
+    assertTemplate1AppliedToProject(view);
+    assertTemplate1AppliedToProject(developer);
+  }
+
+  @Test
+  public void bulk_apply_template_by_template_name() {
+    ComponentDto project = componentDb.insertComponent(newProjectDto());
+
+    call(ws.newRequest().setParam(PARAM_TEMPLATE_NAME, template1.getName()));
+
+    assertTemplate1AppliedToProject(project);
+  }
+
+  @Test
+  public void apply_template_by_qualifier() {
+    ComponentDto project = componentDb.insertComponent(newProjectDto());
+    ComponentDto view = componentDb.insertComponent(newView());
+
+    call(ws.newRequest()
+      .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
+      .setParam(PARAM_QUALIFIER, project.qualifier()));
+
+    assertTemplate1AppliedToProject(project);
+    assertNoPermissionOnProject(view);
+  }
+
+  @Test
+  public void apply_template_by_query_on_name_and_key() {
+    ComponentDto projectFoundByKey = newProjectDto().setKey("sonar");
+    componentDb.insertProjectAndSnapshot(projectFoundByKey);
+    ComponentDto projectFoundByName = newProjectDto().setName("name-sonar-name");
+    componentDb.insertProjectAndSnapshot(projectFoundByName);
+    // match must be exact on key
+    ComponentDto projectUntouched = newProjectDto().setKey("new-sonar").setName("project-name");
+    componentDb.insertProjectAndSnapshot(projectUntouched);
+    componentDb.indexProjects();
+
+    call(ws.newRequest()
+      .setParam(PARAM_TEMPLATE_ID, template1.getUuid())
+      .setParam(Param.TEXT_QUERY, "sonar"));
+
+    assertTemplate1AppliedToProject(projectFoundByKey);
+    assertTemplate1AppliedToProject(projectFoundByName);
+    assertNoPermissionOnProject(projectUntouched);
+  }
+
+  @Test
+  public void fail_if_no_template_parameter() {
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Template name or template id must be provided, not both.");
+
+    call(ws.newRequest());
+  }
+
+  @Test
+  public void fail_if_template_name_is_incorrect() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Permission template with id 'unknown-template-uuid' is not found");
+
+    call(ws.newRequest().setParam(PARAM_TEMPLATE_ID, "unknown-template-uuid"));
+  }
+
+  private void call(TestRequest request) {
+    request.execute();
+    db.commit();
+  }
+
+  private void assertTemplate1AppliedToProject(ComponentDto project) {
+    assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).extracting("name").containsExactly(group1.getName());
+    assertThat(selectProjectPermissionGroups(project, UserRole.USER)).extracting("name").containsExactly(group2.getName());
+    assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
+    assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).extracting("login").containsExactly(user1.getLogin());
+    assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).extracting("login").containsExactly(user2.getLogin());
+  }
+
+  private void assertNoPermissionOnProject(ComponentDto project) {
+    assertThat(selectProjectPermissionGroups(project, UserRole.ADMIN)).isEmpty();
+    assertThat(selectProjectPermissionGroups(project, UserRole.CODEVIEWER)).isEmpty();
+    assertThat(selectProjectPermissionGroups(project, UserRole.ISSUE_ADMIN)).isEmpty();
+    assertThat(selectProjectPermissionGroups(project, UserRole.USER)).isEmpty();
+    assertThat(selectProjectPermissionUsers(project, UserRole.ADMIN)).isEmpty();
+    assertThat(selectProjectPermissionUsers(project, UserRole.CODEVIEWER)).isEmpty();
+    assertThat(selectProjectPermissionUsers(project, UserRole.ISSUE_ADMIN)).isEmpty();
+    assertThat(selectProjectPermissionUsers(project, UserRole.USER)).isEmpty();
+  }
+
+  private PermissionTemplateDto insertTemplate(PermissionTemplateDto template) {
+    return dbClient.permissionTemplateDao().insert(dbSession, template);
+  }
+
+  private void addUserToTemplate(UserDto user, PermissionTemplateDto permissionTemplate, String permission) {
+    dbClient.permissionTemplateDao().insertUserPermission(dbSession, permissionTemplate.getId(), user.getId(), permission);
+  }
+
+  private void addGroupToTemplate(GroupDto group, PermissionTemplateDto permissionTemplate, String permission) {
+    dbClient.permissionTemplateDao().insertGroupPermission(dbSession, permissionTemplate.getId(), group.getId(), permission);
+  }
+
+  private void addUserPermissionToProject(UserDto user, ComponentDto project, String permission) {
+    dbClient.roleDao().insertUserRole(dbSession, new UserRoleDto()
+      .setRole(permission)
+      .setUserId(user.getId())
+      .setResourceId(project.getId()));
+  }
+
+  private void addGroupPermissionToProject(GroupDto group, ComponentDto project, String permission) {
+    dbClient.roleDao().insertGroupRole(dbSession, new GroupRoleDto()
+      .setRole(permission)
+      .setResourceId(project.getId())
+      .setGroupId(group.getId()));
+  }
+
+  private List<GroupWithPermissionDto> selectProjectPermissionGroups(ComponentDto project, String permission) {
+    return FluentIterable.from(dbClient.permissionDao().selectGroups(dbSession, query(permission), project.getId()))
+      .filter(new PermissionNotNull())
+      .toList();
+  }
+
+  private List<UserWithPermissionDto> selectProjectPermissionUsers(ComponentDto project, String permission) {
+    return dbClient.permissionDao().selectUsers(dbSession, query(permission), project.getId(), 0, Integer.MAX_VALUE);
+  }
+
+  private void commit() {
+    dbSession.commit();
+  }
+
+  private static PermissionQuery query(String permission) {
+    return PermissionQuery.builder().membership(IN).permission(permission).build();
+  }
+
+  private static class PermissionNotNull implements Predicate<GroupWithPermissionDto> {
+    @Override
+    public boolean apply(@Nullable GroupWithPermissionDto input) {
+      return input.getPermission() != null;
+    }
+  }
+}
index 538ab6e8f463ec5e0d14fdcf895642ea67e81776..fbff51076e6d4e5cc5cecc48409e3ddb5af197d1 100644 (file)
@@ -89,7 +89,7 @@ public class ComponentQuery {
     }
 
     public Builder setQualifiers(String... qualifiers) {
-      this.qualifiers = validateQualifiers(qualifiers);
+      this.qualifiers = qualifiers;
       return this;
     }
 
index 8dc2a0e550cfcad43515ce20ccf62e4bce3d6fb6..d310528ad8abb9291e249095812689b871e75563 100644 (file)
     <where>
       AND p.enabled=${_true}
       AND p.copy_resource_id is null
+      <if test="query.qualifiers!=null">
       AND p.qualifier in
-      <foreach collection="query.qualifiers" item="qualifier" open="(" close=")" separator=",">
-        #{qualifier}
-      </foreach>
+        <foreach collection="query.qualifiers" item="qualifier" open="(" close=")" separator=",">
+          #{qualifier}
+        </foreach>
+      </if>
       <if test="query.language!=null">
         AND p.language = #{query.language}
       </if>
             SELECT ri.resource_id
             FROM resource_index ri
             WHERE ri.kee like #{query.nameOrKeyQueryToSqlForResourceIndex} ESCAPE '/'
+            <if test="query.qualifiers!=null">
             AND ri.qualifier in
-            <foreach collection="query.qualifiers" item="qualifier" open="(" close=")" separator=",">
-              #{qualifier}
-            </foreach>
+              <foreach collection="query.qualifiers" item="qualifier" open="(" close=")" separator=",">
+                #{qualifier}
+              </foreach>
+            </if>
           )
         )
       </if>
index 0d835b443def8211ecbe24c1ce09f68ac76a96a8..1026c04ab0453542af2cde84e08ea6cd77956fd6 100644 (file)
@@ -46,7 +46,6 @@ import static org.sonar.db.component.ComponentTesting.newProjectDto;
 import static org.sonar.db.component.ComponentTesting.newSubView;
 import static org.sonar.db.component.ComponentTesting.newView;
 
-
 public class ComponentDaoTest {
 
   @Rule
@@ -679,7 +678,6 @@ public class ComponentDaoTest {
     for (int i = 9; i >= 1; i--) {
       componentDb.insertProjectAndSnapshot(newProjectDto().setName("project-" + i));
     }
-    db.commit();
     componentDb.indexProjects();
 
     ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("oJect").setQualifiers(Qualifiers.PROJECT).build();
@@ -693,7 +691,6 @@ public class ComponentDaoTest {
   @Test
   public void select_by_query_name_with_special_characters() {
     componentDb.insertProjectAndSnapshot(newProjectDto().setName("project-\\_%/-name"));
-    db.commit();
     componentDb.indexProjects();
 
     ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("-\\_%/-").setQualifiers(Qualifiers.PROJECT).build();
@@ -705,9 +702,7 @@ public class ComponentDaoTest {
 
   @Test
   public void select_by_query_key_with_special_characters() {
-    componentDb.insertProjectAndSnapshot(newProjectDto()
-      .setKey("project-_%-key"));
-    db.commit();
+    componentDb.insertProjectAndSnapshot(newProjectDto().setKey("project-_%-key"));
     componentDb.indexProjects();
 
     ComponentQuery query = ComponentQuery.builder().setNameOrKeyQuery("project-_%-key").setQualifiers(Qualifiers.PROJECT).build();
@@ -721,7 +716,6 @@ public class ComponentDaoTest {
   public void select_by_query_filter_on_language() {
     componentDb.insertComponent(newProjectDto().setKey("java-project-key").setLanguage("java"));
     componentDb.insertComponent(newProjectDto().setKey("cpp-project-key").setLanguage("cpp"));
-    db.commit();
 
     ComponentQuery query = ComponentQuery.builder().setLanguage("java").setQualifiers(Qualifiers.PROJECT).build();
     List<ComponentDto> result = underTest.selectByQuery(dbSession, query, 0, 10);
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/permission/BulkApplyTemplateWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/permission/BulkApplyTemplateWsRequest.java
new file mode 100644 (file)
index 0000000..f5271f8
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonarqube.ws.client.permission;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+public class BulkApplyTemplateWsRequest {
+  private String templateId;
+  private String templateName;
+  private String query;
+  private String qualifier;
+
+  @CheckForNull
+  public String getTemplateId() {
+    return templateId;
+  }
+
+  public BulkApplyTemplateWsRequest setTemplateId(@Nullable String templateId) {
+    this.templateId = templateId;
+    return this;
+  }
+
+  @CheckForNull
+  public String getTemplateName() {
+    return templateName;
+  }
+
+  public BulkApplyTemplateWsRequest setTemplateName(@Nullable String templateName) {
+    this.templateName = templateName;
+    return this;
+  }
+
+  @CheckForNull
+  public String getQuery() {
+    return query;
+  }
+
+  public BulkApplyTemplateWsRequest setQuery(@Nullable String query) {
+    this.query = query;
+    return this;
+  }
+
+  @CheckForNull
+  public String getQualifier() {
+    return qualifier;
+  }
+
+  public BulkApplyTemplateWsRequest setQualifier(@Nullable String qualifier) {
+    this.qualifier = qualifier;
+    return this;
+  }
+}