Initial commit: CloudOps infrastructure platform
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\IntegrationNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\AuthenticationInterface;
|
||||
use Mautic\PluginBundle\Entity\Integration;
|
||||
|
||||
class AuthIntegrationsHelper
|
||||
{
|
||||
/**
|
||||
* @var AuthenticationInterface[]
|
||||
*/
|
||||
private array $integrations = [];
|
||||
|
||||
public function __construct(
|
||||
private IntegrationsHelper $integrationsHelper,
|
||||
) {
|
||||
}
|
||||
|
||||
public function addIntegration(AuthenticationInterface $integration): void
|
||||
{
|
||||
$this->integrations[$integration->getName()] = $integration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
*/
|
||||
public function getIntegration(string $integration): AuthenticationInterface
|
||||
{
|
||||
if (!isset($this->integrations[$integration])) {
|
||||
throw new IntegrationNotFoundException("$integration either doesn't exist or has not been tagged with mautic.authentication_integration");
|
||||
}
|
||||
|
||||
// Ensure the configuration is hydrated
|
||||
$this->integrationsHelper->getIntegrationConfiguration($this->integrations[$integration]);
|
||||
|
||||
return $this->integrations[$integration];
|
||||
}
|
||||
|
||||
public function saveIntegrationConfiguration(Integration $integrationConfiguration): void
|
||||
{
|
||||
$this->integrationsHelper->saveIntegrationConfiguration($integrationConfiguration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\IntegrationNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\BuilderInterface;
|
||||
use Mautic\PluginBundle\Entity\Integration;
|
||||
|
||||
class BuilderIntegrationsHelper
|
||||
{
|
||||
/**
|
||||
* @var BuilderInterface[]
|
||||
*/
|
||||
private array $builders = [];
|
||||
|
||||
public function __construct(
|
||||
private IntegrationsHelper $integrationsHelper,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first enabled builder that supports the given feature.
|
||||
*
|
||||
* @throws IntegrationNotFoundException
|
||||
*/
|
||||
public function getBuilder(string $feature): BuilderInterface
|
||||
{
|
||||
foreach ($this->builders as $builder) {
|
||||
// Ensure the configuration is hydrated
|
||||
$this->integrationsHelper->getIntegrationConfiguration($builder);
|
||||
|
||||
if ($builder->isSupported($feature) && $builder->getIntegrationConfiguration()->getIsPublished()) {
|
||||
return $builder;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IntegrationNotFoundException();
|
||||
}
|
||||
|
||||
public function getBuilderNames(): array
|
||||
{
|
||||
$names = [];
|
||||
foreach ($this->builders as $builder) {
|
||||
$names[$builder->getName()] = $builder->getDisplayName();
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
public function addIntegration(BuilderInterface $integration): void
|
||||
{
|
||||
$this->builders[$integration->getName()] = $integration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
*/
|
||||
public function getIntegration(string $integration): BuilderInterface
|
||||
{
|
||||
if (!isset($this->builders[$integration])) {
|
||||
throw new IntegrationNotFoundException("$integration either doesn't exist or has not been tagged with mautic.builder_integration");
|
||||
}
|
||||
|
||||
// Ensure the configuration is hydrated
|
||||
$this->integrationsHelper->getIntegrationConfiguration($this->builders[$integration]);
|
||||
|
||||
return $this->builders[$integration];
|
||||
}
|
||||
|
||||
public function saveIntegrationConfiguration(Integration $integrationConfiguration): void
|
||||
{
|
||||
$this->integrationsHelper->saveIntegrationConfiguration($integrationConfiguration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\IntegrationNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\ConfigFormInterface;
|
||||
use Mautic\PluginBundle\Entity\Integration;
|
||||
|
||||
class ConfigIntegrationsHelper
|
||||
{
|
||||
/**
|
||||
* @var ConfigFormInterface[]
|
||||
*/
|
||||
private array $integrations = [];
|
||||
|
||||
public function __construct(
|
||||
private IntegrationsHelper $integrationsHelper,
|
||||
) {
|
||||
}
|
||||
|
||||
public function addIntegration(ConfigFormInterface $integration): void
|
||||
{
|
||||
$this->integrations[$integration->getName()] = $integration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ConfigFormInterface
|
||||
*
|
||||
* @throws IntegrationNotFoundException
|
||||
*/
|
||||
public function getIntegration(string $integration)
|
||||
{
|
||||
if (!isset($this->integrations[$integration])) {
|
||||
throw new IntegrationNotFoundException("$integration either doesn't exist or has not been tagged with mautic.config_integration");
|
||||
}
|
||||
|
||||
// Ensure the configuration is hydrated
|
||||
$this->integrationsHelper->getIntegrationConfiguration($this->integrations[$integration]);
|
||||
|
||||
return $this->integrations[$integration];
|
||||
}
|
||||
|
||||
public function saveIntegrationConfiguration(Integration $integrationConfiguration): void
|
||||
{
|
||||
$this->integrationsHelper->saveIntegrationConfiguration($integrationConfiguration);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\ConfigFormSyncInterface;
|
||||
use Mautic\IntegrationsBundle\Mapping\MappedFieldInfoInterface;
|
||||
|
||||
class FieldFilterHelper
|
||||
{
|
||||
private int $totalFieldCount = 0;
|
||||
|
||||
/**
|
||||
* @var MappedFieldInfoInterface[]
|
||||
*/
|
||||
private array $filteredFields = [];
|
||||
|
||||
public function __construct(
|
||||
private ConfigFormSyncInterface $integrationObject,
|
||||
) {
|
||||
}
|
||||
|
||||
public function filterFieldsByPage(string $objectName, int $page, int $limit = 15): void
|
||||
{
|
||||
$allFields = $this->integrationObject->getAllFieldsForMapping($objectName);
|
||||
$this->filteredFields = $this->getPageOfFields($allFields, $page, $limit);
|
||||
$this->totalFieldCount = count($allFields);
|
||||
}
|
||||
|
||||
public function filterFieldsByKeyword(string $objectName, string $keyword, int $page, int $limit = 15): void
|
||||
{
|
||||
$allFields = $this->integrationObject->getAllFieldsForMapping($objectName);
|
||||
$this->filteredFields = $this->getFieldsByKeyword($allFields, $keyword);
|
||||
|
||||
// Paginate filtered fields
|
||||
$this->totalFieldCount = count($this->filteredFields);
|
||||
$this->filteredFields = $this->getPageOfFields($this->filteredFields, $page, $limit);
|
||||
}
|
||||
|
||||
public function getTotalFieldCount(): int
|
||||
{
|
||||
return $this->totalFieldCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MappedFieldInfoInterface[]
|
||||
*/
|
||||
public function getFilteredFields(): array
|
||||
{
|
||||
return $this->filteredFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MappedFieldInfoInterface[]
|
||||
*/
|
||||
private function getPageOfFields(array $fields, int $page, int $limit): array
|
||||
{
|
||||
$offset = ($page - 1) * $limit;
|
||||
|
||||
return array_slice($fields, $offset, $limit, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MappedFieldInfoInterface[]
|
||||
*/
|
||||
private function getFieldsByKeyword(array $fields, string $keyword): array
|
||||
{
|
||||
$found = [];
|
||||
|
||||
foreach ($fields as $name => $field) {
|
||||
if (!stristr($field->getLabel(), $keyword)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$found[$name] = $field;
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\InvalidFormOptionException;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\ConfigFormSyncInterface;
|
||||
use Mautic\IntegrationsBundle\Mapping\MappedFieldInfoInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\ObjectMappingDAO;
|
||||
|
||||
class FieldMergerHelper
|
||||
{
|
||||
/**
|
||||
* @var MappedFieldInfoInterface[]
|
||||
*/
|
||||
private ?array $allFields = null;
|
||||
|
||||
public function __construct(
|
||||
private ConfigFormSyncInterface $integrationObject,
|
||||
private array $currentFieldMappings,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidFormOptionException
|
||||
*/
|
||||
public function mergeSyncFieldMapping(string $object, array $updatedFieldMappings): void
|
||||
{
|
||||
$this->allFields = $this->integrationObject->getAllFieldsForMapping($object);
|
||||
|
||||
$this->removeNonExistentFieldMappings($object);
|
||||
|
||||
$this->bindUpdatedFieldMappings($object, $updatedFieldMappings);
|
||||
}
|
||||
|
||||
public function getFieldMappings(): array
|
||||
{
|
||||
return $this->currentFieldMappings;
|
||||
}
|
||||
|
||||
private function removeNonExistentFieldMappings(string $object): void
|
||||
{
|
||||
if (!isset($this->currentFieldMappings[$object])) {
|
||||
$this->currentFieldMappings[$object] = [];
|
||||
}
|
||||
|
||||
// Remove any fields that no longer exist
|
||||
$this->currentFieldMappings[$object] = array_intersect_key($this->currentFieldMappings[$object], $this->allFields);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidFormOptionException
|
||||
*/
|
||||
private function bindUpdatedFieldMappings(string $object, array $updatedFieldMappings): void
|
||||
{
|
||||
// Merge updated fields into current fields
|
||||
foreach ($updatedFieldMappings as $fieldName => $fieldMapping) {
|
||||
if (!isset($this->allFields[$fieldName])) {
|
||||
// Ignore as this field doesn't exist
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($this->currentFieldMappings[$object][$fieldName]) && !$fieldMapping) {
|
||||
// Mapping was deleted
|
||||
unset($this->currentFieldMappings[$object][$fieldName]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($this->currentFieldMappings[$object][$fieldName])) {
|
||||
// Merge the data
|
||||
$this->currentFieldMappings[$object][$fieldName] = [
|
||||
'mappedField' => $this->getMergedMappedField($fieldMapping, $object, $fieldName),
|
||||
'syncDirection' => $this->getMergedSyncDirection($fieldMapping, $object, $fieldName),
|
||||
];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($fieldMapping['mappedField'])) {
|
||||
// Ignore this one because just direction was updated without a mapped field
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($fieldMapping['syncDirection'])) {
|
||||
$fieldMapping['syncDirection'] = $this->getDefaultSyncDirection($object, $fieldName);
|
||||
}
|
||||
|
||||
$this->currentFieldMappings[$object][$fieldName] = $fieldMapping;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidFormOptionException
|
||||
*/
|
||||
private function getDefaultSyncDirection(string $object, string $fieldName): string
|
||||
{
|
||||
$supportedDirections = $this->getSupportedSyncDirections($fieldName);
|
||||
|
||||
if (!empty($this->currentFieldMappings[$object][$fieldName]['syncDirection'])
|
||||
&& in_array(
|
||||
$this->currentFieldMappings[$object][$fieldName]['syncDirection'],
|
||||
$supportedDirections
|
||||
)) {
|
||||
// Keep the already configured value
|
||||
return $this->currentFieldMappings[$object][$fieldName]['syncDirection'];
|
||||
}
|
||||
|
||||
return reset($supportedDirections);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidFormOptionException
|
||||
*/
|
||||
private function getSupportedSyncDirections(string $fieldName): array
|
||||
{
|
||||
$field = $this->allFields[$fieldName];
|
||||
$supportedDirections = [];
|
||||
|
||||
if ($field->isBidirectionalSyncEnabled()) {
|
||||
$supportedDirections[] = ObjectMappingDAO::SYNC_BIDIRECTIONALLY;
|
||||
}
|
||||
|
||||
if ($field->isToIntegrationSyncEnabled()) {
|
||||
$supportedDirections[] = ObjectMappingDAO::SYNC_TO_INTEGRATION;
|
||||
}
|
||||
|
||||
if ($field->isToMauticSyncEnabled()) {
|
||||
$supportedDirections[] = ObjectMappingDAO::SYNC_TO_MAUTIC;
|
||||
}
|
||||
|
||||
if (empty($supportedDirections)) {
|
||||
throw new InvalidFormOptionException('field "'.$field->getName().'" must allow at least 1 direction for sync');
|
||||
}
|
||||
|
||||
return $supportedDirections;
|
||||
}
|
||||
|
||||
private function getMergedSyncDirection(array $fieldMapping, string $object, string $fieldName): string
|
||||
{
|
||||
if (empty($fieldMapping['syncDirection'])) {
|
||||
return $this->getDefaultSyncDirection($object, $fieldName);
|
||||
}
|
||||
|
||||
$supportedDirections = $this->getSupportedSyncDirections($fieldName);
|
||||
if (in_array($fieldMapping['syncDirection'], $supportedDirections)) {
|
||||
return $fieldMapping['syncDirection'];
|
||||
}
|
||||
|
||||
return reset($supportedDirections);
|
||||
}
|
||||
|
||||
private function getMergedMappedField(array $fieldMapping, string $object, string $fieldName): string
|
||||
{
|
||||
if (empty($fieldMapping['mappedField'])) {
|
||||
// Updating just the sync direction so return original value
|
||||
return $this->currentFieldMappings[$object][$fieldName]['mappedField'];
|
||||
}
|
||||
|
||||
return $fieldMapping['mappedField'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\ConfigFormFeaturesInterface;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\ConfigFormSyncInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Helper\FieldHelper;
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class FieldValidationHelper
|
||||
{
|
||||
private ?ConfigFormSyncInterface $integrationObject = null;
|
||||
|
||||
public function __construct(
|
||||
private FieldHelper $fieldHelper,
|
||||
private TranslatorInterface $translator,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FormInterface<mixed> $form
|
||||
*/
|
||||
public function validateRequiredFields(FormInterface $form, ConfigFormSyncInterface $integrationObject, array $fieldMappings): void
|
||||
{
|
||||
$integrationConfiguration = $integrationObject->getIntegrationConfiguration();
|
||||
if (!$integrationConfiguration->getIsPublished()) {
|
||||
// Don't bind form errors if the integration is not published
|
||||
return;
|
||||
}
|
||||
|
||||
$features = $integrationConfiguration->getSupportedFeatures();
|
||||
if (!in_array(ConfigFormFeaturesInterface::FEATURE_SYNC, $features)) {
|
||||
// Don't bind form errors if sync is not enabled
|
||||
return;
|
||||
}
|
||||
|
||||
$this->integrationObject = $integrationObject;
|
||||
|
||||
$settings = $integrationConfiguration->getFeatureSettings();
|
||||
foreach ($settings['sync']['objects'] as $object) {
|
||||
$objectFieldMappings = $fieldMappings[$object] ?? [];
|
||||
$fieldMappingForm = $form['featureSettings']['sync']['fieldMappings'][$object];
|
||||
|
||||
try {
|
||||
$missingFields = $this->findMissingIntegrationRequiredFieldMappings($object, $objectFieldMappings);
|
||||
$this->validateIntegrationRequiredFields($fieldMappingForm, $missingFields);
|
||||
|
||||
$this->validateMauticRequiredFields($fieldMappingForm, $object, $objectFieldMappings);
|
||||
} catch (\Throwable $exception) {
|
||||
$fieldMappingForm->addError(new FormError($exception->getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function validateIntegrationRequiredFields(Form $fieldMappingsForm, array $missingFields): void
|
||||
{
|
||||
$hasMissingFields = false;
|
||||
$errorsOnGivenPage = false;
|
||||
|
||||
if (!empty($missingFields)) {
|
||||
$hasMissingFields = true;
|
||||
}
|
||||
|
||||
foreach ($missingFields as $field) {
|
||||
if (!isset($fieldMappingsForm[$field])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$errorsOnGivenPage = true;
|
||||
|
||||
/** @var Form $formField */
|
||||
$formField = $fieldMappingsForm[$field]['mappedField'];
|
||||
$formField->addError(
|
||||
new FormError(
|
||||
$this->translator->trans('mautic.core.value.required', [], 'validators')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!$errorsOnGivenPage && $hasMissingFields) {
|
||||
// A hidden page has required fields that are missing so we have to tell the form there is an error
|
||||
$fieldMappingsForm->addError(
|
||||
new FormError(
|
||||
$this->translator->trans('mautic.core.value.required', [], 'validators')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function findMissingIntegrationRequiredFieldMappings(string $object, array $mappedFields): array
|
||||
{
|
||||
$requiredFields = $this->integrationObject->getRequiredFieldsForMapping($object);
|
||||
|
||||
$missingFields = [];
|
||||
foreach ($requiredFields as $field => $fieldObject) {
|
||||
if (empty($mappedFields[$field]['mappedField'])) {
|
||||
$missingFields[] = $field;
|
||||
}
|
||||
}
|
||||
|
||||
return $missingFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ObjectNotFoundException
|
||||
*/
|
||||
private function validateMauticRequiredFields(Form $fieldMappingsForm, string $object, array $objectFieldMappings): void
|
||||
{
|
||||
$missingFields = $this->findMissingInternalRequiredFieldMappings($object, $objectFieldMappings);
|
||||
if (empty($missingFields)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fieldMappingsForm->addError(
|
||||
new FormError(
|
||||
$this->translator->trans(
|
||||
'mautic.integration.sync.missing_mautic_field_mappings',
|
||||
[
|
||||
'%fields%' => implode(', ', $missingFields),
|
||||
],
|
||||
'validators'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ObjectNotFoundException
|
||||
*/
|
||||
private function findMissingInternalRequiredFieldMappings(string $object, array $objectFieldMappings): array
|
||||
{
|
||||
$mappedObjects = $this->integrationObject->getSyncMappedObjects();
|
||||
|
||||
if (!isset($mappedObjects[$object])) {
|
||||
throw new ObjectNotFoundException($object);
|
||||
}
|
||||
|
||||
// Get Mautic mapped fields
|
||||
$mauticMappedFields = [];
|
||||
foreach ($objectFieldMappings as $mapping) {
|
||||
if (empty($mapping['mappedField'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$mauticMappedFields[$mapping['mappedField']] = true;
|
||||
}
|
||||
|
||||
$requiredFields = $this->fieldHelper->getRequiredFields($mappedObjects[$object]);
|
||||
|
||||
return array_diff_key($requiredFields, $mauticMappedFields);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Event\KeysDecryptionEvent;
|
||||
use Mautic\IntegrationsBundle\Event\KeysEncryptionEvent;
|
||||
use Mautic\IntegrationsBundle\Exception\IntegrationNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Facade\EncryptionService;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\IntegrationInterface;
|
||||
use Mautic\IntegrationsBundle\IntegrationEvents;
|
||||
use Mautic\PluginBundle\Entity\Integration;
|
||||
use Mautic\PluginBundle\Entity\IntegrationRepository;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
class IntegrationsHelper
|
||||
{
|
||||
/**
|
||||
* @var IntegrationInterface[]
|
||||
*/
|
||||
private array $integrations = [];
|
||||
|
||||
private array $decryptedIntegrationConfigurations = [];
|
||||
|
||||
public function __construct(
|
||||
private IntegrationRepository $integrationRepository,
|
||||
private EncryptionService $encryptionService,
|
||||
private EventDispatcherInterface $eventDispatcher,
|
||||
) {
|
||||
}
|
||||
|
||||
public function addIntegration(IntegrationInterface $integration): void
|
||||
{
|
||||
$this->integrations[$integration->getName()] = $integration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IntegrationInterface
|
||||
*
|
||||
* @throws IntegrationNotFoundException
|
||||
*/
|
||||
public function getIntegration(string $integration)
|
||||
{
|
||||
if (!isset($this->integrations[$integration])) {
|
||||
throw new IntegrationNotFoundException("$integration either doesn't exist or has not been tagged with mautic.basic_integration");
|
||||
}
|
||||
|
||||
// Ensure the configuration is hydrated
|
||||
$this->getIntegrationConfiguration($this->integrations[$integration]);
|
||||
|
||||
return $this->integrations[$integration];
|
||||
}
|
||||
|
||||
public function saveIntegrationConfiguration(Integration $configuration): void
|
||||
{
|
||||
// Encrypt the keys before saving
|
||||
$decryptedApiKeys = $configuration->getApiKeys();
|
||||
|
||||
// Dispatch event before encryption
|
||||
$encryptionEvent = new KeysEncryptionEvent($configuration, $decryptedApiKeys);
|
||||
$this->eventDispatcher->dispatch($encryptionEvent, IntegrationEvents::INTEGRATION_KEYS_BEFORE_ENCRYPTION);
|
||||
|
||||
// Encrypt and store the keys
|
||||
$encryptedApiKeys = $this->encryptionService->encrypt($encryptionEvent->getKeys());
|
||||
$configuration->setApiKeys($encryptedApiKeys);
|
||||
|
||||
// Save
|
||||
$this->integrationRepository->saveEntity($configuration);
|
||||
|
||||
// Restore decrypted for use
|
||||
$configuration->setApiKeys($decryptedApiKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
*/
|
||||
public function getIntegrationConfiguration(IntegrationInterface $integration): Integration
|
||||
{
|
||||
if (!$integration->hasIntegrationConfiguration()) {
|
||||
/** @var Integration $configuration */
|
||||
$configuration = $this->integrationRepository->findOneByName($integration->getName());
|
||||
|
||||
if (!$configuration) {
|
||||
throw new IntegrationNotFoundException("{$integration->getName()} doesn't exist in the database");
|
||||
}
|
||||
|
||||
$integration->setIntegrationConfiguration($configuration);
|
||||
}
|
||||
|
||||
// Make sure the keys are decrypted
|
||||
if (!isset($this->decryptedIntegrationConfigurations[$integration->getName()])) {
|
||||
$configuration = $integration->getIntegrationConfiguration();
|
||||
$encryptedApiKeys = $configuration->getApiKeys();
|
||||
$decryptedApiKeys = $this->encryptionService->decrypt($encryptedApiKeys);
|
||||
|
||||
// Dispatch event after decryption
|
||||
$decryptionEvent = new KeysDecryptionEvent($configuration, $decryptedApiKeys);
|
||||
$this->eventDispatcher->dispatch($decryptionEvent, IntegrationEvents::INTEGRATION_KEYS_AFTER_DECRYPTION);
|
||||
|
||||
$configuration->setApiKeys($decryptionEvent->getKeys());
|
||||
|
||||
$this->decryptedIntegrationConfigurations[$integration->getName()] = true;
|
||||
}
|
||||
|
||||
return $integration->getIntegrationConfiguration();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Helper;
|
||||
|
||||
use Mautic\IntegrationsBundle\Exception\IntegrationNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\ConfigFormFeaturesInterface;
|
||||
use Mautic\IntegrationsBundle\Integration\Interfaces\SyncInterface;
|
||||
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\MappingManualDAO;
|
||||
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\ObjectProvider;
|
||||
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\SyncDataExchangeInterface;
|
||||
|
||||
class SyncIntegrationsHelper
|
||||
{
|
||||
/**
|
||||
* @var SyncInterface[]
|
||||
*/
|
||||
private array $integrations = [];
|
||||
|
||||
/**
|
||||
* @var array<int,string>|null
|
||||
*/
|
||||
private ?array $enabled = null;
|
||||
|
||||
public function __construct(
|
||||
private IntegrationsHelper $integrationsHelper,
|
||||
private ObjectProvider $objectProvider,
|
||||
) {
|
||||
}
|
||||
|
||||
public function addIntegration(SyncInterface $integration): void
|
||||
{
|
||||
$this->integrations[$integration->getName()] = $integration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SyncInterface
|
||||
*
|
||||
* @throws IntegrationNotFoundException
|
||||
*/
|
||||
public function getIntegration(string $integration)
|
||||
{
|
||||
if (!isset($this->integrations[$integration])) {
|
||||
throw new IntegrationNotFoundException("$integration either doesn't exist or has not been tagged with mautic.sync_integration");
|
||||
}
|
||||
|
||||
return $this->integrations[$integration];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,string>|null
|
||||
*/
|
||||
public function getEnabledIntegrations()
|
||||
{
|
||||
if (null !== $this->enabled) {
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
$this->enabled = [];
|
||||
foreach ($this->integrations as $name => $syncIntegration) {
|
||||
try {
|
||||
$integrationConfiguration = $this->integrationsHelper->getIntegrationConfiguration($syncIntegration);
|
||||
|
||||
if ($integrationConfiguration->getIsPublished()) {
|
||||
$this->enabled[] = $name;
|
||||
}
|
||||
} catch (IntegrationNotFoundException) {
|
||||
// Just ignore as the plugin hasn't been installed yet
|
||||
}
|
||||
}
|
||||
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
* @throws ObjectNotFoundException
|
||||
*/
|
||||
public function hasObjectSyncEnabled(string $mauticObject): bool
|
||||
{
|
||||
// Ensure the internal object exists.
|
||||
$this->objectProvider->getObjectByName($mauticObject);
|
||||
|
||||
$enabledIntegrations = $this->getEnabledIntegrations();
|
||||
|
||||
foreach ($enabledIntegrations as $integration) {
|
||||
$syncIntegration = $this->getIntegration($integration);
|
||||
$integrationConfiguration = $syncIntegration->getIntegrationConfiguration();
|
||||
|
||||
// Sync is enabled
|
||||
$enabledFeatures = $integrationConfiguration->getSupportedFeatures();
|
||||
if (!in_array(ConfigFormFeaturesInterface::FEATURE_SYNC, $enabledFeatures)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// At least one object is enabled
|
||||
$featureSettings = $integrationConfiguration->getFeatureSettings();
|
||||
if (empty($featureSettings['sync']['objects'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// Find what object is mapped to Mautic's object
|
||||
$mappingManual = $syncIntegration->getMappingManual();
|
||||
$mappedObjectNames = $mappingManual->getMappedIntegrationObjectsNames($mauticObject);
|
||||
foreach ($mappedObjectNames as $mappedObjectName) {
|
||||
if (in_array($mappedObjectName, $featureSettings['sync']['objects'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (ObjectNotFoundException) {
|
||||
// Object is not supported so just continue
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
*/
|
||||
public function getMappingManual(string $integration): MappingManualDAO
|
||||
{
|
||||
$integration = $this->getIntegration($integration);
|
||||
|
||||
return $integration->getMappingManual();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IntegrationNotFoundException
|
||||
*/
|
||||
public function getSyncDataExchange(string $integration): SyncDataExchangeInterface
|
||||
{
|
||||
$integration = $this->getIntegration($integration);
|
||||
|
||||
return $integration->getSyncDataExchange();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mautic\IntegrationsBundle\Helper;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Mautic\IntegrationsBundle\DTO\IntegrationObjectToken as Token;
|
||||
|
||||
class TokenParser
|
||||
{
|
||||
public const TOKEN = '{mapped-integration-object=(.*?)}';
|
||||
|
||||
public function findTokens(string $content): ArrayCollection
|
||||
{
|
||||
$tokens = new ArrayCollection();
|
||||
|
||||
preg_match_all('/'.self::TOKEN.'/', $content, $matches);
|
||||
|
||||
if (empty($matches[1])) {
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
foreach ($matches[1] as $key => $tokenDataRaw) {
|
||||
$token = new Token($matches[0][$key]);
|
||||
$parts = $this->getPartsDividedByPipe($tokenDataRaw);
|
||||
|
||||
$token->setObjectName($parts[0]);
|
||||
foreach ($parts as $part) {
|
||||
$options = $this->trimArrayElements(explode('=', $part));
|
||||
|
||||
if (2 !== count($options)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$keyword = $options[0];
|
||||
$value = $options[1];
|
||||
|
||||
if ('mapped-integration-object' === $keyword) {
|
||||
$token->setObjectName($value);
|
||||
}
|
||||
|
||||
if ('integration' === $keyword) {
|
||||
$token->setIntegration($value);
|
||||
}
|
||||
|
||||
if ('default' === $keyword) {
|
||||
$token->setDefaultValue($value);
|
||||
}
|
||||
|
||||
if ('link-text' == $keyword) {
|
||||
$token->setLinkText($value);
|
||||
}
|
||||
|
||||
if ('base-url' == $keyword) {
|
||||
$token->setBaseURL($value);
|
||||
}
|
||||
}
|
||||
|
||||
$tokens->set($token->getToken(), $token);
|
||||
}
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
public function buildTokenWithDefaultOptions($integrationObjectName, $integration, $default, $linkText, $baseURL): string
|
||||
{
|
||||
return sprintf(
|
||||
'{mapped-integration-object=%s | integration=%s | default=%s | link-text=%s | base-url=%s}',
|
||||
$integrationObjectName,
|
||||
$integration,
|
||||
$default,
|
||||
$linkText,
|
||||
$baseURL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getPartsDividedByPipe(string $tokenDataRaw): array
|
||||
{
|
||||
return $this->trimArrayElements(explode('|', $tokenDataRaw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $array
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
private function trimArrayElements(array $array): array
|
||||
{
|
||||
return array_map('trim', $array);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user