]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8761 new WS api/organizations/enable_support
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 10 Feb 2017 14:13:56 +0000 (15:13 +0100)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 10 Feb 2017 21:49:08 +0000 (22:49 +0100)
server/sonar-server/src/main/java/org/sonar/server/organization/ws/EnableSupportAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsModule.java
server/sonar-server/src/main/java/org/sonar/server/organization/ws/OrganizationsWsSupport.java
server/sonar-server/src/main/java/org/sonar/server/property/InternalProperties.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/CreateActionTest.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/EnableSupportActionTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/organization/ws/OrganizationsWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/SearchActionTest.java
server/sonar-server/src/test/java/org/sonar/server/organization/ws/UpdateActionTest.java

diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/EnableSupportAction.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/EnableSupportAction.java
new file mode 100644 (file)
index 0000000..61759ee
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.organization.ws;
+
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.organization.DefaultOrganizationProvider;
+import org.sonar.server.property.InternalProperties;
+import org.sonar.server.user.UserSession;
+
+import static java.lang.String.valueOf;
+import static java.util.Objects.requireNonNull;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+
+public class EnableSupportAction implements OrganizationsAction {
+  private static final String ACTION = "enable_support";
+
+  private final UserSession userSession;
+  private final DbClient dbClient;
+  private final DefaultOrganizationProvider defaultOrganizationProvider;
+  private final OrganizationsWsSupport support;
+
+  public EnableSupportAction(UserSession userSession, DbClient dbClient, DefaultOrganizationProvider defaultOrganizationProvider, OrganizationsWsSupport support) {
+    this.userSession = userSession;
+    this.dbClient = dbClient;
+    this.defaultOrganizationProvider = defaultOrganizationProvider;
+    this.support = support;
+  }
+
+  @Override
+  public void define(WebService.NewController context) {
+    context.createAction(ACTION)
+      .setPost(true)
+      .setDescription("Enable support of organizations.<br />" +
+        "'Administer System' permission is required. The logged-in user will be flagged as root and will be able to manage organizations and other root users.")
+      .setInternal(true)
+      .setPost(true)
+      .setSince("6.3")
+      .setHandler(this);
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    verifySystemAdministrator();
+
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      verifyFeatureIsDisabled(dbSession);
+      flagCurrentUserAsRoot(dbSession);
+      enableFeature(dbSession);
+      dbSession.commit();
+    }
+    response.noContent();
+  }
+
+  private void verifySystemAdministrator() {
+    userSession.checkLoggedIn().checkOrganizationPermission(defaultOrganizationProvider.get().getUuid(), SYSTEM_ADMIN);
+  }
+
+  private void verifyFeatureIsDisabled(DbSession dbSession) {
+    if (support.isFeatureEnabled(dbSession)) {
+      throw new BadRequestException("Organizations are already enabled");
+    }
+  }
+
+  private void flagCurrentUserAsRoot(DbSession dbSession) {
+    dbClient.userDao().setRoot(dbSession, requireNonNull(userSession.getLogin()), true);
+  }
+
+  private void enableFeature(DbSession dbSession) {
+    dbClient.internalPropertiesDao().save(dbSession, InternalProperties.ORGANIZATION_ENABLED, valueOf(true));
+  }
+
+}
index 41c9dfcb92c2adf5b73cb5c86e85f04af17aeb74..c05b428bc39e9537bb7c60d2421293a1ae8e58e7 100644 (file)
@@ -30,6 +30,7 @@ public class OrganizationsWsModule extends Module {
       OrganizationsWsSupport.class,
       // actions
       CreateAction.class,
+      EnableSupportAction.class,
       SearchAction.class,
       UpdateAction.class,
       DeleteAction.class,
index 42019093cd604a752ec677d10f1db62a67294c84..90c5f6e5c39844f641956f7fe4b3fcd6ee8b0a8b 100644 (file)
  */
 package org.sonar.server.organization.ws;
 
+import java.util.Optional;
 import javax.annotation.CheckForNull;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.WebService;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.server.organization.OrganizationValidation;
+import org.sonar.server.property.InternalProperties;
 import org.sonarqube.ws.Organizations;
 
 import static org.sonar.core.util.Protobuf.setNullable;
@@ -39,9 +43,11 @@ public class OrganizationsWsSupport {
   static final String PARAM_AVATAR_URL = "avatar";
 
   private final OrganizationValidation organizationValidation;
+  private final DbClient dbClient;
 
-  public OrganizationsWsSupport(OrganizationValidation organizationValidation) {
+  public OrganizationsWsSupport(OrganizationValidation organizationValidation, DbClient dbClient) {
     this.organizationValidation = organizationValidation;
+    this.dbClient = dbClient;
   }
 
   String getAndCheckMandatoryName(Request request) {
@@ -112,4 +118,9 @@ public class OrganizationsWsSupport {
     setNullable(dto.getAvatarUrl(), builder::setAvatar);
     return builder.build();
   }
+
+  boolean isFeatureEnabled(DbSession dbSession) {
+    Optional<String> value = dbClient.internalPropertiesDao().selectByKey(dbSession, InternalProperties.ORGANIZATION_ENABLED);
+    return value.isPresent() && Boolean.parseBoolean(value.get());
+  }
 }
index 8c94e5072b6267eff7fd8311b44a987a589b37c2..1d84ad9441ab33e4f8f4dc3957bac15a83d42dc4 100644 (file)
@@ -32,6 +32,8 @@ public interface InternalProperties {
    */
   String DEFAULT_ORGANIZATION = "organization.default";
 
+  String ORGANIZATION_ENABLED = "organization.enabled";
+
   /**
    * Read the value of the specified property.
    *
index 46461d96e8f3a586edbd97db66619166d58e6d15..70f69075edffab6304c6d1e446999aeedea51f26 100644 (file)
@@ -90,7 +90,7 @@ public class CreateActionTest {
   private UuidFactory uuidFactory = mock(UuidFactory.class);
   private OrganizationValidation organizationValidation = new OrganizationValidationImpl();
   private OrganizationCreation organizationCreation = new OrganizationCreationImpl(dbClient, system2, uuidFactory, organizationValidation, settings);
-  private CreateAction underTest = new CreateAction(settings, userSession, dbClient, new OrganizationsWsSupport(organizationValidation), organizationValidation, organizationCreation);
+  private CreateAction underTest = new CreateAction(settings, userSession, dbClient, new OrganizationsWsSupport(organizationValidation, dbClient), organizationValidation, organizationCreation);
   private WsActionTester wsTester = new WsActionTester(underTest);
 
   @Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/organization/ws/EnableSupportActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/organization/ws/EnableSupportActionTest.java
new file mode 100644 (file)
index 0000000..52e6590
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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.organization.ws;
+
+import java.net.HttpURLConnection;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.db.DbTester;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.organization.DefaultOrganizationProvider;
+import org.sonar.server.organization.OrganizationValidationImpl;
+import org.sonar.server.organization.TestDefaultOrganizationProvider;
+import org.sonar.server.property.InternalProperties;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+
+public class EnableSupportActionTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+  @Rule
+  public DbTester db = DbTester.create();
+
+  private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
+  private OrganizationsWsSupport support = new OrganizationsWsSupport(new OrganizationValidationImpl(), db.getDbClient());
+  private EnableSupportAction underTest = new EnableSupportAction(userSession, db.getDbClient(), defaultOrganizationProvider, support);
+  private WsActionTester tester = new WsActionTester(underTest);
+
+  @Test
+  public void enabling_support_saves_internal_property_and_flags_caller_as_root() {
+    UserDto user = db.users().insertUser();
+    db.rootFlag().verify(user.getLogin(), false);
+    logInAsSystemAdministrator(user.getLogin());
+
+    call();
+
+    assertThat(db.getDbClient().internalPropertiesDao().selectByKey(db.getSession(), InternalProperties.ORGANIZATION_ENABLED)).hasValue("true");
+    db.rootFlag().verify(user.getLogin(), true);
+  }
+
+  @Test
+  public void throw_UnauthorizedException_if_not_logged_in() {
+    userSession.anonymous();
+
+    expectedException.expect(UnauthorizedException.class);
+    expectedException.expectMessage("Authentication is required");
+
+    call();
+  }
+
+  @Test
+  public void throw_ForbiddenException_if_not_system_administrator() {
+    userSession.logIn();
+
+    expectedException.expect(ForbiddenException.class);
+    expectedException.expectMessage("Insufficient privileges");
+
+    call();
+  }
+
+  @Test
+  public void throw_BadRequestException_if_support_is_already_enabled() {
+    logInAsSystemAdministrator("foo");
+
+    call();
+
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Organizations are already enabled");
+
+    call();
+  }
+
+  @Test
+  public void test_definition() {
+    WebService.Action def = tester.getDef();
+    assertThat(def.key()).isEqualTo("enable_support");
+    assertThat(def.isPost()).isTrue();
+    assertThat(def.isInternal()).isTrue();
+    assertThat(def.params()).isEmpty();
+  }
+
+  private void logInAsSystemAdministrator(String login) {
+    userSession.logIn(login).addOrganizationPermission(db.getDefaultOrganization().getUuid(), SYSTEM_ADMIN);
+  }
+
+  private void call() {
+    TestResponse response = tester.newRequest().setMethod("POST").execute();
+    assertThat(response.getStatus()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT);
+  }
+}
index 0b42c200bb25320eb13f880e43bcad42493029e1..eccaae0ecc56b123b1da6ecc3c0e8bb250aa7e84 100644 (file)
@@ -33,7 +33,7 @@ public class OrganizationsWsModuleTest {
     ComponentContainer container = new ComponentContainer();
     underTest.configure(container);
     assertThat(container.getPicoContainer().getComponentAdapters())
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 7);
+      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 8);
   }
 
 }
index b2a6977848b947676ebc6385f58a1890bc75c893..5e0588450376fdc57cc147cb6e7687cfee4d6d67 100644 (file)
@@ -68,7 +68,7 @@ public class SearchActionTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
-  private SearchAction underTest = new SearchAction(dbTester.getDbClient(), new OrganizationsWsSupport(new OrganizationValidationImpl()));
+  private SearchAction underTest = new SearchAction(dbTester.getDbClient(), new OrganizationsWsSupport(new OrganizationValidationImpl(), dbTester.getDbClient()));
   private WsActionTester wsTester = new WsActionTester(underTest);
 
   @Test
index 01c90b27fd2b0c5f543b11df587c9b4cc7669c45..4339eec14ac1f984823fca81d956c4a179c29087 100644 (file)
@@ -59,7 +59,7 @@ public class UpdateActionTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
-  private UpdateAction underTest = new UpdateAction(userSession, new OrganizationsWsSupport(new OrganizationValidationImpl()), dbTester.getDbClient());
+  private UpdateAction underTest = new UpdateAction(userSession, new OrganizationsWsSupport(new OrganizationValidationImpl(), dbTester.getDbClient()), dbTester.getDbClient());
   private WsActionTester wsTester = new WsActionTester(underTest);
 
   @Test