"ORGANIZATION_UUID" VARCHAR(40),
"PROJECT_UUID" VARCHAR(40),
"CREATED_AT" BIGINT NOT NULL,
- "UPDATED_AT" BIGINT
+ "UPDATED_AT" BIGINT NOT NULL
);
CREATE UNIQUE INDEX "PK_WEBHOOKS" ON "WEBHOOKS" ("UUID");
CREATE INDEX "ORGANIZATION_WEBHOOK" ON "WEBHOOKS" ("ORGANIZATION_UUID");
import org.sonar.api.utils.System2;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
import static com.google.common.base.Preconditions.checkState;
return Optional.ofNullable(mapper(dbSession).selectByUuid(uuid));
}
- public List<WebhookDto> selectByOrganizationUuid(DbSession dbSession, String organizationUuid) {
- return mapper(dbSession).selectForOrganizationUuidOrderedByName(organizationUuid);
+ public List<WebhookDto> selectByOrganizationUuid(DbSession dbSession, OrganizationDto organizationDto) {
+ return mapper(dbSession).selectForOrganizationUuidOrderedByName(organizationDto.getUuid());
}
- public List<WebhookDto> selectByProjectUuid(DbSession dbSession, String projectUuid) {
- return mapper(dbSession).selectForProjectUuidOrderedByName(projectUuid);
+ public List<WebhookDto> selectByProjectUuid(DbSession dbSession, ComponentDto componentDto) {
+ return mapper(dbSession).selectForProjectUuidOrderedByName(componentDto.uuid());
}
public void insert(DbSession dbSession, WebhookDto dto) {
-
checkState(dto.getOrganizationUuid() != null || dto.getProjectUuid() != null,
"A webhook can not be created if not linked to an organization or a project.");
-
checkState(dto.getOrganizationUuid() == null || dto.getProjectUuid() == null,
"A webhook can not be linked to both an organization and a project.");
-
- mapper(dbSession).insert(dto.setCreatedAt(system2.now()));
-
+ mapper(dbSession).insert(dto.setCreatedAt(system2.now()).setUpdatedAt(system2.now()));
}
public void update(DbSession dbSession, WebhookDto dto) {
public class WebhookDto {
/** Technical unique identifier, can't be null */
- protected String uuid;
+ private String uuid;
/** Name, can't be null */
- protected String name;
+ private String name;
/** URL, can't be null */
- protected String url;
+ private String url;
@Nullable
- protected String organizationUuid;
+ private String organizationUuid;
@Nullable
- protected String projectUuid;
+ private String projectUuid;
- /** createdAt, can't be null */
- protected Long createdAt;
- /** URL, can be null */
- @Nullable
- protected Long updatedAt;
+ private long createdAt;
+ private long updatedAt;
public WebhookDto setUuid(String uuid) {
this.uuid = uuid;
return this;
}
- WebhookDto setCreatedAt(Long createdAt) {
+ WebhookDto setCreatedAt(long createdAt) {
this.createdAt = createdAt;
return this;
}
- WebhookDto setUpdatedAt(@Nullable Long updatedAt) {
+ WebhookDto setUpdatedAt(long updatedAt) {
this.updatedAt = updatedAt;
return this;
}
return projectUuid;
}
- public Long getCreatedAt() {
+ public long getCreatedAt() {
return createdAt;
}
@Nullable
- public Long getUpdatedAt() {
+ public long getUpdatedAt() {
return updatedAt;
}
}
+++ /dev/null
-/*
- * 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.db.webhook;
-
-import java.util.Calendar;
-
-import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
-
-public class WebhookTesting {
-
- private WebhookTesting() {
- // only statics
- }
-
- public static WebhookDto newWebhookDtoForProject(String projectUuid) {
- return getWebhookDto()
- .setProjectUuid(projectUuid);
- }
-
- public static WebhookDto newWebhookDtoForOrganization(String organizationUuid) {
- return getWebhookDto()
- .setOrganizationUuid(organizationUuid);
- }
-
- private static WebhookDto getWebhookDto() {
- return new WebhookDto()
- .setUuid(randomAlphanumeric(40))
- .setName(randomAlphanumeric(64))
- .setUrl("https://www.random-site/" + randomAlphanumeric(256))
- .setCreatedAt(Calendar.getInstance().getTimeInMillis());
- }
-}
<mapper namespace="org.sonar.db.webhook.WebhookMapper">
- <sql id="sqlLiteColumns">
+ <sql id="sqlColumns">
uuid,
name,
url,
<select id="selectByUuid" parameterType="String" resultType="org.sonar.db.webhook.WebhookDto">
- select <include refid="sqlLiteColumns" />
+ select <include refid="sqlColumns" />
from webhooks
where uuid = #{webhookUuid,jdbcType=VARCHAR}
</select>
<select id="selectForOrganizationUuidOrderedByName" parameterType="String" resultType="org.sonar.db.webhook.WebhookDto">
- select <include refid="sqlLiteColumns" />
+ select <include refid="sqlColumns" />
from webhooks
where organization_uuid = #{organizationUuid,jdbcType=VARCHAR}
order by name asc
</select>
<select id="selectForProjectUuidOrderedByName" parameterType="String" resultType="org.sonar.db.webhook.WebhookDto">
- select <include refid="sqlLiteColumns" />
+ select <include refid="sqlColumns" />
from webhooks
where project_uuid = #{projectUuid,jdbcType=VARCHAR}
order by name asc
assertThat(stored.getOrganizationUuid()).isEqualTo(dto.getOrganizationUuid());
assertThat(stored.getProjectUuid()).isNull();
assertThat(new Date(stored.getCreatedAt())).isInSameMinuteWindowAs(new Date(system2.now()));
- assertThat(stored.getUpdatedAt()).isNull();
+ assertThat(new Date(stored.getUpdatedAt())).isInSameMinuteWindowAs(new Date(system2.now()));
}
@Test
assertThat(reloaded.getOrganizationUuid()).isNull();
assertThat(reloaded.getProjectUuid()).isEqualTo(dto.getProjectUuid());
assertThat(new Date(reloaded.getCreatedAt())).isInSameMinuteWindowAs(new Date(system2.now()));
- assertThat(reloaded.getUpdatedAt()).isNull();
+ assertThat(new Date(reloaded.getUpdatedAt())).isInSameMinuteWindowAs(new Date(system2.now()));
}
@Test
public void update() {
OrganizationDto organization = organizationDbTester.insert();
- WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(organization);
underTest.update(dbSession, dto.setName("a-fancy-webhook").setUrl("http://www.fancy-webhook.io"));
- WebhookDto reloaded = underTest.selectByUuid(dbSession, dto.uuid).get();
+ WebhookDto reloaded = underTest.selectByUuid(dbSession, dto.getUuid()).get();
assertThat(reloaded.getUuid()).isEqualTo(dto.getUuid());
assertThat(reloaded.getName()).isEqualTo("a-fancy-webhook");
assertThat(reloaded.getUrl()).isEqualTo("http://www.fancy-webhook.io");
public void delete() {
OrganizationDto organization = organizationDbTester.insert();
- WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(organization);
underTest.delete(dbSession, dto.getUuid());
- Optional<WebhookDto> reloaded = underTest.selectByUuid(dbSession, dto.uuid);
+ Optional<WebhookDto> reloaded = underTest.selectByUuid(dbSession, dto.getUuid());
assertThat(reloaded).isEmpty();
}
import java.util.Optional;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
-import static org.sonar.db.webhook.WebhookTesting.newWebhookDtoForOrganization;
-import static org.sonar.db.webhook.WebhookTesting.newWebhookDtoForProject;
+import static org.sonar.db.webhook.WebhookTesting.newWebhook;
public class WebhookDbTester {
this.dbTester = dbTester;
}
- public WebhookDto insertForOrganizationUuid(String organizationUuid) {
- return insert(newWebhookDtoForOrganization(organizationUuid));
+ public WebhookDto insertWebhook(OrganizationDto organizationDto) {
+ return insert(newWebhook(organizationDto));
}
- public WebhookDto insertWebhookForProjectUuid(String projectUuid) {
- return insert(newWebhookDtoForProject(projectUuid));
+ public WebhookDto insertWebhook(ComponentDto project) {
+ return insert(newWebhook(project));
}
public WebhookDto insert(WebhookDto dto) {
--- /dev/null
+/*
+ * 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.db.webhook;
+
+import java.util.Calendar;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
+
+public class WebhookTesting {
+
+ private WebhookTesting() {
+ // only statics
+ }
+
+ public static WebhookDto newWebhook(ComponentDto project) {
+ return getWebhookDto()
+ .setProjectUuid(project.uuid());
+ }
+
+ public static WebhookDto newWebhook(OrganizationDto organizationDto) {
+ return getWebhookDto()
+ .setOrganizationUuid(organizationDto.getUuid());
+ }
+
+ private static WebhookDto getWebhookDto() {
+ return new WebhookDto()
+ .setUuid(randomAlphanumeric(40))
+ .setName(randomAlphanumeric(64))
+ .setUrl("https://www.random-site/" + randomAlphanumeric(256))
+ .setCreatedAt(Calendar.getInstance().getTimeInMillis());
+ }
+}
.setIsNullable(false)
.setLimit(UUID_SIZE)
.build();
- private static final int NAME_COLUMN_SIZE = 100;
private static final VarcharColumnDef NAME_COLUMN = newVarcharColumnDefBuilder()
.setColumnName("name")
.setIsNullable(false)
- .setLimit(NAME_COLUMN_SIZE)
+ .setLimit(100)
.build();
- private static final int URL_COLUMN_SIZE = 2000;
private static final VarcharColumnDef URL_COLUMN = newVarcharColumnDefBuilder()
.setColumnName("url")
.setIsNullable(false)
- .setLimit(URL_COLUMN_SIZE)
+ .setLimit(2000)
.build();
private static final VarcharColumnDef ORGANIZATION_UUID_COLUMN = newVarcharColumnDefBuilder()
.setColumnName("organization_uuid")
.setIsNullable(true)
.build();
- private Database db;
-
public CreateWebhooksTable(Database db) {
super(db);
- this.db = db;
}
@Override
}
private boolean tableExists() throws SQLException {
- try (Connection connection = db.getDataSource().getConnection()) {
+ try (Connection connection = getDatabase().getDataSource().getConnection()) {
return DatabaseUtils.tableExists(TABLE_NAME, connection);
}
}
*/
package org.sonar.server.webhook;
-import java.util.Arrays;
import java.util.List;
-import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
-import org.sonar.api.config.Configuration;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import org.sonar.core.config.WebhookProperties;
import org.sonar.core.util.stream.MoreCollectors;
+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.WebhookDao;
+import org.sonar.db.webhook.WebhookDto;
import org.sonar.server.async.AsyncExecution;
-import static java.lang.String.format;
-import static org.sonar.core.config.WebhookProperties.MAX_WEBHOOKS_PER_TYPE;
+import static java.util.Optional.ofNullable;
+import static org.sonar.server.ws.WsUtils.checkStateWithOptional;
public class WebHooksImpl implements WebHooks {
private static final Logger LOGGER = Loggers.get(WebHooksImpl.class);
- private static final String WEBHOOK_PROPERTY_FORMAT = "%s.%s";
private final WebhookCaller caller;
private final WebhookDeliveryStorage deliveryStorage;
private final AsyncExecution asyncExecution;
+ private final DbClient dbClient;
- public WebHooksImpl(WebhookCaller caller, WebhookDeliveryStorage deliveryStorage, AsyncExecution asyncExecution) {
+ public WebHooksImpl(WebhookCaller caller, WebhookDeliveryStorage deliveryStorage, AsyncExecution asyncExecution, DbClient dbClient) {
this.caller = caller;
this.deliveryStorage = deliveryStorage;
this.asyncExecution = asyncExecution;
+ this.dbClient = dbClient;
}
@Override
- public boolean isEnabled(Configuration config) {
- return readWebHooksFrom(config)
+ public boolean isEnabled(ComponentDto projectDto) {
+ return readWebHooksFrom(projectDto)
.findAny()
.isPresent();
}
- public static Stream<NameUrl> readWebHooksFrom(Configuration config) {
- return Stream.concat(
- getWebhookProperties(config, WebhookProperties.GLOBAL_KEY).stream(),
- getWebhookProperties(config, WebhookProperties.PROJECT_KEY).stream())
- .map(
- webHookProperty -> {
- String name = config.get(format(WEBHOOK_PROPERTY_FORMAT, webHookProperty, WebhookProperties.NAME_FIELD)).orElse(null);
- String url = config.get(format(WEBHOOK_PROPERTY_FORMAT, webHookProperty, WebhookProperties.URL_FIELD)).orElse(null);
- if (name == null || url == null) {
- return null;
- }
- return new NameUrl(name, url);
- })
- .filter(Objects::nonNull);
- }
-
- private static List<String> getWebhookProperties(Configuration config, String propertyKey) {
- String[] webhookIds = config.getStringArray(propertyKey);
- return Arrays.stream(webhookIds)
- .map(webhookId -> format(WEBHOOK_PROPERTY_FORMAT, propertyKey, webhookId))
- .limit(MAX_WEBHOOKS_PER_TYPE)
- .collect(MoreCollectors.toList(webhookIds.length));
+ private Stream<WebhookDto> readWebHooksFrom(ComponentDto projectDto) {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ Optional<OrganizationDto> optionalDto = dbClient.organizationDao().selectByUuid(dbSession, projectDto.getOrganizationUuid());
+ OrganizationDto organizationDto = checkStateWithOptional(optionalDto, "the requested organization '%s' was not found", projectDto.getOrganizationUuid());
+ WebhookDao dao = dbClient.webhookDao();
+ return Stream.concat(
+ dao.selectByProjectUuid(dbSession, projectDto).stream(),
+ dao.selectByOrganizationUuid(dbSession, organizationDto).stream());
+ }
}
@Override
- public void sendProjectAnalysisUpdate(Configuration config, Analysis analysis, Supplier<WebhookPayload> payloadSupplier) {
- List<Webhook> webhooks = readWebHooksFrom(config)
- .map(nameUrl -> new Webhook(analysis.getProjectUuid(), analysis.getCeTaskUuid(), analysis.getAnalysisUuid(), nameUrl.getName(), nameUrl.getUrl()))
+ public void sendProjectAnalysisUpdate(ComponentDto componentDto, Analysis analysis, Supplier<WebhookPayload> payloadSupplier) {
+ List<Webhook> webhooks = readWebHooksFrom(componentDto)
+ .map(dto -> new Webhook(analysis.getProjectUuid(), analysis.getCeTaskUuid(), analysis.getAnalysisUuid(), dto.getName(), dto.getUrl()))
.collect(MoreCollectors.toList());
if (webhooks.isEmpty()) {
return;
asyncExecution.addToQueue(() -> deliveryStorage.purge(analysis.getProjectUuid()));
}
+ @Override
+ public void sendProjectAnalysisUpdate(Analysis analysis, Supplier<WebhookPayload> payloadSupplier) {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ Optional<ComponentDto> optionalDto = ofNullable(dbClient.componentDao().selectByUuid(dbSession, analysis.getProjectUuid()).orNull());
+ ComponentDto projectDto = checkStateWithOptional(optionalDto, "the requested project '%s' was not found", analysis.getProjectUuid());
+ sendProjectAnalysisUpdate(projectDto, analysis, payloadSupplier);
+ }
+ }
+
private static void log(WebhookDelivery delivery) {
Optional<String> error = delivery.getErrorMessage();
if (error.isPresent()) {
}
}
- public static final class NameUrl {
- private final String name;
- private final String url;
-
- private NameUrl(String name, String url) {
- this.name = name;
- this.url = url;
- }
-
- public String getName() {
- return name;
- }
-
- public String getUrl() {
- return url;
- }
- }
}
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
import org.sonar.db.webhook.WebhookDto;
-import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.user.UserSession;
import org.sonarqube.ws.Webhooks;
import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
+import static java.util.Optional.ofNullable;
import static org.apache.commons.lang.StringUtils.isNotBlank;
import static org.sonar.server.webhook.ws.WebhooksWsParameters.ACTION_CREATE;
import static org.sonar.server.webhook.ws.WebhooksWsParameters.NAME_PARAM;
WebService.NewAction action = controller.createAction(ACTION_CREATE)
.setPost(true)
.setDescription("Create a Webhook.<br>" +
- "Requires the global, organization or project permission.")
+ "Requires 'Administer' permission on the specified project, or global 'Administer' permission.")
.setSince("7.1")
.setResponseExample(getClass().getResource("example-webhook-create.json"))
.setHandler(this);
action.createParam(NAME_PARAM)
.setRequired(true)
.setMaximumLength(NAME_PARAM_MAXIMUM_LENGTH)
- .setDescription("The name of the webhook to create")
+ .setDescription("Name displayed in the administration console of webhooks")
.setExampleValue(NAME_WEBHOOK_EXAMPLE_001);
action.createParam(URL_PARAM)
.setRequired(true)
.setMaximumLength(URL_PARAM_MAXIMUM_LENGTH)
- .setDescription("The url to be called by the webhook")
+ .setDescription("Server endpoint that will receive the webhook payload, for example 'http://my_server/foo'." +
+ " If HTTP Basic authentication is used, HTTPS is recommended to avoid man in the middle attacks." +
+ " Example: 'https://myLogin:myPassword@my_server/foo'")
.setExampleValue(URL_WEBHOOK_EXAMPLE_001);
action.createParam(PROJECT_KEY_PARAM)
ComponentDto projectDto = null;
if (isNotBlank(projectKey)) {
- Optional<ComponentDto> dtoOptional = Optional.ofNullable(dbClient.componentDao().selectByKey(dbSession, projectKey).orNull());
+ Optional<ComponentDto> dtoOptional = ofNullable(dbClient.componentDao().selectByKey(dbSession, projectKey).orNull());
ComponentDto componentDto = checkFoundWithOptional(dtoOptional, "No project with key '%s'", projectKey);
- checkThatProjectBelongsToOrganization(componentDto, organizationDto, "Project '%s' does not belong to organisation '%s'", projectKey, organizationKey);
- webhookSupport.checkUserPermissionOn(componentDto);
+ webhookSupport.checkThatProjectBelongsToOrganization(componentDto, organizationDto, "Project '%s' does not belong to organisation '%s'", projectKey, organizationKey);
+ webhookSupport.checkPermission(componentDto);
projectDto = componentDto;
} else {
- webhookSupport.checkUserPermissionOn(organizationDto);
+ webhookSupport.checkPermission(organizationDto);
}
webhookSupport.checkUrlPattern(url, "Url parameter with value '%s' is not a valid url", url);
}
}
- private int numberOfWebhookOf(DbSession dbSession, OrganizationDto organization) {
- return dbClient.webhookDao().selectByOrganizationUuid(dbSession, organization.getUuid()).size();
+ private int numberOfWebhookOf(DbSession dbSession, OrganizationDto organizationDto) {
+ return dbClient.webhookDao().selectByOrganizationUuid(dbSession, organizationDto).size();
}
- private int numberOfWebhookOf(DbSession dbSession, ComponentDto project) {
- return dbClient.webhookDao().selectByProjectUuid(dbSession, project.uuid()).size();
- }
-
- private static void checkThatProjectBelongsToOrganization(ComponentDto componentDto, OrganizationDto organizationDto, String message, Object... messageArguments) {
- if (!organizationDto.getUuid().equals(componentDto.getOrganizationUuid())) {
- throw new NotFoundException(format(message, messageArguments));
- }
+ private int numberOfWebhookOf(DbSession dbSession, ComponentDto componentDto) {
+ return dbClient.webhookDao().selectByProjectUuid(dbSession, componentDto).size();
}
private OrganizationDto defaultOrganizationDto(DbSession dbSession) {
WebService.NewAction action = controller.createAction(DELETE_ACTION)
.setPost(true)
.setDescription("Delete a Webhook.<br>" +
- "Requires the global, organization or project permission.")
+ "Requires 'Administer' permission on the specified project, or global 'Administer' 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")
+ .setDescription("The key of the webhook to be deleted,"+
+ "auto-generated value can be obtained through api/webhooks/create or api/webhooks/list")
.setExampleValue(KEY_PROJECT_EXAMPLE_001);
}
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);
+ webhookSupport.checkPermission(organizationDto);
deleteWebhook(dbSession, webhookDto);
}
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);
+ webhookSupport.checkPermission(componentDto);
deleteWebhook(dbSession, webhookDto);
}
--- /dev/null
+/*
+ * 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 com.google.common.io.Resources;
+import java.util.List;
+import java.util.Optional;
+import javax.annotation.Nullable;
+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.organization.DefaultOrganizationProvider;
+import org.sonar.server.user.UserSession;
+import org.sonarqube.ws.Webhooks.SearchWsResponse.Builder;
+
+import static java.util.Optional.ofNullable;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.sonar.server.webhook.ws.WebhooksWsParameters.LIST_ACTION;
+import static org.sonar.server.webhook.ws.WebhooksWsParameters.ORGANIZATION_KEY_PARAM;
+import static org.sonar.server.webhook.ws.WebhooksWsParameters.PROJECT_KEY_PARAM;
+import static org.sonar.server.ws.KeyExamples.KEY_ORG_EXAMPLE_001;
+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;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.Webhooks.SearchWsResponse.newBuilder;
+
+public class ListAction implements WebhooksWsAction {
+
+ private final DbClient dbClient;
+ private final UserSession userSession;
+ private final DefaultOrganizationProvider defaultOrganizationProvider;
+ private final WebhookSupport webhookSupport;
+
+ public ListAction(DbClient dbClient, UserSession userSession, DefaultOrganizationProvider defaultOrganizationProvider, WebhookSupport webhookSupport) {
+ this.dbClient = dbClient;
+ this.userSession = userSession;
+ this.defaultOrganizationProvider = defaultOrganizationProvider;
+ this.webhookSupport = webhookSupport;
+ }
+
+ @Override
+ public void define(WebService.NewController controller) {
+
+ WebService.NewAction action = controller.createAction(LIST_ACTION)
+ .setDescription("Search for global webhooks or project webhooks. Webhooks are ordered by name.<br>" +
+ "Requires 'Administer' permission on the specified project, or global 'Administer' permission.")
+ .setSince("7.1")
+ .setResponseExample(Resources.getResource(this.getClass(), "example-webhooks-search.json"))
+ .setHandler(this);
+
+ action.createParam(ORGANIZATION_KEY_PARAM)
+ .setDescription("Organization key. If no organization is provided, the default organization is used.")
+ .setInternal(true)
+ .setRequired(false)
+ .setExampleValue(KEY_ORG_EXAMPLE_001);
+
+ action.createParam(PROJECT_KEY_PARAM)
+ .setDescription("Project key")
+ .setRequired(false)
+ .setExampleValue(KEY_PROJECT_EXAMPLE_001);
+
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+
+ String projectKey = request.param(PROJECT_KEY_PARAM);
+ String organizationKey = request.param(ORGANIZATION_KEY_PARAM);
+
+ userSession.checkLoggedIn();
+
+ writeResponse(request, response, doHandle(organizationKey, projectKey));
+
+ }
+
+ private List<WebhookDto> doHandle(@Nullable String organizationKey, @Nullable String projectKey) {
+
+ try (DbSession dbSession = dbClient.openSession(true)) {
+
+ OrganizationDto organizationDto;
+ if (isNotBlank(organizationKey)) {
+ Optional<OrganizationDto> dtoOptional = dbClient.organizationDao().selectByKey(dbSession, organizationKey);
+ organizationDto = checkFoundWithOptional(dtoOptional, "No organization with key '%s'", organizationKey);
+ } else {
+ organizationDto = defaultOrganizationDto(dbSession);
+ }
+
+ if (isNotBlank(projectKey)) {
+
+ Optional<ComponentDto> optional = ofNullable(dbClient.componentDao().selectByKey(dbSession, projectKey).orNull());
+ ComponentDto componentDto = checkFoundWithOptional(optional, "project %s does not exist", projectKey);
+ webhookSupport.checkPermission(componentDto);
+ webhookSupport.checkThatProjectBelongsToOrganization(componentDto, organizationDto, "Project '%s' does not belong to organisation '%s'", projectKey, organizationKey);
+ webhookSupport.checkPermission(componentDto);
+ return dbClient.webhookDao().selectByProjectUuid(dbSession, componentDto);
+
+ } else {
+
+ webhookSupport.checkPermission(organizationDto);
+ return dbClient.webhookDao().selectByOrganizationUuid(dbSession, organizationDto);
+
+ }
+
+ }
+ }
+
+ private static void writeResponse(Request request, Response response, List<WebhookDto> webhookDtos) {
+
+ Builder responseBuilder = newBuilder();
+
+ webhookDtos
+ .stream()
+ .forEach(webhook -> responseBuilder.addWebhooksBuilder()
+ .setKey(webhook.getUuid())
+ .setName(webhook.getName())
+ .setUrl(webhook.getUrl()));
+
+ writeProtobuf(responseBuilder.build(), request, response);
+ }
+
+ private OrganizationDto defaultOrganizationDto(DbSession dbSession) {
+ String uuid = defaultOrganizationProvider.get().getUuid();
+ Optional<OrganizationDto> organizationDto = dbClient.organizationDao().selectByUuid(dbSession, uuid);
+ return checkStateWithOptional(organizationDto, "the default organization '%s' was not found", uuid);
+ }
+
+}
+++ /dev/null
-/*
- * 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 com.google.common.base.Optional;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.io.Resources;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import javax.annotation.Nullable;
-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.server.setting.ws.Setting;
-import org.sonar.server.setting.ws.SettingsFinder;
-import org.sonar.server.user.UserSession;
-import org.sonarqube.ws.Webhooks.SearchWsResponse.Builder;
-
-import static org.apache.commons.lang.StringUtils.isNotBlank;
-import static org.sonar.api.web.UserRole.ADMIN;
-import static org.sonar.server.webhook.ws.WebhooksWsParameters.ORGANIZATION_KEY_PARAM;
-import static org.sonar.server.webhook.ws.WebhooksWsParameters.PROJECT_KEY_PARAM;
-import static org.sonar.server.webhook.ws.WebhooksWsParameters.SEARCH_ACTION;
-import static org.sonar.server.ws.KeyExamples.KEY_ORG_EXAMPLE_001;
-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.writeProtobuf;
-import static org.sonarqube.ws.Webhooks.SearchWsResponse.newBuilder;
-
-public class SearchAction implements WebhooksWsAction {
-
- private final DbClient dbClient;
- private final UserSession userSession;
- private final SettingsFinder settingsFinder;
-
- public SearchAction(DbClient dbClient, UserSession userSession, SettingsFinder settingsFinder) {
- this.dbClient = dbClient;
- this.userSession = userSession;
- this.settingsFinder = settingsFinder;
- }
-
- @Override
- public void define(WebService.NewController controller) {
-
- WebService.NewAction action = controller.createAction(SEARCH_ACTION)
- .setDescription("Search for global or project webhooks")
- .setSince("7.1")
- .setResponseExample(Resources.getResource(this.getClass(), "example-webhooks-search.json"))
- .setHandler(this);
-
- action.createParam(ORGANIZATION_KEY_PARAM)
- .setDescription("Organization key. If no organization is provided, the default organization is used.")
- .setInternal(true)
- .setRequired(false)
- .setExampleValue(KEY_ORG_EXAMPLE_001);
-
- action.createParam(PROJECT_KEY_PARAM)
- .setDescription("Project key")
- .setRequired(false)
- .setExampleValue(KEY_PROJECT_EXAMPLE_001);
-
- }
-
- @Override
- public void handle(Request request, Response response) throws Exception {
-
- String projectKey = request.param(PROJECT_KEY_PARAM);
-
- userSession.checkLoggedIn();
-
- writeResponse(request, response, doHandle(projectKey));
-
- }
-
- private List<Setting> doHandle(@Nullable String projectKey) {
-
- try (DbSession dbSession = dbClient.openSession(true)) {
-
- if (isNotBlank(projectKey)) {
- Optional<ComponentDto> component = dbClient.componentDao().selectByKey(dbSession, projectKey);
- checkFoundWithOptional(component, "project %s does not exist", projectKey);
- userSession.checkComponentPermission(ADMIN, component.get());
- return new ArrayList<>(settingsFinder.loadComponentSettings(dbSession,
- ImmutableSet.of("sonar.webhooks.project"), component.get()).get(component.get().uuid()));
- } else {
- userSession.checkIsSystemAdministrator();
- return settingsFinder.loadGlobalSettings(dbSession, ImmutableSet.of("sonar.webhooks.global"));
- }
- }
- }
-
- private static void writeResponse(Request request, Response response, List<Setting> settings) {
-
- Builder responseBuilder = newBuilder();
-
- settings
- .stream()
- .map(Setting::getPropertySets)
- .flatMap(Collection::stream)
- .forEach(map -> responseBuilder.addWebhooksBuilder()
- .setKey("")
- .setName(map.get("name"))
- .setUrl(map.get("url")));
-
- writeProtobuf(responseBuilder.build(), request, response);
- }
-
-}
WebService.NewAction action = controller.createAction(UPDATE_ACTION)
.setPost(true)
.setDescription("Update a Webhook.<br>" +
- "Requires the global, organization or project permission.")
+ "Requires 'Administer' permission on the specified project, or global 'Administer' 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 updated")
+ .setDescription("The key of the webhook to be updated,"+
+ "auto-generated value can be obtained through api/webhooks/create or api/webhooks/list")
.setExampleValue(KEY_PROJECT_EXAMPLE_001);
action.createParam(NAME_PARAM)
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);
+ webhookSupport.checkPermission(organizationDto);
updateWebhook(dbSession, webhookDto, name, url);
}
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);
+ webhookSupport.checkPermission(componentDto);
updateWebhook(dbSession, webhookDto, name, url);
}
import org.sonar.db.component.ComponentDto;
import org.sonar.db.organization.OrganizationDto;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession;
import static java.lang.String.format;
-import static java.util.Locale.ENGLISH;
import static org.sonar.api.web.UserRole.ADMIN;
import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
private final UserSession userSession;
- public WebhookSupport(UserSession userSession) {
+ WebhookSupport(UserSession userSession) {
this.userSession = userSession;
}
- void checkUserPermissionOn(ComponentDto componentDto) {
+ void checkPermission(ComponentDto componentDto) {
userSession.checkComponentPermission(ADMIN, componentDto);
}
- void checkUserPermissionOn(OrganizationDto organizationDto) {
+ void checkPermission(OrganizationDto organizationDto) {
userSession.checkPermission(ADMINISTER, organizationDto);
}
void checkUrlPattern(String url, String message, Object... messageArguments) {
- if (!url.toLowerCase(ENGLISH).startsWith("http://") && !url.toLowerCase(ENGLISH).startsWith("https://")) {
+ if (okhttp3.HttpUrl.parse(url) == null) {
throw new IllegalArgumentException(format(message, messageArguments));
}
- String sub = url.substring("http://".length());
- if (sub.contains(":") && !sub.substring(sub.indexOf(':')).contains("@")) {
- throw new IllegalArgumentException(format(message, messageArguments));
+ }
+
+ void checkThatProjectBelongsToOrganization(ComponentDto componentDto, OrganizationDto organizationDto, String message, Object... messageArguments) {
+ if (!organizationDto.getUuid().equals(componentDto.getOrganizationUuid())) {
+ throw new NotFoundException(format(message, messageArguments));
}
}
add(
WebhookSupport.class,
WebhooksWs.class,
- SearchAction.class,
+ ListAction.class,
CreateAction.class,
UpdateAction.class,
DeleteAction.class,
static final String WEBHOOKS_CONTROLLER = "api/webhooks";
- static final String SEARCH_ACTION = "search";
+ static final String LIST_ACTION = "list";
static final String ACTION_CREATE = "create";
static final String UPDATE_ACTION = "update";
static final String DELETE_ACTION = "delete";
static final int NAME_PARAM_MAXIMUM_LENGTH = 100;
static final String URL_PARAM = "url";
static final int URL_PARAM_MAXIMUM_LENGTH = 512;
- static final String COMPONENT_KEY_PARAM = "component";
- static final int COMPONENT_KEY_PARAM_MAXIMUM_LENGTH = 255;
- static final String KEY_PARAM = "key";
+ static final String KEY_PARAM = "webhook";
static final int KEY_PARAM_MAXIMUN_LENGTH = 40;
private WebhooksWsParameters() {
public static final String KEY_BRANCH_EXAMPLE_001 = "feature/my_branch";
- public static final String NAME_WEBHOOK_EXAMPLE_001 = "my-webhook";
+ public static final String NAME_WEBHOOK_EXAMPLE_001 = "My Webhook";
public static final String URL_WEBHOOK_EXAMPLE_001 = "https://www.my-webhook-listener.com/sonar";
private KeyExamples() {
{
"webhook": {
"key": "uuid",
- "name": "my-webhook",
+ "name": "My webhook",
"url": "https://www.my-webhook-listener.com/sonar"
}
}
\ No newline at end of file
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.utils.System2;
+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.server.async.AsyncExecution;
+import org.sonar.server.organization.DefaultOrganizationProvider;
import static java.util.Objects.requireNonNull;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.sonar.db.DbTester.create;
+import static org.sonar.db.webhook.WebhookTesting.newWebhook;
+import static org.sonar.server.organization.TestDefaultOrganizationProvider.from;
public class AsynchronousWebHooksImplTest {
+
+ private System2 system2 = mock(System2.class);
+
+ @Rule
+ public DbTester db = create(system2);
+ private WebhookDbTester webhookDbTester = db.webhooks();
+ private ComponentDbTester componentDbTester = db.components();
+ private OrganizationDbTester organizationDbTester = db.organizations();
+ private DefaultOrganizationProvider defaultOrganizationProvider = from(db);
+
private static final long NOW = 1_500_000_000_000L;
- private static final String PROJECT_UUID = "P1_UUID";
- private final MapSettings settings = new MapSettings();
+
private final TestWebhookCaller caller = new TestWebhookCaller();
private final WebhookDeliveryStorage deliveryStorage = mock(WebhookDeliveryStorage.class);
private final WebhookPayload mock = mock(WebhookPayload.class);
private final RecordingAsyncExecution asyncExecution = new RecordingAsyncExecution();
- private final WebHooksImpl underTest = new WebHooksImpl(caller, deliveryStorage, asyncExecution);
+ private final WebHooksImpl underTest = new WebHooksImpl(caller, deliveryStorage, asyncExecution, db.getDbClient());
@Test
public void send_global_webhooks() {
- settings.setProperty("sonar.webhooks.global", "1,2");
- settings.setProperty("sonar.webhooks.global.1.name", "First");
- settings.setProperty("sonar.webhooks.global.1.url", "http://url1");
- settings.setProperty("sonar.webhooks.global.2.name", "Second");
- settings.setProperty("sonar.webhooks.global.2.url", "http://url2");
+
+ OrganizationDto organizationDto = db.getDefaultOrganization() ;
+ ComponentDto project = componentDbTester.insertPrivateProject(componentDto -> componentDto.setOrganizationUuid(organizationDto.getUuid()));
+ webhookDbTester.insert(newWebhook(organizationDto).setName("First").setUrl("http://url1"));
+ webhookDbTester.insert(newWebhook(organizationDto).setName("Second").setUrl("http://url2"));
+
caller.enqueueSuccess(NOW, 200, 1_234);
caller.enqueueFailure(NOW, new IOException("Fail to connect"));
- underTest.sendProjectAnalysisUpdate(settings.asConfig(), new WebHooks.Analysis(PROJECT_UUID, "1", "#1"), () -> mock);
+ underTest.sendProjectAnalysisUpdate(new WebHooks.Analysis(project.uuid(), "1", "#1"), () -> mock);
assertThat(caller.countSent()).isZero();
verifyZeroInteractions(deliveryStorage);
assertThat(caller.countSent()).isEqualTo(2);
verify(deliveryStorage, times(2)).persist(any(WebhookDelivery.class));
- verify(deliveryStorage).purge(PROJECT_UUID);
+ verify(deliveryStorage).purge(project.uuid());
}
private static class RecordingAsyncExecution implements AsyncExecution {
package org.sonar.server.webhook;
import java.io.IOException;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
+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.webhook.WebhookDbTester;
import org.sonar.server.async.AsyncExecution;
+import org.sonar.server.organization.DefaultOrganizationProvider;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.sonar.api.utils.log.LoggerLevel.DEBUG;
+import static org.sonar.db.DbTester.create;
+import static org.sonar.db.webhook.WebhookTesting.newWebhook;
+import static org.sonar.server.organization.TestDefaultOrganizationProvider.from;
public class SynchronousWebHooksImplTest {
private static final long NOW = 1_500_000_000_000L;
- private static final String PROJECT_UUID = "P1_UUID";
@Rule
public LogTester logTester = new LogTester();
- private final MapSettings settings = new MapSettings();
+ @Rule
+ public DbTester db = create();
+ private DbClient dbClient = db.getDbClient();
+
+ private WebhookDbTester webhookDbTester = db.webhooks();
+ private ComponentDbTester componentDbTester = db.components();
+ private DefaultOrganizationProvider defaultOrganizationProvider = from(db);
+
private final TestWebhookCaller caller = new TestWebhookCaller();
private final WebhookDeliveryStorage deliveryStorage = mock(WebhookDeliveryStorage.class);
private final WebhookPayload mock = mock(WebhookPayload.class);
private final AsyncExecution synchronousAsyncExecution = Runnable::run;
- private final WebHooksImpl underTest = new WebHooksImpl(caller, deliveryStorage, synchronousAsyncExecution);
-
- @Test
- public void isEnabled_returns_false_if_no_webHoolds() {
- assertThat(underTest.isEnabled(settings.asConfig())).isFalse();
- }
-
- @Test
- public void isEnabled_returns_true_if_one_valid_global_webhook() {
- settings.setProperty("sonar.webhooks.global", "1");
- settings.setProperty("sonar.webhooks.global.1.name", "First");
- settings.setProperty("sonar.webhooks.global.1.url", "http://url1");
-
- assertThat(underTest.isEnabled(settings.asConfig())).isTrue();
- }
+ private final WebHooksImpl underTest = new WebHooksImpl(caller, deliveryStorage, synchronousAsyncExecution, dbClient);
@Test
- public void isEnabled_returns_false_if_only_one_global_webhook_without_url() {
- settings.setProperty("sonar.webhooks.global", "1");
- settings.setProperty("sonar.webhooks.global.1.name", "First");
+ public void isEnabled_returns_false_if_no_webhooks() {
+ ComponentDto componentDto = componentDbTester.insertPrivateProject();
- assertThat(underTest.isEnabled(settings.asConfig())).isFalse();
+ assertThat(underTest.isEnabled(componentDto)).isFalse();
}
@Test
- public void isEnabled_returns_false_if_only_one_global_webhook_without_name() {
- settings.setProperty("sonar.webhooks.global", "1");
- settings.setProperty("sonar.webhooks.global.1.url", "http://url1");
+ public void isEnabled_returns_true_if_one_valid_global_webhook() {
+ ComponentDto componentDto = componentDbTester.insertPrivateProject();
+ webhookDbTester.insert(newWebhook(componentDto).setName("First").setUrl("http://url1"));
- assertThat(underTest.isEnabled(settings.asConfig())).isFalse();
+ assertThat(underTest.isEnabled(componentDto)).isTrue();
}
@Test
public void isEnabled_returns_true_if_one_valid_project_webhook() {
- settings.setProperty("sonar.webhooks.project", "1");
- settings.setProperty("sonar.webhooks.project.1.name", "First");
- settings.setProperty("sonar.webhooks.project.1.url", "http://url1");
-
- assertThat(underTest.isEnabled(settings.asConfig())).isTrue();
- }
-
- @Test
- public void isEnabled_returns_false_if_only_one_project_webhook_without_url() {
- settings.setProperty("sonar.webhooks.project", "1");
- settings.setProperty("sonar.webhooks.project.1.name", "First");
+ String organizationUuid = defaultOrganizationProvider.get().getUuid();
+ ComponentDto componentDto = componentDbTester.insertPrivateProject().setOrganizationUuid(organizationUuid);
+ webhookDbTester.insert(newWebhook(componentDto).setName("First").setUrl("http://url1"));
- assertThat(underTest.isEnabled(settings.asConfig())).isFalse();
+ assertThat(underTest.isEnabled(componentDto)).isTrue();
}
- @Test
- public void isEnabled_returns_false_if_only_one_project_webhook_without_name() {
- settings.setProperty("sonar.webhooks.project", "1");
- settings.setProperty("sonar.webhooks.project.1.url", "http://url1");
-
- assertThat(underTest.isEnabled(settings.asConfig())).isFalse();
- }
@Test
public void do_nothing_if_no_webhooks() {
- underTest.sendProjectAnalysisUpdate(settings.asConfig(), new WebHooks.Analysis(PROJECT_UUID, "1", "#1"), () -> mock);
+ ComponentDto componentDto = componentDbTester.insertPrivateProject().setOrganizationUuid(defaultOrganizationProvider.get().getUuid());
+
+ underTest.sendProjectAnalysisUpdate(new WebHooks.Analysis(componentDto.uuid(), "1", "#1"), () -> mock);
assertThat(caller.countSent()).isEqualTo(0);
- assertThat(logTester.logs(LoggerLevel.DEBUG)).isEmpty();
+ assertThat(logTester.logs(DEBUG)).isEmpty();
verifyZeroInteractions(deliveryStorage);
}
@Test
public void send_global_webhooks() {
- settings.setProperty("sonar.webhooks.global", "1,2");
- settings.setProperty("sonar.webhooks.global.1.name", "First");
- settings.setProperty("sonar.webhooks.global.1.url", "http://url1");
- settings.setProperty("sonar.webhooks.global.2.name", "Second");
- settings.setProperty("sonar.webhooks.global.2.url", "http://url2");
+
+ ComponentDto componentDto = componentDbTester.insertPrivateProject();
+ webhookDbTester.insert(newWebhook(componentDto).setName("First").setUrl("http://url1"));
+ webhookDbTester.insert(newWebhook(componentDto).setName("Second").setUrl("http://url2"));
caller.enqueueSuccess(NOW, 200, 1_234);
caller.enqueueFailure(NOW, new IOException("Fail to connect"));
- underTest.sendProjectAnalysisUpdate(settings.asConfig(), new WebHooks.Analysis(PROJECT_UUID, "1", "#1"), () -> mock);
+ underTest.sendProjectAnalysisUpdate(new WebHooks.Analysis(componentDto.uuid(), "1", "#1"), () -> mock);
assertThat(caller.countSent()).isEqualTo(2);
- assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("Sent webhook 'First' | url=http://url1 | time=1234ms | status=200");
- assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("Failed to send webhook 'Second' | url=http://url2 | message=Fail to connect");
+ assertThat(logTester.logs(DEBUG)).contains("Sent webhook 'First' | url=http://url1 | time=1234ms | status=200");
+ assertThat(logTester.logs(DEBUG)).contains("Failed to send webhook 'Second' | url=http://url2 | message=Fail to connect");
verify(deliveryStorage, times(2)).persist(any(WebhookDelivery.class));
- verify(deliveryStorage).purge(PROJECT_UUID);
+ verify(deliveryStorage).purge(componentDto.uuid());
+
}
@Test
public void send_project_webhooks() {
- settings.setProperty("sonar.webhooks.project", "1");
- settings.setProperty("sonar.webhooks.project.1.name", "First");
- settings.setProperty("sonar.webhooks.project.1.url", "http://url1");
+
+ String organizationUuid = defaultOrganizationProvider.get().getUuid();
+ ComponentDto componentDto = componentDbTester.insertPrivateProject().setOrganizationUuid(organizationUuid);
+ webhookDbTester.insert(newWebhook(componentDto).setName("First").setUrl("http://url1"));
caller.enqueueSuccess(NOW, 200, 1_234);
- underTest.sendProjectAnalysisUpdate(settings.asConfig(), new WebHooks.Analysis(PROJECT_UUID, "1", "#1"), () -> mock);
+ underTest.sendProjectAnalysisUpdate(new WebHooks.Analysis(componentDto.uuid(), "1", "#1"), () -> mock);
assertThat(caller.countSent()).isEqualTo(1);
- assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("Sent webhook 'First' | url=http://url1 | time=1234ms | status=200");
+ assertThat(logTester.logs(DEBUG)).contains("Sent webhook 'First' | url=http://url1 | time=1234ms | status=200");
verify(deliveryStorage).persist(any(WebhookDelivery.class));
- verify(deliveryStorage).purge(PROJECT_UUID);
- }
-
- @Test
- public void process_only_the_10_first_global_webhooks() {
- testMaxWebhooks("sonar.webhooks.global");
- }
-
- @Test
- public void process_only_the_10_first_project_webhooks() {
- testMaxWebhooks("sonar.webhooks.project");
- }
-
- private void testMaxWebhooks(String property) {
- IntStream.range(1, 15)
- .forEach(i -> {
- settings.setProperty(property + "." + i + ".name", "First");
- settings.setProperty(property + "." + i + ".url", "http://url");
- caller.enqueueSuccess(NOW, 200, 1_234);
- });
- settings.setProperty(property, IntStream.range(1, 15).mapToObj(String::valueOf).collect(Collectors.joining(",")));
-
- underTest.sendProjectAnalysisUpdate(settings.asConfig(), new WebHooks.Analysis(PROJECT_UUID, "1", "#1"), () -> mock);
+ verify(deliveryStorage).purge(componentDto.uuid());
- assertThat(caller.countSent()).isEqualTo(10);
- assertThat(logTester.logs(LoggerLevel.DEBUG).stream().filter(log -> log.contains("Sent"))).hasSize(10);
}
}
expectedException.expectMessage(format("Maximum number of webhook reached for project '%s'", project.getKey()));
for (int i = 0; i < 10; i++) {
- webhookDbTester.insertWebhookForProjectUuid(project.uuid());
+ webhookDbTester.insertWebhook(project);
}
userSession.logIn().addProjectPermission(ADMIN, project);
expectedException.expectMessage(format("Maximum number of webhook reached for organization '%s'", organization.getKey()));
for (int i = 0; i < 10; i++) {
- webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ webhookDbTester.insertWebhook(organization);
}
userSession.logIn().addPermission(ADMINISTER, organization.getUuid());
assertThat(action.params())
.extracting(WebService.Param::key, WebService.Param::isRequired)
- .containsExactlyInAnyOrder(tuple("key", true));
+ .containsExactlyInAnyOrder(tuple("webhook", true));
}
public void delete_a_project_webhook() {
ComponentDto project = componentDbTester.insertPrivateProject();
- WebhookDto dto = webhookDbTester.insertWebhookForProjectUuid(project.uuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(project);
userSession.logIn().addProjectPermission(ADMIN, project);
TestResponse response = wsActionTester.newRequest()
public void delete_an_organization_webhook() {
OrganizationDto organization = organizationDbTester.insert();
- WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(organization);
userSession.logIn().addPermission(ADMINISTER, organization.getUuid());
TestResponse response = wsActionTester.newRequest()
public void fail_if_not_logged_in() throws Exception {
OrganizationDto organization = organizationDbTester.insert();
- WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(organization);
userSession.anonymous();
expectedException.expect(UnauthorizedException.class);
public void fail_if_no_permission_on_webhook_scope_project() {
ComponentDto project = componentDbTester.insertPrivateProject();
- WebhookDto dto = webhookDbTester.insertWebhookForProjectUuid(project.uuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(project);
userSession.logIn();
public void fail_if_no_permission_on_webhook_scope_organization() {
OrganizationDto organization = organizationDbTester.insert();
- WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(organization);
userSession.logIn();
--- /dev/null
+/*
+ * 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 org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.Param;
+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.WsActionTester;
+import org.sonarqube.ws.Webhooks.SearchWsResponse;
+import org.sonarqube.ws.Webhooks.SearchWsResponse.Search;
+
+import static java.lang.String.format;
+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.ORGANIZATION_KEY_PARAM;
+import static org.sonar.server.webhook.ws.WebhooksWsParameters.PROJECT_KEY_PARAM;
+
+public class ListActionTest {
+
+ @Rule
+ public ExpectedException expectedException = none();
+
+ @Rule
+ public UserSessionRule userSession = standalone();
+
+ @Rule
+ public DbTester db = create();
+
+ private DbClient dbClient = db.getDbClient();
+ private DefaultOrganizationProvider defaultOrganizationProvider = from(db);
+ private WebhookSupport webhookSupport = new WebhookSupport(userSession);
+ private ListAction underTest = new ListAction(dbClient, userSession, defaultOrganizationProvider, webhookSupport);
+
+ private ComponentDbTester componentDbTester = db.components();
+ private WebhookDbTester webhookDbTester = db.webhooks();
+ private OrganizationDbTester organizationDbTester = db.organizations();
+ private WsActionTester wsActionTester = new WsActionTester(underTest);
+
+ @Test
+ public void definition() {
+
+ WebService.Action action = wsActionTester.getDef();
+
+ assertThat(action).isNotNull();
+ assertThat(action.isInternal()).isFalse();
+ assertThat(action.isPost()).isFalse();
+ assertThat(action.responseExampleAsString()).isNotEmpty();
+ assertThat(action.params())
+ .extracting(Param::key, Param::isRequired)
+ .containsExactlyInAnyOrder(
+ tuple("organization", false),
+ tuple("project", false));
+
+ }
+
+ @Test
+ public void search_global_webhooks() {
+
+ WebhookDto dto1 = webhookDbTester.insertWebhook(db.getDefaultOrganization());
+ WebhookDto dto2 = webhookDbTester.insertWebhook(db.getDefaultOrganization());
+ userSession.logIn().addPermission(ADMINISTER, db.getDefaultOrganization().getUuid());
+
+ SearchWsResponse response = wsActionTester.newRequest()
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(response.getWebhooksList())
+ .extracting(Search::getName, Search::getUrl)
+ .contains(tuple(dto1.getName(), dto1.getUrl()),
+ tuple(dto2.getName(), dto2.getUrl()));
+
+ }
+
+ @Test
+ public void search_project_webhooks_when_no_organization_is_provided() {
+
+ ComponentDto project1 = componentDbTester.insertPrivateProject();
+ userSession.logIn().addProjectPermission(ADMIN, project1);
+
+ WebhookDto dto1 = webhookDbTester.insertWebhook(project1);
+ WebhookDto dto2 = webhookDbTester.insertWebhook(project1);
+
+ SearchWsResponse response = wsActionTester.newRequest()
+ .setParam(PROJECT_KEY_PARAM, project1.getKey())
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(response.getWebhooksList())
+ .extracting(Search::getName, Search::getUrl)
+ .contains(tuple(dto1.getName(), dto1.getUrl()),
+ tuple(dto2.getName(), dto2.getUrl()));
+
+ }
+
+ @Test
+ public void search_organization_webhooks() {
+
+ OrganizationDto organizationDto = organizationDbTester.insert();
+ WebhookDto dto1 = webhookDbTester.insertWebhook(organizationDto);
+ WebhookDto dto2 = webhookDbTester.insertWebhook(organizationDto);
+ userSession.logIn().addPermission(ADMINISTER, organizationDto.getUuid());
+
+ SearchWsResponse response = wsActionTester.newRequest()
+ .setParam(ORGANIZATION_KEY_PARAM, organizationDto.getKey())
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(response.getWebhooksList())
+ .extracting(Search::getName, Search::getUrl)
+ .contains(tuple(dto1.getName(), dto1.getUrl()),
+ tuple(dto2.getName(), dto2.getUrl()));
+
+ }
+
+ @Test
+ public void search_project_webhooks_when_organization_is_provided() {
+
+ OrganizationDto organization = organizationDbTester.insert();
+ ComponentDto project = componentDbTester.insertPrivateProject(organization);
+ userSession.logIn().addProjectPermission(ADMIN, project);
+
+ WebhookDto dto1 = webhookDbTester.insertWebhook(project);
+ WebhookDto dto2 = webhookDbTester.insertWebhook(project);
+
+ SearchWsResponse response = wsActionTester.newRequest()
+ .setParam(ORGANIZATION_KEY_PARAM, organization.getKey())
+ .setParam(PROJECT_KEY_PARAM, project.getKey())
+ .executeProtobuf(SearchWsResponse.class);
+
+ assertThat(response.getWebhooksList())
+ .extracting(Search::getName, Search::getUrl)
+ .contains(tuple(dto1.getName(), dto1.getUrl()),
+ tuple(dto2.getName(), dto2.getUrl()));
+
+ }
+
+ @Test
+ public void return_NotFoundException_if_requested_project_is_not_found() throws Exception {
+
+ userSession.logIn().setSystemAdministrator();
+ expectedException.expect(NotFoundException.class);
+
+ wsActionTester.newRequest()
+ .setParam(PROJECT_KEY_PARAM, "pipo")
+ .executeProtobuf(SearchWsResponse.class);
+
+ }
+
+ @Test
+ public void return_NotFoundException_if_requested_organization_is_not_found() throws Exception {
+
+ userSession.logIn().setSystemAdministrator();
+ expectedException.expect(NotFoundException.class);
+
+ wsActionTester.newRequest()
+ .setParam(ORGANIZATION_KEY_PARAM, "pipo")
+ .executeProtobuf(SearchWsResponse.class);
+
+ }
+
+ @Test
+ public void fail_if_project_exists_but_does_not_belong_to_requested_organization() {
+
+ OrganizationDto organization = organizationDbTester.insert();
+ ComponentDto project = componentDbTester.insertPrivateProject();
+
+ expectedException.expect(NotFoundException.class);
+ expectedException.expectMessage(format("Project '%s' does not belong to organisation '%s'", project.getKey(), organization.getKey()));
+
+ userSession.logIn().addProjectPermission(ADMIN, project);
+
+ wsActionTester.newRequest()
+ .setParam(ORGANIZATION_KEY_PARAM, organization.getKey())
+ .setParam(PROJECT_KEY_PARAM, project.getKey())
+ .execute();
+
+ }
+
+ @Test
+ public void return_UnauthorizedException_if_not_logged_in() throws Exception {
+
+ userSession.anonymous();
+ expectedException.expect(UnauthorizedException.class);
+
+ wsActionTester.newRequest()
+ .executeProtobuf(SearchWsResponse.class);
+
+ }
+
+ @Test
+ public void throw_ForbiddenException_if_not_organization_administrator() {
+
+ userSession.logIn();
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage("Insufficient privileges");
+
+ wsActionTester.newRequest()
+ .executeProtobuf(SearchWsResponse.class);
+ }
+
+ @Test
+ public void throw_ForbiddenException_if_not_project_administrator() {
+
+ ComponentDto project = componentDbTester.insertPrivateProject();
+
+ userSession.logIn();
+
+ expectedException.expect(ForbiddenException.class);
+ expectedException.expectMessage("Insufficient privileges");
+
+ wsActionTester.newRequest()
+ .setParam(PROJECT_KEY_PARAM, project.getKey())
+ .executeProtobuf(SearchWsResponse.class);
+
+ }
+
+}
+++ /dev/null
-/*
- * 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 org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.config.PropertyDefinition;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.api.server.ws.WebService.Param;
-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.OrganizationDto;
-import org.sonar.db.property.PropertyDbTester;
-import org.sonar.server.exceptions.ForbiddenException;
-import org.sonar.server.exceptions.NotFoundException;
-import org.sonar.server.exceptions.UnauthorizedException;
-import org.sonar.server.setting.ws.SettingsFinder;
-import org.sonar.server.tester.UserSessionRule;
-import org.sonar.server.ws.WsActionTester;
-import org.sonarqube.ws.Webhooks.SearchWsResponse;
-import org.sonarqube.ws.Webhooks.SearchWsResponse.Search;
-
-import static com.google.common.collect.ImmutableMap.of;
-import static java.util.Arrays.asList;
-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.PropertyType.PROPERTY_SET;
-import static org.sonar.api.config.PropertyFieldDefinition.build;
-import static org.sonar.api.web.UserRole.ADMIN;
-import static org.sonar.db.DbTester.create;
-import static org.sonar.server.tester.UserSessionRule.standalone;
-import static org.sonar.server.webhook.ws.WebhooksWsParameters.PROJECT_KEY_PARAM;
-
-public class SearchActionTest {
-
- @Rule
- public ExpectedException expectedException = none();
-
- @Rule
- public UserSessionRule userSession = standalone();
-
- @Rule
- public DbTester db = create();
-
- private DbClient dbClient = db.getDbClient();
- private PropertyDefinitions definitions = new PropertyDefinitions();
- private SettingsFinder settingsFinder = new SettingsFinder(dbClient, definitions);
- private SearchAction underTest = new SearchAction(dbClient, userSession, settingsFinder);
- private WsActionTester wsActionTester = new WsActionTester(underTest);
-
- private ComponentDbTester componentDbTester = new ComponentDbTester(db);
-
- private PropertyDbTester propertyDb = new PropertyDbTester(db);
-
- @Test
- public void definition() {
-
- WebService.Action action = wsActionTester.getDef();
-
- assertThat(action).isNotNull();
- assertThat(action.isInternal()).isFalse();
- assertThat(action.isPost()).isFalse();
- assertThat(action.responseExampleAsString()).isNotEmpty();
- assertThat(action.params())
- .extracting(Param::key, Param::isRequired)
- .containsExactlyInAnyOrder(
- tuple("organization", false),
- tuple("project", false));
- }
-
- @Test
- public void search_global_webhooks() {
-
- definitions.addComponent(PropertyDefinition
- .builder("sonar.webhooks.global")
- .type(PROPERTY_SET)
- .fields(asList(
- build("name").name("name").build(),
- build("url").name("url").build()))
- .build());
- propertyDb.insertPropertySet("sonar.webhooks.global", null,
- of("name", "my first global webhook", "url", "http://127.0.0.1/first-global"),
- of("name", "my second global webhook", "url", "http://127.0.0.1/second-global"));
-
- userSession.logIn().setSystemAdministrator();
-
- SearchWsResponse response = wsActionTester.newRequest()
- .executeProtobuf(SearchWsResponse.class);
-
- assertThat(response.getWebhooksList())
- .extracting(Search::getName, Search::getUrl)
- .containsExactly(tuple("my first global webhook", "http://127.0.0.1/first-global"),
- tuple("my second global webhook", "http://127.0.0.1/second-global"));
- }
-
- @Test
- public void search_project_webhooks_when_no_organization_is_provided() {
- OrganizationDto defaultOrganization = db.getDefaultOrganization();
- ComponentDto project = db.components().insertPublicProject(defaultOrganization);
-
- definitions.addComponent(PropertyDefinition
- .builder("sonar.webhooks.global")
- .type(PROPERTY_SET)
- .fields(asList(
- build("name").name("name").build(),
- build("url").name("url").build()))
- .build());
- propertyDb.insertPropertySet("sonar.webhooks.global", null,
- of("name", "my first global webhook", "url", "http://127.0.0.1/first-global"),
- of("name", "my second global webhook", "url", "http://127.0.0.1/second-global"));
-
- definitions.addComponent(PropertyDefinition
- .builder("sonar.webhooks.project")
- .type(PROPERTY_SET)
- .fields(asList(
- build("name").name("name").build(),
- build("url").name("url").build()))
- .build());
- propertyDb.insertPropertySet("sonar.webhooks.project", project,
- of("name", "my first project webhook", "url", "http://127.0.0.1/first-project"),
- of("name", "my second project webhook", "url", "http://127.0.0.1/second-project"));
-
- userSession.logIn().addProjectPermission(ADMIN, project);
-
- SearchWsResponse response = wsActionTester.newRequest()
- .setParam(PROJECT_KEY_PARAM, project.getKey())
- .executeProtobuf(SearchWsResponse.class);
-
- assertThat(response.getWebhooksList())
- .extracting(Search::getName, Search::getUrl)
- .containsExactly(tuple("my first project webhook", "http://127.0.0.1/first-project"),
- tuple("my second project webhook", "http://127.0.0.1/second-project"));
-
- }
-
- @Test
- public void return_UnauthorizedException_if_not_logged_in() throws Exception {
-
- userSession.anonymous();
- expectedException.expect(UnauthorizedException.class);
-
- wsActionTester.newRequest()
- .executeProtobuf(SearchWsResponse.class);
- }
-
- @Test
- public void return_NotFoundException_if_not_project_is_not_found() throws Exception {
-
- userSession.logIn().setSystemAdministrator();
- expectedException.expect(NotFoundException.class);
-
- wsActionTester.newRequest()
- .setParam(PROJECT_KEY_PARAM, "pipo")
- .executeProtobuf(SearchWsResponse.class);
- }
-
- @Test
- public void throw_ForbiddenException_if_not_organization_administrator() {
-
- userSession.logIn();
-
- expectedException.expect(ForbiddenException.class);
- expectedException.expectMessage("Insufficient privileges");
-
- wsActionTester.newRequest()
- .executeProtobuf(SearchWsResponse.class);
- }
-
- @Test
- public void throw_ForbiddenException_if_not_project_administrator() {
-
- ComponentDto project = componentDbTester.insertPrivateProject();
-
- userSession.logIn();
-
- expectedException.expect(ForbiddenException.class);
- expectedException.expectMessage("Insufficient privileges");
-
- wsActionTester.newRequest()
- .setParam(PROJECT_KEY_PARAM, project.getKey())
- .executeProtobuf(SearchWsResponse.class);
-
- }
-
-}
assertThat(action.params())
.extracting(WebService.Param::key, WebService.Param::isRequired)
.containsExactlyInAnyOrder(
- tuple("key", true),
+ tuple("webhook", true),
tuple("name", true),
tuple("url", true));
public void update_a_project_webhook() {
ComponentDto project = componentDbTester.insertPrivateProject();
- WebhookDto dto = webhookDbTester.insertWebhookForProjectUuid(project.uuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(project);
userSession.logIn().addProjectPermission(ADMIN, project);
TestResponse response = wsActionTester.newRequest()
public void update_an_organization_webhook() {
OrganizationDto organization = organizationDbTester.insert();
- WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(organization);
userSession.logIn().addPermission(ADMINISTER, organization.getUuid());
TestResponse response = wsActionTester.newRequest()
public void fail_if_not_logged_in() throws Exception {
OrganizationDto organization = organizationDbTester.insert();
- WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(organization);
userSession.anonymous();
expectedException.expect(UnauthorizedException.class);
public void fail_if_no_permission_on_webhook_scope_project() {
ComponentDto project = componentDbTester.insertPrivateProject();
- WebhookDto dto = webhookDbTester.insertWebhookForProjectUuid(project.uuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(project);
userSession.logIn();
public void fail_if_no_permission_on_webhook_scope_organization() {
OrganizationDto organization = organizationDbTester.insert();
- WebhookDto dto = webhookDbTester.insertForOrganizationUuid(organization.getUuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(organization);
userSession.logIn();
public void fail_if_url_is_not_valid() throws Exception {
ComponentDto project = componentDbTester.insertPrivateProject();
- WebhookDto dto = webhookDbTester.insertWebhookForProjectUuid(project.uuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(project);
userSession.logIn().addProjectPermission(ADMIN, project);
expectedException.expect(IllegalArgumentException.class);
public void fail_if_credential_in_url_is_have_a_wrong_format() throws Exception {
ComponentDto project = componentDbTester.insertPrivateProject();
- WebhookDto dto = webhookDbTester.insertWebhookForProjectUuid(project.uuid());
+ WebhookDto dto = webhookDbTester.insertWebhook(project);
userSession.logIn().addProjectPermission(ADMIN, project);
expectedException.expect(IllegalArgumentException.class);