Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
<?php
namespace Mautic\WebhookBundle\Controller;
use Mautic\CoreBundle\Controller\AjaxController as CommonAjaxController;
use Mautic\CoreBundle\Helper\InputHelper;
use Mautic\CoreBundle\Helper\PathsHelper;
use Mautic\WebhookBundle\Exception\PrivateAddressException;
use Mautic\WebhookBundle\Http\Client;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class AjaxController extends CommonAjaxController
{
public function sendHookTestAction(Request $request, Client $client, PathsHelper $pathsHelper): JsonResponse
{
try {
return $this->processWebhookTest($request, $client, $pathsHelper);
} catch (PrivateAddressException) {
return $this->createErrorResponse(
'mautic.webhook.error.private_address'
);
} catch (\Exception) {
return $this->createErrorResponse(
'mautic.webhook.label.warning'
);
}
}
private function processWebhookTest(Request $request, Client $client, PathsHelper $pathsHelper): JsonResponse
{
$url = $this->validateUrl($request);
if (!$url) {
return $this->createErrorResponse('mautic.webhook.label.no.url');
}
$selectedTypes = InputHelper::cleanArray($request->request->all()['types']) ?? [];
$payloadPaths = $this->getPayloadPaths($selectedTypes, $pathsHelper);
$payload = $this->loadPayloads($payloadPaths);
$payload['timestamp'] = (new \DateTimeImmutable())->format('c');
$secret = InputHelper::string($request->request->get('secret'));
$response = $client->post($url, $payload, $secret);
return $this->createResponseFromStatusCode($response->getStatusCode());
}
private function validateUrl(Request $request): ?string
{
$url = InputHelper::url($request->request->get('url'));
return '' !== $url ? $url : null;
}
private function createResponseFromStatusCode(int $statusCode): JsonResponse
{
$isSuccess = str_starts_with((string) $statusCode, '2');
$message = $isSuccess
? 'mautic.webhook.label.success'
: 'mautic.webhook.label.warning';
$cssClass = $isSuccess ? 'has-success' : 'has-error';
return $this->createJsonResponse($message, $cssClass);
}
private function createErrorResponse(string $message): JsonResponse
{
return $this->createJsonResponse($message, 'has-error', Response::HTTP_BAD_REQUEST);
}
private function createJsonResponse(
string $message,
string $cssClass,
int $status = Response::HTTP_OK,
): JsonResponse {
$html = sprintf(
'<div class="%s"><span class="help-block">%s</span></div>',
$cssClass,
$this->translator->trans($message)
);
return $this->sendJsonResponse(
['html' => $html],
$status
);
}
/*
* Get an array of all the payload paths we need to load
*
* @param $types array
* @return array
*/
/**
* @return non-falsy-string[]
*/
public function getPayloadPaths($types, PathsHelper $pathsHelper): array
{
$payloadPaths = [];
foreach ($types as $type) {
// takes an input like mautic.lead_on_something
// converts to array pieces using _
$typePath = explode('_', $type);
// pull the prefix into its own variable
$prefix = $typePath[0];
// now that we have the remove it from the array
unset($typePath[0]);
// build the event name by putting the pieces back together
$eventName = implode('_', $typePath);
// default the path to core
$payloadPath = $pathsHelper->getSystemPath('bundles', true);
// if plugin is in first part of the string this is an addon
// input is plugin.bundlename or mautic.bundlename
if (strpos('plugin.', $prefix)) {
$payloadPath = $pathsHelper->getSystemPath('plugins', true);
}
$prefixParts = explode('.', $prefix);
$bundleName = array_pop($prefixParts);
$payloadPath .= '/'.ucfirst($bundleName).'Bundle/Assets/WebhookPayload/'.$bundleName.'_'.$eventName.'.json';
$payloadPaths[$type] = $payloadPath;
}
return $payloadPaths;
}
/*
* Iterate through the paths and get the json payloads
*
* @param $paths array
* @return $payload array
*/
/**
* @return mixed[]
*/
public function loadPayloads($paths): array
{
$payloads = [];
foreach ($paths as $key => $path) {
if (file_exists($path)) {
$payloads[$key] = json_decode(file_get_contents($path), true);
}
}
return $payloads;
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace Mautic\WebhookBundle\Controller\Api;
use Doctrine\Persistence\ManagerRegistry;
use Mautic\ApiBundle\Controller\CommonApiController;
use Mautic\ApiBundle\Helper\EntityResultHelper;
use Mautic\CoreBundle\Factory\ModelFactory;
use Mautic\CoreBundle\Helper\AppVersion;
use Mautic\CoreBundle\Helper\CoreParametersHelper;
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
use Mautic\CoreBundle\Translation\Translator;
use Mautic\WebhookBundle\Entity\Webhook;
use Mautic\WebhookBundle\Model\WebhookModel;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
/**
* @extends CommonApiController<Webhook>
*/
class WebhookApiController extends CommonApiController
{
/**
* @var WebhookModel|null
*/
protected $model;
public function __construct(
CorePermissions $security,
Translator $translator,
EntityResultHelper $entityResultHelper,
RouterInterface $router,
FormFactoryInterface $formFactory,
AppVersion $appVersion,
private RequestStack $requestStack,
ManagerRegistry $doctrine,
ModelFactory $modelFactory,
EventDispatcherInterface $dispatcher,
CoreParametersHelper $coreParametersHelper,
) {
$webhookModel = $modelFactory->getModel('webhook');
\assert($webhookModel instanceof WebhookModel);
$this->model = $webhookModel;
$this->entityClass = Webhook::class;
$this->entityNameOne = 'hook';
$this->entityNameMulti = 'hooks';
$this->serializerGroups = ['hookDetails', 'categoryList', 'publishDetails'];
parent::__construct($security, $translator, $entityResultHelper, $router, $formFactory, $appVersion, $requestStack, $doctrine, $modelFactory, $dispatcher, $coreParametersHelper);
}
/**
* Gives child controllers opportunity to analyze and do whatever to an entity before going through serializer.
*/
protected function preSerializeEntity(object $entity, string $action = 'view'): void
{
// We have to use this hack to have a simple array instead of the one the serializer gives us
$entity->buildTriggers();
}
protected function preSaveEntity(&$entity, $form, $parameters, $action = 'edit')
{
$eventsToKeep = [];
// Build webhook events from the triggers
if (isset($parameters['triggers']) && is_array($parameters['triggers'])) {
$entity->setTriggers($parameters['triggers']);
$eventsToKeep = $parameters['triggers'];
}
// Remove events missing in the PUT request
if ('PUT' === $this->requestStack->getCurrentRequest()->getMethod()) {
foreach ($entity->getEvents() as $event) {
if (!in_array($event->getEventType(), $eventsToKeep)) {
$entity->removeEvent($event);
}
}
}
}
public function getTriggersAction()
{
return $this->handleView(
$this->view(
[
'triggers' => $this->model->getEvents(),
]
)
);
}
}

View File

@@ -0,0 +1,113 @@
<?php
namespace Mautic\WebhookBundle\Controller;
use Doctrine\Persistence\ManagerRegistry;
use Mautic\CoreBundle\Controller\FormController;
use Mautic\CoreBundle\Factory\ModelFactory;
use Mautic\CoreBundle\Helper\CoreParametersHelper;
use Mautic\CoreBundle\Helper\UserHelper;
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
use Mautic\CoreBundle\Service\FlashBag;
use Mautic\CoreBundle\Translation\Translator;
use Mautic\FormBundle\Helper\FormFieldHelper;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
class WebhookController extends FormController
{
public function __construct(FormFactoryInterface $formFactory, FormFieldHelper $fieldHelper, ManagerRegistry $doctrine, ModelFactory $modelFactory, UserHelper $userHelper, CoreParametersHelper $coreParametersHelper, EventDispatcherInterface $dispatcher, Translator $translator, FlashBag $flashBag, RequestStack $requestStack, CorePermissions $security)
{
$this->setStandardParameters(
'webhook.webhook', // model name
'webhook:webhooks', // permission base
'mautic_webhook', // route base
'mautic_webhook', // session base
'mautic.webhook', // lang string base
'@MauticWebhook/Webhook', // template base
'mautic_webhook', // activeLink
'mauticWebhook' // mauticContent
);
parent::__construct($formFactory, $fieldHelper, $doctrine, $modelFactory, $userHelper, $coreParametersHelper, $dispatcher, $translator, $flashBag, $requestStack, $security);
}
/**
* @param int $page
*
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function indexAction(Request $request, $page = 1): \Symfony\Component\HttpFoundation\Response
{
return parent::indexStandard($request, $page);
}
/**
* Generates new form and processes post data.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function newAction(Request $request)
{
return parent::newStandard($request);
}
/**
* Generates edit form and processes post data.
*
* @param int $objectId
* @param bool $ignorePost
*
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function editAction(Request $request, $objectId, $ignorePost = false)
{
return parent::editStandard($request, $objectId, $ignorePost);
}
/**
* Displays details on a Focus.
*
* @return array|\Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function viewAction(Request $request, $objectId)
{
return $this->viewStandard($request, $objectId, 'webhook', 'webhook', null, 'item');
}
/**
* Clone an entity.
*
* @param int $objectId
*
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function cloneAction(Request $request, $objectId)
{
return parent::cloneStandard($request, $objectId);
}
/**
* Deletes the entity.
*
* @param int $objectId
*
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function deleteAction(Request $request, $objectId)
{
return parent::deleteStandard($request, $objectId);
}
/**
* Deletes a group of entities.
*
* @return \Symfony\Component\HttpFoundation\JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse
*/
public function batchDeleteAction(Request $request)
{
return parent::batchDeleteStandard($request);
}
}