]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8055 Create /api/emails/update_configuration WS to update email settings
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 1 Sep 2016 12:34:29 +0000 (14:34 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 2 Sep 2016 09:45:05 +0000 (11:45 +0200)
server/sonar-server/src/main/java/org/sonar/server/email/ws/EmailsWs.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/email/ws/EmailsWsAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/email/ws/EmailsWsModule.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/email/ws/UpdateConfigurationAction.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/email/ws/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
server/sonar-server/src/test/java/org/sonar/server/email/ws/EmailsWsModuleTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/email/ws/UpdateConfigurationActionTest.java [new file with mode: 0644]

diff --git a/server/sonar-server/src/main/java/org/sonar/server/email/ws/EmailsWs.java b/server/sonar-server/src/main/java/org/sonar/server/email/ws/EmailsWs.java
new file mode 100644 (file)
index 0000000..a33cac5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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.email.ws;
+
+import org.sonar.api.server.ws.WebService;
+
+public class EmailsWs implements WebService {
+
+  private final EmailsWsAction[] actions;
+
+  public EmailsWs(EmailsWsAction... actions) {
+    this.actions = actions;
+  }
+
+  @Override
+  public void define(Context context) {
+    NewController controller = context.createController("api/emails")
+      .setDescription("Manage emails")
+      .setSince("6.1");
+    for (EmailsWsAction action : actions) {
+      action.define(controller);
+    }
+    controller.done();
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/email/ws/EmailsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/email/ws/EmailsWsAction.java
new file mode 100644 (file)
index 0000000..bbfd9b2
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.email.ws;
+
+import org.sonar.server.ws.WsAction;
+
+public interface EmailsWsAction extends WsAction {
+  // marker interface
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/email/ws/EmailsWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/email/ws/EmailsWsModule.java
new file mode 100644 (file)
index 0000000..9db3639
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.email.ws;
+
+import org.sonar.core.platform.Module;
+
+public class EmailsWsModule extends Module {
+  @Override
+  protected void configureModule() {
+    add(
+      EmailsWs.class,
+      UpdateConfigurationAction.class);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/email/ws/UpdateConfigurationAction.java b/server/sonar-server/src/main/java/org/sonar/server/email/ws/UpdateConfigurationAction.java
new file mode 100644 (file)
index 0000000..524efb8
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * 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.email.ws;
+
+import javax.annotation.Nullable;
+import org.sonar.api.config.Settings;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.server.user.UserSession;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.sonar.api.config.EmailSettings.FROM;
+import static org.sonar.api.config.EmailSettings.FROM_DEFAULT;
+import static org.sonar.api.config.EmailSettings.PREFIX;
+import static org.sonar.api.config.EmailSettings.PREFIX_DEFAULT;
+import static org.sonar.api.config.EmailSettings.SMTP_HOST;
+import static org.sonar.api.config.EmailSettings.SMTP_PASSWORD;
+import static org.sonar.api.config.EmailSettings.SMTP_PORT;
+import static org.sonar.api.config.EmailSettings.SMTP_PORT_DEFAULT;
+import static org.sonar.api.config.EmailSettings.SMTP_SECURE_CONNECTION;
+import static org.sonar.api.config.EmailSettings.SMTP_USERNAME;
+
+public class UpdateConfigurationAction implements EmailsWsAction {
+
+  private static final String PARAM_HOST = "host";
+  private static final String PARAM_PORT = "port";
+  private static final String PARAM_SECURE = "secure";
+  private static final String PARAM_USERNAME = "username";
+  private static final String PARAM_PASSWORD = "password";
+  private static final String PARAM_FROM = "from";
+  private static final String PARAM_PREFIX = "prefix";
+
+  private static final String SSL_VALUE = "ssl";
+  private static final String STARTTLS_VALUE = "starttls";
+
+  private final DbClient dbClient;
+  private final UserSession userSession;
+
+  // TODO remove this when EmailSettings won't use Settings in memory to get settings
+  private final Settings settings;
+
+  public UpdateConfigurationAction(DbClient dbClient, UserSession userSession, Settings settings) {
+    this.dbClient = dbClient;
+    this.userSession = userSession;
+    this.settings = settings;
+  }
+
+  @Override
+  public void define(WebService.NewController context) {
+    WebService.NewAction action = context.createAction("update_configuration")
+      .setDescription("Update email configuration<br/>" +
+        "If a parameter is not set, it will be reset<br>" +
+        "Requires 'Administer System' permission.")
+      .setSince("6.1")
+      .setInternal(true)
+      .setPost(true)
+      .setHandler(this);
+
+    action.createParam(PARAM_HOST)
+      .setDescription("SMTP host.")
+      .setExampleValue("smtp.gmail.com");
+
+    action.createParam(PARAM_PORT)
+      .setDescription("Port number to connect with SMTP server.")
+      .setExampleValue(SMTP_PORT_DEFAULT);
+
+    action.createParam(PARAM_SECURE)
+      .setDescription("Whether to use secure connection and its type.")
+      .setPossibleValues(SSL_VALUE, STARTTLS_VALUE)
+      .setExampleValue(SSL_VALUE);
+
+    action.createParam(PARAM_USERNAME)
+      .setDescription("Username to use with authenticated SMTP.")
+      .setExampleValue("my_username");
+
+    action.createParam(PARAM_PASSWORD)
+      .setDescription("Username to use with authenticated SMTP.")
+      .setExampleValue("my_password");
+
+    action.createParam(PARAM_FROM)
+      .setDescription("Emails will come from this address. For example - \"noreply@sonarsource.com\". Note that server may ignore this setting.")
+      .setExampleValue(FROM_DEFAULT);
+
+    action.createParam(PARAM_PREFIX)
+      .setDescription("Prefix will be prepended to all outgoing email subjects.")
+      .setExampleValue(PREFIX_DEFAULT);
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    userSession.checkPermission(GlobalPermissions.SYSTEM_ADMIN);
+
+    DbSession dbSession = dbClient.openSession(false);
+    try {
+      save(dbSession, SMTP_HOST, request.param(PARAM_HOST), PARAM_HOST);
+      save(dbSession, SMTP_PORT, request.hasParam(PARAM_PORT) ? Integer.toString(request.paramAsInt(PARAM_PORT)) : null, PARAM_PORT);
+      save(dbSession, SMTP_SECURE_CONNECTION, request.param(PARAM_SECURE), PARAM_SECURE);
+      save(dbSession, SMTP_USERNAME, request.param(PARAM_USERNAME), PARAM_USERNAME);
+      save(dbSession, SMTP_PASSWORD, request.param(PARAM_PASSWORD), PARAM_PASSWORD);
+      save(dbSession, FROM, request.param(PARAM_FROM), PARAM_FROM);
+      save(dbSession, PREFIX, request.param(PARAM_PREFIX), PARAM_PREFIX);
+      dbSession.commit();
+    } finally {
+      dbClient.closeSession(dbSession);
+    }
+    response.noContent();
+  }
+
+  private void save(DbSession dbSession, String settingKey, @Nullable String value, String requestKey) {
+    checkArgument(value == null || !value.isEmpty(), "Parameter '%s' cannot have an empty value", requestKey);
+    settings.setProperty(settingKey, value);
+    if (value != null) {
+      dbClient.propertiesDao().insertProperty(dbSession, new PropertyDto().setKey(settingKey).setValue(value));
+    } else {
+      dbClient.propertiesDao().deleteGlobalProperty(settingKey, dbSession);
+    }
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/email/ws/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/email/ws/package-info.java
new file mode 100644 (file)
index 0000000..c447b1d
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.email.ws;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index b2a65af59695be2f4f7280b4f6aff16306504e9c..1e7b008bc60f6b75d0c06385e3778d75ff86752c 100644 (file)
@@ -84,6 +84,7 @@ import org.sonar.server.debt.DebtRulesXMLImporter;
 import org.sonar.server.duplication.ws.DuplicationsJsonWriter;
 import org.sonar.server.duplication.ws.DuplicationsParser;
 import org.sonar.server.duplication.ws.DuplicationsWs;
+import org.sonar.server.email.ws.EmailsWsModule;
 import org.sonar.server.es.IndexCreator;
 import org.sonar.server.es.IndexDefinitions;
 import org.sonar.server.event.NewAlerts;
@@ -572,6 +573,7 @@ public class PlatformLevel4 extends PlatformLevel {
       NotificationService.class,
       NotificationCenter.class,
       DefaultNotificationManager.class,
+      EmailsWsModule.class,
 
       // Tests
       TestsWs.class,
diff --git a/server/sonar-server/src/test/java/org/sonar/server/email/ws/EmailsWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/email/ws/EmailsWsModuleTest.java
new file mode 100644 (file)
index 0000000..e42ea79
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.email.ws;
+
+import org.junit.Test;
+import org.sonar.core.platform.ComponentContainer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class EmailsWsModuleTest {
+  @Test
+  public void verify_count_of_added_components() {
+    ComponentContainer container = new ComponentContainer();
+    new EmailsWsModule().configure(container);
+    assertThat(container.size()).isEqualTo(2 + 2);
+  }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/email/ws/UpdateConfigurationActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/email/ws/UpdateConfigurationActionTest.java
new file mode 100644 (file)
index 0000000..899cc95
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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.email.ws;
+
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.System2;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.property.PropertyDbTester;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.assertj.core.api.Java6Assertions.assertThat;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;
+
+public class UpdateConfigurationActionTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+
+  DbClient dbClient = db.getDbClient();
+  PropertyDbTester propertyDb = new PropertyDbTester(db);
+  org.sonar.api.config.Settings settings = new org.sonar.api.config.Settings();
+
+  WsActionTester ws = new WsActionTester(new UpdateConfigurationAction(dbClient, userSession, settings));
+
+  @Test
+  public void update_email_settings() throws Exception {
+    setUserAsSystemAdmin();
+
+    executeRequest("smtp.gmail.com", 25, "starttls", "john", "12345", "noreply@email.com", "[EMAIL]");
+
+    assertSetting("email.smtp_host.secured", "smtp.gmail.com");
+    assertSetting("email.smtp_port.secured", "25");
+    assertSetting("email.smtp_secure_connection.secured", "starttls");
+    assertSetting("email.smtp_username.secured", "john");
+    assertSetting("email.smtp_password.secured", "12345");
+    assertSetting("email.from", "noreply@email.com");
+    assertSetting("email.prefix", "[EMAIL]");
+  }
+
+  @Test
+  public void does_not_save_settings_when_no_value_sent() throws Exception {
+    setUserAsSystemAdmin();
+
+    executeRequest(null, null, null, null, null, null, null);
+
+    assertThat(db.countRowsOfTable(db.getSession(), "properties")).isZero();
+  }
+
+  @Test
+  public void remove_existing_settings_when_no_value_sent() throws Exception {
+    setUserAsSystemAdmin();
+    addSetting("email.smtp_host.secured", "smtp.gmail.com");
+    addSetting("email.smtp_port.secured", "25");
+    addSetting("email.smtp_secure_connection.secured", "starttls");
+    addSetting("email.smtp_username.secured", "john");
+    addSetting("email.smtp_password.secured", "12345");
+    addSetting("email.from", "noreply@email.com");
+    addSetting("email.prefix", "[EMAIL]");
+
+    executeRequest(null, null, null, null, null, null, null);
+
+    assertThat(db.countRowsOfTable(db.getSession(), "properties")).isZero();
+  }
+
+  @Test
+  public void fail_when_secure_param_is_invalid() {
+    setUserAsSystemAdmin();
+
+    expectedException.expect(IllegalArgumentException.class);
+
+    executeRequest(null, null, "unknown", null, null, null, null);
+  }
+
+  @Test
+  public void fail_when_insufficient_privileges() {
+    userSession.anonymous().setGlobalPermissions(GlobalPermissions.QUALITY_PROFILE_ADMIN);
+    expectedException.expect(ForbiddenException.class);
+
+    ws.newRequest().execute();
+  }
+
+  @Test
+  public void fail_when_parameter_is_empty() {
+    setUserAsSystemAdmin();
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Parameter 'host' cannot have an empty value");
+
+    executeRequest("", null, null, null, null, null, null);
+  }
+
+  @Test
+  public void test_ws_definition() {
+    WebService.Action action = ws.getDef();
+    assertThat(action).isNotNull();
+    assertThat(action.isInternal()).isTrue();
+    assertThat(action.isPost()).isTrue();
+    assertThat(action.responseExampleAsString()).isNull();
+    assertThat(action.params()).hasSize(7);
+  }
+
+  private void assertSetting(String key, String value) {
+    PropertyDto result = dbClient.propertiesDao().selectGlobalProperty(key);
+
+    assertThat(result)
+      .extracting(PropertyDto::getKey, PropertyDto::getValue, PropertyDto::getResourceId)
+      .containsExactly(key, value, null);
+
+    assertThat(settings.getString(key)).isEqualTo(value);
+  }
+
+  private void executeRequest(@Nullable String host, @Nullable Integer port, @Nullable String secure,
+    @Nullable String username, @Nullable String password, @Nullable String from, @Nullable String prefix) {
+    TestRequest request = ws.newRequest();
+    if (host != null) {
+      request.setParam("host", host);
+    }
+    if (port != null) {
+      request.setParam("port", Integer.toString(port));
+    }
+    if (secure != null) {
+      request.setParam("secure", secure);
+    }
+    if (username != null) {
+      request.setParam("username", username);
+    }
+    if (password != null) {
+      request.setParam("password", password);
+    }
+    if (from != null) {
+      request.setParam("from", from);
+    }
+    if (prefix != null) {
+      request.setParam("prefix", prefix);
+    }
+    request.execute();
+  }
+
+  private void addSetting(String key, String value) {
+    propertyDb.insertProperty(newGlobalPropertyDto(key, value));
+    settings.setProperty(key, value);
+  }
+
+  private void setUserAsSystemAdmin() {
+    userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
+  }
+
+}