From b69a60365eb961b969ba3ee699624761433495f6 Mon Sep 17 00:00:00 2001 From: Patryk Gruszka Date: Thu, 27 Jul 2023 12:53:14 +0200 Subject: [PATCH 01/41] fix: [DPMMA-1079] URL hit point action fixed --- .../PageBundle/Entity/HitRepository.php | 4 +- .../PageBundle/Helper/PointActionHelper.php | 13 +- .../Tests/Helper/PointActionHelperTest.php | 267 ++++++++++++++++++ 3 files changed, 279 insertions(+), 5 deletions(-) create mode 100644 app/bundles/PageBundle/Tests/Helper/PointActionHelperTest.php diff --git a/app/bundles/PageBundle/Entity/HitRepository.php b/app/bundles/PageBundle/Entity/HitRepository.php index 9c93b1864cd..ed27ac44492 100644 --- a/app/bundles/PageBundle/Entity/HitRepository.php +++ b/app/bundles/PageBundle/Entity/HitRepository.php @@ -217,7 +217,7 @@ public function countVisitors($seconds = 60, $notLeft = false): int * * @param array $options */ - public function getLatestHit($options): \DateTime + public function getLatestHit($options): ?\DateTime { $sq = $this->_em->getConnection()->createQueryBuilder(); $sq->select('h.date_hit latest_hit') @@ -242,7 +242,7 @@ public function getLatestHit($options): \DateTime } $result = $sq->executeQuery()->fetchAssociative(); - return new \DateTime($result['latest_hit'], new \DateTimeZone('UTC')); + return $result ? new \DateTime($result['latest_hit'], new \DateTimeZone('UTC')) : null; } /** diff --git a/app/bundles/PageBundle/Helper/PointActionHelper.php b/app/bundles/PageBundle/Helper/PointActionHelper.php index 4ff9cc117ce..722cc7bf073 100644 --- a/app/bundles/PageBundle/Helper/PointActionHelper.php +++ b/app/bundles/PageBundle/Helper/PointActionHelper.php @@ -3,6 +3,7 @@ namespace Mautic\PageBundle\Helper; use Mautic\CoreBundle\Factory\MauticFactory; +use Mautic\PageBundle\Entity\Hit; use Mautic\PageBundle\Entity\Page; class PointActionHelper @@ -64,7 +65,13 @@ public static function validateUrlHit($factory, $eventDetails, $action): bool } } $now = new \DateTime(); - $latestHit = $hitRepository->getLatestHit(['leadId' => $lead->getId(), $urlWithSqlWC, 'second_to_last' => $eventDetails->getId()]); + + if ($action['properties']['returns_within'] || $action['properties']['returns_after']) { + // get the latest hit only when it's needed + $latestHit = $hitRepository->getLatestHit(['leadId' => $lead->getId(), $urlWithSqlWC, 'second_to_last' => $eventDetails->getId()]); + } else { + $latestHit = null; + } if ($action['properties']['accumulative_time']) { if (!isset($hitStats)) { @@ -92,14 +99,14 @@ public static function validateUrlHit($factory, $eventDetails, $action): bool } } if ($action['properties']['returns_within']) { - if ($now->getTimestamp() - $latestHit->getTimestamp() <= $action['properties']['returns_within']) { + if ($latestHit && $now->getTimestamp() - $latestHit->getTimestamp() <= $action['properties']['returns_within']) { $changePoints['returns_within'] = true; } else { $changePoints['returns_within'] = false; } } if ($action['properties']['returns_after']) { - if ($now->getTimestamp() - $latestHit->getTimestamp() >= $action['properties']['returns_after']) { + if ($latestHit && $now->getTimestamp() - $latestHit->getTimestamp() >= $action['properties']['returns_after']) { $changePoints['returns_after'] = true; } else { $changePoints['returns_after'] = false; diff --git a/app/bundles/PageBundle/Tests/Helper/PointActionHelperTest.php b/app/bundles/PageBundle/Tests/Helper/PointActionHelperTest.php new file mode 100644 index 00000000000..ac56f24fb9b --- /dev/null +++ b/app/bundles/PageBundle/Tests/Helper/PointActionHelperTest.php @@ -0,0 +1,267 @@ +createMock(MauticFactory::class); + $entityManager = $this->createMock(EntityManagerInterface::class); + $lead = $this->createMock(Lead::class); + $eventDetails = $this->createMock(Hit::class); + $eventDetails->method('getUrl')->willReturn('http://localhost:7000/ppk'); + + // Set the action properties for the test scenario + $action = [ + 'id' => 2, + 'type' => 'url.hit', + 'name' => 'Hit page', + 'properties' => [ + 'page_url' => 'http://localhost:7000/ppk', + 'page_hits' => 1, + 'accumulative_time_unit' => 'H', + 'accumulative_time' => 0, + 'returns_within_unit' => 'H', + 'returns_within' => 0, + 'returns_after_unit' => 'H', + 'returns_after' => 0, + ], + 'points' => 5, + ]; + + // Set up the mocks + $factory->method('getEntityManager')->willReturn($entityManager); + $eventDetails->method('getLead')->willReturn($lead); + + // Mock the HitRepository and configure the getDwellTimesForUrl method to return the desired array + $hitRepository = $this->createMock(HitRepository::class); + $hitRepository->method('getDwellTimesForUrl')->willReturn([ + 'sum' => 0, + 'min' => 0, + 'max' => 0, + 'average' => 0.0, + 'count' => 1, + ]); + $entityManager->method('getRepository')->willReturn($hitRepository); + + // Getting the latest Hit is not needed for this action + $hitRepository->expects($this->never())->method('getLatestHit'); + + // Test the method + $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); + + // Assert the result is true as the URL matches the pattern and meets the conditions for the first hit + $this->assertTrue($result); + } + + public function testValidateUrlReturnWithinAction(): void + { + // Mock the required objects + $factory = $this->createMock(MauticFactory::class); + $entityManager = $this->createMock(EntityManagerInterface::class); + $lead = $this->createMock(Lead::class); + $eventDetails = $this->createMock(Hit::class); + $eventDetails->method('getUrl')->willReturn('https://example.com/test/'); + + // Set the action properties for the test scenario + $action = [ + 'id' => 1, + 'type' => 'url.hit', + 'name' => 'Test return within', + 'properties' => [ + 'page_url' => 'https://example.com/test/', + 'page_hits' => null, + 'accumulative_time_unit' => 'H', + 'accumulative_time' => 0, + 'returns_within_unit' => 'H', + 'returns_within' => 14400, // 4 hours in seconds + 'returns_after_unit' => 'H', + 'returns_after' => 0, + ], + 'points' => 3, + ]; + + // Set up the mocks + $factory->method('getEntityManager')->willReturn($entityManager); + $eventDetails->method('getLead')->willReturn($lead); + + $hitRepository = $this->createMock(HitRepository::class); + + // Mock the getLatestHit method to return the current time minus 3 hours + $currentTimestamp = time(); + $threeHoursAgoTimestamp = $currentTimestamp - (3 * 3600); + $latestHit = new \DateTime(); + $latestHit->setTimestamp($threeHoursAgoTimestamp); + $hitRepository->method('getLatestHit')->willReturn($latestHit); + + $entityManager->method('getRepository')->willReturn($hitRepository); + + // Test the method + $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); + + // Assert the result is true as the URL matches the pattern and meets the "returns_within" condition + $this->assertTrue($result); + } + + public function testValidateUrlReturnWithinActionWhenNoLastHitFound(): void + { + // Mock the required objects + $factory = $this->createMock(MauticFactory::class); + $entityManager = $this->createMock(EntityManagerInterface::class); + $lead = $this->createMock(Lead::class); + $eventDetails = $this->createMock(Hit::class); + $eventDetails->method('getUrl')->willReturn('https://example.com/test/'); + + // Set the action properties for the test scenario + $action = [ + 'id' => 1, + 'type' => 'url.hit', + 'name' => 'Test return within when no last hit found', + 'properties' => [ + 'page_url' => 'https://example.com/test/', + 'page_hits' => null, + 'accumulative_time_unit' => 'H', + 'accumulative_time' => 0, + 'returns_within_unit' => 'H', + 'returns_within' => 14400, // 4 hours in seconds + 'returns_after_unit' => 'H', + 'returns_after' => 0, + ], + 'points' => 3, + ]; + + // Set up the mocks + $factory->method('getEntityManager')->willReturn($entityManager); + $eventDetails->method('getLead')->willReturn($lead); + $hitRepository = $this->createMock(HitRepository::class); + $hitRepository->method('getLatestHit')->willReturn(null); + $entityManager->method('getRepository')->willReturn($hitRepository); + + $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); + + // Assert the result is false as this was the first URL hit + $this->assertFalse($result); + } + + public function testValidateUrlAccumulativeTimeAction(): void + { + // Mock the required objects + $factory = $this->createMock(MauticFactory::class); + $entityManager = $this->createMock(EntityManagerInterface::class); + $lead = $this->createMock(Lead::class); + $eventDetails = $this->createMock(Hit::class); + $eventDetails->method('getUrl')->willReturn('http://localhost:7000/ppk/'); + + // Set the action properties for the test scenario + $action = [ + 'id' => 1, + 'type' => 'url.hit', + 'name' => 'Test accumulative time', + 'properties' => [ + 'page_url' => 'http://localhost:7000/ppk/', + 'page_hits' => null, + 'accumulative_time_unit' => 'H', + 'accumulative_time' => 7200, // 2 hours in seconds + 'returns_within_unit' => 'H', + 'returns_within' => 0, + 'returns_after_unit' => 'H', + 'returns_after' => 0, + ], + 'points' => 3, + ]; + + // Set up the mocks + $factory->method('getEntityManager')->willReturn($entityManager); + $eventDetails->method('getLead')->willReturn($lead); + + // Mock the HitRepository and configure the getDwellTimesForUrl method to return the desired array + $hitRepository = $this->createMock(HitRepository::class); + $hitRepository->method('getDwellTimesForUrl')->willReturn([ + 'sum' => 14400, // 4 hours in seconds + 'min' => 3600, // 1 hour in seconds + 'max' => 7200, // 2 hours in seconds + 'average' => 3600.0, // 1 hour in seconds + 'count' => 4, // 4 hits recorded + ]); + + // Getting the latest Hit is not needed for this action + $hitRepository->expects($this->never())->method('getLatestHit'); + + $entityManager->method('getRepository')->willReturn($hitRepository); + + // Test the method + $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); + + // Assert the result is true as the accumulated time exceeds the specified threshold + $this->assertTrue($result); + } + + public function testValidateUrlReturnsAfterAction(): void + { + // Mock the required objects + $factory = $this->createMock(MauticFactory::class); + $entityManager = $this->createMock(EntityManagerInterface::class); + $lead = $this->createMock(Lead::class); + $eventDetails = $this->createMock(Hit::class); + $eventDetails->method('getUrl')->willReturn('http://localhost:7000/ppk/'); + + // Set the action properties for the test scenario + $action = [ + 'id' => 1, + 'type' => 'url.hit', + 'name' => 'Test returns after', + 'properties' => [ + 'page_url' => 'http://localhost:7000/ppk/', + 'page_hits' => null, + 'accumulative_time_unit' => 'H', + 'accumulative_time' => 0, + 'returns_within_unit' => 'H', + 'returns_within' => 0, + 'returns_after_unit' => 'H', + 'returns_after' => 7200, // 2 hours in seconds + ], + 'points' => 3, + ]; + + // Set up the mocks + $factory->method('getEntityManager')->willReturn($entityManager); + $eventDetails->method('getLead')->willReturn($lead); + + // Mock the HitRepository and configure the getDwellTimesForUrl method to return the desired array + $hitRepository = $this->createMock(HitRepository::class); + $hitRepository->method('getDwellTimesForUrl')->willReturn([ + 'sum' => 0, + 'min' => 0, + 'max' => 0, + 'average' => 0.0, + 'count' => 1, // Only one hit recorded + ]); + + // Mock the getLatestHit method to return a DateTime object representing 3 hours ago + $currentTimestamp = time(); + $threeHoursAgoTimestamp = $currentTimestamp - (3 * 3600); + $latestHit = new \DateTime(); + $latestHit->setTimestamp($threeHoursAgoTimestamp); + $hitRepository->method('getLatestHit')->willReturn($latestHit); + + $entityManager->method('getRepository')->willReturn($hitRepository); + + // Test the method + $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); + + // Assert the result is true as the time elapsed since the last hit exceeds the specified threshold + $this->assertTrue($result); + } +} From c10f05cab7ac542619b2dc7f63ccff19e03742d6 Mon Sep 17 00:00:00 2001 From: Patryk Gruszka Date: Thu, 27 Jul 2023 14:10:12 +0200 Subject: [PATCH 02/41] fix: [DPMMA-1079] additional tests and refactor --- .../Tests/Helper/PointActionHelperTest.php | 366 +++++++----------- 1 file changed, 149 insertions(+), 217 deletions(-) diff --git a/app/bundles/PageBundle/Tests/Helper/PointActionHelperTest.php b/app/bundles/PageBundle/Tests/Helper/PointActionHelperTest.php index ac56f24fb9b..6379bc81e7a 100644 --- a/app/bundles/PageBundle/Tests/Helper/PointActionHelperTest.php +++ b/app/bundles/PageBundle/Tests/Helper/PointActionHelperTest.php @@ -10,258 +10,190 @@ use Mautic\PageBundle\Entity\Hit; use Mautic\PageBundle\Entity\HitRepository; use Mautic\PageBundle\Helper\PointActionHelper; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class PointActionHelperTest extends TestCase { - public function testValidateUrlPageHitsAction(): void + /** + * @var MockObject|MauticFactory + */ + private $factory; + + /** + * @var MockObject|EntityManagerInterface + */ + private $entityManager; + + /** + * @var MockObject|HitRepository + */ + private $hitRepository; + + /** + * @var MockObject|Lead + */ + private $lead; + + /** + * @var MockObject|Hit + */ + private $eventDetails; + + protected function setUp(): void { - // Mock the required objects - $factory = $this->createMock(MauticFactory::class); - $entityManager = $this->createMock(EntityManagerInterface::class); - $lead = $this->createMock(Lead::class); - $eventDetails = $this->createMock(Hit::class); - $eventDetails->method('getUrl')->willReturn('http://localhost:7000/ppk'); - - // Set the action properties for the test scenario - $action = [ - 'id' => 2, - 'type' => 'url.hit', - 'name' => 'Hit page', - 'properties' => [ - 'page_url' => 'http://localhost:7000/ppk', - 'page_hits' => 1, - 'accumulative_time_unit' => 'H', - 'accumulative_time' => 0, - 'returns_within_unit' => 'H', - 'returns_within' => 0, - 'returns_after_unit' => 'H', - 'returns_after' => 0, - ], - 'points' => 5, - ]; - - // Set up the mocks - $factory->method('getEntityManager')->willReturn($entityManager); - $eventDetails->method('getLead')->willReturn($lead); + /** @phpstan-ignore-next-line */ + $this->factory = $this->createMock(MauticFactory::class); + $this->entityManager = $this->createMock(EntityManagerInterface::class); + $this->hitRepository = $this->createMock(HitRepository::class); + $this->lead = $this->createMock(Lead::class); + $this->eventDetails = $this->createMock(Hit::class); + + $this->factory->method('getEntityManager')->willReturn($this->entityManager); + $this->eventDetails->method('getLead')->willReturn($this->lead); + $this->entityManager->method('getRepository')->willReturn($this->hitRepository); + } - // Mock the HitRepository and configure the getDwellTimesForUrl method to return the desired array - $hitRepository = $this->createMock(HitRepository::class); - $hitRepository->method('getDwellTimesForUrl')->willReturn([ + /** + * @param array $action + * + * @dataProvider urlHitsActionDataProvider + */ + public function testValidateUrlPageHitsAction(array $action, bool $expectedResult): void + { + $this->eventDetails->method('getUrl')->willReturn('https://example.com/ppk'); + $this->hitRepository->method('getDwellTimesForUrl')->willReturn([ 'sum' => 0, 'min' => 0, 'max' => 0, 'average' => 0.0, 'count' => 1, ]); - $entityManager->method('getRepository')->willReturn($hitRepository); - - // Getting the latest Hit is not needed for this action - $hitRepository->expects($this->never())->method('getLatestHit'); + $this->hitRepository->expects($this->never())->method('getLatestHit'); - // Test the method - $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); + $result = PointActionHelper::validateUrlHit($this->factory, $this->eventDetails, $action); - // Assert the result is true as the URL matches the pattern and meets the conditions for the first hit - $this->assertTrue($result); + $this->assertSame($expectedResult, $result); } - public function testValidateUrlReturnWithinAction(): void + /** + * @return array> + */ + public function urlHitsActionDataProvider(): array { - // Mock the required objects - $factory = $this->createMock(MauticFactory::class); - $entityManager = $this->createMock(EntityManagerInterface::class); - $lead = $this->createMock(Lead::class); - $eventDetails = $this->createMock(Hit::class); - $eventDetails->method('getUrl')->willReturn('https://example.com/test/'); - - // Set the action properties for the test scenario - $action = [ - 'id' => 1, - 'type' => 'url.hit', - 'name' => 'Test return within', - 'properties' => [ - 'page_url' => 'https://example.com/test/', - 'page_hits' => null, - 'accumulative_time_unit' => 'H', - 'accumulative_time' => 0, - 'returns_within_unit' => 'H', - 'returns_within' => 14400, // 4 hours in seconds - 'returns_after_unit' => 'H', - 'returns_after' => 0, + return [ + 'url_matches_first_hit' => [ + [ + 'id' => 2, + 'type' => 'url.hit', + 'name' => 'Hit page', + 'properties' => [ + 'page_url' => 'https://example.com/ppk', + 'page_hits' => 1, + 'accumulative_time_unit' => 'H', + 'accumulative_time' => 0, + 'returns_within_unit' => 'H', + 'returns_within' => 0, + 'returns_after_unit' => 'H', + 'returns_after' => 0, + ], + 'points' => 5, + ], + true, ], - 'points' => 3, - ]; - - // Set up the mocks - $factory->method('getEntityManager')->willReturn($entityManager); - $eventDetails->method('getLead')->willReturn($lead); - - $hitRepository = $this->createMock(HitRepository::class); - - // Mock the getLatestHit method to return the current time minus 3 hours - $currentTimestamp = time(); - $threeHoursAgoTimestamp = $currentTimestamp - (3 * 3600); - $latestHit = new \DateTime(); - $latestHit->setTimestamp($threeHoursAgoTimestamp); - $hitRepository->method('getLatestHit')->willReturn($latestHit); - - $entityManager->method('getRepository')->willReturn($hitRepository); - - // Test the method - $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); - - // Assert the result is true as the URL matches the pattern and meets the "returns_within" condition - $this->assertTrue($result); - } - - public function testValidateUrlReturnWithinActionWhenNoLastHitFound(): void - { - // Mock the required objects - $factory = $this->createMock(MauticFactory::class); - $entityManager = $this->createMock(EntityManagerInterface::class); - $lead = $this->createMock(Lead::class); - $eventDetails = $this->createMock(Hit::class); - $eventDetails->method('getUrl')->willReturn('https://example.com/test/'); - - // Set the action properties for the test scenario - $action = [ - 'id' => 1, - 'type' => 'url.hit', - 'name' => 'Test return within when no last hit found', - 'properties' => [ - 'page_url' => 'https://example.com/test/', - 'page_hits' => null, - 'accumulative_time_unit' => 'H', - 'accumulative_time' => 0, - 'returns_within_unit' => 'H', - 'returns_within' => 14400, // 4 hours in seconds - 'returns_after_unit' => 'H', - 'returns_after' => 0, - ], - 'points' => 3, - ]; - - // Set up the mocks - $factory->method('getEntityManager')->willReturn($entityManager); - $eventDetails->method('getLead')->willReturn($lead); - $hitRepository = $this->createMock(HitRepository::class); - $hitRepository->method('getLatestHit')->willReturn(null); - $entityManager->method('getRepository')->willReturn($hitRepository); - - $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); - - // Assert the result is false as this was the first URL hit - $this->assertFalse($result); - } - - public function testValidateUrlAccumulativeTimeAction(): void - { - // Mock the required objects - $factory = $this->createMock(MauticFactory::class); - $entityManager = $this->createMock(EntityManagerInterface::class); - $lead = $this->createMock(Lead::class); - $eventDetails = $this->createMock(Hit::class); - $eventDetails->method('getUrl')->willReturn('http://localhost:7000/ppk/'); - - // Set the action properties for the test scenario - $action = [ - 'id' => 1, - 'type' => 'url.hit', - 'name' => 'Test accumulative time', - 'properties' => [ - 'page_url' => 'http://localhost:7000/ppk/', - 'page_hits' => null, - 'accumulative_time_unit' => 'H', - 'accumulative_time' => 7200, // 2 hours in seconds - 'returns_within_unit' => 'H', - 'returns_within' => 0, - 'returns_after_unit' => 'H', - 'returns_after' => 0, + 'url_does_not_match' => [ + [ + 'id' => 3, + 'type' => 'url.hit', + 'name' => 'Invalid URL', + 'properties' => [ + 'page_url' => 'https://example.com/invalid', + 'page_hits' => 1, + 'accumulative_time_unit' => 'H', + 'accumulative_time' => 0, + 'returns_within_unit' => 'H', + 'returns_within' => 0, + 'returns_after_unit' => 'H', + 'returns_after' => 0, + ], + 'points' => 5, + ], + false, ], - 'points' => 3, ]; - - // Set up the mocks - $factory->method('getEntityManager')->willReturn($entityManager); - $eventDetails->method('getLead')->willReturn($lead); - - // Mock the HitRepository and configure the getDwellTimesForUrl method to return the desired array - $hitRepository = $this->createMock(HitRepository::class); - $hitRepository->method('getDwellTimesForUrl')->willReturn([ - 'sum' => 14400, // 4 hours in seconds - 'min' => 3600, // 1 hour in seconds - 'max' => 7200, // 2 hours in seconds - 'average' => 3600.0, // 1 hour in seconds - 'count' => 4, // 4 hits recorded - ]); - - // Getting the latest Hit is not needed for this action - $hitRepository->expects($this->never())->method('getLatestHit'); - - $entityManager->method('getRepository')->willReturn($hitRepository); - - // Test the method - $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); - - // Assert the result is true as the accumulated time exceeds the specified threshold - $this->assertTrue($result); } - public function testValidateUrlReturnsAfterAction(): void + /** + * @param array $action + * + * @dataProvider returnWithinActionDataProvider + */ + public function testValidateUrlReturnWithinAction(array $action, bool $expectedResult): void { - // Mock the required objects - $factory = $this->createMock(MauticFactory::class); - $entityManager = $this->createMock(EntityManagerInterface::class); - $lead = $this->createMock(Lead::class); - $eventDetails = $this->createMock(Hit::class); - $eventDetails->method('getUrl')->willReturn('http://localhost:7000/ppk/'); - - // Set the action properties for the test scenario - $action = [ - 'id' => 1, - 'type' => 'url.hit', - 'name' => 'Test returns after', - 'properties' => [ - 'page_url' => 'http://localhost:7000/ppk/', - 'page_hits' => null, - 'accumulative_time_unit' => 'H', - 'accumulative_time' => 0, - 'returns_within_unit' => 'H', - 'returns_within' => 0, - 'returns_after_unit' => 'H', - 'returns_after' => 7200, // 2 hours in seconds - ], - 'points' => 3, - ]; - - // Set up the mocks - $factory->method('getEntityManager')->willReturn($entityManager); - $eventDetails->method('getLead')->willReturn($lead); - - // Mock the HitRepository and configure the getDwellTimesForUrl method to return the desired array - $hitRepository = $this->createMock(HitRepository::class); - $hitRepository->method('getDwellTimesForUrl')->willReturn([ + $this->eventDetails->method('getUrl')->willReturn('https://example.com/test/'); + $this->hitRepository->method('getDwellTimesForUrl')->willReturn([ 'sum' => 0, 'min' => 0, 'max' => 0, 'average' => 0.0, - 'count' => 1, // Only one hit recorded + 'count' => 1, ]); - // Mock the getLatestHit method to return a DateTime object representing 3 hours ago $currentTimestamp = time(); $threeHoursAgoTimestamp = $currentTimestamp - (3 * 3600); $latestHit = new \DateTime(); $latestHit->setTimestamp($threeHoursAgoTimestamp); - $hitRepository->method('getLatestHit')->willReturn($latestHit); + $this->hitRepository->method('getLatestHit')->willReturn($latestHit); - $entityManager->method('getRepository')->willReturn($hitRepository); + $result = PointActionHelper::validateUrlHit($this->factory, $this->eventDetails, $action); - // Test the method - $result = PointActionHelper::validateUrlHit($factory, $eventDetails, $action); + $this->assertSame($expectedResult, $result); + } - // Assert the result is true as the time elapsed since the last hit exceeds the specified threshold - $this->assertTrue($result); + /** + * @return array> + */ + public function returnWithinActionDataProvider(): array + { + return [ + 'valid_return_within' => [ + [ + 'id' => 1, + 'type' => 'url.hit', + 'name' => 'Test return within', + 'properties' => [ + 'page_url' => 'https://example.com/test/', + 'page_hits' => null, + 'accumulative_time_unit' => 'H', + 'accumulative_time' => 0, + 'returns_within_unit' => 'H', + 'returns_within' => 14400, // 4 hours in seconds + 'returns_after_unit' => 'H', + 'returns_after' => 0, + ], + 'points' => 3, + ], + true, + ], + 'invalid_return_within' => [ + [ + 'id' => 4, + 'type' => 'url.hit', + 'name' => 'Invalid Return Within', + 'properties' => [ + 'page_url' => 'https://example.com/test/', + 'page_hits' => null, + 'accumulative_time_unit' => 'H', + 'accumulative_time' => 0, + 'returns_within_unit' => 'H', + 'returns_within' => 3600, // 1 hour in seconds + 'returns_after_unit' => 'H', + 'returns_after' => 0, + ], + 'points' => 3, + ], + false, + ], + ]; } } From 8499c5bb5bb85dc06ae37cdbc8a114a840fe6bff Mon Sep 17 00:00:00 2001 From: Zdeno Kuzmany Date: Fri, 19 Jan 2024 09:30:32 +0100 Subject: [PATCH 03/41] Fix replace entity with reference for detached lists --- app/bundles/LeadBundle/Model/ListModel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/bundles/LeadBundle/Model/ListModel.php b/app/bundles/LeadBundle/Model/ListModel.php index f568496f0ff..8c79b8eadd5 100644 --- a/app/bundles/LeadBundle/Model/ListModel.php +++ b/app/bundles/LeadBundle/Model/ListModel.php @@ -614,7 +614,7 @@ public function addLead($lead, $lists, $manuallyAdded = false, $batchProcess = f } } else { $listLead = new ListLead(); - $listLead->setList($this->leadChangeLists[$listId]); + $listLead->setList($this->em->getReference(LeadList::class, $listId)); $listLead->setLead($lead); $listLead->setManuallyAdded($manuallyAdded); $listLead->setDateAdded($dateManipulated); From 8452c15cebcd9636148d708c3bba01ddfef05129 Mon Sep 17 00:00:00 2001 From: Zdeno Kuzmany Date: Fri, 19 Jan 2024 10:25:21 +0100 Subject: [PATCH 04/41] Update preview form script source path for dev enviroment --- .../FormBundle/Resources/views/Builder/_script.html.twig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/bundles/FormBundle/Resources/views/Builder/_script.html.twig b/app/bundles/FormBundle/Resources/views/Builder/_script.html.twig index 5a34ea5e255..1561e41e182 100644 --- a/app/bundles/FormBundle/Resources/views/Builder/_script.html.twig +++ b/app/bundles/FormBundle/Resources/views/Builder/_script.html.twig @@ -1,6 +1,8 @@ -{% set scriptSrc = getAssetUrl('media/js/' ~ ('dev' == app.environment ? 'mautic-form-src.js' : 'mautic-form.js'), null, null, true)|replace({ - '/index.php': '' +{% set src = 'dev' == app.environment ? 'app/assets/js/mautic-form-src.js' : 'media/js/mautic-form.js' %} +{% set scriptSrc = getAssetUrl(src, null, null, true)|replace({ + '/index.php': '' }) %} +