]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7986 WS settings/reset check scope and qualifier 1221/head
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 7 Sep 2016 17:20:00 +0000 (19:20 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 8 Sep 2016 07:21:34 +0000 (09:21 +0200)
server/sonar-server/src/main/java/org/sonar/server/setting/ws/ResetAction.java
server/sonar-server/src/main/java/org/sonar/server/setting/ws/SetAction.java
server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingValidator.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsWsModule.java
server/sonar-server/src/test/java/org/sonar/server/setting/ws/ResetActionTest.java
server/sonar-server/src/test/java/org/sonar/server/setting/ws/SetActionTest.java
server/sonar-server/src/test/java/org/sonar/server/setting/ws/SettingsWsModuleTest.java

index 7d1c636a5dded58280e81c0ee245234d34509073..744b5ad8913097fc6498580ed914a05902c17264 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.sonar.server.setting.ws;
 
+import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
@@ -35,9 +36,11 @@ import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.setting.ws.SettingValidator.SettingData;
 import org.sonar.server.user.UserSession;
 import org.sonarqube.ws.client.setting.ResetRequest;
 
+import static org.sonar.server.setting.ws.SettingValidator.validateScope;
 import static org.sonar.server.setting.ws.SettingsWsComponentParameters.addComponentParameters;
 import static org.sonarqube.ws.client.ce.CeWsParameters.PARAM_COMPONENT_KEY;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_RESET;
@@ -51,13 +54,16 @@ public class ResetAction implements SettingsWsAction {
   private final SettingsUpdater settingsUpdater;
   private final UserSession userSession;
   private final PropertyDefinitions definitions;
+  private final SettingValidator settingValidator;
 
-  public ResetAction(DbClient dbClient, ComponentFinder componentFinder, SettingsUpdater settingsUpdater, UserSession userSession, PropertyDefinitions definitions) {
+  public ResetAction(DbClient dbClient, ComponentFinder componentFinder, SettingsUpdater settingsUpdater, UserSession userSession, PropertyDefinitions definitions,
+    SettingValidator settingValidator) {
     this.dbClient = dbClient;
     this.settingsUpdater = settingsUpdater;
     this.userSession = userSession;
     this.componentFinder = componentFinder;
     this.definitions = definitions;
+    this.settingValidator = settingValidator;
   }
 
   @Override
@@ -89,6 +95,11 @@ public class ResetAction implements SettingsWsAction {
       ResetRequest resetRequest = toWsRequest(request);
       Optional<ComponentDto> component = getComponent(dbSession, resetRequest);
       checkPermissions(component);
+      resetRequest.getKeys().forEach(key -> {
+        SettingData data = new SettingData(key, definitions.get(key), component.orElse(null));
+        ImmutableList.of(validateScope(), settingValidator.validateQualifier())
+          .forEach(validation -> validation.validate(data));
+      });
 
       List<String> keys = getKeys(resetRequest);
       if (component.isPresent()) {
index f2e5f9a28d9784c33d0b66a2dd0362ff8a5e8119..2a9cd7337ef1061516fe1d433617f3f2682c4ade 100644 (file)
@@ -21,6 +21,7 @@
 package org.sonar.server.setting.ws;
 
 import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ListMultimap;
 import com.google.gson.Gson;
 import com.google.gson.JsonSyntaxException;
@@ -55,11 +56,13 @@ import org.sonar.scanner.protocol.GsonHelper;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.platform.SettingsChangeNotifier;
+import org.sonar.server.setting.ws.SettingValidator.SettingData;
 import org.sonar.server.user.UserSession;
 import org.sonar.server.ws.KeyExamples;
 import org.sonarqube.ws.client.setting.SetRequest;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.sonar.server.setting.ws.SettingValidator.validateScope;
 import static org.sonar.server.ws.WsUtils.checkRequest;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_SET;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_COMPONENT_ID;
@@ -79,9 +82,10 @@ public class SetAction implements SettingsWsAction {
   private final UserSession userSession;
   private final SettingsUpdater settingsUpdater;
   private final SettingsChangeNotifier settingsChangeNotifier;
+  private final SettingValidator settingValidator;
 
   public SetAction(PropertyDefinitions propertyDefinitions, I18n i18n, DbClient dbClient, ComponentFinder componentFinder, UserSession userSession,
-    SettingsUpdater settingsUpdater, SettingsChangeNotifier settingsChangeNotifier) {
+    SettingsUpdater settingsUpdater, SettingsChangeNotifier settingsChangeNotifier, SettingValidator settingValidator) {
     this.propertyDefinitions = propertyDefinitions;
     this.i18n = i18n;
     this.dbClient = dbClient;
@@ -89,6 +93,7 @@ public class SetAction implements SettingsWsAction {
     this.userSession = userSession;
     this.settingsUpdater = settingsUpdater;
     this.settingsChangeNotifier = settingsChangeNotifier;
+    this.settingValidator = settingValidator;
   }
 
   @Override
@@ -173,12 +178,6 @@ public class SetAction implements SettingsWsAction {
     }
   }
 
-  private void commonChecks(SetRequest request, @Nullable PropertyDefinition definition, Optional<ComponentDto> component) {
-    checkValueIsSet(request);
-    checkGlobalOrProject(request, definition, component);
-    checkComponentQualifier(request, definition, component);
-  }
-
   private String doHandlePropertySet(DbSession dbSession, SetRequest request, @Nullable PropertyDefinition definition, Optional<ComponentDto> component) {
     validatePropertySet(request, definition);
 
@@ -207,6 +206,13 @@ public class SetAction implements SettingsWsAction {
     }
   }
 
+  private void commonChecks(SetRequest request, @Nullable PropertyDefinition definition, Optional<ComponentDto> component) {
+    checkValueIsSet(request);
+    SettingData settingData = new SettingData(request.getKey(), definition, component.orElse(null));
+    ImmutableList.of(validateScope(), settingValidator.validateQualifier()).stream()
+      .forEach(validation -> validation.validate(settingData));
+  }
+
   private void validatePropertySet(SetRequest request, @Nullable PropertyDefinition definition) {
     checkRequest(definition != null, "Setting '%s' is undefined", request.getKey());
     checkRequest(PropertyType.PROPERTY_SET.equals(definition.type()), "Parameter '%s' is used for setting of property set type only", PARAM_FIELD_VALUES);
@@ -252,18 +258,6 @@ public class SetAction implements SettingsWsAction {
       "Parameter '%s' must be used for single value setting. Parameter '%s' must be used for multi value setting.", PARAM_VALUE, PARAM_VALUES);
   }
 
-  private static void checkGlobalOrProject(SetRequest request, @Nullable PropertyDefinition definition, Optional<ComponentDto> component) {
-    checkRequest(component.isPresent() || definition == null || definition.global(), "Setting '%s' cannot be global", request.getKey());
-  }
-
-  private void checkComponentQualifier(SetRequest request, @Nullable PropertyDefinition definition, Optional<ComponentDto> component) {
-    String qualifier = component.isPresent() ? component.get().qualifier() : "";
-    checkRequest(!component.isPresent()
-      || definition == null
-      || definition.qualifiers().contains(component.get().qualifier()),
-      "Setting '%s' cannot be set on a %s", request.getKey(), i18n.message(Locale.ENGLISH, "qualifier." + qualifier, null));
-  }
-
   private void checkType(SetRequest request, PropertyDefinition definition) {
     List<String> values = valuesFromRequest(request);
     Optional<PropertyDefinition.Result> failingResult = values.stream()
diff --git a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingValidator.java b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingValidator.java
new file mode 100644 (file)
index 0000000..e0930cb
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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.setting.ws;
+
+import java.util.Locale;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.api.i18n.I18n;
+import org.sonar.db.component.ComponentDto;
+
+import static org.sonar.server.ws.WsUtils.checkRequest;
+
+public class SettingValidator {
+  private final I18n i18n;
+
+  public SettingValidator(I18n i18n) {
+    this.i18n = i18n;
+  }
+
+  public static SettingValidation validateScope() {
+    return data -> checkRequest(data.component != null || data.definition == null || data.definition.global(), "Setting '%s' cannot be global", data.key);
+  }
+
+  public SettingValidation validateQualifier() {
+    return data -> {
+      String qualifier = data.component == null ? "" : data.component.qualifier();
+      checkRequest(data.component == null || data.definition == null || data.definition.qualifiers().contains(data.component.qualifier()),
+        "Setting '%s' cannot be set on a %s", data.key, i18n.message(Locale.ENGLISH, "qualifier." + qualifier, null));
+    };
+  }
+
+  @FunctionalInterface
+  public interface SettingValidation {
+    void validate(SettingData data);
+  }
+
+  public static class SettingData {
+    private final String key;
+    @CheckForNull
+    private final PropertyDefinition definition;
+    @CheckForNull
+    private final ComponentDto component;
+
+    public SettingData(String key, @Nullable PropertyDefinition definition, @Nullable ComponentDto component) {
+      this.key = key;
+      this.definition = definition;
+      this.component = component;
+    }
+
+  }
+}
index b81ac302d9897dd3aa9ed90ef9c312eebd5db805..35288677612928bb1c95f8044ab8abdba2c19b8c 100644 (file)
@@ -35,6 +35,7 @@ public class SettingsWsModule extends Module {
       EncryptAction.class,
       GenerateSecretKeyAction.class,
       CheckSecretKeyAction.class,
-      SettingsUpdater.class);
+      SettingsUpdater.class,
+      SettingValidator.class);
   }
 }
index 7ba924ec5a1030c1468a09810b4b6881ccb2f4e5..f0b670b33c25e5ce4efce0c527294ae359d1f089 100644 (file)
@@ -27,6 +27,7 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.config.PropertyDefinition;
 import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbClient;
@@ -39,7 +40,9 @@ import org.sonar.db.property.PropertyQuery;
 import org.sonar.db.user.UserDto;
 import org.sonar.db.user.UserTesting;
 import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.i18n.I18nRule;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.TestResponse;
@@ -68,6 +71,8 @@ public class ResetActionTest {
   @Rule
   public DbTester db = DbTester.create(System2.INSTANCE);
 
+  I18nRule i18n = new I18nRule();
+
   PropertyDbTester propertyDb = new PropertyDbTester(db);
   ComponentDbTester componentDb = new ComponentDbTester(db);
   DbClient dbClient = db.getDbClient();
@@ -75,10 +80,11 @@ public class ResetActionTest {
   ComponentFinder componentFinder = new ComponentFinder(dbClient);
   PropertyDefinitions definitions = new PropertyDefinitions();
   SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, definitions);
+  SettingValidator settingValidator = new SettingValidator(i18n);
 
   ComponentDto project;
 
-  ResetAction underTest = new ResetAction(dbClient, componentFinder, settingsUpdater, userSession, definitions);
+  ResetAction underTest = new ResetAction(dbClient, componentFinder, settingsUpdater, userSession, definitions, settingValidator);
   WsActionTester ws = new WsActionTester(underTest);
 
   @Before
@@ -206,6 +212,33 @@ public class ResetActionTest {
     executeRequestOnComponentSetting("foo", project);
   }
 
+  @Test
+  public void fail_when_not_global_and_no_component() {
+    setUserAsSystemAdmin();
+    definitions.addComponent(PropertyDefinition.builder("foo")
+      .onlyOnQualifiers(Qualifiers.VIEW)
+      .build());
+
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Setting 'foo' cannot be global");
+
+    executeRequestOnGlobalSetting("foo");
+  }
+
+  @Test
+  public void fail_when_qualifier_not_included() {
+    setUserAsSystemAdmin();
+    definitions.addComponent(PropertyDefinition.builder("foo")
+      .onQualifiers(Qualifiers.VIEW)
+      .build());
+    i18n.put("qualifier." + Qualifiers.PROJECT, "project");
+
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Setting 'foo' cannot be set on a project");
+
+    executeRequestOnComponentSetting("foo", project);
+  }
+
   private void executeRequestOnGlobalSetting(String key) {
     executeRequest(key, null, null);
   }
index d9d43e6dacf185b521f4a1a7356bffbf8497c7f1..ca51572f567322b0a91f91d42f3e14c81e047a65 100644 (file)
@@ -86,8 +86,9 @@ public class SetActionTest {
   PropertyDefinitions propertyDefinitions = new PropertyDefinitions();
   FakeSettingsNotifier settingsChangeNotifier = new FakeSettingsNotifier(dbClient);
   SettingsUpdater settingsUpdater = new SettingsUpdater(dbClient, propertyDefinitions);
+  SettingValidator settingValidator = new SettingValidator(i18n);
 
-  SetAction underTest = new SetAction(propertyDefinitions, i18n, dbClient, componentFinder, userSession, settingsUpdater, settingsChangeNotifier);
+  SetAction underTest = new SetAction(propertyDefinitions, i18n, dbClient, componentFinder, userSession, settingsUpdater, settingsChangeNotifier, settingValidator);
 
   WsActionTester ws = new WsActionTester(underTest);
 
index 19a40eb621b5be6d6b2e03fd12c39234efd21bf7..5d24b68828063399ebee310f75bf4d125a4b571d 100644 (file)
@@ -29,6 +29,6 @@ public class SettingsWsModuleTest {
   public void verify_count_of_added_components() {
     ComponentContainer container = new ComponentContainer();
     new SettingsWsModule().configure(container);
-    assertThat(container.size()).isEqualTo(11 + 2);
+    assertThat(container.size()).isEqualTo(12 + 2);
   }
 }