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,76 @@
<?php
namespace Mautic\LeadBundle\Tracker\Service\ContactTrackingService;
use Mautic\CoreBundle\Helper\CookieHelper;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Entity\LeadDeviceRepository;
use Mautic\LeadBundle\Entity\LeadRepository;
use Mautic\LeadBundle\Entity\MergeRecordRepository;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Used to ensure that contacts tracked under the old method are continued to be tracked under the new.
*/
final class ContactTrackingService implements ContactTrackingServiceInterface
{
public function __construct(
private CookieHelper $cookieHelper,
private LeadDeviceRepository $leadDeviceRepository,
private LeadRepository $leadRepository,
private MergeRecordRepository $mergeRecordRepository,
private RequestStack $requestStack,
) {
}
/**
* @return Lead|null
*/
public function getTrackedLead()
{
$request = $this->requestStack->getCurrentRequest();
if (null === $request) {
return null;
}
$trackingId = $this->getTrackedIdentifier();
if (null === $trackingId) {
return null;
}
$leadId = $this->cookieHelper->getCookie($trackingId, null);
if (null === $leadId) {
$leadId = $request->get('mtc_id', null);
if (null === $leadId) {
return null;
}
}
$lead = $this->leadRepository->getEntity($leadId);
if (null === $lead) {
// Check if this contact was merged into another and if so, return the new contact
$lead = $this->mergeRecordRepository->findMergedContact($leadId);
if (null === $lead) {
return null;
}
// Hydrate fields with custom field data
$fields = $this->leadRepository->getFieldValues($lead->getId());
$lead->setFields($fields);
}
$anotherDeviceAlreadyTracked = $this->leadDeviceRepository->isAnyLeadDeviceTracked($lead);
return $anotherDeviceAlreadyTracked ? null : $lead;
}
/**
* @return string|null
*/
public function getTrackedIdentifier()
{
return $this->cookieHelper->getCookie('mautic_session_id', null);
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Mautic\LeadBundle\Tracker\Service\ContactTrackingService;
use Mautic\LeadBundle\Entity\Lead;
/**
* Interface ContactTrackingInterface.
*/
interface ContactTrackingServiceInterface
{
/**
* Return current tracked Lead.
*
* @return Lead|null
*/
public function getTrackedLead();
/**
* @return string|null Unique identifier
*/
public function getTrackedIdentifier();
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Mautic\LeadBundle\Tracker\Service\DeviceCreatorService;
use DeviceDetector\DeviceDetector;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Entity\LeadDevice;
final class DeviceCreatorService implements DeviceCreatorServiceInterface
{
public function getCurrentFromDetector(DeviceDetector $deviceDetector, Lead $assignedLead): LeadDevice
{
$device = new LeadDevice();
$device->setClientInfo($deviceDetector->getClient());
$device->setDevice($deviceDetector->getDeviceName());
$device->setDeviceBrand($deviceDetector->getBrandName());
$device->setDeviceModel($deviceDetector->getModel());
$device->setDeviceOs($deviceDetector->getOs());
$device->setDateAdded(new \DateTime());
$device->setLead($assignedLead);
return $device;
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Mautic\LeadBundle\Tracker\Service\DeviceCreatorService;
use DeviceDetector\DeviceDetector;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Entity\LeadDevice;
/**
* Interface DeviceCreatorServiceInterface.
*/
interface DeviceCreatorServiceInterface
{
/**
* @return LeadDevice|null Null is returned if device can't be detected
*/
public function getCurrentFromDetector(DeviceDetector $deviceDetector, Lead $assignedLead);
}

View File

@@ -0,0 +1,132 @@
<?php
namespace Mautic\LeadBundle\Tracker\Service\DeviceTrackingService;
use Doctrine\ORM\EntityManagerInterface;
use Mautic\CoreBundle\Helper\CookieHelper;
use Mautic\CoreBundle\Helper\RandomHelper\RandomHelperInterface;
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
use Mautic\LeadBundle\Entity\LeadDevice;
use Mautic\LeadBundle\Entity\LeadDeviceRepository;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\RequestStack;
final class DeviceTrackingService implements DeviceTrackingServiceInterface
{
private ?LeadDevice $trackedDevice = null;
public function __construct(
private CookieHelper $cookieHelper,
private EntityManagerInterface $entityManager,
private LeadDeviceRepository $leadDeviceRepository,
private RandomHelperInterface $randomHelper,
private RequestStack $requestStack,
private CorePermissions $security,
) {
}
public function isTracked(): bool
{
return null !== $this->getTrackedDevice();
}
/**
* @return ?LeadDevice
*/
public function getTrackedDevice()
{
if (!$this->security->isAnonymous()) {
// Do not track Mautic users
return null;
}
if ($this->trackedDevice) {
return $this->trackedDevice;
}
$trackingId = $this->getTrackedIdentifier();
if (null === $trackingId) {
return null;
}
return $this->leadDeviceRepository->getByTrackingId($trackingId);
}
/**
* @param bool $replaceExistingTracking
*
* @return LeadDevice
*/
public function trackCurrentDevice(LeadDevice $device, $replaceExistingTracking = false)
{
$trackedDevice = $this->getTrackedDevice();
if (null !== $trackedDevice && false === $replaceExistingTracking) {
return $trackedDevice;
}
if (null !== $existingDevice = $this->leadDeviceRepository->findExistingDevice($device)) {
$device = $existingDevice;
}
if (empty($device->getTrackingId())) {
// Ensure all devices have a tracking ID (new devices will not and pre 2.13.0 devices may not)
$device->setTrackingId($this->getUniqueTrackingIdentifier());
$this->entityManager->persist($device);
$this->entityManager->flush();
}
$this->createTrackingCookies($device);
// Store the device in case a service uses this within the same session
$this->trackedDevice = $device;
return $device;
}
public function clearTrackingCookies(): void
{
$this->cookieHelper->deleteCookie('mautic_device_id');
$this->cookieHelper->deleteCookie('mtc_id');
}
private function getTrackedIdentifier(): ?string
{
$request = $this->requestStack->getCurrentRequest();
if (null === $request) {
return null;
}
if ($this->trackedDevice) {
// Use the device tracked in case the cookies were just created
return $this->trackedDevice->getTrackingId();
}
$deviceTrackingId = $this->cookieHelper->getCookie('mautic_device_id', null);
if (null === $deviceTrackingId) {
$deviceTrackingId = $request->get('mautic_device_id', null);
}
return $deviceTrackingId;
}
private function getUniqueTrackingIdentifier(): string
{
do {
$generatedIdentifier = $this->randomHelper->generate(23);
$device = $this->leadDeviceRepository->getByTrackingId($generatedIdentifier);
} while (null !== $device);
return $generatedIdentifier;
}
private function createTrackingCookies(LeadDevice $device): void
{
// Device cookie
$this->cookieHelper->setCookie('mautic_device_id', $device->getTrackingId(), 31_536_000, sameSite: Cookie::SAMESITE_NONE);
// Mainly for landing pages so that JS has the same access as 3rd party tracking code
$this->cookieHelper->setCookie('mtc_id', $device->getLead()->getId(), null, sameSite: Cookie::SAMESITE_NONE);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Mautic\LeadBundle\Tracker\Service\DeviceTrackingService;
use Mautic\LeadBundle\Entity\LeadDevice;
/**
* Interface DeviceTrackingServiceInterface.
*/
interface DeviceTrackingServiceInterface
{
/**
* @return bool
*/
public function isTracked();
/**
* @return LeadDevice|null
*/
public function getTrackedDevice();
/**
* @param bool $replaceExistingTracking
*
* @return LeadDevice
*/
public function trackCurrentDevice(LeadDevice $device, $replaceExistingTracking = false);
public function clearTrackingCookies();
}