Initial commit: CloudOps infrastructure platform
This commit is contained in:
@@ -0,0 +1,746 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\WebhookBundle\Model;
|
||||
|
||||
use Doctrine\Common\Collections\Order;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use JMS\Serializer\SerializationContext;
|
||||
use JMS\Serializer\SerializerInterface;
|
||||
use Mautic\ApiBundle\Serializer\Exclusion\PublishDetailsExclusionStrategy;
|
||||
use Mautic\CoreBundle\Helper\CoreParametersHelper;
|
||||
use Mautic\CoreBundle\Helper\DateTimeHelper;
|
||||
use Mautic\CoreBundle\Helper\EncryptionHelper;
|
||||
use Mautic\CoreBundle\Helper\UserHelper;
|
||||
use Mautic\CoreBundle\Model\FormModel;
|
||||
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
|
||||
use Mautic\CoreBundle\Translation\Translator;
|
||||
use Mautic\WebhookBundle\Entity\Event;
|
||||
use Mautic\WebhookBundle\Entity\EventRepository;
|
||||
use Mautic\WebhookBundle\Entity\Log;
|
||||
use Mautic\WebhookBundle\Entity\LogRepository;
|
||||
use Mautic\WebhookBundle\Entity\Webhook;
|
||||
use Mautic\WebhookBundle\Entity\WebhookQueue;
|
||||
use Mautic\WebhookBundle\Entity\WebhookQueueRepository;
|
||||
use Mautic\WebhookBundle\Entity\WebhookRepository;
|
||||
use Mautic\WebhookBundle\Event as Events;
|
||||
use Mautic\WebhookBundle\Event\WebhookEvent;
|
||||
use Mautic\WebhookBundle\Form\Type\WebhookType;
|
||||
use Mautic\WebhookBundle\Http\Client;
|
||||
use Mautic\WebhookBundle\Service\WebhookService;
|
||||
use Mautic\WebhookBundle\WebhookEvents;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Contracts\EventDispatcher\Event as SymfonyEvent;
|
||||
|
||||
/**
|
||||
* @extends FormModel<Webhook>
|
||||
*/
|
||||
class WebhookModel extends FormModel
|
||||
{
|
||||
/**
|
||||
* 2 possible types of the processing of the webhooks.
|
||||
*/
|
||||
public const COMMAND_PROCESS = 'command_process';
|
||||
|
||||
public const IMMEDIATE_PROCESS = 'immediate_process';
|
||||
|
||||
private const DELETE_BATCH_LIMIT = 5000;
|
||||
|
||||
public const WEBHOOK_LOG_MAX = 1000;
|
||||
|
||||
/**
|
||||
* Whet queue mode is turned on.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $queueMode;
|
||||
|
||||
/**
|
||||
* How many entities to add into one queued webhook.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $webhookLimit;
|
||||
|
||||
/**
|
||||
* Sets min webhook queue ID to get/process.
|
||||
*/
|
||||
protected ?int $minQueueId = null;
|
||||
|
||||
/**
|
||||
* Sets max webhook queue ID to get/process.
|
||||
*/
|
||||
protected ?int $maxQueueId = null;
|
||||
|
||||
/**
|
||||
* How long the webhook processing can run in seconds.
|
||||
*/
|
||||
private int $webhookTimeLimit;
|
||||
|
||||
/**
|
||||
* How many responses in 1 row can fail until the webhook disables itself.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $disableLimit;
|
||||
|
||||
/**
|
||||
* How many seconds will we wait for the response.
|
||||
*
|
||||
* @var int in seconds
|
||||
*/
|
||||
protected $webhookTimeout;
|
||||
|
||||
/**
|
||||
* The key is queue ID, the value is the WebhookQueue object.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $webhookQueueIdList = [];
|
||||
|
||||
/**
|
||||
* How many recent log records should be kept.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $logMax;
|
||||
|
||||
/**
|
||||
* Queued events default order by dir
|
||||
* Possible values: ['ASC', 'DESC'].
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $eventsOrderByDir;
|
||||
|
||||
/**
|
||||
* Timestamp when the webhook processing starts.
|
||||
*/
|
||||
private ?float $startTime = null;
|
||||
|
||||
private bool $disableAutoUnpublish;
|
||||
private int $webhookRetryDelay;
|
||||
|
||||
public function __construct(
|
||||
CoreParametersHelper $coreParametersHelper,
|
||||
protected SerializerInterface $serializer,
|
||||
private Client $httpClient,
|
||||
EntityManager $em,
|
||||
CorePermissions $security,
|
||||
EventDispatcherInterface $dispatcher,
|
||||
UrlGeneratorInterface $router,
|
||||
Translator $translator,
|
||||
UserHelper $userHelper,
|
||||
LoggerInterface $mauticLogger,
|
||||
private WebhookService $webhookService,
|
||||
) {
|
||||
$this->setConfigProps($coreParametersHelper);
|
||||
parent::__construct($em, $security, $dispatcher, $router, $translator, $userHelper, $mauticLogger, $coreParametersHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Webhook $entity
|
||||
*/
|
||||
public function saveEntity($entity, $unlock = true): void
|
||||
{
|
||||
if (null === $entity->getSecret()) {
|
||||
$entity->setSecret(EncryptionHelper::generateKey());
|
||||
}
|
||||
|
||||
parent::saveEntity($entity, $unlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Webhook $entity
|
||||
* @param array<mixed> $options
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
|
||||
*/
|
||||
public function createForm($entity, FormFactoryInterface $formFactory, $action = null, $options = []): \Symfony\Component\Form\FormInterface
|
||||
{
|
||||
if (!$entity instanceof Webhook) {
|
||||
throw new MethodNotAllowedHttpException(['Webhook']);
|
||||
}
|
||||
|
||||
if (!empty($action)) {
|
||||
$options['action'] = $action;
|
||||
}
|
||||
|
||||
$options['events'] = $this->getEvents();
|
||||
|
||||
return $formFactory->create(WebhookType::class, $entity, $options);
|
||||
}
|
||||
|
||||
public function getEntity($id = null): ?Webhook
|
||||
{
|
||||
if (null === $id) {
|
||||
return new Webhook();
|
||||
}
|
||||
|
||||
return parent::getEntity($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WebhookRepository
|
||||
*/
|
||||
public function getRepository()
|
||||
{
|
||||
return $this->em->getRepository(Webhook::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets array of custom events from bundles subscribed MauticWehbhookBundle::WEBHOOK_ON_BUILD.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEvents()
|
||||
{
|
||||
static $events;
|
||||
|
||||
if (empty($events)) {
|
||||
// build them
|
||||
$events = [];
|
||||
$event = new Events\WebhookBuilderEvent($this->translator);
|
||||
$this->dispatcher->dispatch($event, WebhookEvents::WEBHOOK_ON_BUILD);
|
||||
$events = $event->getEvents();
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of webhooks by matching events.
|
||||
*
|
||||
* @param string $type string of event type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEventWebooksByType($type)
|
||||
{
|
||||
return $this->getEventRepository()->getEntitiesByEventType($type);
|
||||
}
|
||||
|
||||
public function queueWebhooksByType($type, $payload, array $groups = []): void
|
||||
{
|
||||
$this->queueWebhooks(
|
||||
$this->getEventWebooksByType($type),
|
||||
$payload,
|
||||
$groups
|
||||
);
|
||||
}
|
||||
|
||||
public function queueWebhooks($webhookEvents, $payload, array $serializationGroups = []): void
|
||||
{
|
||||
if (!count($webhookEvents) || !is_array($webhookEvents)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Event $event */
|
||||
foreach ($webhookEvents as $event) {
|
||||
$webhook = $event->getWebhook();
|
||||
$queue = $this->queueWebhook($webhook, $event, $payload, $serializationGroups);
|
||||
|
||||
if (self::COMMAND_PROCESS === $this->queueMode) {
|
||||
// Queue to the database to process later
|
||||
$this->getQueueRepository()->saveEntity($queue);
|
||||
} else {
|
||||
// Immediately process
|
||||
$this->processWebhook($webhook, $queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WebhookQueue entity, sets the date and returns the created entity.
|
||||
*/
|
||||
public function queueWebhook(Webhook $webhook, $event, $payload, array $serializationGroups = []): WebhookQueue
|
||||
{
|
||||
$serializedPayload = $this->serializeData($payload, $serializationGroups);
|
||||
|
||||
$queue = new WebhookQueue();
|
||||
$queue->setWebhook($webhook);
|
||||
$queue->setDateAdded(new \DateTime());
|
||||
$queue->setEvent($event);
|
||||
$queue->setPayload($serializedPayload);
|
||||
|
||||
// fire events for when the queues are created
|
||||
if ($this->dispatcher->hasListeners(WebhookEvents::WEBHOOK_QUEUE_ON_ADD)) {
|
||||
$webhookQueueEvent = $event = new Events\WebhookQueueEvent($queue, $webhook, true);
|
||||
$this->dispatcher->dispatch($webhookQueueEvent, WebhookEvents::WEBHOOK_QUEUE_ON_ADD);
|
||||
}
|
||||
|
||||
return $queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a list of webhooks to their specified endpoints.
|
||||
*
|
||||
* @param array|\Doctrine\ORM\Tools\Pagination\Paginator $webhooks
|
||||
*/
|
||||
public function processWebhooks($webhooks): void
|
||||
{
|
||||
$this->startTime = microtime(true);
|
||||
|
||||
foreach ($webhooks as $webhook) {
|
||||
$this->processWebhook($webhook);
|
||||
}
|
||||
}
|
||||
|
||||
public function processWebhook(Webhook $webhook, ?WebhookQueue $queue = null): bool
|
||||
{
|
||||
// get the webhook payload
|
||||
$payload = $this->getWebhookPayload($webhook, $queue);
|
||||
|
||||
// if there wasn't a payload we can stop here.
|
||||
if (empty($payload)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$start = microtime(true);
|
||||
$logged = false;
|
||||
$webhookQueueRepo = $this->getQueueRepository();
|
||||
|
||||
try {
|
||||
$response = $this->httpClient->post($webhook->getWebhookUrl(), $payload, $webhook->getSecret());
|
||||
// remove successfully processed queues from the Webhook object so they won't get stored again
|
||||
$queueIds = array_keys($this->webhookQueueIdList);
|
||||
$chunkedQueueIds = array_chunk($queueIds, self::DELETE_BATCH_LIMIT);
|
||||
|
||||
$responseStatusCode = $response->getStatusCode();
|
||||
if ($responseStatusCode >= 300 || $responseStatusCode < 200) {
|
||||
foreach ($chunkedQueueIds as $queueIds) {
|
||||
$webhookQueueRepo->incrementRetryCount($queueIds);
|
||||
}
|
||||
} else {
|
||||
foreach ($chunkedQueueIds as $queueIds) {
|
||||
$webhookQueueRepo->deleteQueuesById($queueIds);
|
||||
}
|
||||
$this->markWebhookHealthy($webhook);
|
||||
}
|
||||
|
||||
$responseBody = $response->getBody()->getContents();
|
||||
if (!$responseBody) {
|
||||
$responseBody = null; // Save null value to database
|
||||
}
|
||||
|
||||
$this->addLog($webhook, $responseStatusCode, microtime(true) - $start, $responseBody);
|
||||
$logged = true;
|
||||
|
||||
// throw an error exception if we don't get a 200 back
|
||||
if ($responseStatusCode >= 300 || $responseStatusCode < 200) {
|
||||
// The receiver of the webhook is telling us to stop bothering him with our requests by code 410
|
||||
if (410 === $responseStatusCode) {
|
||||
$this->killWebhook($webhook, 'mautic.webhook.stopped.reason.410');
|
||||
}
|
||||
|
||||
throw new \ErrorException($webhook->getWebhookUrl().' returned '.$responseStatusCode.' with payload: '.json_encode($payload));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if ($this->isSick($webhook)) {
|
||||
if (!$this->disableAutoUnpublish && !$webhook->wasModifiedRecently()) {
|
||||
$this->killWebhook($webhook);
|
||||
$message .= ' '.$this->translator->trans('mautic.webhook.killed', ['%limit%' => $this->disableLimit]);
|
||||
}
|
||||
$this->markWebhookUnHealthy($webhook, $e->getMessage());
|
||||
} else {
|
||||
$this->markWebhookHealthy($webhook);
|
||||
}
|
||||
|
||||
// log any errors but allow the script to keep running
|
||||
$this->logger->error($message);
|
||||
|
||||
if (!$logged) {
|
||||
// log that the request failed to display it to the user
|
||||
$this->addLog($webhook, 'N/A', microtime(true) - $start, $message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run this on command as well as immediate send because if switched from queue to immediate
|
||||
// it can have some rows in the queue which will be send in every webhook forever
|
||||
if (!empty($this->webhookQueueIdList)) {
|
||||
// delete all the queued items we just processed
|
||||
$webhookQueueRepo->deleteQueuesById(array_keys($this->webhookQueueIdList));
|
||||
$nextWebhookExists = $webhookQueueRepo->exists($webhook->getId());
|
||||
|
||||
// reset the array to blank so none of the IDs are repeated
|
||||
$this->webhookQueueIdList = [];
|
||||
|
||||
// if there are still items in the queue after processing we re-process
|
||||
// WARNING: this is recursive
|
||||
if ($nextWebhookExists && !$this->isProcessingExpired()) {
|
||||
$this->processWebhook($webhook);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look into the history and check if all the responses we care about had failed.
|
||||
* But let it run for a while after the user modified it. Lets not aggravate the user.
|
||||
*/
|
||||
public function isSick(Webhook $webhook): bool
|
||||
{
|
||||
$successRadio = $this->getLogRepository()->getSuccessVsErrorStatusCodeRatio($webhook->getId(), $this->disableLimit);
|
||||
|
||||
// If there are no log rows yet, consider it healthy
|
||||
if (null === $successRadio) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !$successRadio;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpublish the webhook so it will stop emit the requests
|
||||
* and notify user about it.
|
||||
*
|
||||
* @param string $reason
|
||||
*/
|
||||
public function killWebhook(Webhook $webhook, $reason = 'mautic.webhook.stopped.reason'): void
|
||||
{
|
||||
$webhook->setIsPublished(false);
|
||||
$this->saveEntity($webhook);
|
||||
$event = new WebhookEvent($webhook, false, $reason);
|
||||
$this->dispatcher->dispatch($event, WebhookEvents::WEBHOOK_KILL);
|
||||
}
|
||||
|
||||
public function markWebhookUnHealthy(Webhook $webhook, string $reason): void
|
||||
{
|
||||
$webhook->setMarkedUnhealthyAt(new \DateTimeImmutable());
|
||||
$webhook->getUnHealthySince() ?: $webhook->setUnHealthySince(new \DateTimeImmutable());
|
||||
if ($this->webhookService->sendWebhookFailureNotification($webhook, $reason)) {
|
||||
$webhook->setLastNotificationSentAt(new \DateTimeImmutable());
|
||||
}
|
||||
$this->saveEntity($webhook);
|
||||
}
|
||||
|
||||
public function markWebhookHealthy(Webhook $webhook): void
|
||||
{
|
||||
if (null === $webhook->getMarkedUnhealthyAt()) {
|
||||
return;
|
||||
}
|
||||
$webhook->setMarkedUnhealthyAt(null);
|
||||
$webhook->setUnHealthySince(null);
|
||||
$webhook->setLastNotificationSentAt(null);
|
||||
$this->saveEntity($webhook);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a log for the webhook response HTTP status and save it.
|
||||
*
|
||||
* @param int $statusCode
|
||||
* @param float $runtime in seconds
|
||||
* @param string $note
|
||||
* $runtime variable unit is in seconds
|
||||
*/
|
||||
public function addLog(Webhook $webhook, $statusCode, $runtime, $note = null): void
|
||||
{
|
||||
if (!$webhook->getId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->coreParametersHelper->get('clean_webhook_logs_in_background')) {
|
||||
$this->getLogRepository()->removeLimitExceedLogs($webhook->getId(), $this->logMax);
|
||||
}
|
||||
|
||||
$log = new Log();
|
||||
$log->setWebhook($webhook);
|
||||
$log->setNote($note);
|
||||
$log->setRuntime($runtime);
|
||||
$log->setStatusCode($statusCode);
|
||||
$log->setDateAdded(new \DateTime());
|
||||
$webhook->addLog($log);
|
||||
$this->saveEntity($webhook);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WebhookQueueRepository
|
||||
*/
|
||||
public function getQueueRepository()
|
||||
{
|
||||
return $this->em->getRepository(WebhookQueue::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EventRepository
|
||||
*/
|
||||
public function getEventRepository()
|
||||
{
|
||||
return $this->em->getRepository(Event::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LogRepository
|
||||
*/
|
||||
public function getLogRepository()
|
||||
{
|
||||
return $this->em->getRepository(Log::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the payload from the webhook.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getWebhookPayload(Webhook $webhook, ?WebhookQueue $queue = null)
|
||||
{
|
||||
if ($payload = $webhook->getPayload()) {
|
||||
return $payload;
|
||||
}
|
||||
|
||||
$payload = [];
|
||||
|
||||
if (self::COMMAND_PROCESS === $this->queueMode) {
|
||||
$queuesArray = $this->getWebhookQueues($webhook);
|
||||
} else {
|
||||
$queuesArray = null !== $queue ? [$queue] : [];
|
||||
}
|
||||
$this->webhookQueueIdList = [];
|
||||
/* @var WebhookQueue $queueItem */
|
||||
foreach ($queuesArray as $queueItem) {
|
||||
/** @var Event $event */
|
||||
$event = $queueItem->getEvent();
|
||||
$type = $event->getEventType();
|
||||
|
||||
// create new array level for each unique event type
|
||||
if (!isset($payload[$type])) {
|
||||
$payload[$type] = [];
|
||||
}
|
||||
|
||||
$queuePayload = json_decode($queueItem->getPayload(), true);
|
||||
$queuePayload['timestamp'] = $queueItem->getDateAdded()->format('c');
|
||||
|
||||
// its important to decode the payload form the DB as we re-encode it with the
|
||||
$payload[$type][] = $queuePayload;
|
||||
|
||||
// Add to the webhookQueueIdList only if ID exists.
|
||||
// That means if it was stored to DB and not sent via immediate send.
|
||||
if ($queueItem->getId()) {
|
||||
$this->webhookQueueIdList[$queueItem->getId()] = $queueItem;
|
||||
|
||||
// Clear the WebhookQueue entity from memory
|
||||
$this->em->detach($queueItem);
|
||||
}
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the queues and order by date so we get events.
|
||||
*
|
||||
* @return iterable<object>
|
||||
*/
|
||||
public function getWebhookQueues(Webhook $webhook)
|
||||
{
|
||||
/** @var WebhookQueueRepository $queueRepo */
|
||||
$queueRepo = $this->getQueueRepository();
|
||||
|
||||
$webhookRetryTime = (new \DateTimeImmutable())
|
||||
->modify(sprintf('-%d seconds', $this->webhookRetryDelay))
|
||||
->format(DateTimeHelper::FORMAT_DB);
|
||||
$parameters = [
|
||||
'iterable_mode' => true,
|
||||
'start' => 0,
|
||||
'limit' => $this->webhookLimit,
|
||||
'orderBy' => $queueRepo->getTableAlias().'.retries,'.$queueRepo->getTableAlias().'.id',
|
||||
'orderByDir' => $this->getEventsOrderbyDir($webhook),
|
||||
'filter' => [
|
||||
'force' => [
|
||||
[
|
||||
'column' => 'IDENTITY('.$queueRepo->getTableAlias().'.webhook)',
|
||||
'expr' => 'eq',
|
||||
'value' => $webhook->getId(),
|
||||
],
|
||||
],
|
||||
'where' => [
|
||||
[
|
||||
'expr' => 'andX',
|
||||
'val' => [
|
||||
[
|
||||
'expr' => 'orX',
|
||||
'val' => [
|
||||
[
|
||||
'column' => $queueRepo->getTableAlias().'.retries',
|
||||
'expr' => 'eq',
|
||||
'value' => 0,
|
||||
],
|
||||
[
|
||||
'expr' => 'andX',
|
||||
'val' => [
|
||||
[
|
||||
'column' => $queueRepo->getTableAlias().'.retries',
|
||||
'expr' => 'gt',
|
||||
'value' => 0,
|
||||
],
|
||||
[
|
||||
'column' => $queueRepo->getTableAlias().'.dateModified',
|
||||
'expr' => 'lt',
|
||||
'value' => $webhookRetryTime,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
if ($this->minQueueId && $this->maxQueueId) {
|
||||
unset($parameters['start']);
|
||||
unset($parameters['limit']);
|
||||
|
||||
$parameters['filter']['where'][0]['val'][] = [
|
||||
'column' => $queueRepo->getTableAlias().'.id',
|
||||
'expr' => 'gte',
|
||||
'value' => $this->minQueueId,
|
||||
];
|
||||
|
||||
$parameters['filter']['where'][0]['val'][] = [
|
||||
'column' => $queueRepo->getTableAlias().'.id',
|
||||
'expr' => 'lte',
|
||||
'value' => $this->maxQueueId,
|
||||
];
|
||||
}
|
||||
|
||||
return $queueRepo->getEntities($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either Webhook's orderbyDir or the value from configuration as default.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEventsOrderbyDir(?Webhook $webhook = null)
|
||||
{
|
||||
// Try to get the value from Webhook
|
||||
if ($webhook && $orderByDir = $webhook->getEventsOrderbyDir()) {
|
||||
return $orderByDir;
|
||||
}
|
||||
|
||||
// Use the global config value if it's not set in the Webhook
|
||||
return $this->eventsOrderByDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MethodNotAllowedHttpException
|
||||
*/
|
||||
protected function dispatchEvent($action, &$entity, $isNew = false, ?SymfonyEvent $event = null): ?SymfonyEvent
|
||||
{
|
||||
if (!$entity instanceof Webhook) {
|
||||
throw new MethodNotAllowedHttpException(['Webhook'], 'Entity must be of class Webhook()');
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'pre_save':
|
||||
$name = WebhookEvents::WEBHOOK_PRE_SAVE;
|
||||
break;
|
||||
case 'post_save':
|
||||
$name = WebhookEvents::WEBHOOK_POST_SAVE;
|
||||
break;
|
||||
case 'pre_delete':
|
||||
$name = WebhookEvents::WEBHOOK_PRE_DELETE;
|
||||
break;
|
||||
case 'post_delete':
|
||||
$name = WebhookEvents::WEBHOOK_POST_DELETE;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->dispatcher->hasListeners($name)) {
|
||||
if (empty($event)) {
|
||||
$event = new WebhookEvent($entity, $isNew);
|
||||
$event->setEntityManager($this->em);
|
||||
}
|
||||
$this->dispatcher->dispatch($event, $name);
|
||||
|
||||
return $event;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $groups
|
||||
*/
|
||||
public function serializeData($payload, $groups = [], array $customExclusionStrategies = []): string
|
||||
{
|
||||
$context = SerializationContext::create();
|
||||
if (!empty($groups)) {
|
||||
$context->setGroups($groups);
|
||||
}
|
||||
|
||||
// Only include FormEntity properties for the top level entity and not the associated entities
|
||||
$context->addExclusionStrategy(
|
||||
new PublishDetailsExclusionStrategy()
|
||||
);
|
||||
|
||||
foreach ($customExclusionStrategies as $exclusionStrategy) {
|
||||
$context->addExclusionStrategy($exclusionStrategy);
|
||||
}
|
||||
|
||||
// include null values
|
||||
$context->setSerializeNull(true);
|
||||
|
||||
// serialize the data and send it as a payload
|
||||
return $this->serializer->serialize($payload, 'json', $context);
|
||||
}
|
||||
|
||||
public function getPermissionBase(): string
|
||||
{
|
||||
return 'webhook:webhooks';
|
||||
}
|
||||
|
||||
public function getWebhookLimit(): int
|
||||
{
|
||||
return $this->webhookLimit;
|
||||
}
|
||||
|
||||
public function setMinQueueId(int $minQueueId): self
|
||||
{
|
||||
$this->minQueueId = $minQueueId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMaxQueueId(int $maxQueueId): self
|
||||
{
|
||||
$this->maxQueueId = $maxQueueId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function isProcessingExpired(): bool
|
||||
{
|
||||
$currentTime = microtime(true);
|
||||
$runTime = $currentTime - $this->startTime;
|
||||
|
||||
return $runTime >= $this->webhookTimeLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all class properties from CoreParametersHelper.
|
||||
*/
|
||||
private function setConfigProps(CoreParametersHelper $coreParametersHelper): void
|
||||
{
|
||||
$this->webhookLimit = (int) $coreParametersHelper->get('webhook_limit', 10);
|
||||
$this->webhookTimeLimit = (int) $coreParametersHelper->get('webhook_time_limit', 600);
|
||||
$this->disableLimit = (int) $coreParametersHelper->get('webhook_disable_limit', 100);
|
||||
$this->webhookTimeout = (int) $coreParametersHelper->get('webhook_timeout', 15);
|
||||
$this->logMax = (int) $coreParametersHelper->get('webhook_log_max', self::WEBHOOK_LOG_MAX);
|
||||
$this->queueMode = $coreParametersHelper->get('queue_mode');
|
||||
$this->eventsOrderByDir = $coreParametersHelper->get('events_orderby_dir', Order::Ascending);
|
||||
$this->disableAutoUnpublish = (bool) $coreParametersHelper->get('disable_auto_unpublish');
|
||||
$this->webhookRetryDelay = (int) $coreParametersHelper->get('webhook_retry_delay', 3600);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user