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,435 @@
<?php
declare(strict_types=1);
namespace Mautic\PageBundle\Tests\Functional\EventListener;
use Mautic\CategoryBundle\Entity\Category;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\EmailBundle\Entity\Email;
use Mautic\EmailBundle\Entity\Stat;
use Mautic\EmailBundle\Helper\MailHashHelper;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Entity\LeadList as Segment;
use Mautic\PageBundle\Entity\Page;
use PHPUnit\Framework\Assert;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
#[\PHPUnit\Framework\Attributes\PreserveGlobalState(false)]
#[\PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses]
class BuilderSubscriberTest extends MauticMysqlTestCase
{
protected $useCleanupRollback = false;
// Custom preference center page
public const CUSTOM_SEGMENT_SELECTOR = '.pref-segmentlist input';
public const CUSTOM_CATEGORY_SELECTOR = '.pref-categorylist input';
public const CUSTOM_PREFERRED_CHANNEL_SELECTOR = '.pref-preferredchannel select';
public const CUSTOM_CHANNEL_FREQ_SELECTOR = '.pref-channelfrequency div[data-contact-frequency="1"]';
public const CUSTOM_SAVE_BUTTON_SELECTOR = '.prefs-saveprefs a.btn-save';
// Default preference center page
public const DEFAULT_SEGMENT_SELECTOR = '#contact-segments';
public const DEFAULT_CATEGORY_SELECTOR = '#global-categories';
public const DEFAULT_PREFERRED_CHANNEL_SELECTOR = '#preferred_channel';
public const DEFAULT_CHANNEL_FREQ_SELECTOR = '[data-contact-frequency="1"]';
public const DEFAULT_PAUSE_DATES_SELECTOR = '[data-contact-pause-dates="1"]';
public const DEFAULT_SAVE_BUTTON_SELECTOR = '#lead_contact_frequency_rules_buttons_save';
// Common to both custom and default
public const TOKEN_SELECTOR = '#lead_contact_frequency_rules__token';
public const FORM_SELECTOR = 'form[name="lead_contact_frequency_rules"]';
protected function setUp(): void
{
$this->configParams['show_contact_preferences'] = 1;
$data = $this->providedData();
$this->configParams = array_merge($data[0], $this->configParams);
parent::setUp();
}
/**
* Tests both the default and custom preference center pages.
*
* @param mixed[] $configParams
* @param array<string,int> $selectorsAndExpectedCounts
*/
#[\PHPUnit\Framework\Attributes\DataProvider('frequencyFormRenderingDataProvider')]
public function testUnsubscribeFormRendersPreferenceCenterPageCorrectly(array $configParams, array $selectorsAndExpectedCounts, bool $hasPreferenceCenter): void
{
$emailStat = $this->createStat(
$this->createEmail($hasPreferenceCenter),
$lead = $this->createLead()
);
$this->createSegment();
$this->createCategory();
$this->em->flush();
$mailHashHelper = static::getContainer()->get(MailHashHelper::class);
\assert($mailHashHelper instanceof MailHashHelper);
$unsubscribeUrl = $this->router->generate('mautic_email_unsubscribe', [
'idHash' => $emailStat->getTrackingHash(),
'urlEmail' => $lead->getEmail(),
'secretHash' => $mailHashHelper->getEmailHash($lead->getEmail()),
], UrlGeneratorInterface::ABSOLUTE_PATH);
$crawler = $this->client->request('GET', $unsubscribeUrl);
self::assertTrue($this->client->getResponse()->isSuccessful(), $this->client->getResponse()->getContent());
$form = $crawler->filter(static::FORM_SELECTOR);
$html = $form->html();
foreach ($selectorsAndExpectedCounts as $selector => $expectedCount) {
$message = sprintf(
'The form HTML %s not contain the %s section. %s',
0 === $expectedCount ? 'should' : 'does',
$selector,
$html
);
Assert::assertCount(
$expectedCount,
$form->filter($selector),
$message
);
}
// Ensure the token and save button are always included within the <form> tag
Assert::assertCount(1, $form->filter(static::TOKEN_SELECTOR), sprintf('The following HTML does not contain the _token. %s', $html));
if ($hasPreferenceCenter) {
Assert::assertCount(1, $form->filter(static::CUSTOM_SAVE_BUTTON_SELECTOR), sprintf('The following HTML does not contain the save button. %s', $html));
} else {
Assert::assertCount(1, $form->filter(static::DEFAULT_SAVE_BUTTON_SELECTOR), sprintf('The following HTML does not contain the save button. %s', $html));
}
}
public static function frequencyFormRenderingDataProvider(): \Generator
{
yield 'Custom Preference Center: All preferences enabled' => [
[
'show_contact_segments' => 1,
'show_contact_categories' => 1,
'show_contact_preferred_channels' => 1,
'show_contact_frequency' => 1,
'show_contact_pause_dates' => 1,
],
[
static::CUSTOM_SEGMENT_SELECTOR => 1, // determined by show_contact_segments
static::CUSTOM_CATEGORY_SELECTOR => 1, // determined by show_contact_categories
static::CUSTOM_PREFERRED_CHANNEL_SELECTOR => 1, // determined by show_contact_preferred_channels
static::CUSTOM_CHANNEL_FREQ_SELECTOR => 1, // determined by EITHER show_contact_frequency & show_contact_pause_dates
],
true,
];
yield 'Custom Preference Center: Segments & Categories disabled' => [
[
'show_contact_segments' => 0,
'show_contact_categories' => 0,
'show_contact_preferred_channels' => 1,
'show_contact_frequency' => 1,
'show_contact_pause_dates' => 1,
],
[
static::CUSTOM_SEGMENT_SELECTOR => 0, // determined by show_contact_segments
static::CUSTOM_CATEGORY_SELECTOR => 0, // determined by show_contact_categories
static::CUSTOM_PREFERRED_CHANNEL_SELECTOR => 1, // determined by show_contact_preferred_channels
static::CUSTOM_CHANNEL_FREQ_SELECTOR => 1, // determined by EITHER show_contact_frequency & show_contact_pause_dates
],
true,
];
yield 'Custom Preference Center: Preferred Channels & Frequency disabled' => [
[
'show_contact_segments' => 1,
'show_contact_categories' => 1,
'show_contact_preferred_channels' => 0,
'show_contact_frequency' => 0,
'show_contact_pause_dates' => 0,
],
[
static::CUSTOM_SEGMENT_SELECTOR => 1, // determined by show_contact_segments
static::CUSTOM_CATEGORY_SELECTOR => 1, // determined by show_contact_categories
static::CUSTOM_PREFERRED_CHANNEL_SELECTOR => 0, // determined by show_contact_preferred_channels
static::CUSTOM_CHANNEL_FREQ_SELECTOR => 0, // determined by EITHER show_contact_frequency & show_contact_pause_dates
],
true,
];
yield 'Custom Preference Center: Frequency enabled & Pause Dates disabled' => [
[
'show_contact_segments' => 0,
'show_contact_categories' => 0,
'show_contact_preferred_channels' => 0,
'show_contact_frequency' => 1,
'show_contact_pause_dates' => 0,
],
[
static::CUSTOM_SEGMENT_SELECTOR => 0, // determined by show_contact_segments
static::CUSTOM_CATEGORY_SELECTOR => 0, // determined by show_contact_categories
static::CUSTOM_PREFERRED_CHANNEL_SELECTOR => 0, // determined by show_contact_preferred_channels
static::CUSTOM_CHANNEL_FREQ_SELECTOR => 1, // determined by EITHER show_contact_frequency & show_contact_pause_dates
],
true,
];
yield 'Custom Preference Center: Frequency disabled & Pause Dates enabled' => [
[
'show_contact_segments' => 0,
'show_contact_categories' => 0,
'show_contact_preferred_channels' => 0,
'show_contact_frequency' => 0,
'show_contact_pause_dates' => 1,
],
[
static::CUSTOM_SEGMENT_SELECTOR => 0, // determined by show_contact_segments
static::CUSTOM_CATEGORY_SELECTOR => 0, // determined by show_contact_categories
static::CUSTOM_PREFERRED_CHANNEL_SELECTOR => 0, // determined by show_contact_preferred_channels
static::CUSTOM_CHANNEL_FREQ_SELECTOR => 0, // determined by show_contact_frequency
static::DEFAULT_PAUSE_DATES_SELECTOR => 1, // determined by show_contact_pause_dates
],
true,
];
yield 'Custom Preference Center: All preferences disabled' => [
[
'show_contact_segments' => 0,
'show_contact_categories' => 0,
'show_contact_preferred_channels' => 0,
'show_contact_frequency' => 0,
'show_contact_pause_dates' => 0,
],
[
static::CUSTOM_SEGMENT_SELECTOR => 0, // determined by show_contact_segments
static::CUSTOM_CATEGORY_SELECTOR => 0, // determined by show_contact_categories
static::CUSTOM_PREFERRED_CHANNEL_SELECTOR => 0, // determined by show_contact_preferred_channels
static::CUSTOM_CHANNEL_FREQ_SELECTOR => 0, // determined by EITHER show_contact_frequency & show_contact_pause_dates
],
true,
];
yield 'Default Preference Center: All preferences enabled' => [
[
'show_contact_segments' => 1,
'show_contact_categories' => 1,
'show_contact_preferred_channels' => 1,
'show_contact_frequency' => 1,
'show_contact_pause_dates' => 1,
],
[
static::DEFAULT_SEGMENT_SELECTOR => 1, // determined by show_contact_segments
static::DEFAULT_CATEGORY_SELECTOR => 1, // determined by show_contact_categories
static::DEFAULT_PREFERRED_CHANNEL_SELECTOR => 1, // determined by show_contact_preferred_channels
static::DEFAULT_CHANNEL_FREQ_SELECTOR => 1, // determined by show_contact_frequency. This differs from a custom page.
static::DEFAULT_PAUSE_DATES_SELECTOR => 1, // determined FIRST by show_contact_frequency, then by show_contact_pause_dates
],
false,
];
yield 'Default Preference Center: Segments & Categories disabled' => [
[
'show_contact_segments' => 0,
'show_contact_categories' => 0,
'show_contact_preferred_channels' => 1,
'show_contact_frequency' => 1,
'show_contact_pause_dates' => 1,
],
[
static::DEFAULT_SEGMENT_SELECTOR => 0, // determined by show_contact_segments
static::DEFAULT_CATEGORY_SELECTOR => 0, // determined by show_contact_categories
static::DEFAULT_PREFERRED_CHANNEL_SELECTOR => 1, // determined by show_contact_preferred_channels
static::DEFAULT_CHANNEL_FREQ_SELECTOR => 1, // determined by show_contact_frequency. This differs from a custom page.
static::DEFAULT_PAUSE_DATES_SELECTOR => 1, // determined FIRST by show_contact_frequency, then by show_contact_pause_dates
],
false,
];
yield 'Default Preference Center: Preferred Channels & Frequency disabled' => [
[
'show_contact_segments' => 1,
'show_contact_categories' => 1,
'show_contact_preferred_channels' => 0,
'show_contact_frequency' => 0,
'show_contact_pause_dates' => 0,
],
[
static::DEFAULT_SEGMENT_SELECTOR => 1, // determined by show_contact_segments
static::DEFAULT_CATEGORY_SELECTOR => 1, // determined by show_contact_categories
static::DEFAULT_PREFERRED_CHANNEL_SELECTOR => 0, // determined by show_contact_preferred_channels
static::DEFAULT_CHANNEL_FREQ_SELECTOR => 0, // determined by show_contact_frequency. This differs from a custom page.
static::DEFAULT_PAUSE_DATES_SELECTOR => 0, // determined FIRST by show_contact_frequency, then by show_contact_pause_dates
],
false,
];
yield 'Default Preference Center: Frequency enabled & Pause Dates disabled' => [
[
'show_contact_segments' => 0,
'show_contact_categories' => 0,
'show_contact_preferred_channels' => 0,
'show_contact_frequency' => 1,
'show_contact_pause_dates' => 0,
],
[
static::DEFAULT_SEGMENT_SELECTOR => 0, // determined by show_contact_segments
static::DEFAULT_CATEGORY_SELECTOR => 0, // determined by show_contact_categories
static::DEFAULT_PREFERRED_CHANNEL_SELECTOR => 0, // determined by show_contact_preferred_channels
static::DEFAULT_CHANNEL_FREQ_SELECTOR => 1, // determined by show_contact_frequency. This differs from a custom page.
static::DEFAULT_PAUSE_DATES_SELECTOR => 0, // determined FIRST by show_contact_frequency, then by show_contact_pause_dates
],
false,
];
yield 'Default Preference Center: Frequency disabled & Pause Dates enabled' => [
[
'show_contact_segments' => 0,
'show_contact_categories' => 0,
'show_contact_preferred_channels' => 0,
'show_contact_frequency' => 0,
'show_contact_pause_dates' => 1,
],
[
static::DEFAULT_SEGMENT_SELECTOR => 0, // determined by show_contact_segments
static::DEFAULT_CATEGORY_SELECTOR => 0, // determined by show_contact_categories
static::DEFAULT_PREFERRED_CHANNEL_SELECTOR => 0, // determined by show_contact_preferred_channels
static::DEFAULT_CHANNEL_FREQ_SELECTOR => 0, // determined by show_contact_frequency. This differs from a custom page.
static::DEFAULT_PAUSE_DATES_SELECTOR => 0, // determined FIRST by show_contact_frequency, then by show_contact_pause_dates
],
false,
];
yield 'Default Preference Center: All preferences disabled' => [
[
'show_contact_segments' => 0,
'show_contact_categories' => 0,
'show_contact_preferred_channels' => 0,
'show_contact_frequency' => 0,
'show_contact_pause_dates' => 0,
],
[
static::DEFAULT_SEGMENT_SELECTOR => 0, // determined by show_contact_segments
static::DEFAULT_CATEGORY_SELECTOR => 0, // determined by show_contact_categories
static::DEFAULT_PREFERRED_CHANNEL_SELECTOR => 0, // determined by show_contact_preferred_channels
static::DEFAULT_CHANNEL_FREQ_SELECTOR => 0, // determined by show_contact_frequency. This differs from a custom page.
static::DEFAULT_PAUSE_DATES_SELECTOR => 0, // determined FIRST by show_contact_frequency, then by show_contact_pause_dates
],
false,
];
}
private function createStat(Email $email, Lead $lead): Stat
{
$stat = new Stat();
$stat->setEmail($email);
$stat->setLead($lead);
$stat->setEmailAddress($lead->getEmail());
$stat->setDateSent(new \DateTime());
$stat->setTrackingHash(uniqid());
$this->em->persist($stat);
return $stat;
}
private function createEmail(bool $hasPreferenceCenter = true): Email
{
$email = new Email();
$email->setName('Example');
if ($hasPreferenceCenter) {
$email->setPreferenceCenter($this->createPage());
}
$this->em->persist($email);
return $email;
}
private function createLead(): Lead
{
$lead = new Lead();
$lead->setEmail('test@example.com');
$this->em->persist($lead);
return $lead;
}
private function createSegment(): Segment
{
$segment = new Segment();
$segment->setName('My Segment');
$segment->setPublicName('My Segment');
$segment->setAlias('my-segment');
$segment->setIsPreferenceCenter(true);
$this->em->persist($segment);
return $segment;
}
private function createCategory(): Category
{
$category = new Category();
$category->setTitle('My Category');
$category->setAlias('my-category');
$category->setIsPublished(true);
$category->setBundle('global');
$this->em->persist($category);
return $category;
}
private function createPage(): Page
{
$page = new Page();
$page->setTitle('Preference Center');
$page->setAlias('preference-center');
$page->setIsPreferenceCenter(true);
$page->setCustomHtml($this->getPageContent());
$page->setIsPublished(true);
$this->em->persist($page);
return $page;
}
private function getPageContent(): string
{
return <<<PAGE
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<title>{pagetitle}</title>
<meta name="description" content="{pagemetadescription}">
</head>
<body>
<div>
{langbar}
{sharebuttons}
</div>
<div>
{successmessage}
<div>
{segmentlist}
</div>
<div>
{categorylist}
</div>
<div>
{preferredchannel}
</div>
<div>
{channelfrequency}
</div>
<div>
{saveprefsbutton}
</div>
</div>
</body>
</html>
PAGE;
}
}

View File

@@ -0,0 +1,250 @@
<?php
declare(strict_types=1);
namespace Mautic\PageBundle\Tests\Functional\Model;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\EmailBundle\Entity\Email;
use Mautic\EmailBundle\Entity\Stat;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\PageBundle\Entity\Hit;
use Mautic\PageBundle\Entity\HitRepository;
use Mautic\PageBundle\Entity\Page;
use Mautic\PageBundle\Entity\Redirect;
use PHPUnit\Framework\Assert;
use Symfony\Component\HttpFoundation\Request;
class PageModelTest extends MauticMysqlTestCase
{
private HitRepository $pageHitRepository;
private const DO_NOT_TRACK_IP = '218.30.65.10';
private const BOT_BLOCKED_IP = '218.30.65.11';
private const IP_NOT_IN_ANY_BLOCK_LIST = '218.30.65.12';
private const IP_NOT_IN_ANY_BLOCK_LIST2 = '218.30.65.111';
private const BOT_BLOCKED_USER_AGENTS = [
'AHC/2.1',
'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6',
'Mozilla/5.0 (compatible; Codewisebot/2.0; +http://www.nosite.com/somebot.htm)',
'Mozilla/5.0 (iPhone; CPU iPhone OS 8_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B411 Safari/600.1.4 (compatible; YandexMobileBot/3.0; +http://yandex.com/bots)',
'serpstatbot/2.0 beta (advanced backlink tracking bot; http://serpstatbot.com/; abuse@serpstatbot.com)',
'Mozilla/5.0 (Linux; Android 7.0;) AppleWebKit/537.36 (KHTML, like Gecko) Mobile Safari/537.36 (compatible; AspiegelBot)',
'serpstatbot/2.1 (advanced backlink tracking bot; https://serpstatbot.com/; abuse@serpstatbot.com)',
];
protected function setUp(): void
{
$this->configParams['do_not_track_ips'] = [self::DO_NOT_TRACK_IP];
$this->configParams['bot_helper_blocked_ip_addresses'] = [self::BOT_BLOCKED_IP];
$this->configParams['bot_helper_blocked_user_agents'] = self::BOT_BLOCKED_USER_AGENTS;
$this->configParams['site_url'] = 'https://mautic-cloud.local';
parent::setUp();
$this->pageHitRepository = $this->em->getRepository(Hit::class);
$this->logoutUser();
}
public function testItRegistersPageHitsWithFieldValues(): void
{
$requestParameters = [
'page_title' => $this->generateRandomUTF8String(512),
'page_language' => $this->generateRandomUTF8String(512),
'page_url' => 'https://some.page.url/test/'.$this->generateRandomUTF8String(512),
'counter' => 0,
'timezone_offset' => -120,
'resolution' => '2560x1440',
'platform' => 'MacOs',
'do_not_track' => 'false',
'mautic_device_id' => 'some_device_id',
];
$this->client->request(Request::METHOD_POST, '/mtc/event', $requestParameters);
/** @var Hit $pageHit */
$pageHit = $this->pageHitRepository->findOneBy([]);
Assert::assertInstanceOf(Hit::class, $pageHit);
Assert::assertStringStartsWith($pageHit->getUrlTitle(), $requestParameters['page_title']);
Assert::assertStringStartsWith($pageHit->getPageLanguage(), $requestParameters['page_language']);
Assert::assertStringStartsWith($pageHit->getUrl(), $requestParameters['page_url']);
}
public function generateRandomString(int $length): string
{
return substr(bin2hex(random_bytes($length)), 0, $length);
}
public function generateRandomUTF8String(int $length): string
{
$result = '';
for ($i = 0; $i < $length; ++$i) {
$codePoint = mt_rand(0x80, 0xFFFF);
$char = \IntlChar::chr($codePoint);
if (null !== $char && \IntlChar::isprint($char)) {
$result .= $char;
} else {
--$i;
}
}
return $result;
}
#[\PHPUnit\Framework\Attributes\DataProvider('pageHitBotScenariosProvider')]
public function testItNotRegistersPageHitsFromBot(string $trackingHash, string $sentBefore, string $userAgent, string $ipAddress, bool $isHit): void
{
$lead = new Lead();
$lead->setFirstname('Test Page Hit');
$this->em->persist($lead);
$email = new Email();
$email->setName('Email A');
$email->setSubject('Email A Subject');
$this->em->persist($email);
$this->em->flush();
$emailId = $email->getId();
$clickThrough = [
'source' => ['email', $emailId],
'email' => $emailId,
'stat' => $trackingHash,
'lead' => $lead->getId(),
'channel' => [
'email' => $emailId,
],
'mtc_redirect_destination' => 'https://some.page.url/test/redirect',
];
$requestParameters = [
'page_title' => $this->generateRandomString(50),
'page_language' => $this->generateRandomString(50),
'page_url' => 'https://some.page.url/test/'.$this->generateRandomString(50),
'counter' => 0,
'timezone_offset' => -120,
'resolution' => '2560x1440',
'platform' => 'MacOs',
'do_not_track' => 'false',
'mautic_device_id' => 'some_device_id',
'ct' => base64_encode(serialize($clickThrough)),
];
// Create Email Stat
$emailStat = new Stat();
$emailStat->setEmailAddress('lukas.sykora@acquia.com');
$emailStat->setTrackingHash($trackingHash);
$emailSendTime = new \DateTime();
$emailStat->setDateSent($emailSendTime->modify($sentBefore));
$this->em->persist($emailStat);
$this->em->flush();
// Send Request
$server = [
'HTTP_USER_AGENT' => $userAgent,
'REMOTE_ADDR' => $ipAddress,
];
$this->client->request(Request::METHOD_POST, '/mtc/event', $requestParameters, [], $server);
/** @var Hit $pageHit */
$pageHit = $this->pageHitRepository->findOneBy([]);
if ($isHit) {
Assert::assertInstanceOf(Hit::class, $pageHit);
Assert::assertStringStartsWith($pageHit->getUrlTitle(), $requestParameters['page_title']);
Assert::assertStringStartsWith($pageHit->getPageLanguage(), $requestParameters['page_language']);
Assert::assertStringStartsWith($pageHit->getUrl(), $requestParameters['page_url']);
} else {
Assert::assertNull($pageHit);
}
}
/**
* @return iterable<string, array<mixed>>
*/
public static function pageHitBotScenariosProvider(): iterable
{
// $trackingHash, $sentBefore, $userAgent, $ipAddress, $isHit
yield 'All good' => ['test_hash_bot_ratio_1', '-80 second', 'Mozilla/5.0', self::IP_NOT_IN_ANY_BLOCK_LIST, true];
yield 'Time and User' => ['test_hash_bot_ratio_2', '+80 second', 'AHC/2.1', self::IP_NOT_IN_ANY_BLOCK_LIST, false];
yield 'Time and IP' => ['test_hash_bot_ratio_3', '+80 second', 'Mozilla/5.0', self::BOT_BLOCKED_IP, false];
yield 'Permanently blocked IP' => ['test_hash_bot_ratio_4', '-80 second', 'Mozilla/5.0', self::DO_NOT_TRACK_IP, false];
yield 'Bot Blocked IP address only' => ['test_hash_bot_ratio_5', '-80 second', 'Mozilla/5.0', self::BOT_BLOCKED_IP, true];
yield 'Bot Blocked User Agent only' => ['test_hash_bot_ratio_6', '-80 second', 'AHC/2.1', self::IP_NOT_IN_ANY_BLOCK_LIST, true];
yield 'Time Only' => ['test_hash_bot_ratio_7', '+80 second', 'Mozilla/5.0', self::IP_NOT_IN_ANY_BLOCK_LIST, true];
yield 'Time and Bot User Agent and Bot IP' => ['test_hash_bot_ratio_8', '+80 second', 'AHC/2.1', self::BOT_BLOCKED_IP, false];
yield 'Bot User Agent and Bot IP' => ['test_hash_bot_ratio_9', '-80 second', 'AHC/2.1', self::BOT_BLOCKED_IP, false];
yield 'Permanently blocked User Agent' => ['test_hash_bot_ratio_10', '-80 second', 'MSNBOT', self::IP_NOT_IN_ANY_BLOCK_LIST2, false];
}
#[\PHPUnit\Framework\Attributes\DataProvider('pageHitBotScenariosProvider')]
public function testRedirect(string $trackingHash, string $sentBefore, string $userAgent, string $ipAddress, bool $isHit): void
{
$lead = new Lead();
$lead->setFirstname('Test Page Hit');
$this->em->persist($lead);
$email = new Email();
$email->setName('Email A');
$email->setSubject('Email A Subject');
$this->em->persist($email);
$this->em->flush();
$page = new Page();
$page->setTitle('Page A');
$page->setAlias('page_a');
$page->setCustomHtml('Page A');
$page->setRedirectUrl('http://mautic-cloud.local/page_a');
$this->em->persist($page);
$this->em->flush();
$emailId = $email->getId();
$clickThrough = [
'source' => ['email', $emailId],
'email' => $emailId,
'stat' => $trackingHash,
'lead' => $lead->getId(),
'channel' => [
'email' => $emailId,
],
'mtc_redirect_destination' => 'http://mautic-cloud.local/page_a',
];
// Create Email Stat
$emailStat = new Stat();
$emailStat->setEmailAddress('lukas.sykora@acquia.com');
$emailStat->setTrackingHash($trackingHash);
$emailSendTime = new \DateTime();
$emailStat->setDateSent($emailSendTime->modify($sentBefore));
$this->em->persist($emailStat);
$this->em->flush();
$redirectId = 'abc';
$redirect = new Redirect();
$redirect->setRedirectId($redirectId);
$redirect->setUrl('http://mautic-cloud.local/page_a');
$this->em->persist($redirect);
$this->em->flush();
$redirectModel = $this->getContainer()->get('mautic.page.model.redirect');
$redirectURL = $redirectModel->generateRedirectUrl($redirect, $clickThrough);
// Send Request
$server = [
'HTTP_USER_AGENT' => $userAgent,
'REMOTE_ADDR' => $ipAddress,
];
$this->client->request(Request::METHOD_GET, $redirectURL, [], [], $server);
/** @var Hit $pageHit */
$pageHit = $this->pageHitRepository->findOneBy([]);
if ($isHit) {
Assert::assertInstanceOf(Hit::class, $pageHit);
Assert::assertStringStartsWith($pageHit->getUrl(), $page->getRedirectUrl());
} else {
Assert::assertNull($pageHit);
}
}
}