mirror of https://github.com/apache/cloudstack.git
webhook: fixes, filter enhancement (#12023)
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
This commit is contained in:
parent
81b991ae9c
commit
cd55796972
|
|
@ -375,6 +375,7 @@ public class ApiConstants {
|
|||
public static final String MAC_ADDRESS = "macaddress";
|
||||
public static final String MAC_ADDRESSES = "macaddresses";
|
||||
public static final String MANUAL_UPGRADE = "manualupgrade";
|
||||
public static final String MATCH_TYPE = "matchtype";
|
||||
public static final String MAX = "max";
|
||||
public static final String MAX_SNAPS = "maxsnaps";
|
||||
public static final String MAX_BACKUPS = "maxbackups";
|
||||
|
|
|
|||
|
|
@ -23,3 +23,19 @@
|
|||
-- Update value to firstfit for the config 'vm.allocation.algorithm' or 'volume.allocation.algorithm' if configured as userconcentratedpod_firstfit
|
||||
UPDATE `cloud`.`configuration` SET value='random' WHERE name IN ('vm.allocation.algorithm', 'volume.allocation.algorithm') AND value='userconcentratedpod_random';
|
||||
UPDATE `cloud`.`configuration` SET value='firstfit' WHERE name IN ('vm.allocation.algorithm', 'volume.allocation.algorithm') AND value='userconcentratedpod_firstfit';
|
||||
|
||||
-- Create webhook_filter table
|
||||
DROP TABLE IF EXISTS `cloud`.`webhook_filter`;
|
||||
CREATE TABLE IF NOT EXISTS `cloud`.`webhook_filter` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id of the webhook filter',
|
||||
`uuid` varchar(255) COMMENT 'uuid of the webhook filter',
|
||||
`webhook_id` bigint unsigned NOT NULL COMMENT 'id of the webhook',
|
||||
`type` varchar(20) COMMENT 'type of the filter',
|
||||
`mode` varchar(20) COMMENT 'mode of the filter',
|
||||
`match_type` varchar(20) COMMENT 'match type of the filter',
|
||||
`value` varchar(256) NOT NULL COMMENT 'value of the filter used for matching',
|
||||
`created` datetime NOT NULL COMMENT 'date created',
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `i_webhook_filter__webhook_id`(`webhook_id`),
|
||||
CONSTRAINT `fk_webhook_filter__webhook_id` FOREIGN KEY(`webhook_id`) REFERENCES `webhook`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import org.apache.cloudstack.api.Identity;
|
|||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
public interface Webhook extends ControlledEntity, Identity, InternalIdentity {
|
||||
public static final long ID_DUMMY = 0L;
|
||||
public static final String NAME_DUMMY = "Test";
|
||||
long ID_DUMMY = 0L;
|
||||
String NAME_DUMMY = "Test";
|
||||
enum State {
|
||||
Enabled, Disabled;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -18,14 +18,18 @@
|
|||
package org.apache.cloudstack.mom.webhook;
|
||||
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.AddWebhookFilterCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.CreateWebhookCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookDeliveryCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookFilterCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.ExecuteWebhookDeliveryCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookDeliveriesCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookFiltersCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhooksCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.UpdateWebhookCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookDeliveryResponse;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
|
||||
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
|
|
@ -41,4 +45,7 @@ public interface WebhookApiService extends PluggableService {
|
|||
ListResponse<WebhookDeliveryResponse> listWebhookDeliveries(ListWebhookDeliveriesCmd cmd);
|
||||
int deleteWebhookDelivery(DeleteWebhookDeliveryCmd cmd) throws CloudRuntimeException;
|
||||
WebhookDeliveryResponse executeWebhookDelivery(ExecuteWebhookDeliveryCmd cmd) throws CloudRuntimeException;
|
||||
ListResponse<WebhookFilterResponse> listWebhookFilters(ListWebhookFiltersCmd cmd) throws CloudRuntimeException;
|
||||
WebhookFilterResponse addWebhookFilter(AddWebhookFilterCmd cmd) throws CloudRuntimeException;
|
||||
int deleteWebhookFilter(DeleteWebhookFilterCmd cmd) throws CloudRuntimeException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,23 +29,30 @@ import org.apache.cloudstack.acl.SecurityChecker;
|
|||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.AddWebhookFilterCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.CreateWebhookCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookDeliveryCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.DeleteWebhookFilterCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.ExecuteWebhookDeliveryCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookDeliveriesCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhookFiltersCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.ListWebhooksCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.command.user.UpdateWebhookCmd;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookDeliveryResponse;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookDao;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryDao;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryJoinDao;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookFilterDao;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookJoinDao;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryJoinVO;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookJoinVO;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookVO;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
|
@ -59,6 +66,7 @@ import com.cloud.exception.PermissionDeniedException;
|
|||
import com.cloud.projects.Project;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.utils.EnumUtils;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.Ternary;
|
||||
import com.cloud.utils.UriUtils;
|
||||
|
|
@ -84,6 +92,8 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
@Inject
|
||||
WebhookDeliveryJoinDao webhookDeliveryJoinDao;
|
||||
@Inject
|
||||
WebhookFilterDao webhookFilterDao;
|
||||
@Inject
|
||||
ManagementServerHostDao managementServerHostDao;
|
||||
@Inject
|
||||
WebhookService webhookService;
|
||||
|
|
@ -225,6 +235,25 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
throw new InvalidParameterValueException(error);
|
||||
}
|
||||
|
||||
protected WebhookFilterResponse createWebhookFilterResponse(WebhookFilter webhookFilter, WebhookVO webhookVO) {
|
||||
WebhookFilterResponse response = new WebhookFilterResponse();
|
||||
response.setObjectName("webhookfilter");
|
||||
response.setId(webhookFilter.getUuid());
|
||||
if (webhookVO == null) {
|
||||
webhookVO = webhookDao.findById(webhookFilter.getWebhookId());
|
||||
}
|
||||
if (webhookVO != null) {
|
||||
response.setWebhookId(webhookVO.getUuid());
|
||||
response.setWebhookName(webhookVO.getName());
|
||||
}
|
||||
response.setType(webhookFilter.getType().toString());
|
||||
response.setMode(webhookFilter.getMode().toString());
|
||||
response.setMatchType(webhookFilter.getMatchType().toString());
|
||||
response.setValue(webhookFilter.getValue());
|
||||
response.setCreated(webhookFilter.getCreated());
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponse<WebhookResponse> listWebhooks(ListWebhooksCmd cmd) {
|
||||
final CallContext ctx = CallContext.current();
|
||||
|
|
@ -234,6 +263,25 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
final String name = cmd.getName();
|
||||
final String keyword = cmd.getKeyword();
|
||||
final String scopeStr = cmd.getScope();
|
||||
Webhook.Scope scope = null;
|
||||
if (StringUtils.isNotEmpty(scopeStr)) {
|
||||
scope = EnumUtils.getEnumIgnoreCase(Webhook.Scope.class, scopeStr);
|
||||
if (scope == null) {
|
||||
throw new InvalidParameterValueException("Invalid scope specified");
|
||||
}
|
||||
}
|
||||
if ((Webhook.Scope.Global.equals(scope) && !Account.Type.ADMIN.equals(caller.getType())) ||
|
||||
(Webhook.Scope.Domain.equals(scope) &&
|
||||
!List.of(Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN).contains(caller.getType()))) {
|
||||
throw new InvalidParameterValueException(String.format("Scope %s can not be specified", scope));
|
||||
}
|
||||
Webhook.State state = null;
|
||||
if (StringUtils.isNotEmpty(stateStr)) {
|
||||
state = EnumUtils.getEnumIgnoreCase(Webhook.State.class, stateStr);
|
||||
if (state == null) {
|
||||
throw new InvalidParameterValueException("Invalid state specified");
|
||||
}
|
||||
}
|
||||
List<WebhookResponse> responsesList = new ArrayList<>();
|
||||
List<Long> permittedAccounts = new ArrayList<>();
|
||||
Ternary<Long, Boolean, Project.ListProjectResourcesCriteria> domainIdRecursiveListProject =
|
||||
|
|
@ -258,27 +306,6 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
SearchCriteria<WebhookJoinVO> sc = sb.create();
|
||||
accountManager.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts,
|
||||
listProjectResourcesCriteria);
|
||||
Webhook.Scope scope = null;
|
||||
if (StringUtils.isNotEmpty(scopeStr)) {
|
||||
try {
|
||||
scope = Webhook.Scope.valueOf(scopeStr);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new InvalidParameterValueException("Invalid scope specified");
|
||||
}
|
||||
}
|
||||
if ((Webhook.Scope.Global.equals(scope) && !Account.Type.ADMIN.equals(caller.getType())) ||
|
||||
(Webhook.Scope.Domain.equals(scope) &&
|
||||
!List.of(Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN).contains(caller.getType()))) {
|
||||
throw new InvalidParameterValueException(String.format("Scope %s can not be specified", scope));
|
||||
}
|
||||
Webhook.State state = null;
|
||||
if (StringUtils.isNotEmpty(stateStr)) {
|
||||
try {
|
||||
state = Webhook.State.valueOf(stateStr);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new InvalidParameterValueException("Invalid state specified");
|
||||
}
|
||||
}
|
||||
if (scope != null) {
|
||||
sc.setParameters("scope", scope.name());
|
||||
}
|
||||
|
|
@ -316,9 +343,8 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
final String stateStr = cmd.getState();
|
||||
Webhook.Scope scope = Webhook.Scope.Local;
|
||||
if (StringUtils.isNotEmpty(scopeStr)) {
|
||||
try {
|
||||
scope = Webhook.Scope.valueOf(scopeStr);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
scope = EnumUtils.getEnumIgnoreCase(Webhook.Scope.class, scopeStr);
|
||||
if (scope == null) {
|
||||
throw new InvalidParameterValueException("Invalid scope specified");
|
||||
}
|
||||
}
|
||||
|
|
@ -330,9 +356,8 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
}
|
||||
Webhook.State state = Webhook.State.Enabled;
|
||||
if (StringUtils.isNotEmpty(stateStr)) {
|
||||
try {
|
||||
state = Webhook.State.valueOf(stateStr);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
state = EnumUtils.getEnumIgnoreCase(Webhook.State.class, stateStr);
|
||||
if (state == null) {
|
||||
throw new InvalidParameterValueException("Invalid state specified");
|
||||
}
|
||||
}
|
||||
|
|
@ -353,6 +378,7 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
WebhookVO webhook = new WebhookVO(name, description, state, domainId, owner.getId(), payloadUrl, secretKey,
|
||||
sslVerification, scope);
|
||||
webhook = webhookDao.persist(webhook);
|
||||
webhookService.invalidateWebhooksCache();
|
||||
return createWebhookResponse(webhook.getId());
|
||||
}
|
||||
|
||||
|
|
@ -365,7 +391,11 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
throw new InvalidParameterValueException("Unable to find the webhook with the specified ID");
|
||||
}
|
||||
accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhook);
|
||||
return webhookDao.remove(id);
|
||||
boolean removed = webhookDao.remove(id);
|
||||
if (removed) {
|
||||
webhookService.invalidateWebhooksCache();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -394,18 +424,19 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
updateNeeded = true;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(stateStr)) {
|
||||
try {
|
||||
Webhook.State state = Webhook.State.valueOf(stateStr);
|
||||
webhook.setState(state);
|
||||
updateNeeded = true;
|
||||
} catch (IllegalArgumentException iae) {
|
||||
Webhook.State state = EnumUtils.getEnumIgnoreCase(Webhook.State.class, stateStr);
|
||||
if (state == null) {
|
||||
throw new InvalidParameterValueException("Invalid state specified");
|
||||
}
|
||||
webhook.setState(state);
|
||||
updateNeeded = true;
|
||||
}
|
||||
Account owner = accountManager.getAccount(webhook.getAccountId());
|
||||
if (StringUtils.isNotEmpty(scopeStr)) {
|
||||
try {
|
||||
Webhook.Scope scope = Webhook.Scope.valueOf(scopeStr);
|
||||
Webhook.Scope scope = EnumUtils.getEnumIgnoreCase(Webhook.Scope.class, scopeStr);
|
||||
if (scope == null) {
|
||||
throw new InvalidParameterValueException("Invalid scope specified");
|
||||
}
|
||||
if ((Webhook.Scope.Global.equals(scope) && !Account.Type.ADMIN.equals(owner.getType())) ||
|
||||
(Webhook.Scope.Domain.equals(scope) &&
|
||||
!List.of(Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN).contains(owner.getType()))) {
|
||||
|
|
@ -414,9 +445,6 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
}
|
||||
webhook.setScope(scope);
|
||||
updateNeeded = true;
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new InvalidParameterValueException("Invalid scope specified");
|
||||
}
|
||||
}
|
||||
URI uri = URI.create(webhook.getPayloadUrl());
|
||||
if (StringUtils.isNotEmpty(payloadUrl)) {
|
||||
|
|
@ -427,7 +455,7 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
updateNeeded = true;
|
||||
}
|
||||
if (sslVerification != null) {
|
||||
if (Boolean.TRUE.equals(sslVerification) && !HttpConstants.HTTPS.equalsIgnoreCase(uri.getScheme())) {
|
||||
if (sslVerification && !HttpConstants.HTTPS.equalsIgnoreCase(uri.getScheme())) {
|
||||
throw new InvalidParameterValueException(
|
||||
String.format("SSL verification can be specified only for HTTPS URLs, %s", payloadUrl));
|
||||
}
|
||||
|
|
@ -444,6 +472,7 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
if (updateNeeded && !webhookDao.update(id, webhook)) {
|
||||
return null;
|
||||
}
|
||||
webhookService.invalidateWebhooksCache();
|
||||
return createWebhookResponse(webhook.getId());
|
||||
}
|
||||
|
||||
|
|
@ -455,8 +484,7 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
|
||||
@Override
|
||||
public ListResponse<WebhookDeliveryResponse> listWebhookDeliveries(ListWebhookDeliveriesCmd cmd) {
|
||||
final CallContext ctx = CallContext.current();
|
||||
final Account caller = ctx.getCallingAccount();
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
final Long id = cmd.getId();
|
||||
final Long webhookId = cmd.getWebhookId();
|
||||
final Long managementServerId = cmd.getManagementServerId();
|
||||
|
|
@ -507,20 +535,23 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
|
||||
@Override
|
||||
public WebhookDeliveryResponse executeWebhookDelivery(ExecuteWebhookDeliveryCmd cmd) throws CloudRuntimeException {
|
||||
final CallContext ctx = CallContext.current();
|
||||
final Account caller = ctx.getCallingAccount();
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
final Long deliveryId = cmd.getId();
|
||||
final Long webhookId = cmd.getWebhookId();
|
||||
final String payloadUrl = getNormalizedPayloadUrl(cmd.getPayloadUrl());
|
||||
final String secretKey = cmd.getSecretKey();
|
||||
final Boolean sslVerification = cmd.isSslVerification();
|
||||
final String payload = cmd.getPayload();
|
||||
final Account owner = accountManager.finalizeOwner(caller, null, null, null);
|
||||
|
||||
if (ObjectUtils.allNull(deliveryId, webhookId) && StringUtils.isBlank(payloadUrl)) {
|
||||
throw new InvalidParameterValueException(String.format("One of the %s, %s or %s must be specified",
|
||||
ApiConstants.ID, ApiConstants.WEBHOOK_ID, ApiConstants.PAYLOAD_URL));
|
||||
}
|
||||
if (deliveryId != null && (webhookId != null || StringUtils.isNotBlank(payloadUrl))) {
|
||||
throw new InvalidParameterValueException(
|
||||
String.format("%s cannot be specified with %s or %s", ApiConstants.ID, ApiConstants.WEBHOOK_ID,
|
||||
ApiConstants.PAYLOAD_URL));
|
||||
}
|
||||
WebhookDeliveryVO existingDelivery = null;
|
||||
WebhookVO webhook = null;
|
||||
if (deliveryId != null) {
|
||||
|
|
@ -545,11 +576,14 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
webhook.setSecretKey(secretKey);
|
||||
}
|
||||
if (sslVerification != null) {
|
||||
webhook.setSslVerification(Boolean.TRUE.equals(sslVerification));
|
||||
webhook.setSslVerification(sslVerification);
|
||||
}
|
||||
}
|
||||
if (webhook != null) {
|
||||
accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhook);
|
||||
}
|
||||
if (ObjectUtils.allNull(deliveryId, webhookId)) {
|
||||
webhook = new WebhookVO(owner.getDomainId(), owner.getId(), payloadUrl, secretKey,
|
||||
webhook = new WebhookVO(caller.getDomainId(), caller.getId(), payloadUrl, secretKey,
|
||||
Boolean.TRUE.equals(sslVerification));
|
||||
}
|
||||
WebhookDelivery webhookDelivery = webhookService.executeWebhookDelivery(existingDelivery, webhook, payload);
|
||||
|
|
@ -559,6 +593,87 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
return createTestWebhookDeliveryResponse(webhookDelivery, webhook);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListResponse<WebhookFilterResponse> listWebhookFilters(ListWebhookFiltersCmd cmd) throws CloudRuntimeException {
|
||||
Pair<List<WebhookFilterVO>, Integer> filtersAndCount = webhookFilterDao.searchBy(cmd.getId(), cmd.getWebhookId(),
|
||||
cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||
List<WebhookFilterResponse> responsesList = new ArrayList<>();
|
||||
WebhookVO webhookVO = null;
|
||||
if (filtersAndCount.second() > 0) {
|
||||
webhookVO = webhookDao.findById(filtersAndCount.first().get(0).getWebhookId());
|
||||
}
|
||||
for (WebhookFilterVO filter : filtersAndCount.first()) {
|
||||
WebhookFilterResponse response = createWebhookFilterResponse(filter, webhookVO);
|
||||
responsesList.add(response);
|
||||
}
|
||||
ListResponse<WebhookFilterResponse> response = new ListResponse<>();
|
||||
response.setResponses(responsesList, responsesList.size());
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebhookFilterResponse addWebhookFilter(AddWebhookFilterCmd cmd) throws CloudRuntimeException {
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
final long id = cmd.getId();
|
||||
final String typeStr = cmd.getType();
|
||||
final String modeStr = cmd.getMode();
|
||||
final String matchTypeStr = cmd.getMatchType();
|
||||
final String value = cmd.getValue();
|
||||
WebhookVO webhook = webhookDao.findById(id);
|
||||
if (webhook == null) {
|
||||
throw new InvalidParameterValueException("Unable to find the webhook with the specified ID");
|
||||
}
|
||||
accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhook);
|
||||
WebhookFilter.Type type = EnumUtils.getEnumIgnoreCase(WebhookFilter.Type.class, typeStr, WebhookFilter.Type.EventType);
|
||||
WebhookFilter.Mode mode = WebhookFilter.Mode.Include;
|
||||
if (StringUtils.isNotBlank(modeStr)) {
|
||||
mode = EnumUtils.getEnumIgnoreCase(WebhookFilter.Mode.class, modeStr);
|
||||
if (mode == null) {
|
||||
throw new InvalidParameterValueException("Invalid mode specified");
|
||||
}
|
||||
}
|
||||
WebhookFilter.MatchType matchType = WebhookFilter.MatchType.Exact;
|
||||
if (StringUtils.isNotBlank(matchTypeStr)) {
|
||||
matchType = EnumUtils.getEnumIgnoreCase(WebhookFilter.MatchType.class, matchTypeStr);
|
||||
if (matchType == null) {
|
||||
throw new InvalidParameterValueException("Invalid match type specified");
|
||||
}
|
||||
}
|
||||
WebhookFilterVO webhookFilter = new WebhookFilterVO(webhook.getId(), type, mode, matchType, value);
|
||||
List<? extends WebhookFilter> existingFilters = webhookFilterDao.listByWebhook(webhook.getId());
|
||||
if (CollectionUtils.isNotEmpty(existingFilters)) {
|
||||
WebhookFilter conflicting = webhookFilter.getConflicting(existingFilters);
|
||||
if (conflicting != null) {
|
||||
logger.error("Conflict detected when adding WebhookFilter having type: {}, mode: {}, " +
|
||||
"matchtype: {}, value: {} with existing {} for {}", type, mode, matchType, value, conflicting,
|
||||
webhook);
|
||||
throw new InvalidParameterValueException(String.format("Conflicting Webhook filter exists ID: %s",
|
||||
conflicting.getId()));
|
||||
}
|
||||
}
|
||||
webhookFilter = webhookFilterDao.persist(webhookFilter);
|
||||
webhookService.invalidateWebhookFiltersCache(webhook.getId());
|
||||
return createWebhookFilterResponse(webhookFilter, webhook);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteWebhookFilter(DeleteWebhookFilterCmd cmd) throws CloudRuntimeException {
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
final Pair<List<WebhookFilterVO>, Integer> filtersAndCount =
|
||||
webhookFilterDao.searchBy(cmd.getId(), cmd.getWebhookId(), 0L, 1L);
|
||||
if (filtersAndCount.second() == 0) {
|
||||
return 0;
|
||||
}
|
||||
final long webhookId = filtersAndCount.first().get(0).getWebhookId();
|
||||
Webhook webhook = webhookDao.findById(webhookId);
|
||||
accountManager.checkAccess(caller, SecurityChecker.AccessType.OperateEntry, false, webhook);
|
||||
int result = webhookFilterDao.delete(cmd.getId(), webhookId);
|
||||
if (result > 0) {
|
||||
webhookService.invalidateWebhookFiltersCache(webhookId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<?>> getCommands() {
|
||||
List<Class<?>> cmdList = new ArrayList<>();
|
||||
|
|
@ -569,6 +684,9 @@ public class WebhookApiServiceImpl extends ManagerBase implements WebhookApiServ
|
|||
cmdList.add(ListWebhookDeliveriesCmd.class);
|
||||
cmdList.add(DeleteWebhookDeliveryCmd.class);
|
||||
cmdList.add(ExecuteWebhookDeliveryCmd.class);
|
||||
cmdList.add(ListWebhookFiltersCmd.class);
|
||||
cmdList.add(AddWebhookFilterCmd.class);
|
||||
cmdList.add(DeleteWebhookFilterCmd.class);
|
||||
return cmdList;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
|
||||
public interface WebhookFilter extends Identity, InternalIdentity {
|
||||
|
||||
enum Type {
|
||||
EventType
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
Include, Exclude
|
||||
}
|
||||
|
||||
enum MatchType {
|
||||
Exact, Prefix, Suffix, Contains
|
||||
}
|
||||
|
||||
long getId();
|
||||
long getWebhookId();
|
||||
Type getType();
|
||||
Mode getMode();
|
||||
MatchType getMatchType();
|
||||
String getValue();
|
||||
Date getCreated();
|
||||
|
||||
static boolean overlaps(WebhookFilter.MatchType oldMatchType, String oldValue, WebhookFilter.MatchType newMatchType, String newValue) {
|
||||
switch (oldMatchType) {
|
||||
case Exact:
|
||||
switch (newMatchType) {
|
||||
case Exact:
|
||||
return oldValue.equals(newValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case Prefix:
|
||||
switch (newMatchType) {
|
||||
case Exact:
|
||||
case Prefix:
|
||||
return newValue.startsWith(oldValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case Suffix:
|
||||
switch (newMatchType) {
|
||||
case Exact:
|
||||
case Suffix:
|
||||
return newValue.endsWith(oldValue);
|
||||
}
|
||||
break;
|
||||
|
||||
case Contains:
|
||||
switch (newMatchType) {
|
||||
case Exact:
|
||||
case Prefix:
|
||||
case Suffix:
|
||||
case Contains:
|
||||
return newValue.contains(oldValue);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default WebhookFilter getConflicting(List<? extends WebhookFilter> existing) {
|
||||
for (WebhookFilter f : existing) {
|
||||
if (f.getType() != this.getType()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 1. Duplicate entry (same mode, match type, and value)
|
||||
if (f.getMode() == this.getMode()
|
||||
&& f.getMatchType() == this.getMatchType()
|
||||
&& f.getValue().equalsIgnoreCase(this.getValue())) {
|
||||
return f;
|
||||
}
|
||||
|
||||
// 2. Opposite mode (INCLUDE vs EXCLUDE) — check for overlap
|
||||
if (f.getMode() != this.getMode()) {
|
||||
String oldVal = f.getValue().toUpperCase();
|
||||
String newVal = this.getValue().toUpperCase();
|
||||
|
||||
if (overlaps(f.getMatchType(), oldVal, this.getMatchType(), newVal)) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -60,4 +60,6 @@ public interface WebhookService extends PluggableService, Configurable {
|
|||
void handleEvent(Event event) throws EventBusException;
|
||||
WebhookDelivery executeWebhookDelivery(WebhookDelivery delivery, Webhook webhook, String payload)
|
||||
throws CloudRuntimeException;
|
||||
void invalidateWebhooksCache();
|
||||
void invalidateWebhookFiltersCache(long webhookId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
|
@ -32,7 +33,6 @@ import javax.inject.Inject;
|
|||
import javax.naming.ConfigurationException;
|
||||
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.framework.async.AsyncCallFuture;
|
||||
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
|
||||
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
|
||||
import org.apache.cloudstack.framework.async.AsyncRpcContext;
|
||||
|
|
@ -42,10 +42,14 @@ import org.apache.cloudstack.framework.events.EventBusException;
|
|||
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookDao;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryDao;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookFilterDao;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookVO;
|
||||
import org.apache.cloudstack.utils.cache.LazyCache;
|
||||
import org.apache.cloudstack.utils.identity.ManagementServerNode;
|
||||
import org.apache.cloudstack.webhook.WebhookHelper;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.cloud.api.query.vo.EventJoinVO;
|
||||
|
|
@ -75,7 +79,9 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
@Inject
|
||||
WebhookDao webhookDao;
|
||||
@Inject
|
||||
protected WebhookDeliveryDao webhookDeliveryDao;
|
||||
WebhookDeliveryDao webhookDeliveryDao;
|
||||
@Inject
|
||||
WebhookFilterDao webhookFilterDao;
|
||||
@Inject
|
||||
ManagementServerHostDao managementServerHostDao;
|
||||
@Inject
|
||||
|
|
@ -83,6 +89,9 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
@Inject
|
||||
AccountManager accountManager;
|
||||
|
||||
protected LazyCache<org.apache.commons.lang3.tuple.Pair<Long, List<Long>>, List<WebhookVO>> webhooksCache;
|
||||
protected LazyCache<Long, List<WebhookFilterVO>> webhookFiltersCache;
|
||||
|
||||
protected WebhookDeliveryThread getDeliveryJob(Event event, Webhook webhook, Pair<Integer, Integer> configs) {
|
||||
WebhookDeliveryThread.WebhookDeliveryContext<WebhookDeliveryThread.WebhookDeliveryResult> context =
|
||||
new WebhookDeliveryThread.WebhookDeliveryContext<>(null, event.getEventId(), webhook.getId());
|
||||
|
|
@ -97,13 +106,74 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
return job;
|
||||
}
|
||||
|
||||
protected String getEventValueByFilterType(Event event, WebhookFilter.Type filterType) {
|
||||
if (WebhookFilter.Type.EventType.equals(filterType)) {
|
||||
return event.getEventType();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean isValueMatchingFilter(String eventValue, WebhookFilter.MatchType matchType, String filterValue) {
|
||||
switch (matchType) {
|
||||
case Exact:
|
||||
return eventValue.equals(filterValue);
|
||||
case Prefix:
|
||||
return eventValue.startsWith(filterValue);
|
||||
case Suffix:
|
||||
return eventValue.endsWith(filterValue);
|
||||
case Contains:
|
||||
return eventValue.contains(filterValue);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isEventMatchingFilters(Event event, List<? extends WebhookFilter> filters) {
|
||||
if (CollectionUtils.isEmpty(filters)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean hasAnyInclude = false;
|
||||
boolean anyIncludeMatched = false;
|
||||
|
||||
// First pass: short-circuit on any Exclude match; track Include presence/match
|
||||
for (WebhookFilter f : filters) {
|
||||
final WebhookFilter.Type type = f.getType();
|
||||
String eventValue = getEventValueByFilterType(event, type);
|
||||
|
||||
if (f.getMode() == WebhookFilter.Mode.Exclude) {
|
||||
if (eventValue != null && isValueMatchingFilter(eventValue, f.getMatchType(), f.getValue())) {
|
||||
logger.trace("{} matched Exclude {}, webhook delivery will be skipped", event, f);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (f.getMode() == WebhookFilter.Mode.Include) {
|
||||
hasAnyInclude = true;
|
||||
if (!anyIncludeMatched && eventValue != null &&
|
||||
isValueMatchingFilter(eventValue, f.getMatchType(), f.getValue())) {
|
||||
logger.trace("{} matched Include {}", event, f);
|
||||
anyIncludeMatched = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there were includes, we must have matched at least one; otherwise allow by default
|
||||
if (hasAnyInclude && !anyIncludeMatched) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected List<Runnable> getDeliveryJobs(Event event) throws EventBusException {
|
||||
List<Runnable> jobs = new ArrayList<>();
|
||||
if (!EventCategory.ACTION_EVENT.getName().equals(event.getEventCategory())) {
|
||||
return jobs;
|
||||
}
|
||||
if (event.getResourceAccountId() == null) {
|
||||
logger.warn("Skipping delivering event {} to any webhook as account ID is missing", event);
|
||||
logger.warn("Skipping delivering {} to any webhook as account ID is missing", event);
|
||||
throw new EventBusException(String.format("Account missing for the event ID: %s", event.getEventUuid()));
|
||||
}
|
||||
List<Long> domainIds = new ArrayList<>();
|
||||
|
|
@ -112,9 +182,14 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
domainIds.addAll(domainDao.getDomainParentIds(event.getResourceDomainId()));
|
||||
}
|
||||
List<WebhookVO> webhooks =
|
||||
webhookDao.listByEnabledForDelivery(event.getResourceAccountId(), domainIds);
|
||||
webhooksCache.get(org.apache.commons.lang3.tuple.Pair.of(event.getResourceAccountId(), domainIds));
|
||||
Map<Long, Pair<Integer, Integer>> domainConfigs = new HashMap<>();
|
||||
for (WebhookVO webhook : webhooks) {
|
||||
List<? extends WebhookFilter> filters = webhookFiltersCache.get(webhook.getId());
|
||||
if (!isEventMatchingFilters(event, filters)) {
|
||||
logger.debug("Skipping delivering {} to {} as it doesn't match filters", event, webhook);
|
||||
continue;
|
||||
}
|
||||
if (!domainConfigs.containsKey(webhook.getDomainId())) {
|
||||
domainConfigs.put(webhook.getDomainId(),
|
||||
new Pair<>(WebhookDeliveryTries.valueIn(webhook.getDomainId()),
|
||||
|
|
@ -128,7 +203,7 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
}
|
||||
|
||||
protected Runnable getManualDeliveryJob(WebhookDelivery existingDelivery, Webhook webhook, String payload,
|
||||
AsyncCallFuture<WebhookDeliveryThread.WebhookDeliveryResult> future) {
|
||||
CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future) {
|
||||
if (StringUtils.isBlank(payload)) {
|
||||
payload = "{ \"CloudStack\": \"works!\" }";
|
||||
}
|
||||
|
|
@ -155,7 +230,7 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
event.setDescription(description);
|
||||
event.setResourceAccountUuid(resourceAccountUuid);
|
||||
ManualDeliveryContext<WebhookDeliveryThread.WebhookDeliveryResult> context =
|
||||
new ManualDeliveryContext<>(null, webhook, future);
|
||||
new ManualDeliveryContext<>(null, future);
|
||||
AsyncCallbackDispatcher<WebhookServiceImpl, WebhookDeliveryThread.WebhookDeliveryResult> caller =
|
||||
AsyncCallbackDispatcher.create(this);
|
||||
caller.setCallback(caller.getTarget().manualDeliveryCompleteCallback(null, null))
|
||||
|
|
@ -181,7 +256,7 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
AsyncCallbackDispatcher<WebhookServiceImpl, WebhookDeliveryThread.WebhookDeliveryResult> callback,
|
||||
ManualDeliveryContext<WebhookDeliveryThread.WebhookDeliveryResult> context) {
|
||||
WebhookDeliveryThread.WebhookDeliveryResult result = callback.getResult();
|
||||
context.future.complete(result);
|
||||
context.getFuture().complete(result);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -205,8 +280,20 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
return processed;
|
||||
}
|
||||
|
||||
protected void initCaches() {
|
||||
webhooksCache = new LazyCache<>(
|
||||
16, 60,
|
||||
(key) -> webhookDao.listByEnabledForDelivery(key.getLeft(), key.getRight())
|
||||
);
|
||||
webhookFiltersCache = new LazyCache<>(
|
||||
16, 60,
|
||||
(webhookId) -> webhookFilterDao.listByWebhook(webhookId)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
initCaches();
|
||||
try {
|
||||
webhookJobExecutor = Executors.newFixedThreadPool(WebhookDeliveryThreadPoolSize.value(),
|
||||
new NamedThreadFactory(WEBHOOK_JOB_POOL_THREAD_PREFIX));
|
||||
|
|
@ -273,7 +360,7 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
@Override
|
||||
public WebhookDelivery executeWebhookDelivery(WebhookDelivery delivery, Webhook webhook, String payload)
|
||||
throws CloudRuntimeException {
|
||||
AsyncCallFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = new AsyncCallFuture<>();
|
||||
CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = new CompletableFuture<>();
|
||||
Runnable job = getManualDeliveryJob(delivery, webhook, payload, future);
|
||||
webhookJobExecutor.submit(job);
|
||||
WebhookDeliveryThread.WebhookDeliveryResult result = null;
|
||||
|
|
@ -297,22 +384,33 @@ public class WebhookServiceImpl extends ManagerBase implements WebhookService, W
|
|||
return webhookDeliveryVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateWebhooksCache() {
|
||||
webhooksCache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateWebhookFiltersCache(long webhookId) {
|
||||
webhookFiltersCache.invalidate(webhookId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<?>> getCommands() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
static public class ManualDeliveryContext<T> extends AsyncRpcContext<T> {
|
||||
final Webhook webhook;
|
||||
final AsyncCallFuture<WebhookDeliveryThread.WebhookDeliveryResult> future;
|
||||
protected static class ManualDeliveryContext<T> extends AsyncRpcContext<T> {
|
||||
private final CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future;
|
||||
|
||||
public ManualDeliveryContext(AsyncCompletionCallback<T> callback, Webhook webhook,
|
||||
AsyncCallFuture<WebhookDeliveryThread.WebhookDeliveryResult> future) {
|
||||
super(callback);
|
||||
this.webhook = webhook;
|
||||
this.future = future;
|
||||
public CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> getFuture() {
|
||||
return future;
|
||||
}
|
||||
|
||||
public ManualDeliveryContext(AsyncCompletionCallback<T> callback,
|
||||
CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future) {
|
||||
super(callback);
|
||||
this.future = future;
|
||||
}
|
||||
}
|
||||
|
||||
public class WebhookDeliveryCleanupWorker extends ManagedContextRunnable {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.api.command.user;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookFilter;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
@APICommand(name = "addWebhookFilter",
|
||||
description = "Adds a Webhook filter",
|
||||
responseObject = WebhookResponse.class,
|
||||
entityType = {WebhookFilter.class},
|
||||
requestHasSensitiveInfo = false,
|
||||
responseHasSensitiveInfo = false,
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||
since = "4.23.0")
|
||||
public class AddWebhookFilterCmd extends BaseCmd {
|
||||
|
||||
@Inject
|
||||
WebhookApiService webhookApiService;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
@Parameter(name = ApiConstants.WEBHOOK_ID, type = CommandType.UUID, required = true,
|
||||
entityType = WebhookResponse.class, description = "ID for the Webhook")
|
||||
private Long id;
|
||||
|
||||
@Parameter(name = ApiConstants.MODE, type = BaseCmd.CommandType.STRING,
|
||||
description = "Mode for the Webhook filter - Include or Exclude")
|
||||
private String mode;
|
||||
|
||||
@Parameter(name = ApiConstants.MATCH_TYPE, type = BaseCmd.CommandType.STRING,
|
||||
description = "Match type for the Webhook filter - Exact, Prefix, Suffix or Contains")
|
||||
private String matchType;
|
||||
|
||||
@Parameter(name = ApiConstants.VALUE, type = BaseCmd.CommandType.STRING, required = true,
|
||||
description = "Value for the Webhook which that will be matched")
|
||||
private String value;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
return CallContext.current().getCallingAccountId();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return WebhookFilter.Type.EventType.name();
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public String getMatchType() {
|
||||
return matchType;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws ServerApiException {
|
||||
try {
|
||||
WebhookFilterResponse response = webhookApiService.addWebhookFilter(this);
|
||||
if (response == null) {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add webhook filter");
|
||||
}
|
||||
response.setResponseName(getCommandName());
|
||||
setResponseObject(response);
|
||||
} catch (CloudRuntimeException ex) {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,13 +28,12 @@ import org.apache.cloudstack.api.ApiConstants;
|
|||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ResponseObject;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.DomainResponse;
|
||||
import org.apache.cloudstack.api.response.ProjectResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.Webhook;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
|
@ -42,10 +41,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
|
|||
@APICommand(name = "createWebhook",
|
||||
description = "Creates a Webhook",
|
||||
responseObject = WebhookResponse.class,
|
||||
responseView = ResponseObject.ResponseView.Restricted,
|
||||
entityType = {Webhook.class},
|
||||
requestHasSensitiveInfo = false,
|
||||
responseHasSensitiveInfo = true,
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||
since = "4.20.0")
|
||||
public class CreateWebhookCmd extends BaseCmd {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.api.command.user;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookFilter;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
@APICommand(name = "deleteWebhookFilter",
|
||||
description = "Deletes Webhook filter",
|
||||
responseObject = SuccessResponse.class,
|
||||
entityType = {WebhookFilter.class},
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||
since = "4.20.0")
|
||||
public class DeleteWebhookFilterCmd extends BaseCmd {
|
||||
|
||||
@Inject
|
||||
WebhookApiService webhookApiService;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID,
|
||||
entityType = WebhookFilterResponse.class,
|
||||
description = "The ID of the Webhook filter")
|
||||
private Long id;
|
||||
|
||||
@Parameter(name = ApiConstants.WEBHOOK_ID, type = BaseCmd.CommandType.UUID,
|
||||
entityType = WebhookResponse.class,
|
||||
description = "The ID of the Webhook")
|
||||
private Long webhookId;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Long getWebhookId() {
|
||||
return webhookId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
return CallContext.current().getCallingAccountId();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@Override
|
||||
public void execute() throws ServerApiException {
|
||||
try {
|
||||
webhookApiService.deleteWebhookFilter(this);
|
||||
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||
setResponseObject(response);
|
||||
} catch (CloudRuntimeException ex) {
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -39,8 +39,6 @@ import com.cloud.utils.exception.CloudRuntimeException;
|
|||
description = "Executes a Webhook delivery",
|
||||
responseObject = WebhookDeliveryResponse.class,
|
||||
entityType = {WebhookDelivery.class},
|
||||
requestHasSensitiveInfo = false,
|
||||
responseHasSensitiveInfo = false,
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||
since = "4.20.0")
|
||||
public class ExecuteWebhookDeliveryCmd extends BaseCmd {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import org.apache.cloudstack.api.ApiConstants;
|
|||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.BaseListCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ResponseObject;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.api.response.ManagementServerResponse;
|
||||
|
|
@ -39,7 +38,6 @@ import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
|
|||
@APICommand(name = "listWebhookDeliveries",
|
||||
description = "Lists Webhook deliveries",
|
||||
responseObject = WebhookResponse.class,
|
||||
responseView = ResponseObject.ResponseView.Restricted,
|
||||
entityType = {WebhookDelivery.class},
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||
since = "4.20.0")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.api.command.user;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.BaseListCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookFilter;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookDeliveryResponse;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
|
||||
|
||||
@APICommand(name = "listWebhookFilters",
|
||||
description = "Lists Webhook filters",
|
||||
responseObject = WebhookFilterResponse.class,
|
||||
entityType = {WebhookFilter.class},
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||
since = "4.23.0")
|
||||
public class ListWebhookFiltersCmd extends BaseListCmd {
|
||||
|
||||
@Inject
|
||||
WebhookApiService webhookApiService;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
//////////////// API parameters /////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID,
|
||||
entityType = WebhookDeliveryResponse.class,
|
||||
description = "The ID of the Webhook delivery")
|
||||
private Long id;
|
||||
|
||||
@Parameter(name = ApiConstants.WEBHOOK_ID, type = BaseCmd.CommandType.UUID,
|
||||
entityType = WebhookResponse.class,
|
||||
description = "The ID of the Webhook")
|
||||
private Long webhookId;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Long getWebhookId() {
|
||||
return webhookId;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
@Override
|
||||
public void execute() throws ServerApiException {
|
||||
ListResponse<WebhookFilterResponse> response = webhookApiService.listWebhookFilters(this);
|
||||
response.setResponseName(getCommandName());
|
||||
setResponseObject(response);
|
||||
}
|
||||
}
|
||||
|
|
@ -25,17 +25,15 @@ import org.apache.cloudstack.api.APICommand;
|
|||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ResponseObject;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.Webhook;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
|
||||
|
||||
@APICommand(name = "listWebhooks",
|
||||
description = "Lists Webhooks",
|
||||
responseObject = WebhookResponse.class,
|
||||
responseView = ResponseObject.ResponseView.Restricted,
|
||||
entityType = {Webhook.class},
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||
since = "4.20.0")
|
||||
|
|
|
|||
|
|
@ -26,17 +26,16 @@ import org.apache.cloudstack.api.ApiErrorCode;
|
|||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.Parameter;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.Webhook;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookResponse;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
@APICommand(name = "updateWebhook",
|
||||
description = "Updates a Webhook",
|
||||
responseObject = SuccessResponse.class,
|
||||
responseObject = WebhookResponse.class,
|
||||
entityType = {Webhook.class},
|
||||
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User},
|
||||
since = "4.20.0")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.api.response;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseResponse;
|
||||
import org.apache.cloudstack.api.EntityReference;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookFilter;
|
||||
|
||||
import com.cloud.serializer.Param;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
@EntityReference(value = {WebhookFilter.class})
|
||||
public class WebhookFilterResponse extends BaseResponse {
|
||||
@SerializedName(ApiConstants.ID)
|
||||
@Param(description = "The ID of the Webhook filter")
|
||||
private String id;
|
||||
|
||||
@SerializedName(ApiConstants.WEBHOOK_ID)
|
||||
@Param(description = "The ID of the Webhook")
|
||||
private String webhookId;
|
||||
|
||||
@SerializedName(ApiConstants.WEBHOOK_NAME)
|
||||
@Param(description = "The name of the Webhook")
|
||||
private String webhookName;
|
||||
|
||||
@SerializedName(ApiConstants.TYPE)
|
||||
@Param(description = "The type of the Webhook filter")
|
||||
private String type;
|
||||
|
||||
@SerializedName(ApiConstants.MODE)
|
||||
@Param(description = "The type of the Webhook filter")
|
||||
private String mode;
|
||||
|
||||
@SerializedName(ApiConstants.MATCH_TYPE)
|
||||
@Param(description = "The type of the Webhook filter")
|
||||
private String matchType;
|
||||
|
||||
@SerializedName(ApiConstants.VALUE)
|
||||
@Param(description = "The type of the Webhook filter")
|
||||
private String value;
|
||||
|
||||
@SerializedName(ApiConstants.CREATED)
|
||||
@Param(description = "The type of the Webhook filter")
|
||||
private Date created;
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setWebhookId(String webhookId) {
|
||||
this.webhookId = webhookId;
|
||||
}
|
||||
|
||||
public void setWebhookName(String webhookName) {
|
||||
this.webhookName = webhookName;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setMode(String mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public void setMatchType(String matchType) {
|
||||
this.matchType = matchType;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
|
||||
import com.cloud.utils.db.Filter;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
|
|
@ -64,6 +65,9 @@ public class WebhookDeliveryDaoImpl extends GenericDaoBase<WebhookDeliveryVO, Lo
|
|||
SearchCriteria<WebhookDeliveryVO> sc = sb.create();
|
||||
sc.setParameters("webhookId", webhookId);
|
||||
List<WebhookDeliveryVO> keep = listBy(sc, searchFilter);
|
||||
if (CollectionUtils.isEmpty(keep)) {
|
||||
return;
|
||||
}
|
||||
SearchBuilder<WebhookDeliveryVO> sbDelete = createSearchBuilder();
|
||||
sbDelete.and("id", sbDelete.entity().getId(), SearchCriteria.Op.NOTIN);
|
||||
SearchCriteria<WebhookDeliveryVO> scDelete = sbDelete.create();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface WebhookFilterDao extends GenericDao<WebhookFilterVO, Long> {
|
||||
Pair<List<WebhookFilterVO>, Integer> searchBy(Long id, Long webhookId, Long startIndex, Long pageSize);
|
||||
List<WebhookFilterVO> listByWebhook(Long webhookId);
|
||||
int delete(Long id, Long webhookId);
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.Filter;
|
||||
import com.cloud.utils.db.GenericDaoBase;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
|
||||
public class WebhookFilterDaoImpl extends GenericDaoBase<WebhookFilterVO, Long> implements WebhookFilterDao {
|
||||
|
||||
SearchBuilder<WebhookFilterVO> IdWebhookIdSearch;
|
||||
|
||||
public WebhookFilterDaoImpl() {
|
||||
IdWebhookIdSearch = createSearchBuilder();
|
||||
IdWebhookIdSearch.and("id", IdWebhookIdSearch.entity().getId(), SearchCriteria.Op.EQ);
|
||||
IdWebhookIdSearch.and("webhookId", IdWebhookIdSearch.entity().getWebhookId(), SearchCriteria.Op.EQ);
|
||||
IdWebhookIdSearch.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<List<WebhookFilterVO>, Integer> searchBy(Long id, Long webhookId, Long startIndex, Long pageSize) {
|
||||
Filter searchFilter = new Filter(WebhookFilterVO.class, "id", false, startIndex,
|
||||
pageSize);
|
||||
SearchCriteria<WebhookFilterVO> sc = IdWebhookIdSearch.create();
|
||||
if (id != null) {
|
||||
sc.setParameters("id", id);
|
||||
}
|
||||
if (webhookId != null) {
|
||||
sc.setParameters("webhookId", webhookId);
|
||||
}
|
||||
return searchAndCount(sc, searchFilter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WebhookFilterVO> listByWebhook(Long webhookId) {
|
||||
SearchCriteria<WebhookFilterVO> sc = IdWebhookIdSearch.create();
|
||||
if (webhookId != null) {
|
||||
sc.setParameters("webhookId", webhookId);
|
||||
}
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Long id, Long webhookId) {
|
||||
SearchCriteria<WebhookFilterVO> sc = IdWebhookIdSearch.create();
|
||||
if (ObjectUtils.allNull(id, webhookId)) {
|
||||
return 0;
|
||||
}
|
||||
if (id != null) {
|
||||
sc.setParameters("id", id);
|
||||
}
|
||||
if (webhookId != null) {
|
||||
sc.setParameters("webhookId", webhookId);
|
||||
}
|
||||
return remove(sc);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.apache.cloudstack.mom.webhook.WebhookFilter;
|
||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
@Entity
|
||||
@Table(name = "webhook_filter")
|
||||
public class WebhookFilterVO implements WebhookFilter {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id", updatable = false, nullable = false)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "uuid")
|
||||
private String uuid;
|
||||
|
||||
@Column(name = "webhook_id", nullable = false)
|
||||
private Long webhookId;
|
||||
|
||||
@Column(name = "type", length = 20)
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
private Type type;
|
||||
|
||||
@Column(name = "mode", length = 20)
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
private Mode mode;
|
||||
|
||||
@Column(name = "match_type", length = 20)
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
private MatchType matchType;
|
||||
|
||||
@Column(name = "value", nullable = false, length = 128)
|
||||
private String value;
|
||||
|
||||
@Column(name = GenericDao.CREATED_COLUMN)
|
||||
private Date created;
|
||||
|
||||
public WebhookFilterVO() {
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public WebhookFilterVO(Long webhookId, Type type, Mode mode, MatchType matchType, String value) {
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
this.webhookId = webhookId;
|
||||
this.type = type;
|
||||
this.mode = mode;
|
||||
this.matchType = matchType;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getWebhookId() {
|
||||
return webhookId;
|
||||
}
|
||||
|
||||
public void setWebhookId(Long webhookId) {
|
||||
this.webhookId = webhookId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
public void setMode(Mode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchType getMatchType() {
|
||||
return matchType;
|
||||
}
|
||||
|
||||
public void setMatchType(MatchType matchType) {
|
||||
this.matchType = matchType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreated() {
|
||||
return created;
|
||||
}
|
||||
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("WebhookFilter %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(
|
||||
this, "id", "uuid", "webhook_id", "type", "mode", "match_type", "value"));
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
<bean id="webhookJoinDao" class="org.apache.cloudstack.mom.webhook.dao.WebhookJoinDaoImpl" />
|
||||
<bean id="webhookDeliveryDao" class="org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryDaoImpl" />
|
||||
<bean id="webhookDeliveryJoinDao" class="org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryJoinDaoImpl" />
|
||||
<bean id="webhookFilterDao" class="org.apache.cloudstack.mom.webhook.dao.WebhookFilterDaoImpl" />
|
||||
<bean id="webhookApiService" class="org.apache.cloudstack.mom.webhook.WebhookApiServiceImpl" />
|
||||
<bean id="webhookService" class="org.apache.cloudstack.mom.webhook.WebhookServiceImpl" />
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,669 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
|
||||
import org.apache.cloudstack.framework.events.Event;
|
||||
import org.apache.cloudstack.framework.events.EventBusException;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookDao;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookDeliveryDao;
|
||||
import org.apache.cloudstack.mom.webhook.dao.WebhookFilterDao;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookVO;
|
||||
import org.apache.cloudstack.utils.cache.LazyCache;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import com.cloud.api.query.vo.EventJoinVO;
|
||||
import com.cloud.cluster.dao.ManagementServerHostDao;
|
||||
import com.cloud.domain.dao.DomainDao;
|
||||
import com.cloud.event.EventCategory;
|
||||
import com.cloud.event.dao.EventJoinDao;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.ComponentContext;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WebhookServiceImplTest {
|
||||
@Mock
|
||||
EventJoinDao eventJoinDao;
|
||||
@Mock
|
||||
WebhookDao webhookDao;
|
||||
@Mock
|
||||
WebhookDeliveryDao webhookDeliveryDao;
|
||||
@Mock
|
||||
WebhookFilterDao webhookFilterDao;
|
||||
@Mock
|
||||
ManagementServerHostDao managementServerHostDao;
|
||||
@Mock
|
||||
DomainDao domainDao;
|
||||
@Mock
|
||||
AccountManager accountManager;
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private WebhookServiceImpl webhookServiceImpl;
|
||||
|
||||
MockedStatic<ComponentContext> componentContextMockedStatic;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
componentContextMockedStatic = Mockito.mockStatic(ComponentContext.class);
|
||||
componentContextMockedStatic.when(() -> ComponentContext.inject(Mockito.any(WebhookDeliveryThread.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
webhookServiceImpl.initCaches();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
componentContextMockedStatic.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeliveryJobReturnsProperlyConfiguredJob() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
Webhook webhook = Mockito.mock(Webhook.class);
|
||||
Pair<Integer, Integer> configs = new Pair<>(4, 5000);
|
||||
|
||||
Mockito.when(event.getEventId()).thenReturn(123L);
|
||||
Mockito.when(webhook.getId()).thenReturn(456L);
|
||||
|
||||
WebhookDeliveryThread job = webhookServiceImpl.getDeliveryJob(event, webhook, configs);
|
||||
|
||||
Assert.assertNotNull(job);
|
||||
Assert.assertEquals(4, ReflectionTestUtils.getField(job, "deliveryTries"));
|
||||
Assert.assertEquals(5000, ReflectionTestUtils.getField(job, "deliveryTimeout"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeliveryJobInjectsDependencies() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
Webhook webhook = Mockito.mock(Webhook.class);
|
||||
Pair<Integer, Integer> configs = new Pair<>(1, 1000);
|
||||
|
||||
WebhookDeliveryThread job = webhookServiceImpl.getDeliveryJob(event, webhook, configs);
|
||||
|
||||
Mockito.verify(webhookServiceImpl, Mockito.times(1)).getDeliveryJob(event, webhook, configs);
|
||||
componentContextMockedStatic.verify(() -> ComponentContext.inject(job), Mockito.times(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEventValueByFilterTypeReturnsEventTypeWhenFilterTypeIsEventType() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
|
||||
|
||||
String result = webhookServiceImpl.getEventValueByFilterType(event, WebhookFilter.Type.EventType);
|
||||
|
||||
Assert.assertEquals("USER.LOGIN", result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEventValueByFilterTypeReturnsNullWhenFilterTypeIsNotEventType() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
|
||||
String result = webhookServiceImpl.getEventValueByFilterType(event, null);
|
||||
|
||||
Assert.assertNull(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValueMatchingFilterReturnsTrueForExactMatch() {
|
||||
boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Exact, "USER.LOGIN");
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValueMatchingFilterReturnsFalseForNonExactMatch() {
|
||||
boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Exact, "USER.LOGOUT");
|
||||
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValueMatchingFilterReturnsTrueForPrefixMatch() {
|
||||
boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Prefix, "USER");
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValueMatchingFilterReturnsFalseForNonPrefixMatch() {
|
||||
boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Prefix, "ADMIN");
|
||||
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValueMatchingFilterReturnsTrueForSuffixMatch() {
|
||||
boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Suffix, "LOGIN");
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValueMatchingFilterReturnsFalseForNonSuffixMatch() {
|
||||
boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Suffix, "LOGOUT");
|
||||
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValueMatchingFilterReturnsTrueForContainsMatch() {
|
||||
boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Contains, "USER");
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValueMatchingFilterReturnsFalseForNonContainsMatch() {
|
||||
boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Contains, "ADMIN");
|
||||
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValueMatchingFilterReturnsFalseForNullFilterValue() {
|
||||
boolean result = webhookServiceImpl.isValueMatchingFilter("USER.LOGIN", WebhookFilter.MatchType.Exact, null);
|
||||
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEventMatchingFiltersReturnsTrueWhenFiltersAreEmpty() {
|
||||
List<WebhookFilter> filters = new ArrayList<>();
|
||||
|
||||
boolean result = webhookServiceImpl.isEventMatchingFilters(Mockito.mock(Event.class), filters);
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEventMatchingFiltersReturnsFalseWhenEventMatchesExcludeFilter() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
WebhookFilter excludeFilter = Mockito.mock(WebhookFilter.class);
|
||||
|
||||
Mockito.when(excludeFilter.getMode()).thenReturn(WebhookFilter.Mode.Exclude);
|
||||
Mockito.when(excludeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
|
||||
Mockito.when(excludeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
|
||||
Mockito.when(excludeFilter.getValue()).thenReturn("USER.LOGIN");
|
||||
Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
|
||||
|
||||
List<WebhookFilter> filters = List.of(excludeFilter);
|
||||
|
||||
boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
|
||||
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEventMatchingFiltersReturnsTrueWhenEventMatchesIncludeFilter() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
WebhookFilter includeFilter = Mockito.mock(WebhookFilter.class);
|
||||
|
||||
Mockito.when(includeFilter.getMode()).thenReturn(WebhookFilter.Mode.Include);
|
||||
Mockito.when(includeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
|
||||
Mockito.when(includeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
|
||||
Mockito.when(includeFilter.getValue()).thenReturn("USER.LOGIN");
|
||||
Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
|
||||
|
||||
List<WebhookFilter> filters = List.of(includeFilter);
|
||||
|
||||
boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEventMatchingFiltersReturnsFalseWhenEventDoesNotMatchAnyIncludeFilter() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
WebhookFilter includeFilter = Mockito.mock(WebhookFilter.class);
|
||||
|
||||
Mockito.when(includeFilter.getMode()).thenReturn(WebhookFilter.Mode.Include);
|
||||
Mockito.when(includeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
|
||||
Mockito.when(includeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
|
||||
Mockito.when(includeFilter.getValue()).thenReturn("USER.LOGOUT");
|
||||
Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
|
||||
|
||||
List<WebhookFilter> filters = List.of(includeFilter);
|
||||
|
||||
boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
|
||||
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEventMatchingFiltersReturnsTrueWhenEventMatchesAtLeastOneIncludeFilter() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
WebhookFilter includeFilter1 = Mockito.mock(WebhookFilter.class);
|
||||
WebhookFilter includeFilter2 = Mockito.mock(WebhookFilter.class);
|
||||
|
||||
Mockito.when(includeFilter1.getMode()).thenReturn(WebhookFilter.Mode.Include);
|
||||
Mockito.when(includeFilter1.getType()).thenReturn(WebhookFilter.Type.EventType);
|
||||
Mockito.when(includeFilter1.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
|
||||
Mockito.when(includeFilter1.getValue()).thenReturn("USER.LOGOUT");
|
||||
|
||||
Mockito.when(includeFilter2.getMode()).thenReturn(WebhookFilter.Mode.Include);
|
||||
Mockito.when(includeFilter2.getType()).thenReturn(WebhookFilter.Type.EventType);
|
||||
Mockito.when(includeFilter2.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
|
||||
Mockito.when(includeFilter2.getValue()).thenReturn("USER.LOGIN");
|
||||
|
||||
Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
|
||||
|
||||
List<WebhookFilter> filters = List.of(includeFilter1, includeFilter2);
|
||||
|
||||
boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
|
||||
|
||||
Assert.assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isEventMatchingFiltersReturnsFalseWhenEventMatchesExcludeFilterEvenWithIncludeFilters() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
WebhookFilter excludeFilter = Mockito.mock(WebhookFilter.class);
|
||||
WebhookFilter includeFilter = Mockito.mock(WebhookFilter.class);
|
||||
|
||||
Mockito.when(includeFilter.getMode()).thenReturn(WebhookFilter.Mode.Include);
|
||||
Mockito.when(includeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
|
||||
Mockito.when(includeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Prefix);
|
||||
Mockito.when(includeFilter.getValue()).thenReturn("USER.");
|
||||
|
||||
Mockito.when(excludeFilter.getMode()).thenReturn(WebhookFilter.Mode.Exclude);
|
||||
Mockito.when(excludeFilter.getType()).thenReturn(WebhookFilter.Type.EventType);
|
||||
Mockito.when(excludeFilter.getMatchType()).thenReturn(WebhookFilter.MatchType.Exact);
|
||||
Mockito.when(excludeFilter.getValue()).thenReturn("USER.LOGIN");
|
||||
|
||||
Mockito.when(event.getEventType()).thenReturn("USER.LOGIN");
|
||||
|
||||
List<WebhookFilter> filters = List.of(includeFilter, excludeFilter);
|
||||
|
||||
boolean result = webhookServiceImpl.isEventMatchingFilters(event, filters);
|
||||
|
||||
Assert.assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeliveryJobsReturnsEmptyListWhenEventCategoryIsNotActionEvent() throws EventBusException {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
Mockito.when(event.getEventCategory()).thenReturn("NON_ACTION_EVENT");
|
||||
|
||||
List<Runnable> jobs = webhookServiceImpl.getDeliveryJobs(event);
|
||||
|
||||
Assert.assertTrue(jobs.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeliveryJobsThrowsExceptionWhenEventAccountIdIsNull() {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
Mockito.when(event.getEventCategory()).thenReturn(EventCategory.ACTION_EVENT.getName());
|
||||
Mockito.when(event.getResourceAccountId()).thenReturn(null);
|
||||
|
||||
Assert.assertThrows(EventBusException.class, () -> webhookServiceImpl.getDeliveryJobs(event));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeliveryJobsReturnsEmptyListWhenNoWebhooksMatchFilters() throws EventBusException {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
Mockito.when(event.getEventCategory()).thenReturn(EventCategory.ACTION_EVENT.getName());
|
||||
Mockito.when(event.getResourceAccountId()).thenReturn(1L);
|
||||
Mockito.when(event.getResourceDomainId()).thenReturn(2L);
|
||||
Mockito.when(domainDao.getDomainParentIds(2L)).thenReturn(Set.of(3L));
|
||||
|
||||
WebhookVO webhook = Mockito.mock(WebhookVO.class);
|
||||
Mockito.when(webhook.getId()).thenReturn(1L);
|
||||
|
||||
Mockito.when(webhookDao.listByEnabledForDelivery(Mockito.anyLong(), Mockito.anyList())).thenReturn(List.of(webhook));
|
||||
Mockito.when(webhookFilterDao.listByWebhook(Mockito.anyLong())).thenReturn(List.of());
|
||||
Mockito.doReturn(false).when(webhookServiceImpl).isEventMatchingFilters(Mockito.any(), Mockito.anyList());
|
||||
|
||||
List<Runnable> jobs = webhookServiceImpl.getDeliveryJobs(event);
|
||||
|
||||
Assert.assertTrue(jobs.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeliveryJobsCreatesJobsForMatchingWebhooks() throws EventBusException {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
Mockito.when(event.getEventCategory()).thenReturn(EventCategory.ACTION_EVENT.getName());
|
||||
Mockito.when(event.getResourceAccountId()).thenReturn(1L);
|
||||
Mockito.when(event.getResourceDomainId()).thenReturn(2L);
|
||||
Mockito.when(domainDao.getDomainParentIds(2L)).thenReturn(Set.of(3L));
|
||||
|
||||
WebhookVO webhook = Mockito.mock(WebhookVO.class);
|
||||
Mockito.when(webhook.getId()).thenReturn(1L);
|
||||
Mockito.when(webhook.getDomainId()).thenReturn(2L);
|
||||
|
||||
Mockito.when(webhookDao.listByEnabledForDelivery(Mockito.anyLong(), Mockito.anyList())).thenReturn(List.of(webhook));
|
||||
Mockito.when(webhookFilterDao.listByWebhook(Mockito.anyLong())).thenReturn(List.of());
|
||||
Mockito.doReturn(true).when(webhookServiceImpl).isEventMatchingFilters(Mockito.any(), Mockito.anyList());
|
||||
Mockito.doReturn(Mockito.mock(WebhookDeliveryThread.class)).when(webhookServiceImpl).getDeliveryJob(Mockito.any(), Mockito.any(), Mockito.any());
|
||||
|
||||
List<Runnable> jobs = webhookServiceImpl.getDeliveryJobs(event);
|
||||
|
||||
Assert.assertEquals(1, jobs.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDeliveryJobsUsesCachedDomainConfigs() throws EventBusException {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
Mockito.when(event.getEventCategory()).thenReturn(EventCategory.ACTION_EVENT.getName());
|
||||
Mockito.when(event.getResourceAccountId()).thenReturn(1L);
|
||||
Mockito.when(event.getResourceDomainId()).thenReturn(2L);
|
||||
Mockito.when(domainDao.getDomainParentIds(2L)).thenReturn(Set.of(3L));
|
||||
|
||||
WebhookVO webhook1 = Mockito.mock(WebhookVO.class);
|
||||
Mockito.when(webhook1.getId()).thenReturn(1L);
|
||||
Mockito.when(webhook1.getDomainId()).thenReturn(2L);
|
||||
|
||||
WebhookVO webhook2 = Mockito.mock(WebhookVO.class);
|
||||
Mockito.when(webhook2.getId()).thenReturn(2L);
|
||||
Mockito.when(webhook2.getDomainId()).thenReturn(2L);
|
||||
|
||||
Mockito.when(webhookDao.listByEnabledForDelivery(Mockito.anyLong(), Mockito.anyList())).thenReturn(List.of(webhook1, webhook2));
|
||||
Mockito.when(webhookFilterDao.listByWebhook(Mockito.anyLong())).thenReturn(List.of());
|
||||
Mockito.doReturn(true).when(webhookServiceImpl).isEventMatchingFilters(Mockito.any(), Mockito.anyList());
|
||||
Mockito.doReturn(Mockito.mock(WebhookDeliveryThread.class)).when(webhookServiceImpl).getDeliveryJob(Mockito.any(), Mockito.any(), Mockito.any());
|
||||
|
||||
List<Runnable> jobs = webhookServiceImpl.getDeliveryJobs(event);
|
||||
|
||||
Assert.assertEquals(2, jobs.size());
|
||||
Mockito.verify(webhookServiceImpl, Mockito.times(1)).getDeliveryJob(Mockito.eq(event), Mockito.eq(webhook1), Mockito.any());
|
||||
Mockito.verify(webhookServiceImpl, Mockito.times(1)).getDeliveryJob(Mockito.eq(event), Mockito.eq(webhook2), Mockito.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getManualDeliveryJobCreatesJobWithDefaultPayloadWhenPayloadIsBlank() {
|
||||
Webhook webhook = Mockito.mock(Webhook.class);
|
||||
CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
|
||||
Account account = Mockito.mock(Account.class);
|
||||
|
||||
Mockito.when(webhook.getAccountId()).thenReturn(2L);
|
||||
Mockito.when(accountManager.getAccount(Mockito.anyLong())).thenReturn(account);
|
||||
|
||||
Runnable job = webhookServiceImpl.getManualDeliveryJob(null, webhook, " ", future);
|
||||
|
||||
Assert.assertNotNull(job);
|
||||
Event event = (Event) ReflectionTestUtils.getField(job, "event");
|
||||
Assert.assertNotNull(event);
|
||||
Assert.assertTrue(StringUtils.isNotBlank(event.getDescription()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getManualDeliveryJobCreatesJobWithExistingDeliveryDetails() {
|
||||
WebhookDelivery existingDelivery = Mockito.mock(WebhookDelivery.class);
|
||||
Webhook webhook = Mockito.mock(Webhook.class);
|
||||
EventJoinVO eventJoinVO = Mockito.mock(EventJoinVO.class);
|
||||
CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
|
||||
|
||||
Mockito.when(existingDelivery.getEventId()).thenReturn(123L);
|
||||
Mockito.when(eventJoinDao.findById(123L)).thenReturn(eventJoinVO);
|
||||
Mockito.when(eventJoinVO.getId()).thenReturn(123L);
|
||||
Mockito.when(eventJoinVO.getType()).thenReturn("TEST.EVENT");
|
||||
Mockito.when(eventJoinVO.getUuid()).thenReturn("test-uuid");
|
||||
Mockito.when(existingDelivery.getPayload()).thenReturn("test-payload");
|
||||
Mockito.when(eventJoinVO.getAccountUuid()).thenReturn("account-uuid");
|
||||
|
||||
Runnable job = webhookServiceImpl.getManualDeliveryJob(existingDelivery, webhook, null, future);
|
||||
|
||||
Assert.assertNotNull(job);
|
||||
Mockito.verify(eventJoinDao, Mockito.times(1)).findById(123L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getManualDeliveryJobCreatesJobWithWebhookAccountDetailsWhenNoExistingDelivery() {
|
||||
Webhook webhook = Mockito.mock(Webhook.class);
|
||||
Account account = Mockito.mock(Account.class);
|
||||
CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
|
||||
|
||||
Mockito.when(webhook.getAccountId()).thenReturn(1L);
|
||||
Mockito.when(accountManager.getAccount(1L)).thenReturn(account);
|
||||
Mockito.when(account.getUuid()).thenReturn("account-uuid");
|
||||
|
||||
Runnable job = webhookServiceImpl.getManualDeliveryJob(null, webhook, "test-payload", future);
|
||||
|
||||
Assert.assertNotNull(job);
|
||||
Mockito.verify(accountManager, Mockito.times(1)).getAccount(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getManualDeliveryJobSetsDeliveryTriesAndTimeoutFromWebhookDomain() {
|
||||
Webhook webhook = Mockito.mock(Webhook.class);
|
||||
CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
|
||||
Account account = Mockito.mock(Account.class);
|
||||
|
||||
Mockito.when(webhook.getDomainId()).thenReturn(2L);
|
||||
Mockito.when(webhook.getAccountId()).thenReturn(2L);
|
||||
Mockito.when(accountManager.getAccount(Mockito.anyLong())).thenReturn(account);
|
||||
|
||||
WebhookDeliveryThread job = (WebhookDeliveryThread) webhookServiceImpl.getManualDeliveryJob(null, webhook, "test-payload", future);
|
||||
|
||||
Assert.assertEquals(3, ReflectionTestUtils.getField(job, "deliveryTries"));
|
||||
Assert.assertEquals(10, ReflectionTestUtils.getField(job, "deliveryTimeout"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deliveryCompleteCallbackPersistsDeliveryVO() {
|
||||
WebhookDeliveryThread.WebhookDeliveryResult result = Mockito.mock(WebhookDeliveryThread.WebhookDeliveryResult.class);
|
||||
WebhookDeliveryThread.WebhookDeliveryContext<Webhook> context = Mockito.mock(WebhookDeliveryThread.WebhookDeliveryContext.class);
|
||||
|
||||
Mockito.when(context.getEventId()).thenReturn(123L);
|
||||
Mockito.when(context.getRuleId()).thenReturn(456L);
|
||||
Mockito.when(result.getHeaders()).thenReturn("headers");
|
||||
Mockito.when(result.getPayload()).thenReturn("payload");
|
||||
Mockito.when(result.isSuccess()).thenReturn(true);
|
||||
Mockito.when(result.getResult()).thenReturn("result");
|
||||
|
||||
AsyncCallbackDispatcher<WebhookServiceImpl, WebhookDeliveryThread.WebhookDeliveryResult> callback = Mockito.mock(AsyncCallbackDispatcher.class);
|
||||
Mockito.when(callback.getResult()).thenReturn(result);
|
||||
|
||||
webhookServiceImpl.deliveryCompleteCallback(callback, context);
|
||||
|
||||
Mockito.verify(webhookDeliveryDao, Mockito.times(1)).persist(Mockito.any(WebhookDeliveryVO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void manualDeliveryCompleteCallbackCompletesFuture() {
|
||||
WebhookDeliveryThread.WebhookDeliveryResult result = Mockito.mock(WebhookDeliveryThread.WebhookDeliveryResult.class);
|
||||
WebhookServiceImpl.ManualDeliveryContext<WebhookDeliveryThread.WebhookDeliveryResult> context = Mockito.mock(WebhookServiceImpl.ManualDeliveryContext.class);
|
||||
CompletableFuture<WebhookDeliveryThread.WebhookDeliveryResult> future = Mockito.mock(CompletableFuture.class);
|
||||
|
||||
Mockito.when(context.getFuture()).thenReturn(future);
|
||||
AsyncCallbackDispatcher<WebhookServiceImpl, WebhookDeliveryThread.WebhookDeliveryResult> callback = Mockito.mock(AsyncCallbackDispatcher.class);
|
||||
Mockito.when(callback.getResult()).thenReturn(result);
|
||||
|
||||
webhookServiceImpl.manualDeliveryCompleteCallback(callback, context);
|
||||
|
||||
Mockito.verify(future, Mockito.times(1)).complete(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cleanupOldWebhookDeliveriesProcessesAllWebhooks() {
|
||||
WebhookVO webhook1 = Mockito.mock(WebhookVO.class);
|
||||
WebhookVO webhook2 = Mockito.mock(WebhookVO.class);
|
||||
|
||||
Mockito.when(webhook1.getId()).thenReturn(1L);
|
||||
Mockito.when(webhook2.getId()).thenReturn(2L);
|
||||
|
||||
List<WebhookVO> webhooks = List.of(webhook1, webhook2);
|
||||
Pair<List<WebhookVO>, Integer> webhooksAndCount = new Pair<>(webhooks, 2);
|
||||
|
||||
Mockito.when(webhookDao.searchAndCount(Mockito.any(), Mockito.any())).thenReturn(webhooksAndCount);
|
||||
|
||||
long processed = webhookServiceImpl.cleanupOldWebhookDeliveries(10);
|
||||
|
||||
Assert.assertEquals(2, processed);
|
||||
Mockito.verify(webhookDeliveryDao, Mockito.times(1)).removeOlderDeliveries(1L, 10);
|
||||
Mockito.verify(webhookDeliveryDao, Mockito.times(1)).removeOlderDeliveries(2L, 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listWebhooksByAccountReturnsEmptyListWhenNoWebhooksExist() {
|
||||
Mockito.when(webhookDao.listByAccount(1L)).thenReturn(new ArrayList<>());
|
||||
|
||||
List<? extends ControlledEntity> result = webhookServiceImpl.listWebhooksByAccount(1L);
|
||||
|
||||
Assert.assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listWebhooksByAccountReturnsWebhooksForValidAccount() {
|
||||
WebhookVO webhook = Mockito.mock(WebhookVO.class);
|
||||
Mockito.when(webhookDao.listByAccount(1L)).thenReturn(List.of(webhook));
|
||||
|
||||
List<? extends ControlledEntity> result = webhookServiceImpl.listWebhooksByAccount(1L);
|
||||
|
||||
Assert.assertEquals(1, result.size());
|
||||
Assert.assertEquals(webhook, result.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleEventSubmitsJobsToExecutor() throws EventBusException {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
Runnable job1 = Mockito.mock(Runnable.class);
|
||||
Runnable job2 = Mockito.mock(Runnable.class);
|
||||
ExecutorService webhookJobExecutor = Mockito.mock(ExecutorService.class);
|
||||
ReflectionTestUtils.setField(webhookServiceImpl, "webhookJobExecutor", webhookJobExecutor);
|
||||
|
||||
Mockito.doReturn(List.of(job1, job2)).when(webhookServiceImpl).getDeliveryJobs(event);
|
||||
|
||||
webhookServiceImpl.handleEvent(event);
|
||||
|
||||
Mockito.verify(webhookJobExecutor, Mockito.times(1)).submit(job1);
|
||||
Mockito.verify(webhookJobExecutor, Mockito.times(1)).submit(job2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleEventDoesNotSubmitJobsWhenNoJobsExist() throws EventBusException {
|
||||
Event event = Mockito.mock(Event.class);
|
||||
ExecutorService webhookJobExecutor = Mockito.mock(ExecutorService.class);
|
||||
ReflectionTestUtils.setField(webhookServiceImpl, "webhookJobExecutor", webhookJobExecutor);
|
||||
|
||||
Mockito.doReturn(new ArrayList<>()).when(webhookServiceImpl).getDeliveryJobs(event);
|
||||
|
||||
webhookServiceImpl.handleEvent(event);
|
||||
|
||||
Mockito.verify(webhookJobExecutor, Mockito.never()).submit(Mockito.any(Runnable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeWebhookDeliveryPersistsDeliveryWhenDeliveryExists() {
|
||||
WebhookDelivery delivery = Mockito.mock(WebhookDelivery.class);
|
||||
Webhook webhook = Mockito.mock(Webhook.class);
|
||||
WebhookDeliveryThread.WebhookDeliveryResult result = Mockito.mock(WebhookDeliveryThread.WebhookDeliveryResult.class);
|
||||
|
||||
Mockito.when(delivery.getEventId()).thenReturn(123L);
|
||||
Mockito.when(delivery.getWebhookId()).thenReturn(456L);
|
||||
Mockito.when(result.getHeaders()).thenReturn("headers");
|
||||
Mockito.when(result.getPayload()).thenReturn("payload");
|
||||
Mockito.when(result.isSuccess()).thenReturn(true);
|
||||
Mockito.when(result.getResult()).thenReturn("result");
|
||||
Mockito.when(result.getStarTime()).thenReturn(new Date(System.currentTimeMillis() - (2 * 1000L)));
|
||||
Mockito.when(result.getEndTime()).thenReturn(new Date(System.currentTimeMillis()));
|
||||
Mockito.when(eventJoinDao.findById(123L)).thenReturn(Mockito.mock(EventJoinVO.class));
|
||||
ExecutorService executorService = Mockito.mock(ExecutorService.class);
|
||||
Mockito.when(executorService.submit(Mockito.any(Runnable.class))).thenAnswer(invocation -> {
|
||||
Runnable runnable = invocation.getArgument(0);
|
||||
WebhookDeliveryThread webhookDeliveryThread = (WebhookDeliveryThread) runnable;
|
||||
webhookDeliveryThread.callback.complete(result);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
});
|
||||
ReflectionTestUtils.setField(webhookServiceImpl, "webhookJobExecutor", executorService);
|
||||
|
||||
WebhookDeliveryVO persistedDelivery = Mockito.mock(WebhookDeliveryVO.class);
|
||||
Mockito.when(webhookDeliveryDao.persist(Mockito.any(WebhookDeliveryVO.class))).thenReturn(persistedDelivery);
|
||||
|
||||
WebhookDelivery returnedDelivery = webhookServiceImpl.executeWebhookDelivery(delivery, webhook, "payload");
|
||||
|
||||
Assert.assertEquals(persistedDelivery, returnedDelivery);
|
||||
Mockito.verify(webhookDeliveryDao, Mockito.times(1)).persist(Mockito.any(WebhookDeliveryVO.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeWebhookDeliveryCreatesAndReturnsNewDeliveryWhenDeliveryIsNull() {
|
||||
Webhook webhook = Mockito.mock(Webhook.class);
|
||||
WebhookDeliveryThread.WebhookDeliveryResult result =
|
||||
Mockito.mock(WebhookDeliveryThread.WebhookDeliveryResult.class);
|
||||
Account account = Mockito.mock(Account.class);
|
||||
|
||||
Mockito.when(webhook.getAccountId()).thenReturn(2L);
|
||||
Mockito.when(accountManager.getAccount(Mockito.anyLong())).thenReturn(account);
|
||||
Mockito.when(result.getHeaders()).thenReturn("headers");
|
||||
Mockito.when(result.getPayload()).thenReturn("payload");
|
||||
Mockito.when(result.isSuccess()).thenReturn(true);
|
||||
Mockito.when(result.getResult()).thenReturn("result");
|
||||
Mockito.when(result.getStarTime()).thenReturn(new Date(System.currentTimeMillis() - (2 * 1000L)));
|
||||
Mockito.when(result.getEndTime()).thenReturn(new Date(System.currentTimeMillis()));
|
||||
ExecutorService executorService = Mockito.mock(ExecutorService.class);
|
||||
Mockito.when(executorService.submit(Mockito.any(Runnable.class))).thenAnswer(invocation -> {
|
||||
System.out.println("Submitting runnable to executor");
|
||||
Runnable runnable = invocation.getArgument(0);
|
||||
WebhookDeliveryThread webhookDeliveryThread = (WebhookDeliveryThread) runnable;
|
||||
webhookDeliveryThread.callback.complete(result);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
});
|
||||
ReflectionTestUtils.setField(webhookServiceImpl, "webhookJobExecutor", executorService);
|
||||
|
||||
WebhookDelivery returnedDelivery = webhookServiceImpl.executeWebhookDelivery(null, webhook, "payload");
|
||||
|
||||
Assert.assertNotNull(returnedDelivery);
|
||||
Assert.assertEquals("headers", returnedDelivery.getHeaders());
|
||||
Assert.assertEquals("payload", returnedDelivery.getPayload());
|
||||
Assert.assertTrue(returnedDelivery.isSuccess());
|
||||
Assert.assertEquals("result", returnedDelivery.getResponse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidateWebhooksCacheClearsCache() {
|
||||
LazyCache<?, ?> cache = Mockito.mock(LazyCache.class);
|
||||
ReflectionTestUtils.setField(webhookServiceImpl, "webhooksCache", cache);
|
||||
|
||||
webhookServiceImpl.invalidateWebhooksCache();
|
||||
|
||||
Mockito.verify(cache, Mockito.times(1)).clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidateWebhookFiltersCacheInvalidatesSpecificCacheEntry() {
|
||||
LazyCache<Long, ?> cache = Mockito.mock(LazyCache.class);
|
||||
ReflectionTestUtils.setField(webhookServiceImpl, "webhookFiltersCache", cache);
|
||||
|
||||
webhookServiceImpl.invalidateWebhookFiltersCache(123L);
|
||||
|
||||
Mockito.verify(cache, Mockito.times(1)).invalidate(123L);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.api.command.user;
|
||||
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AddWebhookFilterCmdTest {
|
||||
@Mock
|
||||
WebhookApiService webhookApiService;
|
||||
|
||||
@Test
|
||||
public void executeAddsWebhookFilterSuccessfully() {
|
||||
AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
|
||||
cmd.webhookApiService = webhookApiService;
|
||||
|
||||
WebhookFilterResponse response = Mockito.mock(WebhookFilterResponse.class);
|
||||
Mockito.when(webhookApiService.addWebhookFilter(cmd)).thenReturn(response);
|
||||
|
||||
cmd.execute();
|
||||
|
||||
Mockito.verify(webhookApiService, Mockito.times(1)).addWebhookFilter(cmd);
|
||||
Assert.assertNotNull(cmd.getResponseObject());
|
||||
Assert.assertEquals(response, cmd.getResponseObject());
|
||||
}
|
||||
|
||||
@Test(expected = ServerApiException.class)
|
||||
public void executeThrowsExceptionWhenServiceReturnsNull() {
|
||||
AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
|
||||
cmd.webhookApiService = webhookApiService;
|
||||
|
||||
Mockito.when(webhookApiService.addWebhookFilter(cmd)).thenReturn(null);
|
||||
|
||||
cmd.execute();
|
||||
}
|
||||
|
||||
@Test(expected = ServerApiException.class)
|
||||
public void executeThrowsExceptionWhenServiceFails() {
|
||||
AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
|
||||
cmd.webhookApiService = webhookApiService;
|
||||
|
||||
Mockito.doThrow(new CloudRuntimeException("Service failure")).when(webhookApiService).addWebhookFilter(cmd);
|
||||
|
||||
cmd.execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntityOwnerIdReturnsCorrectOwnerId() {
|
||||
Account account = Mockito.mock(Account.class);
|
||||
Mockito.when(account.getId()).thenReturn(123L);
|
||||
CallContext.register(Mockito.mock(User.class), account);
|
||||
|
||||
AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
|
||||
|
||||
Assert.assertEquals(123L, cmd.getEntityOwnerId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getModeReturnsCorrectValue() {
|
||||
AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
|
||||
ReflectionTestUtils.setField(cmd, "mode", "Include");
|
||||
|
||||
Assert.assertEquals("Include", cmd.getMode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMatchTypeReturnsCorrectValue() {
|
||||
AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
|
||||
ReflectionTestUtils.setField(cmd, "matchType", "Exact");
|
||||
|
||||
Assert.assertEquals("Exact", cmd.getMatchType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getValueReturnsCorrectValue() {
|
||||
AddWebhookFilterCmd cmd = new AddWebhookFilterCmd();
|
||||
ReflectionTestUtils.setField(cmd, "value", "testValue");
|
||||
|
||||
Assert.assertEquals("testValue", cmd.getValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ package org.apache.cloudstack.mom.webhook.api.command.user;
|
|||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
|
|
@ -105,4 +106,38 @@ public class DeleteWebhookDeliveryCmdTest {
|
|||
cmd.execute();
|
||||
Assert.assertNotNull(cmd.getResponseObject());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getStartDateReturnsCorrectValue() {
|
||||
DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
|
||||
Date date = new Date();
|
||||
ReflectionTestUtils.setField(cmd, "startDate", date);
|
||||
|
||||
Assert.assertEquals(date, cmd.getStartDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getStartDateReturnsNullWhenNotSet() {
|
||||
DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
|
||||
ReflectionTestUtils.setField(cmd, "startDate", null);
|
||||
|
||||
Assert.assertNull(cmd.getStartDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEndDateReturnsCorrectValue() {
|
||||
DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
|
||||
Date date = new Date();
|
||||
ReflectionTestUtils.setField(cmd, "endDate", date);
|
||||
|
||||
Assert.assertEquals(date, cmd.getEndDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEndDateReturnsNullWhenNotSet() {
|
||||
DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
|
||||
ReflectionTestUtils.setField(cmd, "endDate", null);
|
||||
|
||||
Assert.assertNull(cmd.getEndDate());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.api.command.user;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.SuccessResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountVO;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.user.UserVO;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DeleteWebhookFilterCmdTest {
|
||||
@Mock
|
||||
WebhookApiService webhookApiService;
|
||||
|
||||
private Object getCommandMethodValue(Object obj, String methodName) {
|
||||
Object result = null;
|
||||
try {
|
||||
Method method = obj.getClass().getMethod(methodName);
|
||||
result = method.invoke(obj);
|
||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
||||
Assert.fail(String.format("Failed to get method %s value", methodName));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void runLongMemberTest(String memberName) {
|
||||
String methodName = "get" + memberName.substring(0, 1).toUpperCase() + memberName.substring(1);
|
||||
DeleteWebhookDeliveryCmd cmd = new DeleteWebhookDeliveryCmd();
|
||||
ReflectionTestUtils.setField(cmd, memberName, null);
|
||||
Assert.assertNull(getCommandMethodValue(cmd, methodName));
|
||||
Long value = 100L;
|
||||
ReflectionTestUtils.setField(cmd, memberName, value);
|
||||
Assert.assertEquals(value, getCommandMethodValue(cmd, methodName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetId() {
|
||||
runLongMemberTest("id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetWebhookId() {
|
||||
runLongMemberTest("webhookId");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeDeletesWebhookFilterSuccessfully() {
|
||||
DeleteWebhookFilterCmd cmd = new DeleteWebhookFilterCmd();
|
||||
cmd.webhookApiService = webhookApiService;
|
||||
|
||||
Mockito.when(webhookApiService.deleteWebhookFilter(cmd)).thenReturn(1);
|
||||
|
||||
cmd.execute();
|
||||
|
||||
Mockito.verify(webhookApiService, Mockito.times(1)).deleteWebhookFilter(cmd);
|
||||
Assert.assertNotNull(cmd.getResponseObject());
|
||||
Assert.assertTrue(cmd.getResponseObject() instanceof SuccessResponse);
|
||||
Assert.assertEquals(cmd.getCommandName(), ((SuccessResponse) cmd.getResponseObject()).getResponseName());
|
||||
}
|
||||
|
||||
@Test(expected = ServerApiException.class)
|
||||
public void executeThrowsExceptionWhenServiceFails() {
|
||||
DeleteWebhookFilterCmd cmd = new DeleteWebhookFilterCmd();
|
||||
cmd.webhookApiService = webhookApiService;
|
||||
|
||||
Mockito.doThrow(new CloudRuntimeException("Service failure")).when(webhookApiService).deleteWebhookFilter(cmd);
|
||||
|
||||
cmd.execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEntityOwnerIdReturnsCallingAccountId() {
|
||||
Account account = new AccountVO("testaccount", 1L, "networkdomain", Account.Type.NORMAL, "uuid");
|
||||
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
|
||||
CallContext.register(user, account);
|
||||
|
||||
DeleteWebhookFilterCmd cmd = new DeleteWebhookFilterCmd();
|
||||
|
||||
Assert.assertEquals(account.getId(), cmd.getEntityOwnerId());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.api.command.user;
|
||||
|
||||
import org.apache.cloudstack.api.ApiErrorCode;
|
||||
import org.apache.cloudstack.api.ServerApiException;
|
||||
import org.apache.cloudstack.api.response.ListResponse;
|
||||
import org.apache.cloudstack.mom.webhook.WebhookApiService;
|
||||
import org.apache.cloudstack.mom.webhook.api.response.WebhookFilterResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ListWebhookFiltersCmdTest {
|
||||
@Mock
|
||||
WebhookApiService webhookApiService;
|
||||
|
||||
@Test
|
||||
public void executeSetsResponseNameCorrectly() {
|
||||
ListWebhookFiltersCmd cmd = new ListWebhookFiltersCmd();
|
||||
cmd.webhookApiService = webhookApiService;
|
||||
|
||||
ListResponse<WebhookFilterResponse> response = new ListResponse<>();
|
||||
Mockito.when(webhookApiService.listWebhookFilters(cmd)).thenReturn(response);
|
||||
|
||||
cmd.execute();
|
||||
|
||||
Assert.assertNotNull(cmd.getResponseObject());
|
||||
}
|
||||
|
||||
@Test(expected = ServerApiException.class)
|
||||
public void executeThrowsExceptionWhenServiceFails() {
|
||||
ListWebhookFiltersCmd cmd = new ListWebhookFiltersCmd();
|
||||
cmd.webhookApiService = webhookApiService;
|
||||
|
||||
Mockito.doThrow(new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Service failure")).when(webhookApiService).listWebhookFilters(cmd);
|
||||
|
||||
cmd.execute();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getIdReturnsCorrectValue() {
|
||||
ListWebhookFiltersCmd cmd = new ListWebhookFiltersCmd();
|
||||
ReflectionTestUtils.setField(cmd, "id", 123L);
|
||||
|
||||
Assert.assertEquals(Long.valueOf(123L), cmd.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWebhookIdReturnsCorrectValue() {
|
||||
ListWebhookFiltersCmd cmd = new ListWebhookFiltersCmd();
|
||||
ReflectionTestUtils.setField(cmd, "webhookId", 456L);
|
||||
|
||||
Assert.assertEquals(Long.valueOf(456L), cmd.getWebhookId());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.dao;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.mom.webhook.Webhook;
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookVO;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WebhookDaoImplTest {
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private WebhookDaoImpl webhookDao;
|
||||
|
||||
@Mock
|
||||
private WebhookVO mockWebhookVO;
|
||||
@Mock
|
||||
private SearchBuilder<WebhookVO> mockSearchBuilder;
|
||||
@Mock
|
||||
private SearchCriteria<WebhookVO> mockSearchCriteria;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
when(mockSearchBuilder.entity()).thenReturn(mockWebhookVO);
|
||||
when(mockSearchBuilder.and()).thenReturn(mockSearchBuilder);
|
||||
when(mockSearchBuilder.or()).thenReturn(mockSearchBuilder);
|
||||
when(mockSearchBuilder.create()).thenReturn(mockSearchCriteria);
|
||||
doReturn(mockSearchBuilder).when(webhookDao).createSearchBuilder();
|
||||
webhookDao.accountIdSearch = mockSearchBuilder;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listByEnabledForDeliveryReturnsWebhooksWhenAccountIdAndDomainIdsMatch() {
|
||||
Long accountId = 1L;
|
||||
List<Long> domainIds = List.of(2L, 3L);
|
||||
|
||||
doReturn(List.of(mockWebhookVO)).when(webhookDao).listBy(any(SearchCriteria.class));
|
||||
|
||||
List<WebhookVO> result = webhookDao.listByEnabledForDelivery(accountId, domainIds);
|
||||
|
||||
assertNotNull(result);
|
||||
assertFalse(result.isEmpty());
|
||||
verify(mockSearchCriteria).setParameters("state", Webhook.State.Enabled.name());
|
||||
verify(mockSearchCriteria).setParameters("scopeGlobal", Webhook.Scope.Global.name());
|
||||
verify(mockSearchCriteria).setParameters("scopeLocal", Webhook.Scope.Local.name());
|
||||
verify(mockSearchCriteria).setParameters("scopeDomain", Webhook.Scope.Domain.name());
|
||||
verify(mockSearchCriteria).setParameters("domainId", 2L, 3L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listByEnabledForDeliveryReturnsEmptyWhenNoMatchFound() {
|
||||
Long accountId = 100L;
|
||||
List<Long> domainIds = Collections.emptyList();
|
||||
|
||||
doReturn(Collections.emptyList()).when(webhookDao).listBy(any(SearchCriteria.class));
|
||||
|
||||
List<WebhookVO> result = webhookDao.listByEnabledForDelivery(accountId, domainIds);
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.isEmpty());
|
||||
verify(mockSearchCriteria, never()).setParameters("scopeDomain", Webhook.Scope.Domain.name());
|
||||
verify(mockSearchCriteria, never()).setParameters(eq("domainId"), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteByAccountRemovesWebhooksForGivenAccountId() {
|
||||
long accountId = 1L;
|
||||
|
||||
doReturn(1).when(webhookDao).remove(any(SearchCriteria.class));
|
||||
|
||||
webhookDao.deleteByAccount(accountId);
|
||||
|
||||
verify(webhookDao, times(1)).remove(any(SearchCriteria.class));
|
||||
verify(mockSearchCriteria).setParameters("accountId", accountId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listByAccountReturnsWebhooksForGivenAccountId() {
|
||||
long accountId = 1L;
|
||||
|
||||
doReturn(List.of(mockWebhookVO)).when(webhookDao).listBy(any(SearchCriteria.class));
|
||||
|
||||
List<WebhookVO> result = webhookDao.listByAccount(accountId);
|
||||
|
||||
assertNotNull(result);
|
||||
assertFalse(result.isEmpty());
|
||||
verify(mockSearchCriteria).setParameters("accountId", accountId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listByAccountReturnsEmptyWhenNoWebhooksExistForAccountId() {
|
||||
long accountId = 1L;
|
||||
|
||||
doReturn(Collections.emptyList()).when(webhookDao).listBy(any(SearchCriteria.class));
|
||||
|
||||
List<WebhookVO> result = webhookDao.listByAccount(accountId);
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.isEmpty());
|
||||
verify(mockSearchCriteria).setParameters("accountId", accountId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByAccountAndPayloadUrlReturnsWebhookWhenMatchFound() {
|
||||
long accountId = 1L;
|
||||
String payloadUrl = "http://example.com";
|
||||
|
||||
doReturn(mockWebhookVO).when(webhookDao).findOneBy(any());
|
||||
|
||||
WebhookVO result = webhookDao.findByAccountAndPayloadUrl(accountId, payloadUrl);
|
||||
|
||||
assertNotNull(result);
|
||||
verify(mockSearchCriteria).setParameters("accountId", accountId);
|
||||
verify(mockSearchCriteria).setParameters("payloadUrl", payloadUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByAccountAndPayloadUrlReturnsNullWhenNoMatchFound() {
|
||||
long accountId = 1L;
|
||||
String payloadUrl = "http://example.com";
|
||||
|
||||
doReturn(null).when(webhookDao).findOneBy(any());
|
||||
|
||||
WebhookVO result = webhookDao.findByAccountAndPayloadUrl(accountId, payloadUrl);
|
||||
|
||||
assertNull(result);
|
||||
verify(mockSearchCriteria).setParameters("accountId", accountId);
|
||||
verify(mockSearchCriteria).setParameters("payloadUrl", payloadUrl);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.dao;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryVO;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WebhookDeliveryDaoImplTest {
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private WebhookDeliveryDaoImpl webhookDeliveryDao;
|
||||
|
||||
@Mock
|
||||
private WebhookDeliveryVO mockWebhookDeliveryVO;
|
||||
@Mock
|
||||
private SearchBuilder<WebhookDeliveryVO> mockSearchBuilder;
|
||||
@Mock
|
||||
private SearchCriteria<WebhookDeliveryVO> mockSearchCriteria;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
when(mockSearchBuilder.entity()).thenReturn(mockWebhookDeliveryVO);
|
||||
when(mockSearchBuilder.create()).thenReturn(mockSearchCriteria);
|
||||
doReturn(mockSearchBuilder).when(webhookDeliveryDao).createSearchBuilder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteByDeleteApiParamsDeletesWhenParametersMatch() {
|
||||
Long webhookId = 2L;
|
||||
Date startDate = new Date(System.currentTimeMillis() - 10000);
|
||||
|
||||
doReturn(1).when(webhookDeliveryDao).remove(any(SearchCriteria.class));
|
||||
|
||||
int result = webhookDeliveryDao.deleteByDeleteApiParams(null, webhookId, null, startDate, null);
|
||||
|
||||
assertEquals(1, result);
|
||||
verify(webhookDeliveryDao).remove(any(SearchCriteria.class));
|
||||
verify(mockSearchBuilder).and(eq("webhookId"), any(), eq(SearchCriteria.Op.EQ));
|
||||
verify(mockSearchCriteria).setParameters("webhookId", webhookId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteByDeleteApiParamsReturnsZeroWhenNoMatchFound() {
|
||||
Long id = 999L;
|
||||
Long webhookId = 999L;
|
||||
Long managementServerId = 999L;
|
||||
Date startDate = new Date(System.currentTimeMillis() - 10000);
|
||||
Date endDate = new Date();
|
||||
|
||||
doReturn(0).when(webhookDeliveryDao).remove(any(SearchCriteria.class));
|
||||
|
||||
int result = webhookDeliveryDao.deleteByDeleteApiParams(id, webhookId, managementServerId, startDate, endDate);
|
||||
|
||||
assertEquals(0, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeOlderDeliveriesWhenParametersMatch() {
|
||||
long webhookId = 2L;
|
||||
|
||||
WebhookDeliveryVO d1 = mock(WebhookDeliveryVO.class);
|
||||
when(d1.getId()).thenReturn(1L);
|
||||
WebhookDeliveryVO d2 = mock(WebhookDeliveryVO.class);
|
||||
when(d2.getId()).thenReturn(2L);
|
||||
List<WebhookDeliveryVO> list = List.of(d1, d2);
|
||||
doReturn(list).when(webhookDeliveryDao).listBy(any(SearchCriteria.class), any());
|
||||
doReturn(10).when(webhookDeliveryDao).remove(any(SearchCriteria.class));
|
||||
|
||||
webhookDeliveryDao.removeOlderDeliveries(webhookId, 10);
|
||||
verify(webhookDeliveryDao).remove(any(SearchCriteria.class));
|
||||
verify(mockSearchBuilder).and(eq("webhookId"), any(), eq(SearchCriteria.Op.EQ));
|
||||
verify(mockSearchCriteria).setParameters("webhookId", webhookId);
|
||||
verify(mockSearchBuilder).and(eq("id"), any(), eq(SearchCriteria.Op.NOTIN));
|
||||
verify(mockSearchCriteria).setParameters("id", 1L, 2L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeOlderDeliveriesWhenNoKeepDeliveries() {
|
||||
long webhookId = 2L;
|
||||
doReturn(Collections.emptyList()).when(webhookDeliveryDao).listBy(any(SearchCriteria.class), any());
|
||||
|
||||
webhookDeliveryDao.removeOlderDeliveries(webhookId, 10);
|
||||
verify(webhookDeliveryDao, never()).remove(any(SearchCriteria.class));
|
||||
verify(mockSearchBuilder).and(eq("webhookId"), any(), eq(SearchCriteria.Op.EQ));
|
||||
verify(mockSearchCriteria).setParameters("webhookId", webhookId);
|
||||
verify(mockSearchBuilder, never()).and(eq("id"), any(), eq(SearchCriteria.Op.NOTIN));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.dao;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookDeliveryJoinVO;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.Filter;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WebhookDeliveryJoinDaoImplTest {
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private WebhookDeliveryJoinDaoImpl webhookDeliveryJoinDao;
|
||||
|
||||
@Mock
|
||||
private WebhookDeliveryJoinVO mockWebhookDeliveryJoinVO;
|
||||
@Mock
|
||||
private SearchBuilder<WebhookDeliveryJoinVO> mockSearchBuilder;
|
||||
@Mock
|
||||
private SearchCriteria<WebhookDeliveryJoinVO> mockSearchCriteria;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
when(mockSearchBuilder.entity()).thenReturn(mockWebhookDeliveryJoinVO);
|
||||
when(mockSearchBuilder.create()).thenReturn(mockSearchCriteria);
|
||||
doReturn(mockSearchBuilder).when(webhookDeliveryJoinDao).createSearchBuilder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchAndCountByListApiParametersId() {
|
||||
long id = 1L;
|
||||
|
||||
doReturn(new Pair(List.of(mockWebhookDeliveryJoinVO), 1)).when(webhookDeliveryJoinDao)
|
||||
.searchAndCount(any(), any());
|
||||
|
||||
Pair<List<WebhookDeliveryJoinVO>, Integer> result =
|
||||
webhookDeliveryJoinDao.searchAndCountByListApiParameters(id, null, null,
|
||||
null, null, null, null,null);
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.second() > 0);
|
||||
assertFalse(result.first().isEmpty());
|
||||
verify(mockSearchBuilder).and(eq("id"), any(), eq(SearchCriteria.Op.EQ));
|
||||
verify(mockSearchCriteria).setParameters("id", id);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchAndCountByListApiParametersWebhookId() {
|
||||
long webhookId = 1L;
|
||||
|
||||
doReturn(new Pair(List.of(mockWebhookDeliveryJoinVO), 1)).when(webhookDeliveryJoinDao)
|
||||
.searchAndCount(any(), any());
|
||||
|
||||
Pair<List<WebhookDeliveryJoinVO>, Integer> result =
|
||||
webhookDeliveryJoinDao.searchAndCountByListApiParameters(null, List.of(webhookId),
|
||||
null, null, null, null, null, null);
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.second() > 0);
|
||||
assertFalse(result.first().isEmpty());
|
||||
verify(mockSearchBuilder).and(eq("webhookId"), any(), eq(SearchCriteria.Op.IN));
|
||||
verify(mockSearchCriteria).setParameters("webhookId", 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchAndCountByListApiParametersMgmtKeywordStartEnd() {
|
||||
long managementServerId = 1L;
|
||||
String keyword = "error";
|
||||
Date start = new Date(System.currentTimeMillis() - 10000);
|
||||
Date end = new Date();
|
||||
Filter searchFilter = new Filter(WebhookDeliveryJoinVO.class, "id", false, 10L, 10L);
|
||||
|
||||
doReturn(new Pair(List.of(mockWebhookDeliveryJoinVO), 1)).when(webhookDeliveryJoinDao)
|
||||
.searchAndCount(any(), eq(searchFilter));
|
||||
|
||||
Pair<List<WebhookDeliveryJoinVO>, Integer> result =
|
||||
webhookDeliveryJoinDao.searchAndCountByListApiParameters(null, null,
|
||||
managementServerId, keyword, start, end, null, searchFilter);
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.second() > 0);
|
||||
assertFalse(result.first().isEmpty());
|
||||
verify(mockSearchBuilder).and(eq("managementServerId"), any(), eq(SearchCriteria.Op.EQ));
|
||||
verify(mockSearchCriteria).setParameters("managementServerId", managementServerId);
|
||||
verify(mockSearchBuilder).and(eq("keyword"), any(), eq(SearchCriteria.Op.LIKE));
|
||||
verify(mockSearchCriteria).setParameters("keyword", "%" + keyword + "%");
|
||||
verify(mockSearchBuilder).and(eq("startDate"), any(), eq(SearchCriteria.Op.GTEQ));
|
||||
verify(mockSearchCriteria).setParameters("startDate", start);
|
||||
verify(mockSearchBuilder).and(eq("endDate"), any(), eq(SearchCriteria.Op.LTEQ));
|
||||
verify(mockSearchCriteria).setParameters("endDate", end);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.dao;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookFilterVO;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WebhookFilterDaoImplTest {
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private WebhookFilterDaoImpl webhookFilterDaoImpl;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
SearchBuilder<WebhookFilterVO> sb = Mockito.mock(SearchBuilder.class);
|
||||
Mockito.when(sb.create()).thenReturn(Mockito.mock(SearchCriteria.class));
|
||||
webhookFilterDaoImpl.IdWebhookIdSearch = sb;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchByReturnsResultsWhenIdAndWebhookIdMatch() {
|
||||
Long id = 1L;
|
||||
Long webhookId = 2L;
|
||||
Long startIndex = 0L;
|
||||
Long pageSize = 10L;
|
||||
|
||||
Mockito.doReturn(new Pair(List.of(Mockito.mock(WebhookFilterVO.class)), 1))
|
||||
.when(webhookFilterDaoImpl).searchAndCount(Mockito.any(), Mockito.any());
|
||||
|
||||
Pair<List<WebhookFilterVO>, Integer> result = webhookFilterDaoImpl.searchBy(id, webhookId, startIndex, pageSize);
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.first().size() >= 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchByReturnsEmptyWhenNoMatch() {
|
||||
Long id = 999L;
|
||||
Long webhookId = 999L;
|
||||
Long startIndex = 0L;
|
||||
Long pageSize = 10L;
|
||||
|
||||
Mockito.doReturn(new Pair(List.of(), 0))
|
||||
.when(webhookFilterDaoImpl).searchAndCount(Mockito.any(), Mockito.any());
|
||||
|
||||
Pair<List<WebhookFilterVO>, Integer> result = webhookFilterDaoImpl.searchBy(id, webhookId, startIndex, pageSize);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(0, result.first().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listByWebhookReturnsResultsWhenWebhookIdExists() {
|
||||
Long webhookId = 2L;
|
||||
|
||||
Mockito.doReturn(List.of(Mockito.mock(WebhookFilterVO.class)))
|
||||
.when(webhookFilterDaoImpl).listBy(Mockito.any(SearchCriteria.class));
|
||||
|
||||
List<WebhookFilterVO> result = webhookFilterDaoImpl.listByWebhook(webhookId);
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.size() >= 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listByWebhookReturnsEmptyWhenWebhookIdDoesNotExist() {
|
||||
Long webhookId = 999L;
|
||||
|
||||
Mockito.doReturn(List.of())
|
||||
.when(webhookFilterDaoImpl).listBy(Mockito.any(SearchCriteria.class));
|
||||
|
||||
List<WebhookFilterVO> result = webhookFilterDaoImpl.listByWebhook(webhookId);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals(0, result.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteReturnsZeroWhenIdAndWebhookIdAreNull() {
|
||||
int result = webhookFilterDaoImpl.delete(null, null);
|
||||
|
||||
assertEquals(0, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteReturnsNonZeroWhenIdOrWebhookIdExists() {
|
||||
Long id = 1L;
|
||||
Long webhookId = 2L;
|
||||
|
||||
Mockito.doReturn(1)
|
||||
.when(webhookFilterDaoImpl).remove(Mockito.any(SearchCriteria.class));
|
||||
|
||||
int result = webhookFilterDaoImpl.delete(id, webhookId);
|
||||
|
||||
assertTrue(result >= 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package org.apache.cloudstack.mom.webhook.dao;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.mom.webhook.vo.WebhookJoinVO;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import com.cloud.utils.db.SearchBuilder;
|
||||
import com.cloud.utils.db.SearchCriteria;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WebhookJoinDaoImplTest {
|
||||
@Spy
|
||||
@InjectMocks
|
||||
private WebhookJoinDaoImpl webhookJoinDao;
|
||||
|
||||
@Mock
|
||||
private WebhookJoinVO mockWebhookVO;
|
||||
@Mock
|
||||
private SearchBuilder<WebhookJoinVO> mockSearchBuilder;
|
||||
@Mock
|
||||
private SearchCriteria<WebhookJoinVO> mockSearchCriteria;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
when(mockSearchBuilder.entity()).thenReturn(mockWebhookVO);
|
||||
when(mockSearchBuilder.and()).thenReturn(mockSearchBuilder);
|
||||
when(mockSearchBuilder.create()).thenReturn(mockSearchCriteria);
|
||||
doReturn(mockSearchBuilder).when(webhookJoinDao).createSearchBuilder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listByAccountOrDomainReturnsResultsWhenAccountIdMatches() {
|
||||
long accountId = 1L;
|
||||
|
||||
doReturn(List.of(mockWebhookVO)).when(webhookJoinDao).listBy(any(SearchCriteria.class));
|
||||
|
||||
List<WebhookJoinVO> result = webhookJoinDao.listByAccountOrDomain(accountId, null);
|
||||
|
||||
assertNotNull(result);
|
||||
assertFalse(result.isEmpty());
|
||||
verify(mockSearchBuilder).op(eq("accountId"), any(), eq(SearchCriteria.Op.EQ));
|
||||
verify(mockSearchCriteria).setParameters("accountId", accountId);
|
||||
verify(mockSearchBuilder, never()).or(eq("domainPath"), any(), eq(SearchCriteria.Op.LIKE));
|
||||
verify(mockSearchCriteria, never()).setParameters(eq("domainPath"), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listByAccountOrDomainReturnsResultsWhenBothAccountIdAndDomainPathMatch() {
|
||||
long accountId = 10L;
|
||||
String domainPath = "domain/path";
|
||||
|
||||
doReturn(List.of(mockWebhookVO)).when(webhookJoinDao).listBy(any(SearchCriteria.class));
|
||||
|
||||
List<WebhookJoinVO> result = webhookJoinDao.listByAccountOrDomain(accountId, domainPath);
|
||||
|
||||
assertNotNull(result);
|
||||
assertFalse(result.isEmpty());
|
||||
verify(mockSearchBuilder).op(eq("accountId"), any(), eq(SearchCriteria.Op.EQ));
|
||||
verify(mockSearchCriteria).setParameters("accountId", accountId);
|
||||
verify(mockSearchBuilder).or(eq("domainPath"), any(), eq(SearchCriteria.Op.LIKE));
|
||||
verify(mockSearchCriteria).setParameters("domainPath", domainPath);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listByAccountOrDomainReturnsEmptyWhenNoMatchFound() {
|
||||
long accountId = 999L;
|
||||
String domainPath = "nonexistent/path";
|
||||
|
||||
doReturn(Collections.emptyList()).when(webhookJoinDao).listBy(any(SearchCriteria.class));
|
||||
|
||||
List<WebhookJoinVO> result = webhookJoinDao.listByAccountOrDomain(accountId, domainPath);
|
||||
|
||||
assertNotNull(result);
|
||||
assertTrue(result.isEmpty());
|
||||
verify(mockSearchBuilder).op(eq("accountId"), any(), eq(SearchCriteria.Op.EQ));
|
||||
verify(mockSearchCriteria).setParameters("accountId", accountId);
|
||||
verify(mockSearchBuilder).or(eq("domainPath"), any(), eq(SearchCriteria.Op.LIKE));
|
||||
verify(mockSearchCriteria).setParameters("domainPath", domainPath);
|
||||
}
|
||||
}
|
||||
|
|
@ -283,7 +283,7 @@ class TestWebhooks(cloudstackTestCase):
|
|||
description=description,
|
||||
secretkey=secretkey,
|
||||
state=state
|
||||
)['webhook']
|
||||
)
|
||||
self.assertNotEqual(
|
||||
updated_webhook,
|
||||
None,
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@
|
|||
"label.action.cancel.maintenance.mode": "Cancel maintenance mode",
|
||||
"label.action.change.password": "Change password",
|
||||
"label.action.clear.webhook.deliveries": "Clear deliveries",
|
||||
"label.action.delete.webhook.deliveries": "Delete deliveries",
|
||||
"label.action.clear.webhook.filters": "Clear filters",
|
||||
"label.action.change.primary.storage.scope": "Change Primary Storage scope",
|
||||
"label.action.configure.stickiness": "Stickiness",
|
||||
"label.action.configure.storage.access.group": "Update storage access group",
|
||||
|
|
@ -115,6 +115,8 @@
|
|||
"label.action.delete.user": "Delete User",
|
||||
"label.action.delete.vgpu.profile": "Delete vGPU profile",
|
||||
"label.action.delete.volume": "Delete Volume",
|
||||
"label.action.delete.webhook.deliveries": "Delete Deliveries",
|
||||
"label.action.delete.webhook.filters": "Delete Filters",
|
||||
"label.action.delete.zone": "Delete Zone",
|
||||
"label.action.destroy.instance": "Destroy Instance",
|
||||
"label.action.destroy.systemvm": "Destroy System VM",
|
||||
|
|
@ -355,6 +357,7 @@
|
|||
"label.add.vpn.customer.gateway": "Add VPN Customer Gateway",
|
||||
"label.add.vpn.gateway": "Add VPN Gateway",
|
||||
"label.add.vpn.user": "Add VPN User",
|
||||
"label.add.webhook.filter": "Add Webhook Filter",
|
||||
"label.add.zone": "Add Zone",
|
||||
"label.adding": "Adding",
|
||||
"label.adding.user": "Adding User...",
|
||||
|
|
@ -633,6 +636,7 @@
|
|||
"label.consoleproxy": "Console proxy",
|
||||
"label.console.proxy": "Console proxy",
|
||||
"label.console.proxy.vm": "Console proxy VM",
|
||||
"label.contains": "Contains",
|
||||
"label.continue": "Continue",
|
||||
"label.continue.install": "Continue with installation",
|
||||
"label.controlnodes": "Control nodes",
|
||||
|
|
@ -807,6 +811,7 @@
|
|||
"label.delete.vpn.user": "Delete VPN User",
|
||||
"label.delete.webhook": "Delete Webhook",
|
||||
"label.delete.webhook.delivery": "Delete Webhook Delivery",
|
||||
"label.delete.webhook.filter": "Delete Webhook Filter",
|
||||
"label.deleteconfirm": "Please confirm that you would like to delete this",
|
||||
"label.deleting": "Deleting",
|
||||
"label.deleting.failed": "Deleting failed",
|
||||
|
|
@ -1036,8 +1041,10 @@
|
|||
"label.event.timeline": "Event timeline",
|
||||
"label.events": "Events",
|
||||
"label.every": "Every",
|
||||
"label.exact": "Exact",
|
||||
"label.example": "Example",
|
||||
"label.example.plugin": "ExamplePlugin",
|
||||
"label.exclude": "Exclude",
|
||||
"label.existing": "Existing",
|
||||
"label.execute": "Execute",
|
||||
"label.expunge": "Expunge",
|
||||
|
|
@ -1076,6 +1083,7 @@
|
|||
"label.shared.filesystems": "Shared FileSystems",
|
||||
"label.filesystem": "Filesystem",
|
||||
"label.filter": "Filter",
|
||||
"label.filters": "Filters",
|
||||
"label.filter.annotations.all": "All comments",
|
||||
"label.filter.annotations.self": "Created by me",
|
||||
"label.filterby": "Filter by",
|
||||
|
|
@ -1254,6 +1262,7 @@
|
|||
"label.import.volume": "Import Volume",
|
||||
"label.inactive": "Inactive",
|
||||
"label.inbuilt": "Inbuilt",
|
||||
"label.include": "Include",
|
||||
"label.in.progress": "in progress",
|
||||
"label.in.progress.for": "in progress for",
|
||||
"label.info": "Info",
|
||||
|
|
@ -1520,6 +1529,7 @@
|
|||
"label.management.server.peers": "Peers",
|
||||
"label.managementservers": "Number of management servers",
|
||||
"label.matchall": "Match all",
|
||||
"label.matchtype": "Match Type",
|
||||
"label.max": "Max.",
|
||||
"label.max.primary.storage": "Max. primary (GiB)",
|
||||
"label.max.secondary.storage": "Max. secondary (GiB)",
|
||||
|
|
@ -2436,6 +2446,7 @@
|
|||
"label.success.migrations": "Successful migrations",
|
||||
"label.success.set": "Successfully set",
|
||||
"label.success.updated": "Successfully updated",
|
||||
"label.suffix": "Suffix",
|
||||
"label.suitability": "Suitability",
|
||||
"label.suitable": "Suitable",
|
||||
"label.summary": "Summary",
|
||||
|
|
@ -3286,6 +3297,7 @@
|
|||
"message.delete.vpn.gateway.failed": "Failed to delete VPN Gateway.",
|
||||
"message.delete.webhook": "Please confirm that you want to delete this Webhook.",
|
||||
"message.delete.webhook.delivery": "Please confirm that you want to delete this Webhook delivery.",
|
||||
"message.delete.webhook.filter": "Please confirm that you want to delete this Webhook filter.",
|
||||
"message.deleting.firewall.policy": "Deleting Firewall Policy",
|
||||
"message.deleting.node": "Deleting Node",
|
||||
"message.deleting.vm": "Deleting Instance",
|
||||
|
|
@ -3823,6 +3835,7 @@
|
|||
"message.success.add.vpc.network": "Successfully added a VPC network",
|
||||
"message.success.add.vpn.customer.gateway": "Successfully added VPN customer gateway",
|
||||
"message.success.add.vpn.gateway": "Successfully added VPN gateway",
|
||||
"message.success.add.webhook.filter": "Successfully added Webhook Filter",
|
||||
"message.success.assign.sslcert": "Successfully assigned SSL certificate",
|
||||
"message.success.assign.vm": "Successfully assigned Instance",
|
||||
"message.success.apply.network.policy": "Successfully applied Network Policy",
|
||||
|
|
@ -3835,6 +3848,7 @@
|
|||
"message.success.change.password": "Successfully changed password for User",
|
||||
"message.success.change.host.password": "Successfully changed password for host \"{name}\"",
|
||||
"message.success.clear.webhook.deliveries": "Successfully cleared webhook deliveries",
|
||||
"message.success.clear.webhook.filters": "Successfully cleared webhook filters",
|
||||
"message.success.change.scope": "Successfully changed scope for storage pool",
|
||||
"message.success.config.backup.schedule": "Successfully configured Instance backup schedule",
|
||||
"message.success.config.health.monitor": "Successfully Configure Health Monitor",
|
||||
|
|
|
|||
|
|
@ -924,6 +924,16 @@
|
|||
@pressEnter="saveValue(record)"
|
||||
>
|
||||
</a-input>
|
||||
<template v-else-if="['webhook'].includes($route.path.split('/')[1])">
|
||||
<span style="word-break: break-all">{{ text }}</span>
|
||||
<QuickView
|
||||
style="margin-left: 5px"
|
||||
:actions="actions"
|
||||
:resource="record"
|
||||
:enabled="quickViewEnabled() && actions.length > 0"
|
||||
@exec-action="$parent.execAction"
|
||||
/>
|
||||
</template>
|
||||
<div
|
||||
v-else
|
||||
style="width: 200px; word-break: break-all"
|
||||
|
|
@ -1187,7 +1197,7 @@ export default {
|
|||
'/project', '/account', 'buckets', 'objectstore',
|
||||
'/zone', '/pod', '/cluster', '/host', '/storagepool', '/imagestore', '/systemvm', '/router', '/ilbvm', '/annotation',
|
||||
'/computeoffering', '/systemoffering', '/diskoffering', '/backupoffering', '/networkoffering', '/vpcoffering',
|
||||
'/tungstenfabric', '/oauthsetting', '/guestos', '/guestoshypervisormapping', '/webhook', 'webhookdeliveries', '/quotatariff', '/sharedfs',
|
||||
'/tungstenfabric', '/oauthsetting', '/guestos', '/guestoshypervisormapping', '/webhook', 'webhookdeliveries', 'webhookfilters', '/quotatariff', '/sharedfs',
|
||||
'/ipv4subnets', '/managementserver', '/gpucard', '/gpudevices', '/vgpuprofile', '/extension', '/snapshotpolicy', '/backupschedule'].join('|'))
|
||||
.test(this.$route.path)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,416 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="add-row">
|
||||
<a-form
|
||||
:ref="addFormRef"
|
||||
:model="addFilterForm"
|
||||
:rules="addFormRules"
|
||||
@finish="addFilter"
|
||||
layout="vertical"
|
||||
class="add-filter-form">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="12">
|
||||
<a-form-item name="mode" ref="mode">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.mode')" :tooltip="addFilterApiParams.mode.description"/>
|
||||
</template>
|
||||
<a-radio-group v-model:value="addFilterForm.mode" button-style="solid">
|
||||
<a-radio-button value="include">{{ $t('label.include') }}</a-radio-button>
|
||||
<a-radio-button value="exclude">{{ $t('label.exclude') }}</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="12">
|
||||
<a-form-item name="matchtype" ref="matchtype">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.matchtype')" :tooltip="addFilterApiParams.matchtype.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
style="margin-left: 0"
|
||||
v-model:value="addFilterForm.matchtype"
|
||||
placeholder="Select match type"
|
||||
allow-clear>
|
||||
<a-select-option value="exact">{{ $t('label.exact') }}</a-select-option>
|
||||
<a-select-option value="prefix">{{ $t('label.prefix') }}</a-select-option>
|
||||
<a-select-option value="suffix">{{ $t('label.suffix') }}</a-select-option>
|
||||
<a-select-option value="contains">{{ $t('label.contains') }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row :gutter="16" style="margin-top: 8px;">
|
||||
<a-col :span="24">
|
||||
<a-form-item name="value" ref="value">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.value')" :tooltip="addFilterApiParams.value.description"/>
|
||||
</template>
|
||||
<a-input v-model:value="addFilterForm.value" placeholder="Enter filter value" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-row style="margin-top: 16px;">
|
||||
<a-col :span="24" style="text-align: right;">
|
||||
<a-space>
|
||||
<a-button @click="resetAddFilterForm">{{ $t('label.reset') }}</a-button>
|
||||
<a-button type="primary" ref="submit" @click="addFilter">{{ $t('label.add') }}</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</div>
|
||||
|
||||
<a-divider />
|
||||
<a-button
|
||||
v-if="('deleteWebhookFilter' in $store.getters.apis) && (selectedRowKeys && selectedRowKeys.length > 0)"
|
||||
type="danger"
|
||||
danger
|
||||
style="width: 100%; margin-bottom: 15px"
|
||||
@click="clearOrDeleteFiltersConfirmation()">
|
||||
<template #icon><delete-outlined /></template>
|
||||
{{ (selectedRowKeys && selectedRowKeys.length > 0) ? $t('label.action.delete.webhook.filters') : $t('label.action.clear.webhook.filters') }}
|
||||
</a-button>
|
||||
<list-view
|
||||
:tabLoading="tabLoading"
|
||||
:columns="columns"
|
||||
:items="filters"
|
||||
:actions="actions"
|
||||
:columnKeys="columnKeys"
|
||||
:explicitlyAllowRowSelection="true"
|
||||
:selectedColumns="selectedColumnKeys"
|
||||
ref="listview"
|
||||
@update-selected-columns="updateSelectedColumns"
|
||||
@refresh="this.fetchData"
|
||||
@selection-change="updateSelectedRows"/>
|
||||
<a-pagination
|
||||
class="row-element"
|
||||
style="margin-top: 10px"
|
||||
size="small"
|
||||
:current="page"
|
||||
:pageSize="pageSize"
|
||||
:total="totalCount"
|
||||
:showTotal="total => `${$t('label.showing')} ${Math.min(total, 1+((page-1)*pageSize))}-${Math.min(page*pageSize, total)} ${$t('label.of')} ${total} ${$t('label.items')}`"
|
||||
:pageSizeOptions="pageSizeOptions"
|
||||
@change="changePage"
|
||||
@showSizeChange="changePage"
|
||||
showSizeChanger
|
||||
showQuickJumper>
|
||||
<template #buildOptionText="props">
|
||||
<span>{{ props.value }} / {{ $t('label.page') }}</span>
|
||||
</template>
|
||||
</a-pagination>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, reactive, toRaw } from 'vue'
|
||||
import { getAPI, postAPI } from '@/api'
|
||||
import { mixinForm } from '@/utils/mixin'
|
||||
import { genericCompare } from '@/utils/sort.js'
|
||||
import TooltipLabel from '@/components/widgets/TooltipLabel'
|
||||
import ListView from '@/components/view/ListView'
|
||||
|
||||
export default {
|
||||
name: 'WebhookFiltersTab',
|
||||
mixins: [mixinForm],
|
||||
components: {
|
||||
TooltipLabel,
|
||||
ListView
|
||||
},
|
||||
props: {
|
||||
resource: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
tabLoading: false,
|
||||
columnKeys: ['value', 'type', 'mode', 'matchtype'],
|
||||
selectedColumnKeys: ['value', 'mode', 'matchtype'],
|
||||
selectedRowKeys: [],
|
||||
columns: [],
|
||||
cols: [],
|
||||
filters: [],
|
||||
actions: [
|
||||
{
|
||||
api: 'deleteWebhookFilter',
|
||||
icon: 'delete-outlined',
|
||||
label: 'label.delete.webhook.filter',
|
||||
message: 'message.delete.webhook.filter',
|
||||
dataView: true,
|
||||
popup: true
|
||||
}
|
||||
],
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
totalCount: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pageSizeOptions () {
|
||||
var sizes = [20, 50, 100, 200, this.$store.getters.defaultListViewPageSize]
|
||||
if (this.device !== 'desktop') {
|
||||
sizes.unshift(10)
|
||||
}
|
||||
return [...new Set(sizes)].sort(function (a, b) {
|
||||
return a - b
|
||||
}).map(String)
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
this.addFilterApiParams = this.$getApiParams('addWebhookFilter')
|
||||
},
|
||||
created () {
|
||||
this.updateColumns()
|
||||
this.pageSize = this.pageSizeOptions[0] * 1
|
||||
this.initAddFilterForm()
|
||||
this.fetchData()
|
||||
},
|
||||
watch: {
|
||||
resource: {
|
||||
handler () {
|
||||
this.fetchData()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchData () {
|
||||
if ('listview' in this.$refs && this.$refs.listview) {
|
||||
this.$refs.listview.resetSelection()
|
||||
}
|
||||
this.fetchFilters()
|
||||
},
|
||||
fetchFilters () {
|
||||
this.filters = []
|
||||
if (!this.resource.id) {
|
||||
return
|
||||
}
|
||||
const params = {
|
||||
page: this.page,
|
||||
pagesize: this.pageSize,
|
||||
webhookid: this.resource.id,
|
||||
listall: true
|
||||
}
|
||||
this.tabLoading = true
|
||||
getAPI('listWebhookFilters', params).then(json => {
|
||||
this.filters = []
|
||||
this.totalCount = json?.listwebhookfiltersresponse?.count || 0
|
||||
this.filters = json?.listwebhookfiltersresponse?.webhookfilter || []
|
||||
this.tabLoading = false
|
||||
})
|
||||
},
|
||||
changePage (page, pageSize) {
|
||||
this.page = page
|
||||
this.pageSize = pageSize
|
||||
this.fetchFilters()
|
||||
},
|
||||
updateSelectedColumns (key) {
|
||||
if (this.selectedColumnKeys.includes(key)) {
|
||||
this.selectedColumnKeys = this.selectedColumnKeys.filter(x => x !== key)
|
||||
} else {
|
||||
this.selectedColumnKeys.push(key)
|
||||
}
|
||||
this.updateColumns()
|
||||
},
|
||||
updateColumns () {
|
||||
this.columns = []
|
||||
for (var columnKey of this.columnKeys) {
|
||||
const key = columnKey
|
||||
if (!this.selectedColumnKeys.includes(key)) continue
|
||||
var title = this.$t('label.' + String(key).toLowerCase())
|
||||
this.columns.push({
|
||||
key: key,
|
||||
title: title,
|
||||
dataIndex: key,
|
||||
sorter: (a, b) => { return genericCompare(a[key] || '', b[key] || '') }
|
||||
})
|
||||
}
|
||||
if (this.columns.length > 0) {
|
||||
this.columns[this.columns.length - 1].customFilterDropdown = true
|
||||
}
|
||||
},
|
||||
initAddFilterForm () {
|
||||
this.addFormRef = ref()
|
||||
this.addFilterForm = reactive({
|
||||
mode: 'include',
|
||||
matchtype: 'exact',
|
||||
value: null
|
||||
})
|
||||
this.addFormRules = reactive({
|
||||
value: [{ required: true, message: this.$t('message.error.required.input') }]
|
||||
})
|
||||
},
|
||||
resetAddFilterForm () {
|
||||
if (this.addFormRef.value) {
|
||||
this.addFormRef.value.resetFields()
|
||||
}
|
||||
},
|
||||
addFilter (e) {
|
||||
e.preventDefault()
|
||||
if (this.tabLoading) return
|
||||
console.log('Adding webhook filter with form:', this.addFilterForm)
|
||||
this.addFormRef.value.validate().then(() => {
|
||||
const formRaw = toRaw(this.addFilterForm)
|
||||
const values = this.handleRemoveFields(formRaw)
|
||||
const params = {
|
||||
webhookid: this.resource.id,
|
||||
mode: values.mode,
|
||||
matchtype: values.matchtype,
|
||||
value: values.value
|
||||
}
|
||||
console.log('Adding webhook filter with params:', params)
|
||||
this.tabLoading = true
|
||||
postAPI('addWebhookFilter', params).then(json => {
|
||||
this.$notification.success({
|
||||
message: this.$t('label.add.webhook.filter'),
|
||||
description: this.$t('message.success.add.webhook.filter')
|
||||
})
|
||||
setTimeout(() => {
|
||||
this.resetAddFilterForm()
|
||||
}, 250)
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.tabLoading = false
|
||||
this.fetchFilters()
|
||||
})
|
||||
})
|
||||
},
|
||||
updateSelectedRows (keys) {
|
||||
this.selectedRowKeys = keys
|
||||
},
|
||||
clearOrDeleteFiltersConfirmation () {
|
||||
const self = this
|
||||
const title = (this.selectedRowKeys && this.selectedRowKeys.length > 0)
|
||||
? this.$t('label.action.delete.webhook.filters')
|
||||
: this.$t('label.action.clear.webhook.filters')
|
||||
this.$confirm({
|
||||
title: title,
|
||||
okText: this.$t('label.ok'),
|
||||
okType: 'danger',
|
||||
cancelText: this.$t('label.cancel'),
|
||||
onOk () {
|
||||
if (self.selectedRowKeys && self.selectedRowKeys.length > 0) {
|
||||
self.deletedSelectedFilters()
|
||||
return
|
||||
}
|
||||
self.clearFilters()
|
||||
}
|
||||
})
|
||||
},
|
||||
deletedSelectedFilters () {
|
||||
const promises = []
|
||||
this.selectedRowKeys.forEach(id => {
|
||||
const params = {
|
||||
id: id
|
||||
}
|
||||
promises.push(new Promise((resolve, reject) => {
|
||||
postAPI('deleteWebhookFilter', params).then(json => {
|
||||
return resolve(id)
|
||||
}).catch(error => {
|
||||
return reject(error)
|
||||
})
|
||||
}))
|
||||
})
|
||||
const msg = this.$t('label.action.delete.webhook.filters')
|
||||
this.$message.info({
|
||||
content: msg,
|
||||
duration: 3
|
||||
})
|
||||
this.tabLoading = true
|
||||
Promise.all(promises).finally(() => {
|
||||
this.tabLoading = false
|
||||
this.fetchData()
|
||||
})
|
||||
},
|
||||
clearFilters () {
|
||||
const params = {
|
||||
webhookid: this.resource.id
|
||||
}
|
||||
this.tabLoading = true
|
||||
postAPI('deleteWebhookFilter', params).then(json => {
|
||||
this.$message.success(this.$t('message.success.clear.webhook.filters'))
|
||||
this.fetchData()
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.tabLoading = false
|
||||
})
|
||||
},
|
||||
deleteFilterConfirmation (item) {
|
||||
const self = this
|
||||
this.$confirm({
|
||||
title: this.$t('label.delete.webhook.filter'),
|
||||
okText: this.$t('label.ok'),
|
||||
okType: 'primary',
|
||||
cancelText: this.$t('label.cancel'),
|
||||
onOk () {
|
||||
self.deleteFilter(item)
|
||||
}
|
||||
})
|
||||
},
|
||||
deleteFilter (item) {
|
||||
const params = {
|
||||
id: item.id
|
||||
}
|
||||
this.tabLoading = true
|
||||
postAPI('deleteWebhookFilter', params).then(json => {
|
||||
const message = `${this.$t('message.success.delete')} ${this.$t('label.webhook.filter')}`
|
||||
this.$message.success(message)
|
||||
this.fetchData()
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
}).finally(() => {
|
||||
this.tabLoading = false
|
||||
})
|
||||
},
|
||||
execAction (action) {
|
||||
if (action.api === 'deleteWebhookFilter') {
|
||||
this.deleteFilterConfirmation(action.resource)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ant-tag {
|
||||
padding: 0 7px 0 0;
|
||||
}
|
||||
.ant-select {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.info-icon {
|
||||
margin: 0 10px 0 5px;
|
||||
}
|
||||
.filter-row {
|
||||
margin-bottom: 2.5%;
|
||||
}
|
||||
.filter-row-inner {
|
||||
margin-top: 3%;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -116,6 +116,10 @@ export default {
|
|||
name: 'details',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'filters',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/WebhookFiltersTab.vue')))
|
||||
},
|
||||
{
|
||||
name: 'recent.deliveries',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/WebhookDeliveriesTab.vue')))
|
||||
|
|
|
|||
Loading…
Reference in New Issue