*/
package org.sonar.server.setting.ws;
+import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.i18n.I18n;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
};
}
+ private static final Set<String> SUPPORTED_QUALIFIERS = ImmutableSet.of(Qualifiers.PROJECT, Qualifiers.VIEW, Qualifiers.MODULE, Qualifiers.SUBVIEW);
+
public Consumer<SettingData> qualifier() {
return data -> {
String qualifier = data.component == null ? "" : data.component.qualifier();
PropertyDefinition definition = definitions.get(data.key);
- checkRequest(data.component == null || definition == null || definition.qualifiers().contains(data.component.qualifier()),
+ checkRequest(checkComponentScopeAndQualifier(data, definition),
"Setting '%s' cannot be set on a %s", data.key, i18n.message(Locale.ENGLISH, "qualifier." + qualifier, null));
};
}
+ private static boolean checkComponentScopeAndQualifier(SettingData data, @Nullable PropertyDefinition definition) {
+ ComponentDto component = data.component;
+ if (component == null) {
+ return true;
+ }
+ if (!Scopes.PROJECT.equals(component.scope())) {
+ return false;
+ }
+ if (definition == null) {
+ return SUPPORTED_QUALIFIERS.contains(component.qualifier());
+ }
+ return definition.qualifiers().contains(component.qualifier());
+ }
+
public Consumer<SettingData> valueType() {
return new ValueTypeValidation();
}
return !definition.global() && definition.qualifiers().isEmpty();
}
- public static class SettingData {
+ static class SettingData {
private final String key;
private final List<String> values;
@CheckForNull
private final ComponentDto component;
- public SettingData(String key, List<String> values, @Nullable ComponentDto component) {
+ SettingData(String key, List<String> values, @Nullable ComponentDto component) {
this.key = requireNonNull(key);
this.values = requireNonNull(values);
this.component = component;
*/
package org.sonar.server.setting.ws;
+import java.util.Random;
import javax.annotation.Nullable;
import org.junit.Before;
import org.junit.Rule;
executeRequestOnComponentSetting("foo", project);
}
+ @Test
+ public void succeed_for_property_without_definition_when_set_on_project_component() {
+ ComponentDto project = randomPublicOrPrivateProject();
+ succeedForPropertyWithoutDefinitionAndValidComponent(project, project);
+ }
+
+ @Test
+ public void succeed_for_property_without_definition_when_set_on_module_component() {
+ ComponentDto project = randomPublicOrPrivateProject();
+ ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project));
+ succeedForPropertyWithoutDefinitionAndValidComponent(project, module);
+ }
+
+ @Test
+ public void fail_for_property_without_definition_when_set_on_directory_component() {
+ ComponentDto project = randomPublicOrPrivateProject();
+ ComponentDto directory = db.components().insertComponent(ComponentTesting.newDirectory(project, "A/B"));
+ failForPropertyWithoutDefinitionOnUnsupportedComponent(project, directory);
+ }
+
+ @Test
+ public void fail_for_property_without_definition_when_set_on_file_component() {
+ ComponentDto project = randomPublicOrPrivateProject();
+ ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
+ failForPropertyWithoutDefinitionOnUnsupportedComponent(project, file);
+ }
+
+ @Test
+ public void succeed_for_property_without_definition_when_set_on_view_component() {
+ ComponentDto view = db.components().insertView();
+ succeedForPropertyWithoutDefinitionAndValidComponent(view, view);
+ }
+
+ @Test
+ public void succeed_for_property_without_definition_when_set_on_subview_component() {
+ ComponentDto view = db.components().insertView();
+ ComponentDto subview = db.components().insertComponent(ComponentTesting.newSubView(view));
+ succeedForPropertyWithoutDefinitionAndValidComponent(view, subview);
+ }
+
+ @Test
+ public void fail_for_property_without_definition_when_set_on_projectCopy_component() {
+ ComponentDto view = db.components().insertView();
+ ComponentDto projectCopy = db.components().insertComponent(ComponentTesting.newProjectCopy("a", db.components().insertPrivateProject(), view));
+
+ failForPropertyWithoutDefinitionOnUnsupportedComponent(view, projectCopy);
+ }
+
+ private void succeedForPropertyWithoutDefinitionAndValidComponent(ComponentDto root, ComponentDto module) {
+ logInAsProjectAdmin(root);
+
+ executeRequestOnComponentSetting("foo", module);
+ }
+
+ private void failForPropertyWithoutDefinitionOnUnsupportedComponent(ComponentDto root, ComponentDto component) {
+ i18n.put("qualifier." + component.qualifier(), "QualifierLabel");
+ logInAsProjectAdmin(root);
+
+ expectedException.expect(BadRequestException.class);
+ expectedException.expectMessage("Setting 'foo' cannot be set on a QualifierLabel");
+
+ executeRequestOnComponentSetting("foo", component);
+ }
+
private void executeRequestOnGlobalSetting(String key) {
executeRequest(key, null);
}
userSession.logIn().addProjectPermission(ADMIN, project);
}
+ private void logInAsProjectAdmin(ComponentDto root) {
+ userSession.logIn().addProjectPermission(ADMIN, root);
+ }
+
private void assertGlobalPropertyDoesNotExist(String key) {
assertThat(dbClient.propertiesDao().selectGlobalProperty(dbSession, key)).isNull();
}
dbSession)).isNotEmpty();
}
+ private ComponentDto randomPublicOrPrivateProject() {
+ return new Random().nextBoolean() ? db.components().insertPrivateProject() : db.components().insertPublicProject();
+ }
+
}
import com.google.gson.Gson;
import java.net.HttpURLConnection;
import java.util.List;
+import java.util.Random;
import javax.annotation.Nullable;
import org.junit.Before;
import org.junit.Rule;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
import org.sonar.db.property.PropertyDbTester;
import org.sonar.db.property.PropertyDto;
import org.sonar.db.property.PropertyQuery;
callForProjectSettingByKey("my.key", "My Value", view.key());
}
+ @Test
+ public void fail_when_property_with_definition_when_component_qualifier_does_not_match() {
+ ComponentDto project = randomPublicOrPrivateProject();
+ ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
+ definitions.addComponent(PropertyDefinition
+ .builder("my.key")
+ .name("foo")
+ .description("desc")
+ .category("cat")
+ .subCategory("subCat")
+ .type(PropertyType.STRING)
+ .defaultValue("default")
+ .onQualifiers(Qualifiers.PROJECT)
+ .build());
+ i18n.put("qualifier." + file.qualifier(), "CptLabel");
+ logInAsProjectAdministrator(project);
+
+ expectedException.expect(BadRequestException.class);
+ expectedException.expectMessage("Setting 'my.key' cannot be set on a CptLabel");
+
+ callForProjectSettingByKey("my.key", "My Value", file.key());
+ }
+
+ @Test
+ public void succeed_for_property_without_definition_when_set_on_project_component() {
+ ComponentDto project = randomPublicOrPrivateProject();
+ succeedForPropertyWithoutDefinitionAndValidComponent(project, project);
+ }
+
+ @Test
+ public void succeed_for_property_without_definition_when_set_on_module_component() {
+ ComponentDto project = randomPublicOrPrivateProject();
+ ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(project));
+ succeedForPropertyWithoutDefinitionAndValidComponent(project, module);
+ }
+
+ @Test
+ public void fail_for_property_without_definition_when_set_on_directory_component() {
+ ComponentDto project = randomPublicOrPrivateProject();
+ ComponentDto directory = db.components().insertComponent(ComponentTesting.newDirectory(project, "A/B"));
+ failForPropertyWithoutDefinitionOnUnsupportedComponent(project, directory);
+ }
+
+ @Test
+ public void fail_for_property_without_definition_when_set_on_file_component() {
+ ComponentDto project = randomPublicOrPrivateProject();
+ ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
+ failForPropertyWithoutDefinitionOnUnsupportedComponent(project, file);
+ }
+
+ @Test
+ public void succeed_for_property_without_definition_when_set_on_view_component() {
+ ComponentDto view = db.components().insertView();
+ succeedForPropertyWithoutDefinitionAndValidComponent(view, view);
+ }
+
+ @Test
+ public void succeed_for_property_without_definition_when_set_on_subview_component() {
+ ComponentDto view = db.components().insertView();
+ ComponentDto subview = db.components().insertComponent(ComponentTesting.newSubView(view));
+ succeedForPropertyWithoutDefinitionAndValidComponent(view, subview);
+ }
+
+ @Test
+ public void fail_for_property_without_definition_when_set_on_projectCopy_component() {
+ ComponentDto view = db.components().insertView();
+ ComponentDto projectCopy = db.components().insertComponent(ComponentTesting.newProjectCopy("a", db.components().insertPrivateProject(), view));
+
+ failForPropertyWithoutDefinitionOnUnsupportedComponent(view, projectCopy);
+ }
+
+ private void succeedForPropertyWithoutDefinitionAndValidComponent(ComponentDto project, ComponentDto module) {
+ logInAsProjectAdministrator(project);
+
+ callForProjectSettingByKey("my.key", "My Value", module.key());
+
+ assertComponentSetting("my.key", "My Value", module.getId());
+ }
+
+ private void failForPropertyWithoutDefinitionOnUnsupportedComponent(ComponentDto root, ComponentDto component) {
+ i18n.put("qualifier." + component.qualifier(), "QualifierLabel");
+ logInAsProjectAdministrator(root);
+
+ expectedException.expect(BadRequestException.class);
+ expectedException.expectMessage("Setting 'my.key' cannot be set on a QualifierLabel");
+
+ callForProjectSettingByKey("my.key", "My Value", component.key());
+ }
+
@Test
public void fail_when_single_and_multi_value_provided() {
expectedException.expect(BadRequestException.class);
}
}
+
private void logInAsProjectAdministrator(ComponentDto project) {
userSession.logIn().addProjectPermission(UserRole.ADMIN, project);
}
+
+ private ComponentDto randomPublicOrPrivateProject() {
+ return new Random().nextBoolean() ? db.components().insertPrivateProject() : db.components().insertPublicProject();
+ }
}