aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--it/it-plugins/billing-plugin/src/main/java/BillingValidations.java8
-rw-r--r--it/it-tests/src/test/java/it/organization/BillingTest.java45
-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.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/organization/ws/UpdateProjectVisibilityAction.java15
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyImplTest.java20
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/organization/ws/UpdateProjectVisibilityActionTest.java50
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/organization/OrganizationService.java7
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/organization/UpdateProjectVisibilityWsRequest.java68
-rw-r--r--sonar-ws/src/test/java/org/sonarqube/ws/client/organization/OrganizationServiceTest.java14
10 files changed, 228 insertions, 12 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 344f24925fd..0e57d8d305d 100644
--- a/it/it-plugins/billing-plugin/src/main/java/BillingValidations.java
+++ b/it/it-plugins/billing-plugin/src/main/java/BillingValidations.java
@@ -44,6 +44,14 @@ public class BillingValidations implements BillingValidationsExtension {
}
@Override
+ public void checkCanUpdateProjectVisibility(Organization organization, boolean updateToPrivate) {
+ boolean preventUpdatingProjectsToPrivate = settings.getBoolean(PREVENT_UPDATING_PROJECTS_VISIBILITY_TO_PRIVATE_SETTING);
+ if (preventUpdatingProjectsToPrivate) {
+ throw new BillingValidationsException(format("Organization %s cannot use private project", organization.getKey()));
+ }
+ }
+
+ @Override
public boolean canUpdateProjectVisibilityToPrivate(Organization organization) {
if (!settings.hasKey(PREVENT_UPDATING_PROJECTS_VISIBILITY_TO_PRIVATE_SETTING)) {
return true;
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 a78fdfc3a66..869f7601943 100644
--- a/it/it-tests/src/test/java/it/organization/BillingTest.java
+++ b/it/it-tests/src/test/java/it/organization/BillingTest.java
@@ -31,15 +31,19 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.HttpException;
import org.sonarqube.ws.client.WsClient;
import org.sonarqube.ws.client.WsResponse;
import org.sonarqube.ws.client.organization.CreateWsRequest;
+import org.sonarqube.ws.client.organization.UpdateProjectVisibilityWsRequest;
+import org.sonarqube.ws.client.project.CreateRequest;
import util.ItUtils;
import util.user.UserRule;
import static it.Category6Suite.enableOrganizationsSupport;
import static java.lang.String.format;
import static org.assertj.core.api.Java6Assertions.assertThat;
+import static org.junit.Assert.fail;
import static org.sonarqube.ws.WsCe.TaskResponse;
import static util.ItUtils.newAdminWsClient;
import static util.ItUtils.newOrganizationKey;
@@ -73,12 +77,12 @@ public class BillingTest {
@Before
public void setUp() throws Exception {
userRule.deactivateUsers(USER_LOGIN);
- resetSettings(orchestrator, "sonar.billing.preventProjectAnalysis");
+ resetSettings(orchestrator, null, "sonar.billing.preventProjectAnalysis", "sonar.billing.preventUpdatingProjectsVisibilityToPrivate");
}
@AfterClass
public static void tearDown() throws Exception {
- resetSettings(orchestrator, "sonar.billing.preventProjectAnalysis");
+ resetSettings(orchestrator, null, "sonar.billing.preventProjectAnalysis", "sonar.billing.preventUpdatingProjectsVisibilityToPrivate");
userRule.deactivateUsers(USER_LOGIN);
}
@@ -124,8 +128,7 @@ public class BillingTest {
@Test
public void api_navigation_component_returns_canUpdateProjectVisibilityToPrivate() {
String organizationKey = createOrganization();
- String projectKey = newProjectKey();
- executeAnalysis(projectKey, organizationKey);
+ String projectKey = createPublicProject(organizationKey);
setServerProperty(orchestrator, "sonar.billing.preventUpdatingProjectsVisibilityToPrivate", "false");
assertWsResponseAsAdmin(new GetRequest("api/navigation/component").setParam("componentKey", projectKey), "\"canUpdateProjectVisibilityToPrivate\":true");
@@ -134,12 +137,42 @@ public class BillingTest {
assertWsResponseAsAdmin(new GetRequest("api/navigation/component").setParam("componentKey", projectKey), "\"canUpdateProjectVisibilityToPrivate\":false");
}
+ @Test
+ public void does_not_fail_to_update_default_projects_visibility_to_private() {
+ String organizationKey = createOrganization();
+ setServerProperty(orchestrator, "sonar.billing.preventUpdatingProjectsVisibilityToPrivate", "false");
+
+ adminClient.organizations().updateProjectVisibility(UpdateProjectVisibilityWsRequest.builder().setOrganization(organizationKey).setProjectVisibility("private").build());
+
+ assertWsResponseAsAdmin(new GetRequest("api/navigation/organization").setParam("organization", organizationKey), "\"projectVisibility\":\"private\"");
+ }
+
+ @Test
+ public void fail_to_update_default_projects_visibility_to_private() {
+ String organizationKey = createOrganization();
+ setServerProperty(orchestrator, "sonar.billing.preventUpdatingProjectsVisibilityToPrivate", "true");
+
+ try {
+ adminClient.organizations().updateProjectVisibility(UpdateProjectVisibilityWsRequest.builder().setOrganization(organizationKey).setProjectVisibility("private").build());
+ fail();
+ } catch (HttpException ex) {
+ assertThat(ex.code()).isEqualTo(400);
+ assertThat(ex.content()).contains(format("Organization %s cannot use private project", organizationKey));
+ }
+ }
+
private static String createOrganization() {
String key = newOrganizationKey();
adminClient.organizations().create(new CreateWsRequest.Builder().setKey(key).setName(key).build()).getOrganization();
return key;
}
+ private static String createPublicProject(String organizationKey) {
+ String projectKey = newProjectKey();
+ adminClient.projects().create(CreateRequest.builder().setKey(projectKey).setName(projectKey).setOrganization(organizationKey).setVisibility("public").build());
+ return projectKey;
+ }
+
private static String executeAnalysis(String organizationKey) {
return executeAnalysis(newProjectKey(), organizationKey);
}
@@ -153,12 +186,12 @@ public class BillingTest {
return ItUtils.extractCeTaskId(buildResult);
}
- private void assertWsResponseAsAdmin(GetRequest request, String expectedContent){
+ 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){
+ 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 14103f7db19..55faca1638a 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
@@ -35,6 +35,11 @@ public interface BillingValidations {
void checkOnProjectAnalysis(Organization organization);
/**
+ * @throws BillingValidationsException when the organization cannot use private projects
+ */
+ void checkCanUpdateProjectVisibility(Organization organization, boolean updateToPrivate);
+
+ /**
* @return true if the organization can use private projects
*/
boolean canUpdateProjectVisibilityToPrivate(Organization organization);
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 c9512f73226..64c2277ead6 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
@@ -42,6 +42,14 @@ public class BillingValidationsProxyImpl implements BillingValidationsProxy {
}
@Override
+ public void checkCanUpdateProjectVisibility(Organization organization, boolean updateToPrivate) {
+ if (billingValidationsExtension == null) {
+ return;
+ }
+ billingValidationsExtension.checkCanUpdateProjectVisibility(organization, updateToPrivate);
+ }
+
+ @Override
public boolean canUpdateProjectVisibilityToPrivate(Organization organization) {
return billingValidationsExtension == null || billingValidationsExtension.canUpdateProjectVisibilityToPrivate(organization);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/UpdateProjectVisibilityAction.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/UpdateProjectVisibilityAction.java
index 6beec1aa8ef..183fa7f02d8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/UpdateProjectVisibilityAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/UpdateProjectVisibilityAction.java
@@ -28,6 +28,8 @@ 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.project.Visibility;
import org.sonar.server.user.UserSession;
@@ -40,10 +42,12 @@ public class UpdateProjectVisibilityAction implements OrganizationsWsAction {
private final UserSession userSession;
private final DbClient dbClient;
+ private final BillingValidationsProxy billingValidations;
- public UpdateProjectVisibilityAction(UserSession userSession, DbClient dbClient) {
+ public UpdateProjectVisibilityAction(UserSession userSession, DbClient dbClient, BillingValidationsProxy billingValidations) {
this.userSession = userSession;
this.dbClient = dbClient;
+ this.billingValidations = billingValidations;
}
@Override
@@ -74,9 +78,18 @@ public class UpdateProjectVisibilityAction implements OrganizationsWsAction {
Optional<OrganizationDto> optionalOrganization = dbClient.organizationDao().selectByKey(dbSession, organizationKey);
OrganizationDto organization = checkFoundWithOptional(optionalOrganization, "No organization with key '" + organizationKey + "' can be found.");
userSession.checkPermission(OrganizationPermission.ADMINISTER, organization.getUuid());
+ checkCanUpdateProjectsVisibility(organization, newProjectsPrivate);
dbClient.organizationDao().setNewProjectPrivate(dbSession, organization, newProjectsPrivate);
dbSession.commit();
}
response.noContent();
}
+
+ private void checkCanUpdateProjectsVisibility(OrganizationDto organization, boolean newProjectsPrivate) {
+ try {
+ billingValidations.checkCanUpdateProjectVisibility(new BillingValidations.Organization(organization.getKey(), organization.getUuid()), newProjectsPrivate);
+ } catch (BillingValidations.BillingValidationsException e) {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyImplTest.java
index 31874248397..616c5973a42 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyImplTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/BillingValidationsProxyImplTest.java
@@ -59,6 +59,26 @@ public class BillingValidationsProxyImplTest {
}
@Test
+ public void checkCanUpdateProjectsVisibility_calls_extension_when_available() {
+ underTest = new BillingValidationsProxyImpl(billingValidationsExtension);
+ Organization organization = new Organization(ORGANIZATION_KEY, ORGANIZATION_UUID);
+
+ underTest.checkCanUpdateProjectVisibility(organization, true);
+
+ verify(billingValidationsExtension).checkCanUpdateProjectVisibility(organization, true);
+ }
+
+ @Test
+ public void checkCanUpdateProjectsVisibility_does_nothing_when_no_extension_available() {
+ underTest = new BillingValidationsProxyImpl();
+ Organization organization = new Organization(ORGANIZATION_KEY, ORGANIZATION_UUID);
+
+ underTest.checkCanUpdateProjectVisibility(organization, true);
+
+ verifyZeroInteractions(billingValidationsExtension);
+ }
+
+ @Test
public void canUpdateProjectsVisibilityToPrivate_calls_extension_when_available() {
underTest = new BillingValidationsProxyImpl(billingValidationsExtension);
Organization organization = new Organization(ORGANIZATION_KEY, ORGANIZATION_UUID);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/UpdateProjectVisibilityActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/UpdateProjectVisibilityActionTest.java
index 7e03a0ec794..9532015c426 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/UpdateProjectVisibilityActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/UpdateProjectVisibilityActionTest.java
@@ -27,11 +27,17 @@ import org.sonar.db.DbTester;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.organization.BillingValidations;
+import org.sonar.server.organization.BillingValidationsProxy;
import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.TestRequest;
import org.sonar.server.ws.WsActionTester;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
import static org.sonar.server.organization.ws.OrganizationsWsSupport.PARAM_ORGANIZATION;
import static org.sonar.server.organization.ws.UpdateProjectVisibilityAction.ACTION;
@@ -45,7 +51,9 @@ public class UpdateProjectVisibilityActionTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private UpdateProjectVisibilityAction underTest = new UpdateProjectVisibilityAction(userSession, dbTester.getDbClient());
+ private BillingValidationsProxy billingValidations = mock(BillingValidationsProxy.class);
+
+ private UpdateProjectVisibilityAction underTest = new UpdateProjectVisibilityAction(userSession, dbTester.getDbClient(), billingValidations);
private WsActionTester wsTester = new WsActionTester(underTest);
@Test
@@ -71,7 +79,7 @@ public class UpdateProjectVisibilityActionTest {
}
@Test
- public void should_change_project_visibility_to_private() {
+ public void change_project_visibility_to_private() {
OrganizationDto organization = dbTester.organizations().insert();
dbTester.organizations().setNewProjectPrivate(organization, false);
userSession.logIn().addPermission(ADMINISTER, organization);
@@ -85,7 +93,7 @@ public class UpdateProjectVisibilityActionTest {
}
@Test
- public void should_change_project_visibility_to_public() {
+ public void change_project_visibility_to_public() {
OrganizationDto organization = dbTester.organizations().insert();
dbTester.organizations().setNewProjectPrivate(organization, true);
userSession.logIn().addPermission(ADMINISTER, organization);
@@ -100,7 +108,40 @@ public class UpdateProjectVisibilityActionTest {
}
@Test
- public void should_fail_if_organization_does_not_exist() {
+ public void fail_to_update_visibility_to_private_when_organization_is_not_allowed_to_use_private_projects() {
+ OrganizationDto organization = dbTester.organizations().insert();
+ dbTester.organizations().setNewProjectPrivate(organization, true);
+ userSession.logIn().addPermission(ADMINISTER, organization);
+ doThrow(new BillingValidations.BillingValidationsException("This organization cannot use project private")).when(billingValidations)
+ .checkCanUpdateProjectVisibility(any(BillingValidations.Organization.class), eq(true));
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("This organization cannot use project private");
+
+ wsTester.newRequest()
+ .setParam(PARAM_ORGANIZATION, organization.getKey())
+ .setParam(PARAM_PROJECT_VISIBILITY, "private")
+ .execute();
+ }
+
+ @Test
+ public void does_not_fail_to_update_visibility_to_public_when_organization_is_not_allowed_to_use_private_projects() {
+ OrganizationDto organization = dbTester.organizations().insert();
+ dbTester.organizations().setNewProjectPrivate(organization, true);
+ userSession.logIn().addPermission(ADMINISTER, organization);
+ doThrow(new BillingValidations.BillingValidationsException("This organization cannot use project private")).when(billingValidations)
+ .checkCanUpdateProjectVisibility(any(BillingValidations.Organization.class), eq(true));
+
+ wsTester.newRequest()
+ .setParam(PARAM_ORGANIZATION, organization.getKey())
+ .setParam(PARAM_PROJECT_VISIBILITY, "public")
+ .execute();
+
+ assertThat(dbTester.organizations().getNewProjectPrivate(organization)).isFalse();
+ }
+
+ @Test
+ public void fail_if_organization_does_not_exist() {
TestRequest request = wsTester.newRequest()
.setParam(PARAM_ORGANIZATION, "does not exist")
.setParam(PARAM_PROJECT_VISIBILITY, "private");
@@ -119,5 +160,4 @@ public class UpdateProjectVisibilityActionTest {
expectedException.expect(ForbiddenException.class);
request.execute();
}
-
}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/organization/OrganizationService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/organization/OrganizationService.java
index 035411fe48e..edede842c06 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/organization/OrganizationService.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/organization/OrganizationService.java
@@ -105,4 +105,11 @@ public class OrganizationService extends BaseService {
call(post);
}
+
+ public void updateProjectVisibility(UpdateProjectVisibilityWsRequest request) {
+ PostRequest post = new PostRequest(path("update_project_visibility"))
+ .setParam("organization", request.getOrganization())
+ .setParam("projectVisibility", request.getProjectVisibility());
+ call(post, UpdateWsResponse.parser());
+ }
}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/organization/UpdateProjectVisibilityWsRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/organization/UpdateProjectVisibilityWsRequest.java
new file mode 100644
index 00000000000..e7af9537548
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/organization/UpdateProjectVisibilityWsRequest.java
@@ -0,0 +1,68 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info 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.sonarqube.ws.client.organization;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.Immutable;
+
+@Immutable
+public class UpdateProjectVisibilityWsRequest {
+ private final String organization;
+ private final String projectVisibility;
+
+ private UpdateProjectVisibilityWsRequest(Builder builder) {
+ this.organization = builder.organization;
+ this.projectVisibility = builder.projectVisibility;
+ }
+
+ @CheckForNull
+ public String getOrganization() {
+ return organization;
+ }
+
+ @CheckForNull
+ public String getProjectVisibility() {
+ return projectVisibility;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String organization;
+ private String projectVisibility;
+
+ public Builder setOrganization(@Nullable String organization) {
+ this.organization = organization;
+ return this;
+ }
+
+ public Builder setProjectVisibility(@Nullable String projectVisibility) {
+ this.projectVisibility = projectVisibility;
+ return this;
+ }
+
+ public UpdateProjectVisibilityWsRequest build() {
+ return new UpdateProjectVisibilityWsRequest(this);
+ }
+ }
+}
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/organization/OrganizationServiceTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/organization/OrganizationServiceTest.java
index b87a1ecc73d..aefc8a6411a 100644
--- a/sonar-ws/src/test/java/org/sonarqube/ws/client/organization/OrganizationServiceTest.java
+++ b/sonar-ws/src/test/java/org/sonarqube/ws/client/organization/OrganizationServiceTest.java
@@ -96,4 +96,18 @@ public class OrganizationServiceTest {
.hasParam("login", "login-1")
.andNoOtherParam();
}
+
+ @Test
+ public void update_project_visibility() {
+ underTest.updateProjectVisibility(UpdateProjectVisibilityWsRequest.builder()
+ .setOrganization("O1")
+ .setProjectVisibility("private")
+ .build());
+
+ serviceTester.assertThat(serviceTester.getPostRequest())
+ .hasPath("update_project_visibility")
+ .hasParam("organization", "O1")
+ .hasParam("projectVisibility", "private")
+ .andNoOtherParam();
+ }
}