]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6499 WS permissions/set_default_template set default permission template for...
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 2 Sep 2015 08:31:20 +0000 (10:31 +0200)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 2 Sep 2015 14:36:19 +0000 (16:36 +0200)
14 files changed:
server/sonar-server/src/main/java/org/sonar/server/permission/DefaultPermissionTemplates.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddGroupToTemplateAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/AddUserToTemplateAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/DeleteTemplateAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/Parameters.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionRequestValidator.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/RemoveGroupFromTemplateAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/RemoveUserFromTemplateAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/SetDefaultTemplateAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/permission/ws/UpdateTemplateAction.java
server/sonar-server/src/main/java/org/sonar/server/permission/ws/WsProjectRef.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/PermissionsWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/permission/ws/SetDefaultTemplateActionTest.java [new file with mode: 0644]

index ed1743a0537b25ad7774afda3f2d90d7ab84b1ac..b7618e2e1851ae17ccdfbe86f856c2b75eda2866 100644 (file)
@@ -24,9 +24,9 @@ import static java.lang.String.format;
 
 public class DefaultPermissionTemplates {
   public static final String DEFAULT_TEMPLATE_PROPERTY = "sonar.permission.template.default";
-  private static final String DEFAULT_ROOT_QUALIFIER_TEMPLATE_PROPERTY = "sonar.permission.template.%s.default";
+  private static final String DEFAULT_ROOT_QUALIFIER_TEMPLATE_PATTERN = "sonar.permission.template.%s.default";
 
   public static String defaultRootQualifierTemplateProperty(String qualifier) {
-    return format(DEFAULT_ROOT_QUALIFIER_TEMPLATE_PROPERTY, qualifier);
+    return format(DEFAULT_ROOT_QUALIFIER_TEMPLATE_PATTERN, qualifier);
   }
 }
index e48bb2232d4816a8a64d2a35b5a91e09a01444a8..524b99f8787ca1cb3e2f54b5e0e04291598513de 100644 (file)
@@ -75,7 +75,7 @@ public class AddGroupToTemplateAction implements PermissionsWsAction {
   public void handle(Request wsRequest, Response wsResponse) throws Exception {
     checkGlobalAdminUser(userSession);
 
-    String templateKey = wsRequest.mandatoryParam(PARAM_TEMPLATE_ID_EXPLICIT);
+    String templateUuid = wsRequest.mandatoryParam(PARAM_TEMPLATE_ID_EXPLICIT);
     String permission = wsRequest.mandatoryParam(PARAM_PERMISSION);
     WsGroupRef group = WsGroupRef.fromRequest(wsRequest);
 
@@ -84,7 +84,7 @@ public class AddGroupToTemplateAction implements PermissionsWsAction {
       validateProjectPermission(permission);
       validateNotAnyoneAndAdminPermission(permission, group.name());
 
-      PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateKey);
+      PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateUuid);
       GroupDto groupDto = dependenciesFinder.getGroup(dbSession, group);
 
       if (!groupAlreadyAdded(dbSession, template.getId(), groupDto, permission)) {
index 7cb65ba0be5ce163114ce01b04089d5958f59ca7..7e9656438e6db6cf200a7bc34b33d9ea8a303361 100644 (file)
@@ -74,14 +74,14 @@ public class AddUserToTemplateAction implements PermissionsWsAction {
   public void handle(Request wsRequest, Response wsResponse) throws Exception {
     checkGlobalAdminUser(userSession);
 
-    String templateKey = wsRequest.mandatoryParam(PARAM_TEMPLATE_ID_EXPLICIT);
+    String templateUuid = wsRequest.mandatoryParam(PARAM_TEMPLATE_ID_EXPLICIT);
     String permission = wsRequest.mandatoryParam(PARAM_PERMISSION);
     final String userLogin = wsRequest.mandatoryParam(PARAM_USER_LOGIN);
 
     DbSession dbSession = dbClient.openSession(false);
     try {
       validateProjectPermission(permission);
-      PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateKey);
+      PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateUuid);
       UserDto user = dependenciesFinder.getUser(dbSession, userLogin);
 
       if (!isUserAlreadyAdded(dbSession, template.getId(), userLogin, permission)) {
index 1e25d69cad12d2f73dcf05f4b402325eec60242a..bdafb42fdeb1b166cb1f6d805ad407193ea9c4bc 100644 (file)
@@ -31,7 +31,7 @@ import org.sonar.server.user.UserSession;
 
 import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser;
 import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_ID;
-import static org.sonar.server.permission.ws.Parameters.createTemplateKeyParameter;
+import static org.sonar.server.permission.ws.Parameters.createTemplateIdParameter;
 import static org.sonar.server.ws.WsUtils.checkRequest;
 
 public class DeleteTemplateAction implements PermissionsWsAction {
@@ -56,7 +56,7 @@ public class DeleteTemplateAction implements PermissionsWsAction {
       .setPost(true)
       .setHandler(this);
 
-    createTemplateKeyParameter(action);
+    createTemplateIdParameter(action);
   }
 
   @Override
index b008c1577c76aa3ac5690b41c7f7318d6981c292..f2ecba4137c038b30d00752ec18f646671bf8208 100644 (file)
@@ -41,6 +41,8 @@ class Parameters {
   static final String PARAM_TEMPLATE_DESCRIPTION = "description";
   static final String PARAM_TEMPLATE_PATTERN = "projectKeyPattern";
 
+  static final String PARAM_QUALIFIER = "qualifier";
+
   private static final String PERMISSION_PARAM_DESCRIPTION = format("Permission" +
     "<ul>" +
     "<li>Possible values for global permissions: %s</li>" +
@@ -125,7 +127,7 @@ class Parameters {
       .setExampleValue("Permissions for all projects related to the financial service");
   }
 
-  static void createTemplateKeyParameter(NewAction action) {
+  static void createTemplateIdParameter(NewAction action) {
     action.createParam(PARAM_TEMPLATE_ID)
       .setRequired(true)
       .setDescription("Key")
index 287547487884966df5b6332b9579da76466539d4..5accd0d63aa23564744176b067fe69801f28305a 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.sonar.server.permission.ws;
 
+import java.util.Set;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 import javax.annotation.Nullable;
@@ -32,6 +33,7 @@ import static java.lang.String.format;
 import static org.apache.commons.lang.StringUtils.isBlank;
 import static org.sonar.api.security.DefaultGroups.isAnyone;
 import static org.sonar.server.permission.ws.Parameters.PARAM_PERMISSION;
+import static org.sonar.server.permission.ws.Parameters.PARAM_QUALIFIER;
 import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_PATTERN;
 import static org.sonar.server.ws.WsUtils.checkRequest;
 
@@ -62,6 +64,11 @@ public class PermissionRequestValidator {
     checkRequest(!isBlank(name), MSG_TEMPLATE_NAME_NOT_BLANK);
   }
 
+  public static void validateQualifier(String qualifier, Set<String> rootQualifiers) {
+    checkRequest(rootQualifiers.contains(qualifier),
+      format("The '%s' parameter must be one of %s. '%s' was passed.", PARAM_QUALIFIER, rootQualifiers, qualifier));
+  }
+
   public static void validateProjectPattern(@Nullable String projectPattern) {
     if (isNullOrEmpty(projectPattern)) {
       return;
index 2c139b1545f6916a97cee89015499f2a96642fc3..0ea55bb75986a2227f6049320019b6f951ec38f3 100644 (file)
@@ -44,6 +44,7 @@ public class PermissionsWsModule extends Module {
       UpdateTemplateAction.class,
       DeleteTemplateAction.class,
       ApplyTemplateAction.class,
+      SetDefaultTemplateAction.class,
       // utility classes
       PermissionChangeBuilder.class,
       SearchProjectPermissionsDataLoader.class,
index 84fcf01fe183c3c3aea2fd6e9cb6eca7d8d44a00..6a367fda991578cddb3a98d5bf275b3aeb4539c1 100644 (file)
@@ -70,7 +70,7 @@ public class RemoveGroupFromTemplateAction implements PermissionsWsAction {
   public void handle(Request wsRequest, Response wsResponse) throws Exception {
     checkGlobalAdminUser(userSession);
 
-    String templateKey = wsRequest.mandatoryParam(PARAM_TEMPLATE_ID_EXPLICIT);
+    String templateUuid = wsRequest.mandatoryParam(PARAM_TEMPLATE_ID_EXPLICIT);
     String permission = wsRequest.mandatoryParam(PARAM_PERMISSION);
     WsGroupRef group = WsGroupRef.fromRequest(wsRequest);
 
@@ -78,7 +78,7 @@ public class RemoveGroupFromTemplateAction implements PermissionsWsAction {
     try {
       validateProjectPermission(permission);
 
-      PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateKey);
+      PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateUuid);
       GroupDto groupDto = dependenciesFinder.getGroup(dbSession, group);
 
       Long groupId = groupDto == null ? null : groupDto.getId();
index fe81fd2938661c932df9b3e277272c68b5476a53..8eeb6269e5eb63c60dc5b56ccf6ae93a55918617 100644 (file)
@@ -68,14 +68,14 @@ public class RemoveUserFromTemplateAction implements PermissionsWsAction {
   public void handle(Request wsRequest, Response wsResponse) throws Exception {
     checkGlobalAdminUser(userSession);
 
-    String templateKey = wsRequest.mandatoryParam(PARAM_TEMPLATE_ID_EXPLICIT);
+    String templateUuid = wsRequest.mandatoryParam(PARAM_TEMPLATE_ID_EXPLICIT);
     String permission = wsRequest.mandatoryParam(PARAM_PERMISSION);
     String userLogin = wsRequest.mandatoryParam(PARAM_USER_LOGIN);
 
     DbSession dbSession = dbClient.openSession(false);
     try {
       validateProjectPermission(permission);
-      PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateKey);
+      PermissionTemplateDto template = dependenciesFinder.getTemplate(dbSession, templateUuid);
       UserDto user = dependenciesFinder.getUser(dbSession, userLogin);
 
       dbClient.permissionTemplateDao().deleteUserPermission(dbSession, template.getId(), user.getId(), permission);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/SetDefaultTemplateAction.java b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/SetDefaultTemplateAction.java
new file mode 100644 (file)
index 0000000..ec13a49
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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;
+
+import java.util.Set;
+import org.sonar.api.i18n.I18n;
+import org.sonar.api.resources.Qualifiers;
+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.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.server.platform.PersistentSettings;
+import org.sonar.server.user.UserSession;
+
+import static com.google.common.collect.FluentIterable.from;
+import static com.google.common.collect.Ordering.natural;
+import static java.lang.String.format;
+import static org.sonar.server.permission.DefaultPermissionTemplates.DEFAULT_TEMPLATE_PROPERTY;
+import static org.sonar.server.permission.DefaultPermissionTemplates.defaultRootQualifierTemplateProperty;
+import static org.sonar.server.permission.PermissionPrivilegeChecker.checkGlobalAdminUser;
+import static org.sonar.server.permission.ws.Parameters.PARAM_QUALIFIER;
+import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_ID_EXPLICIT;
+import static org.sonar.server.permission.ws.Parameters.createExplicitTemplateId;
+import static org.sonar.server.permission.ws.PermissionRequestValidator.validateQualifier;
+import static org.sonar.server.permission.ws.ResourceTypeToQualifier.RESOURCE_TYPE_TO_QUALIFIER;
+
+public class SetDefaultTemplateAction implements PermissionsWsAction {
+  private final DbClient dbClient;
+  private final PermissionDependenciesFinder finder;
+  private final ResourceTypes resourceTypes;
+  private final PersistentSettings settings;
+  private final UserSession userSession;
+  private final I18n i18n;
+
+  public SetDefaultTemplateAction(DbClient dbClient, PermissionDependenciesFinder finder, ResourceTypes resourceTypes, PersistentSettings settings, UserSession userSession,
+    I18n i18n) {
+    this.dbClient = dbClient;
+    this.finder = finder;
+    this.resourceTypes = resourceTypes;
+    this.settings = settings;
+    this.userSession = userSession;
+    this.i18n = i18n;
+  }
+
+  @Override
+  public void define(WebService.NewController context) {
+    WebService.NewAction action = context.createAction("set_default_template")
+      .setDescription("Set a permission template as default.<br />" +
+        "It requires administration permissions to access.")
+      .setPost(true)
+      .setSince("5.2")
+      .setHandler(this);
+
+    createExplicitTemplateId(action);
+
+    action.createParam(PARAM_QUALIFIER)
+      .setDescription("Project qualifier. Possible values are:")
+      .setDefaultValue(Qualifiers.PROJECT)
+      .setPossibleValues(getRootQualifiers());
+  }
+
+  @Override
+  public void handle(Request wsRequest, Response wsResponse) throws Exception {
+    checkGlobalAdminUser(userSession);
+
+    String templateUuid = wsRequest.mandatoryParam(PARAM_TEMPLATE_ID_EXPLICIT);
+    String qualifier = wsRequest.mandatoryParam(PARAM_QUALIFIER);
+
+    checkTemplateExists(templateUuid);
+    validateQualifier(qualifier, getRootQualifiers());
+    setDefaultTemplateUuid(templateUuid, qualifier);
+    wsResponse.noContent();
+  }
+
+  private Set<String> getRootQualifiers() {
+    return from(resourceTypes.getRoots())
+      .transform(RESOURCE_TYPE_TO_QUALIFIER)
+      .toSortedSet(natural());
+  }
+
+  private String buildRootQualifiersDescription() {
+    StringBuilder description = new StringBuilder();
+    description.append("<ul>");
+    String qualifierPattern = "<li>%s - %s</li>";
+    for (String qualifier : getRootQualifiers()) {
+      description.append(format(qualifierPattern, qualifier, i18n(qualifier)));
+    }
+    description.append("</ul>");
+
+    return description.toString();
+  }
+
+  private String i18n(String qualifier) {
+    String qualifiersPropertyPrefix = "qualifiers.";
+    return i18n.message(userSession.locale(), qualifiersPropertyPrefix + qualifier, "");
+  }
+
+  private void checkTemplateExists(String templateUuid) {
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      finder.getTemplate(dbSession, templateUuid);
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+  }
+
+  private void setDefaultTemplateUuid(String templateUuid, String qualifier) {
+    settings.saveProperty(defaultRootQualifierTemplateProperty(qualifier), templateUuid);
+    if (Qualifiers.PROJECT.equals(qualifier)) {
+      settings.saveProperty(DEFAULT_TEMPLATE_PROPERTY, templateUuid);
+    }
+  }
+}
index dc05fda8de5c8e5a8689aaa6493d27e3a569d488..aece6b2282563a4ad7e8bde13e9e5724c4a3f73a 100644 (file)
@@ -41,7 +41,7 @@ import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_ID;
 import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_NAME;
 import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_PATTERN;
 import static org.sonar.server.permission.ws.Parameters.createTemplateDescriptionParameter;
-import static org.sonar.server.permission.ws.Parameters.createTemplateKeyParameter;
+import static org.sonar.server.permission.ws.Parameters.createTemplateIdParameter;
 import static org.sonar.server.permission.ws.Parameters.createTemplateProjectKeyPatternParameter;
 import static org.sonar.server.permission.ws.PermissionRequestValidator.MSG_TEMPLATE_WITH_SAME_NAME;
 import static org.sonar.server.permission.ws.PermissionRequestValidator.validateProjectPattern;
@@ -73,7 +73,7 @@ public class UpdateTemplateAction implements PermissionsWsAction {
       .setPost(true)
       .setHandler(this);
 
-    createTemplateKeyParameter(action);
+    createTemplateIdParameter(action);
 
     action.createParam(PARAM_TEMPLATE_NAME)
       .setDescription("Name")
index c51c87b5c8b6a4330eaea2129862e8cf3a1fa569..fba0dbe5411f6d574d1dfa561e86bbdaddeaf535 100644 (file)
@@ -36,12 +36,9 @@ class WsProjectRef {
   private final String key;
 
   private WsProjectRef(Request wsRequest) {
-    String uuid = wsRequest.param(PARAM_PROJECT_ID);
-    String key = wsRequest.param(PARAM_PROJECT_KEY);
+    this.uuid = wsRequest.param(PARAM_PROJECT_ID);
+    this.key = wsRequest.param(PARAM_PROJECT_KEY);
     checkRequest(uuid != null ^ key != null, "Project id or project key can be provided, not both.");
-
-    this.uuid = uuid;
-    this.key = key;
   }
 
   static Optional<WsProjectRef> optionalFromRequest(Request wsRequest) {
index 37575dd01c182a86142e45601bc84f5e91a30ebe..d00e32fbc6b13507798c15f44876f70d469de4a9 100644 (file)
@@ -30,6 +30,6 @@ public class PermissionsWsModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new PermissionsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(23);
+    assertThat(container.size()).isEqualTo(24);
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/permission/ws/SetDefaultTemplateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/permission/ws/SetDefaultTemplateActionTest.java
new file mode 100644 (file)
index 0000000..88b0475
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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;
+
+import java.util.List;
+import java.util.Properties;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.ResourceType;
+import org.sonar.api.resources.ResourceTypes;
+import org.sonar.api.utils.System2;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.permission.PermissionTemplateDto;
+import org.sonar.db.permission.PermissionTemplateTesting;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.i18n.I18nRule;
+import org.sonar.server.platform.PersistentSettings;
+import org.sonar.server.platform.ServerSettings;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+import org.sonar.test.DbTests;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.resources.Qualifiers.PROJECT;
+import static org.sonar.api.resources.Qualifiers.VIEW;
+import static org.sonar.server.permission.DefaultPermissionTemplates.DEFAULT_TEMPLATE_PROPERTY;
+import static org.sonar.server.permission.DefaultPermissionTemplates.defaultRootQualifierTemplateProperty;
+import static org.sonar.server.permission.ws.Parameters.PARAM_QUALIFIER;
+import static org.sonar.server.permission.ws.Parameters.PARAM_TEMPLATE_ID_EXPLICIT;
+
+@Category(DbTests.class)
+public class SetDefaultTemplateActionTest {
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  I18nRule i18n = new I18nRule();
+
+  WsActionTester ws;
+  PersistentSettings persistentSettings;
+  ResourceTypes resourceTypes = mock(ResourceTypes.class);
+
+  PermissionTemplateDto template;
+
+  @Before
+  public void setUp() {
+    DbClient dbClient = db.getDbClient();
+    persistentSettings = new PersistentSettings(dbClient.propertiesDao(), new ServerSettings(new PropertyDefinitions(), new Properties()));
+    persistentSettings.saveProperty(DEFAULT_TEMPLATE_PROPERTY, "any-template-uuid");
+    persistentSettings.saveProperty(defaultRootQualifierTemplateProperty(PROJECT), "any-template-uuid");
+    persistentSettings.saveProperty(defaultRootQualifierTemplateProperty(VIEW), "any-view-template-uuid");
+    persistentSettings.saveProperty(defaultRootQualifierTemplateProperty("DEV"), "any-dev-template-uuid");
+    when(resourceTypes.getRoots()).thenReturn(rootResourceTypes());
+    userSession.login().setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);
+
+    ws = new WsActionTester(new SetDefaultTemplateAction(
+      dbClient,
+      new PermissionDependenciesFinder(dbClient, new ComponentFinder(dbClient)),
+      resourceTypes,
+      persistentSettings,
+      userSession, i18n));
+
+    template = dbClient.permissionTemplateDao().insert(db.getSession(), PermissionTemplateTesting.newPermissionTemplateDto().setUuid("permission-template-uuid"));
+  }
+
+  @Test
+  public void update_settings_of_default_and_qualifier_default_for_project_qualifier() {
+    // default value is project qualifier's value
+    String result = newRequest(template.getUuid(), null);
+
+    assertThat(result).isEmpty();
+    assertThat(persistentSettings.getString(DEFAULT_TEMPLATE_PROPERTY)).isEqualTo(template.getUuid());
+    assertThat(persistentSettings.getString(defaultRootQualifierTemplateProperty(PROJECT))).isEqualTo(template.getUuid());
+    assertThat(persistentSettings.getString(defaultRootQualifierTemplateProperty(VIEW))).isEqualTo("any-view-template-uuid");
+    assertThat(persistentSettings.getString(defaultRootQualifierTemplateProperty("DEV"))).isEqualTo("any-dev-template-uuid");
+  }
+
+  @Test
+  public void update_settings_of_views_property() {
+    newRequest(template.getUuid(), VIEW);
+
+    assertThat(persistentSettings.getString(DEFAULT_TEMPLATE_PROPERTY)).isEqualTo("any-template-uuid");
+    assertThat(persistentSettings.getString(defaultRootQualifierTemplateProperty(PROJECT))).isEqualTo("any-template-uuid");
+    assertThat(persistentSettings.getString(defaultRootQualifierTemplateProperty(VIEW))).isEqualTo(template.getUuid());
+    assertThat(persistentSettings.getString(defaultRootQualifierTemplateProperty("DEV"))).isEqualTo("any-dev-template-uuid");
+  }
+
+  @Test
+  public void fail_if_anonymous() {
+    expectedException.expect(UnauthorizedException.class);
+    userSession.anonymous();
+
+    newRequest(template.getUuid(), PROJECT);
+  }
+
+  @Test
+  public void fail_if_not_admin() {
+    expectedException.expect(ForbiddenException.class);
+    userSession.login().setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+
+    newRequest(template.getUuid(), PROJECT);
+  }
+
+  @Test
+  public void fail_if_template_not_provided() {
+    expectedException.expect(IllegalArgumentException.class);
+
+    newRequest(null, PROJECT);
+  }
+
+  @Test
+  public void fail_if_template_does_not_exist() {
+    expectedException.expect(NotFoundException.class);
+
+    newRequest("unknown-template-uuid", PROJECT);
+  }
+
+  @Test
+  public void fail_if_qualifier_is_not_root() {
+    expectedException.expect(BadRequestException.class);
+    when(resourceTypes.getRoots()).thenReturn(singletonList(ResourceType.builder(PROJECT).build()));
+
+    newRequest(template.getUuid(), VIEW);
+  }
+
+  private String newRequest(@Nullable String templateUuid, @Nullable String qualifier) {
+    TestRequest request = ws.newRequest();
+    if (templateUuid != null) {
+      request.setParam(PARAM_TEMPLATE_ID_EXPLICIT, templateUuid);
+    }
+    if (qualifier != null) {
+      request.setParam(PARAM_QUALIFIER, qualifier);
+    }
+
+    return request.execute().getInput();
+  }
+
+  private static List<ResourceType> rootResourceTypes() {
+    ResourceType project = ResourceType.builder(PROJECT).build();
+    ResourceType view = ResourceType.builder(Qualifiers.VIEW).build();
+    ResourceType dev = ResourceType.builder("DEV").build();
+
+    return asList(project, view, dev);
+  }
+}