aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorGuillaume Jambet <guillaume.jambet@sonarsource.com>2018-02-08 15:50:43 +0100
committerGuillaume Jambet <guillaume.jambet@gmail.com>2018-03-01 15:21:05 +0100
commita5a65a2c81c6f44b1eb37d5630bd37ffb46c085a (patch)
tree95a1881d785bd678cdee65a0faeefd9c8562a3db /server
parent07a20e83c4037ab7853c57aa92e614d47be74cf4 (diff)
downloadsonarqube-a5a65a2c81c6f44b1eb37d5630bd37ffb46c085a.tar.gz
sonarqube-a5a65a2c81c6f44b1eb37d5630bd37ffb46c085a.zip
SONAR-10345 Add Webhooks delete ws
Diffstat (limited to 'server')
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java5
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookMapper.java2
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookMapper.xml6
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDaoTest.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/webhook/ws/DeleteAction.java109
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsModule.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsParameters.java3
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/webhook/ws/DeleteActionTest.java185
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java2
9 files changed, 321 insertions, 3 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java
index b972edbe665..0711adecf5c 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java
@@ -63,8 +63,11 @@ public class WebhookDao implements Dao {
mapper(dbSession).update(dto.setUpdatedAt(system2.now()));
}
+ public void delete(DbSession dbSession, String uuid) {
+ mapper(dbSession).delete(uuid);
+ }
+
private static WebhookMapper mapper(DbSession dbSession) {
return dbSession.getMapper(WebhookMapper.class);
}
-
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookMapper.java
index 3b5706c62bc..354f0d2de5d 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookMapper.java
@@ -36,4 +36,6 @@ public interface WebhookMapper {
void update(WebhookDto dto);
+ void delete(@Param("uuid") String uuid);
+
}
diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookMapper.xml
index 0eb69994650..33171e72276 100644
--- a/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookMapper.xml
+++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookMapper.xml
@@ -63,4 +63,10 @@
where uuid=#{uuid, jdbcType=VARCHAR}
</update>
+ <delete id="delete" parameterType="String">
+ delete from webhooks
+ where
+ uuid = #{uuid,jdbcType=VARCHAR}
+ </delete>
+
</mapper>
diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDaoTest.java
index 01e8ef62225..2dafd3b90a9 100644
--- a/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDaoTest.java
+++ b/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDaoTest.java
@@ -116,6 +116,17 @@ public class WebhookDaoTest {
assertThat(new Date(reloaded.getUpdatedAt())).isInSameMinuteWindowAs(new Date(system2.now()));
}
+ @Test
+ public void delete() {
+
+ OrganizationDto organization = organizationDbTester.insert();
+ WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+
+ underTest.delete(dbSession, dto.getUuid());
+
+ Optional<WebhookDto> reloaded = underTest.selectByUuid(dbSession, dto.uuid);
+ assertThat(reloaded).isEmpty();
+ }
@Test
public void fail_if_webhook_does_not_have_an_organization_nor_a_project() {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/DeleteAction.java
new file mode 100644
index 00000000000..3888bb5747f
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/DeleteAction.java
@@ -0,0 +1,109 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonar.server.webhook.ws;
+
+import java.util.Optional;
+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.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.webhook.WebhookDto;
+import org.sonar.server.user.UserSession;
+
+import static java.util.Optional.ofNullable;
+import static org.sonar.server.webhook.ws.WebhooksWsParameters.DELETE_ACTION;
+import static org.sonar.server.webhook.ws.WebhooksWsParameters.KEY_PARAM;
+import static org.sonar.server.webhook.ws.WebhooksWsParameters.KEY_PARAM_MAXIMUN_LENGTH;
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+import static org.sonar.server.ws.WsUtils.checkFoundWithOptional;
+import static org.sonar.server.ws.WsUtils.checkStateWithOptional;
+
+public class DeleteAction implements WebhooksWsAction {
+
+ private final DbClient dbClient;
+ private final UserSession userSession;
+ private final WebhookSupport webhookSupport;
+
+ public DeleteAction(DbClient dbClient, UserSession userSession, WebhookSupport webhookSupport) {
+ this.dbClient = dbClient;
+ this.userSession = userSession;
+ this.webhookSupport = webhookSupport;
+ }
+
+ @Override
+ public void define(WebService.NewController controller) {
+
+ WebService.NewAction action = controller.createAction(DELETE_ACTION)
+ .setPost(true)
+ .setDescription("Delete a Webhook.<br>" +
+ "Requires the global, organization or project permission.")
+ .setSince("7.1")
+ .setHandler(this);
+
+ action.createParam(KEY_PARAM)
+ .setRequired(true)
+ .setMaximumLength(KEY_PARAM_MAXIMUN_LENGTH)
+ .setDescription("The key of the webhook to be deleted")
+ .setExampleValue(KEY_PROJECT_EXAMPLE_001);
+
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+
+ userSession.checkLoggedIn();
+
+ String webhookKey = request.param(KEY_PARAM);
+
+ try (DbSession dbSession = dbClient.openSession(false)) {
+
+ Optional<WebhookDto> dtoOptional = dbClient.webhookDao().selectByUuid(dbSession, webhookKey);
+ WebhookDto webhookDto = checkFoundWithOptional(dtoOptional, "No webhook with key '%s'", webhookKey);
+
+ String organizationUuid = webhookDto.getOrganizationUuid();
+ if (organizationUuid != null) {
+ Optional<OrganizationDto> optionalDto = dbClient.organizationDao().selectByUuid(dbSession, organizationUuid);
+ OrganizationDto organizationDto = checkStateWithOptional(optionalDto, "the requested organization '%s' was not found", organizationUuid);
+ webhookSupport.checkUserPermissionOn(organizationDto);
+ deleteWebhook(dbSession, webhookDto);
+ }
+
+ String projectUuid = webhookDto.getProjectUuid();
+ if (projectUuid != null) {
+ Optional<ComponentDto> optionalDto = ofNullable(dbClient.componentDao().selectByUuid(dbSession, projectUuid).orNull());
+ ComponentDto componentDto = checkStateWithOptional(optionalDto, "the requested project '%s' was not found", projectUuid);
+ webhookSupport.checkUserPermissionOn(componentDto);
+ deleteWebhook(dbSession, webhookDto);
+ }
+
+ dbSession.commit();
+ }
+
+ response.noContent();
+ }
+
+ private void deleteWebhook(DbSession dbSession, WebhookDto webhookDto) {
+ dbClient.webhookDao().delete(dbSession, webhookDto.getUuid());
+ }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsModule.java
index 3927c5da41b..12625ea3634 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsModule.java
@@ -30,6 +30,7 @@ public class WebhooksWsModule extends Module {
SearchAction.class,
CreateAction.class,
UpdateAction.class,
+ DeleteAction.class,
WebhookDeliveryAction.class,
WebhookDeliveriesAction.class);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsParameters.java b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsParameters.java
index 10b2c7b0498..bf7c97c2ca6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsParameters.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/webhook/ws/WebhooksWsParameters.java
@@ -24,9 +24,10 @@ class WebhooksWsParameters {
static final String WEBHOOKS_CONTROLLER = "api/webhooks";
+ static final String SEARCH_ACTION = "search";
static final String ACTION_CREATE = "create";
static final String UPDATE_ACTION = "update";
- static final String SEARCH_ACTION = "search";
+ static final String DELETE_ACTION = "delete";
static final String ORGANIZATION_KEY_PARAM = "organization";
diff --git a/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/DeleteActionTest.java
new file mode 100644
index 00000000000..f54d55a6bd1
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/DeleteActionTest.java
@@ -0,0 +1,185 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 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.sonar.server.webhook.ws;
+
+import java.util.Optional;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDbTester;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.webhook.WebhookDbTester;
+import org.sonar.db.webhook.WebhookDto;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.organization.DefaultOrganizationProvider;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+
+import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.tuple;
+import static org.junit.rules.ExpectedException.none;
+import static org.sonar.api.web.UserRole.ADMIN;
+import static org.sonar.db.DbTester.create;
+import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
+import static org.sonar.server.organization.TestDefaultOrganizationProvider.from;
+import static org.sonar.server.tester.UserSessionRule.standalone;
+import static org.sonar.server.webhook.ws.WebhooksWsParameters.KEY_PARAM;
+
+public class DeleteActionTest {
+
+ @Rule
+ public ExpectedException expectedException = none();
+
+ @Rule
+ public UserSessionRule userSession = standalone();
+
+ @Rule
+ public DbTester db = create();
+ private DbClient dbClient = db.getDbClient();
+ private WebhookDbTester webhookDbTester = db.webhooks();
+ private OrganizationDbTester organizationDbTester = db.organizations();
+ private ComponentDbTester componentDbTester = db.components();
+
+ private DefaultOrganizationProvider defaultOrganizationProvider = from(db);
+
+ private WebhookSupport webhookSupport = new WebhookSupport(userSession);
+ private DeleteAction underTest = new DeleteAction(dbClient, userSession, webhookSupport);
+ private WsActionTester wsActionTester = new WsActionTester(underTest);
+
+ @Test
+ public void test_ws_definition() {
+
+ WebService.Action action = wsActionTester.getDef();
+ assertThat(action).isNotNull();
+ assertThat(action.isInternal()).isFalse();
+ assertThat(action.isPost()).isTrue();
+
+ assertThat(action.params())
+ .extracting(WebService.Param::key, WebService.Param::isRequired)
+ .containsExactlyInAnyOrder(tuple("key", true));
+
+ }
+
+ @Test
+ public void delete_a_project_webhook() {
+
+ ComponentDto project = componentDbTester.insertPrivateProject();
+ WebhookDto dto = webhookDbTester.insertWebhookForProjectUuid(project.uuid());
+ userSession.logIn().addProjectPermission(ADMIN, project);
+
+ TestResponse response = wsActionTester.newRequest()
+ .setParam(KEY_PARAM, dto.getUuid())
+ .execute();
+
+ assertThat(response.getStatus()).isEqualTo(HTTP_NO_CONTENT);
+ Optional<WebhookDto> reloaded = webhookDbTester.selectWebhook(dto.getUuid());
+ assertThat(reloaded).isEmpty();
+
+ }
+
+ @Test
+ public void delete_an_organization_webhook() {
+
+ OrganizationDto organization = organizationDbTester.insert();
+ WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ userSession.logIn().addPermission(ADMINISTER, organization.getUuid());
+
+ TestResponse response = wsActionTester.newRequest()
+ .setParam(KEY_PARAM, dto.getUuid())
+ .execute();
+
+ assertThat(response.getStatus()).isEqualTo(HTTP_NO_CONTENT);
+ Optional<WebhookDto> reloaded = webhookDbTester.selectWebhook(dto.getUuid());
+ assertThat(reloaded).isEmpty();
+
+ }
+
+ @Test
+ public void fail_if_webhook_does_not_exist() {
+
+ userSession.logIn().addPermission(ADMINISTER, defaultOrganizationProvider.get().getUuid());
+
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage("No webhook with key 'inexistent-webhook-uuid'");
+
+ wsActionTester.newRequest()
+ .setParam(KEY_PARAM, "inexistent-webhook-uuid")
+ .execute();
+ }
+
+ @Test
+ public void fail_if_not_logged_in() throws Exception {
+
+ OrganizationDto organization = organizationDbTester.insert();
+ WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ userSession.anonymous();
+
+ expectedException.expect(UnauthorizedException.class);
+
+ wsActionTester.newRequest()
+ .setParam(KEY_PARAM, dto.getUuid())
+ .execute();
+
+ }
+
+ @Test
+ public void fail_if_no_permission_on_webhook_scope_project() {
+
+ ComponentDto project = componentDbTester.insertPrivateProject();
+ WebhookDto dto = webhookDbTester.insertWebhookForProjectUuid(project.uuid());
+
+ userSession.logIn();
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage("Insufficient privileges");
+
+ wsActionTester.newRequest()
+ .setParam(KEY_PARAM, dto.getUuid())
+ .execute();
+
+ }
+
+ @Test
+ public void fail_if_no_permission_on_webhook_scope_organization() {
+
+ OrganizationDto organization = organizationDbTester.insert();
+ WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+
+ userSession.logIn();
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage("Insufficient privileges");
+
+ wsActionTester.newRequest()
+ .setParam(KEY_PARAM, dto.getUuid())
+ .execute();
+
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java
index 7afb02511bd..3ef537af8ab 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/webhook/ws/WebhooksWsModuleTest.java
@@ -32,7 +32,7 @@ public class WebhooksWsModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
underTest.configure(container);
- assertThat(container.size()).isEqualTo(3 + 6);
+ assertThat(container.size()).isEqualTo(3 + 7);
}
}