package org.sonar.server.setting.ws;
+import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
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;
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
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()) {
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;
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;
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;
this.userSession = userSession;
this.settingsUpdater = settingsUpdater;
this.settingsChangeNotifier = settingsChangeNotifier;
+ this.settingValidator = settingValidator;
}
@Override
}
}
- 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);
}
}
+ 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);
"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()
--- /dev/null
+/*
+ * 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;
+ }
+
+ }
+}
EncryptAction.class,
GenerateSecretKeyAction.class,
CheckSecretKeyAction.class,
- SettingsUpdater.class);
+ SettingsUpdater.class,
+ SettingValidator.class);
}
}
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;
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;
@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();
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
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);
}
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);
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);
}
}