/* * SonarQube * Copyright (C) 2009-2019 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.List; import java.util.Map; import java.util.Optional; import javax.annotation.Nullable; import org.sonar.api.server.ws.Change; 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.WebhookDeliveryLiteDto; import org.sonar.db.webhook.WebhookDto; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Webhooks; import org.sonarqube.ws.Webhooks.ListResponse; import org.sonarqube.ws.Webhooks.ListResponseElement; import static org.apache.commons.lang.StringUtils.isNotBlank; import static org.sonar.api.utils.DateUtils.formatDateTime; import static org.sonar.server.webhook.HttpUrlHelper.obfuscateCredentials; 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; 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.
" + "Requires 'Administer' permission on the specified project, or global 'Administer' permission.") .setSince("7.1") .setResponseExample(getClass().getResource("example-webhooks-list.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); action.setChangelog(new Change("7.8", "Field 'secret' added to response")); } @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(); try (DbSession dbSession = dbClient.openSession(true)) { List webhookDtos = doHandle(dbSession, organizationKey, projectKey); Map lastDeliveries = loadLastDeliveriesOf(dbSession, webhookDtos); writeResponse(request, response, webhookDtos, lastDeliveries); } } private Map loadLastDeliveriesOf(DbSession dbSession, List webhookDtos) { return dbClient.webhookDeliveryDao().selectLatestDeliveries(dbSession, webhookDtos); } private List doHandle(DbSession dbSession, @Nullable String organizationKey, @Nullable String projectKey) { OrganizationDto organizationDto; if (isNotBlank(organizationKey)) { Optional dtoOptional = dbClient.organizationDao().selectByKey(dbSession, organizationKey); organizationDto = checkFoundWithOptional(dtoOptional, "No organization with key '%s'", organizationKey); } else { organizationDto = defaultOrganizationDto(dbSession); } if (isNotBlank(projectKey)) { Optional optional = dbClient.componentDao().selectByKey(dbSession, projectKey); 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().selectByProject(dbSession, componentDto); } else { webhookSupport.checkPermission(organizationDto); return dbClient.webhookDao().selectByOrganization(dbSession, organizationDto); } } private static void writeResponse(Request request, Response response, List webhookDtos, Map lastDeliveries) { ListResponse.Builder responseBuilder = ListResponse.newBuilder(); webhookDtos .forEach(webhook -> { ListResponseElement.Builder responseElementBuilder = responseBuilder.addWebhooksBuilder(); responseElementBuilder .setKey(webhook.getUuid()) .setName(webhook.getName()) .setUrl(obfuscateCredentials(webhook.getUrl())); if (webhook.getSecret() != null) { responseElementBuilder.setSecret(webhook.getSecret()); } addLastDelivery(responseElementBuilder, webhook, lastDeliveries); }); writeProtobuf(responseBuilder.build(), request, response); } private static void addLastDelivery(ListResponseElement.Builder responseElementBuilder, WebhookDto webhook, Map lastDeliveries) { if (lastDeliveries.containsKey(webhook.getUuid())) { WebhookDeliveryLiteDto delivery = lastDeliveries.get(webhook.getUuid()); Webhooks.LatestDelivery.Builder builder = responseElementBuilder.getLatestDeliveryBuilder() .setId(delivery.getUuid()) .setAt(formatDateTime(delivery.getCreatedAt())) .setSuccess(delivery.isSuccess()); if (delivery.getHttpStatus() != null) { builder.setHttpStatus(delivery.getHttpStatus()); } if (delivery.getDurationMs() != null) { builder.setDurationMs(delivery.getDurationMs()); } builder.build(); } } private OrganizationDto defaultOrganizationDto(DbSession dbSession) { String uuid = defaultOrganizationProvider.get().getUuid(); Optional organizationDto = dbClient.organizationDao().selectByUuid(dbSession, uuid); return checkStateWithOptional(organizationDto, "the default organization '%s' was not found", uuid); } }