aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--it/it-plugins/billing-plugin/src/main/java/BillingValidations.java9
-rw-r--r--it/it-tests/src/test/java/it/organization/BillingTest.java41
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/ui/ws/OrganizationAction.java23
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyImplTest.java (renamed from server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyTest.java)31
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/ui/ws/OrganizationActionTest.java34
7 files changed, 135 insertions, 13 deletions
diff --git a/it/it-plugins/billing-plugin/src/main/java/BillingValidations.java b/it/it-plugins/billing-plugin/src/main/java/BillingValidations.java
index b21d9c64837..344f24925fd 100644
--- a/it/it-plugins/billing-plugin/src/main/java/BillingValidations.java
+++ b/it/it-plugins/billing-plugin/src/main/java/BillingValidations.java
@@ -27,6 +27,7 @@ import static java.lang.String.format;
public class BillingValidations implements BillingValidationsExtension {
private static final String PREVENT_PROJECT_ANALYSIS_SETTING = "sonar.billing.preventProjectAnalysis";
+ private static final String PREVENT_UPDATING_PROJECTS_VISIBILITY_TO_PRIVATE_SETTING = "sonar.billing.preventUpdatingProjectsVisibilityToPrivate";
private final Settings settings;
@@ -41,4 +42,12 @@ public class BillingValidations implements BillingValidationsExtension {
throw new BillingValidationsException(format("Organization %s cannot perform analysis", organization.getKey()));
}
}
+
+ @Override
+ public boolean canUpdateProjectVisibilityToPrivate(Organization organization) {
+ if (!settings.hasKey(PREVENT_UPDATING_PROJECTS_VISIBILITY_TO_PRIVATE_SETTING)) {
+ return true;
+ }
+ return !settings.getBoolean(PREVENT_UPDATING_PROJECTS_VISIBILITY_TO_PRIVATE_SETTING);
+ }
}
diff --git a/it/it-tests/src/test/java/it/organization/BillingTest.java b/it/it-tests/src/test/java/it/organization/BillingTest.java
index 10a623dbe61..11a94a9f7ff 100644
--- a/it/it-tests/src/test/java/it/organization/BillingTest.java
+++ b/it/it-tests/src/test/java/it/organization/BillingTest.java
@@ -24,12 +24,15 @@ import com.sonar.orchestrator.build.BuildResult;
import com.sonar.orchestrator.build.SonarScanner;
import it.Category6Suite;
import org.junit.AfterClass;
+import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.sonarqube.ws.client.GetRequest;
import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.client.WsResponse;
import org.sonarqube.ws.client.organization.CreateWsRequest;
import util.ItUtils;
import util.user.UserRule;
@@ -41,11 +44,15 @@ import static org.sonarqube.ws.WsCe.TaskResponse;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.newOrganizationKey;
import static util.ItUtils.newProjectKey;
+import static util.ItUtils.newUserWsClient;
import static util.ItUtils.projectDir;
import static util.ItUtils.resetSettings;
import static util.ItUtils.setServerProperty;
public class BillingTest {
+
+ private static final String USER_LOGIN = "USER_LOGIN";
+
@ClassRule
public static Orchestrator orchestrator = Category6Suite.ORCHESTRATOR;
@@ -58,15 +65,21 @@ public class BillingTest {
private static WsClient adminClient;
@BeforeClass
- public static void setUp() throws Exception {
+ public static void prepare() throws Exception {
adminClient = newAdminWsClient(orchestrator);
enableOrganizationsSupport();
resetSettings(orchestrator, "sonar.billing.preventProjectAnalysis");
}
+ @Before
+ public void setUp() throws Exception {
+ userRule.deactivateUsers(USER_LOGIN);
+ }
+
@AfterClass
public static void tearDown() throws Exception {
resetSettings(orchestrator, "sonar.billing.preventProjectAnalysis");
+ userRule.deactivateUsers(USER_LOGIN);
}
@Test
@@ -92,6 +105,22 @@ public class BillingTest {
assertThat(taskResponse.getTask().getErrorMessage()).contains(format("Organization %s cannot perform analysis", organizationKey));
}
+ @Test
+ public void api_navigation_organization_return_canUpdateProjectsVisibilityToPrivate() {
+ String organizationKey = createOrganization();
+ userRule.createUser(USER_LOGIN, USER_LOGIN);
+ adminClient.organizations().addMember(organizationKey, USER_LOGIN);
+
+ setServerProperty(orchestrator, "sonar.billing.preventUpdatingProjectsVisibilityToPrivate", "false");
+ assertWsResponseAsAdmin(new GetRequest("api/navigation/organization").setParam("organization", organizationKey), "\"canUpdateProjectsVisibilityToPrivate\":true");
+
+ setServerProperty(orchestrator, "sonar.billing.preventUpdatingProjectsVisibilityToPrivate", "true");
+ assertWsResponseAsAdmin(new GetRequest("api/navigation/organization").setParam("organization", organizationKey), "\"canUpdateProjectsVisibilityToPrivate\":false");
+
+ setServerProperty(orchestrator, "sonar.billing.preventUpdatingProjectsVisibilityToPrivate", "true");
+ assertWsResponseAsUser(new GetRequest("api/navigation/organization").setParam("organization", organizationKey), "\"canUpdateProjectsVisibilityToPrivate\":false");
+ }
+
private static String createOrganization() {
String key = newOrganizationKey();
adminClient.organizations().create(new CreateWsRequest.Builder().setKey(key).setName(key).build()).getOrganization();
@@ -106,4 +135,14 @@ public class BillingTest {
"sonar.password", "admin"));
return ItUtils.extractCeTaskId(buildResult);
}
+
+ private void assertWsResponseAsAdmin(GetRequest request, String expectedContent){
+ WsResponse response = adminClient.wsConnector().call(request).failIfNotSuccessful();
+ assertThat(response.content()).contains(expectedContent);
+ }
+
+ private void assertWsResponseAsUser(GetRequest request, String expectedContent){
+ WsResponse response = newUserWsClient(orchestrator, USER_LOGIN, USER_LOGIN).wsConnector().call(request).failIfNotSuccessful();
+ assertThat(response.content()).contains(expectedContent);
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java
index 1c524acce1a..14103f7db19 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidations.java
@@ -34,6 +34,11 @@ public interface BillingValidations {
*/
void checkOnProjectAnalysis(Organization organization);
+ /**
+ * @return true if the organization can use private projects
+ */
+ boolean canUpdateProjectVisibilityToPrivate(Organization organization);
+
class Organization {
private final String key;
private final String uuid;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java
index c091e346b9e..c9512f73226 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/BillingValidationsProxyImpl.java
@@ -40,4 +40,9 @@ public class BillingValidationsProxyImpl implements BillingValidationsProxy {
}
billingValidationsExtension.checkOnProjectAnalysis(organization);
}
+
+ @Override
+ public boolean canUpdateProjectVisibilityToPrivate(Organization organization) {
+ return billingValidationsExtension == null || billingValidationsExtension.canUpdateProjectVisibilityToPrivate(organization);
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/OrganizationAction.java b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/OrganizationAction.java
index f52bdf87b56..915c69e93ed 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/OrganizationAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/OrganizationAction.java
@@ -31,13 +31,16 @@ import org.sonar.api.web.page.Page;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.organization.OrganizationDto;
-import org.sonar.db.permission.OrganizationPermission;
+import org.sonar.server.organization.BillingValidations;
+import org.sonar.server.organization.BillingValidationsProxy;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.project.Visibility;
import org.sonar.server.ui.PageRepository;
import org.sonar.server.user.UserSession;
import static org.sonar.core.util.stream.MoreCollectors.toList;
+import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
+import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS;
import static org.sonar.server.ws.KeyExamples.KEY_ORG_EXAMPLE_001;
import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
@@ -50,12 +53,15 @@ public class OrganizationAction implements NavigationWsAction {
private final DefaultOrganizationProvider defaultOrganizationProvider;
private final UserSession userSession;
private final PageRepository pageRepository;
+ private final BillingValidationsProxy billingValidations;
- public OrganizationAction(DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider, UserSession userSession, PageRepository pageRepository) {
+ public OrganizationAction(DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider, UserSession userSession, PageRepository pageRepository,
+ BillingValidationsProxy billingValidations) {
this.dbClient = dbClient;
this.defaultOrganizationProvider = defaultOrganizationProvider;
this.userSession = userSession;
this.pageRepository = pageRepository;
+ this.billingValidations = billingValidations;
}
@Override
@@ -94,16 +100,19 @@ public class OrganizationAction implements NavigationWsAction {
private void writeOrganization(JsonWriter json, OrganizationDto organization, boolean newProjectPrivate) {
json.name("organization")
.beginObject()
- .prop("canAdmin", userSession.hasPermission(OrganizationPermission.ADMINISTER, organization))
- .prop("canProvisionProjects", userSession.hasPermission(OrganizationPermission.PROVISION_PROJECTS, organization))
- .prop("canDelete", organization.isGuarded() ? userSession.isSystemAdministrator() : userSession.hasPermission(OrganizationPermission.ADMINISTER, organization))
+ .prop("canAdmin", userSession.hasPermission(ADMINISTER, organization))
+ .prop("canProvisionProjects", userSession.hasPermission(PROVISION_PROJECTS, organization))
+ .prop("canDelete", organization.isGuarded() ? userSession.isSystemAdministrator() : userSession.hasPermission(ADMINISTER, organization))
.prop("isDefault", organization.getKey().equals(defaultOrganizationProvider.get().getKey()))
- .prop("projectVisibility", Visibility.getLabel(newProjectPrivate));
+ .prop("projectVisibility", Visibility.getLabel(newProjectPrivate))
+ .prop("canUpdateProjectsVisibilityToPrivate",
+ userSession.hasPermission(ADMINISTER, organization) &&
+ billingValidations.canUpdateProjectVisibilityToPrivate(new BillingValidations.Organization(organization.getKey(), organization.getUuid())));
Predicate<Page> personalOrgForBilling = page -> organization.getUserId() == null || !page.getKey().startsWith("billing/");
List<Page> pages = pageRepository.getOrganizationPages(false).stream().filter(personalOrgForBilling).collect(toList());
json.name("pages");
writePages(json, pages);
- if (userSession.hasPermission(OrganizationPermission.ADMINISTER, organization)) {
+ if (userSession.hasPermission(ADMINISTER, organization)) {
List<Page> adminPages = pageRepository.getOrganizationPages(true).stream().filter(personalOrgForBilling).collect(toList());
json.name("adminPages");
writePages(json, adminPages);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyImplTest.java
index 649a35cc743..31874248397 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyImplTest.java
@@ -22,12 +22,14 @@ package org.sonar.server.organization;
import org.junit.Test;
+import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
import static org.sonar.server.organization.BillingValidations.Organization;
-public class BillingValidationsProxyTest {
+public class BillingValidationsProxyImplTest {
private static String ORGANIZATION_KEY = "ORGANIZATION_KEY";
private static String ORGANIZATION_UUID = "ORGANIZATION_UUID";
@@ -39,8 +41,8 @@ public class BillingValidationsProxyTest {
@Test
public void checkOnProjectAnalysis_calls_extension_when_available() {
underTest = new BillingValidationsProxyImpl(billingValidationsExtension);
-
Organization organization = new Organization(ORGANIZATION_KEY, ORGANIZATION_UUID);
+
underTest.checkOnProjectAnalysis(organization);
verify(billingValidationsExtension).checkOnProjectAnalysis(organization);
@@ -49,11 +51,34 @@ public class BillingValidationsProxyTest {
@Test
public void checkOnProjectAnalysis_does_nothing_when_no_extension_available() {
underTest = new BillingValidationsProxyImpl();
-
Organization organization = new Organization(ORGANIZATION_KEY, ORGANIZATION_UUID);
+
underTest.checkOnProjectAnalysis(organization);
verifyZeroInteractions(billingValidationsExtension);
}
+ @Test
+ public void canUpdateProjectsVisibilityToPrivate_calls_extension_when_available() {
+ underTest = new BillingValidationsProxyImpl(billingValidationsExtension);
+ Organization organization = new Organization(ORGANIZATION_KEY, ORGANIZATION_UUID);
+ when(billingValidationsExtension.canUpdateProjectVisibilityToPrivate(organization)).thenReturn(false);
+
+ boolean result = underTest.canUpdateProjectVisibilityToPrivate(organization);
+
+ assertThat(result).isFalse();
+ verify(billingValidationsExtension).canUpdateProjectVisibilityToPrivate(organization);
+ }
+
+ @Test
+ public void canUpdateProjectsVisibilityToPrivate_return_true_when_no_extension() {
+ underTest = new BillingValidationsProxyImpl();
+ Organization organization = new Organization(ORGANIZATION_KEY, ORGANIZATION_UUID);
+
+ boolean result = underTest.canUpdateProjectVisibilityToPrivate(organization);
+
+ assertThat(result).isTrue();
+ verifyZeroInteractions(billingValidationsExtension);
+ }
+
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/ws/OrganizationActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/OrganizationActionTest.java
index 3feab3cae3d..a23a57c9eb4 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/ui/ws/OrganizationActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/OrganizationActionTest.java
@@ -32,6 +32,8 @@ import org.sonar.core.platform.PluginRepository;
import org.sonar.db.DbClient;
import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
+import org.sonar.server.organization.BillingValidations;
+import org.sonar.server.organization.BillingValidationsProxy;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.tester.UserSessionRule;
@@ -42,6 +44,7 @@ import org.sonar.server.ws.WsActionTester;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
+import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -61,8 +64,9 @@ public class OrganizationActionTest {
private DbClient dbClient = dbTester.getDbClient();
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester);
private PageRepository pageRepository = mock(PageRepository.class);
+ private BillingValidationsProxy billingValidations = mock(BillingValidationsProxy.class);
- private WsActionTester ws = new WsActionTester(new OrganizationAction(dbClient, defaultOrganizationProvider, userSession, pageRepository));
+ private WsActionTester ws = new WsActionTester(new OrganizationAction(dbClient, defaultOrganizationProvider, userSession, pageRepository, billingValidations));
@Test
public void verify_definition() {
@@ -254,6 +258,23 @@ public class OrganizationActionTest {
assertJson(executeRequest(organization).getInput()).isSimilarTo("{\"organization\": {\"projectVisibility\": \"public\"}}");
}
+ @Test
+ public void returns_non_admin_and_canUpdateProjectsVisibilityToPrivate_false_when_user_logged_in_but_not_admin_and_extension_returns_true() {
+ OrganizationDto defaultOrganization = dbTester.getDefaultOrganization();
+
+ userSession.logIn();
+ when(billingValidations.canUpdateProjectVisibilityToPrivate(any(BillingValidations.Organization.class))).thenReturn(true);
+ verifyCanUpdateProjectsVisibilityToPrivateResponse(executeRequest(dbTester.getDefaultOrganization()), false);
+
+ userSession.logIn().addPermission(ADMINISTER, defaultOrganization);
+ when(billingValidations.canUpdateProjectVisibilityToPrivate(any(BillingValidations.Organization.class))).thenReturn(false);
+ verifyCanUpdateProjectsVisibilityToPrivateResponse(executeRequest(dbTester.getDefaultOrganization()), false);
+
+ userSession.logIn().addPermission(ADMINISTER, defaultOrganization);
+ when(billingValidations.canUpdateProjectVisibilityToPrivate(any(BillingValidations.Organization.class))).thenReturn(true);
+ verifyCanUpdateProjectsVisibilityToPrivateResponse(executeRequest(dbTester.getDefaultOrganization()), true);
+ }
+
private void initWithPages(Page... pages) {
PluginRepository pluginRepository = mock(PluginRepository.class);
when(pluginRepository.hasPlugin(anyString())).thenReturn(true);
@@ -263,7 +284,7 @@ public class OrganizationActionTest {
}
}});
pageRepository.start();
- ws = new WsActionTester(new OrganizationAction(dbClient, defaultOrganizationProvider, userSession, pageRepository));
+ ws = new WsActionTester(new OrganizationAction(dbClient, defaultOrganizationProvider, userSession, pageRepository, billingValidations));
}
private TestResponse executeRequest(@Nullable OrganizationDto organization) {
@@ -285,4 +306,13 @@ public class OrganizationActionTest {
" }" +
"}");
}
+
+ private static void verifyCanUpdateProjectsVisibilityToPrivateResponse(TestResponse response, boolean canUpdateProjectsVisibilityToPrivate) {
+ assertJson(response.getInput())
+ .isSimilarTo("{" +
+ " \"organization\": {" +
+ " \"canUpdateProjectsVisibilityToPrivate\": " + canUpdateProjectsVisibilityToPrivate + "," +
+ " }" +
+ "}");
+ }
}