diff --git a/config/parameters.yml.dist b/config/parameters.yml.dist
index 628f1e45..6de7d2ef 100644
--- a/config/parameters.yml.dist
+++ b/config/parameters.yml.dist
@@ -33,8 +33,8 @@ parameters:
env(APP_POWERED_BY_PHPLIST): '0'
app.preference_page_show_private_lists: '%%env(PREFERENCEPAGE_SHOW_PRIVATE_LISTS)%%'
env(PREFERENCEPAGE_SHOW_PRIVATE_LISTS): '0'
- app.rest_api_domain: '%%env(REST_API_DOMAIN)%%'
- env(REST_API_DOMAIN): 'example.com'
+ app.rest_api_base_url: '%%env(REST_API_BASE_URL)%%'
+ env(REST_API_BASE_URL): 'https://example.com/api/v2'
# Email configuration
app.mailer_from: '%%env(MAILER_FROM)%%'
diff --git a/config/services/services.yml b/config/services/services.yml
index 5e7db66b..53a5f84d 100644
--- a/config/services/services.yml
+++ b/config/services/services.yml
@@ -53,6 +53,10 @@ services:
autoconfigure: true
public: true
+ PhpList\Core\Domain\Analytics\Service\UserMessageService:
+ autowire: true
+ autoconfigure: true
+
PhpList\Core\Domain\Messaging\Service\SendRateLimiter:
autowire: true
autoconfigure: true
diff --git a/src/Domain/Analytics/Model/UserMessageView.php b/src/Domain/Analytics/Model/UserMessageView.php
index 846c8e97..b391d3f3 100644
--- a/src/Domain/Analytics/Model/UserMessageView.php
+++ b/src/Domain/Analytics/Model/UserMessageView.php
@@ -85,6 +85,11 @@ public function setViewed(?DateTime $viewed): self
return $this;
}
+ public function setViewedNow(): self
+ {
+ return $this->setViewed(new DateTime());
+ }
+
public function setIp(?string $ip): self
{
$this->ip = $ip;
diff --git a/src/Domain/Analytics/Service/UserMessageService.php b/src/Domain/Analytics/Service/UserMessageService.php
new file mode 100644
index 00000000..c5a1cc5b
--- /dev/null
+++ b/src/Domain/Analytics/Service/UserMessageService.php
@@ -0,0 +1,56 @@
+subscriberRepository->findOneByUniqueId($uid);
+ $message = $this->messageRepository->findById($messageId);
+
+ if ($subscriber === null || $message === null) {
+ return;
+ }
+
+ $userMessage = $this->userMessageRepository->findByUserAndMessage($subscriber, $message);
+ if ($userMessage === null) {
+ return;
+ }
+
+ $userMessage->setViewedNow();
+ $message->getMetadata()->incrementViews();
+
+ $data = [];
+ foreach (['HTTP_USER_AGENT', 'HTTP_REFERER'] as $key) {
+ if (isset($metadata[$key])) {
+ $data[$key] = htmlspecialchars(strip_tags($metadata[$key]));
+ }
+ }
+
+ $userMessageView = new UserMessageView();
+ $userMessageView->setUserId($subscriber->getId());
+ $userMessageView->setMessageId($messageId);
+ $userMessageView->setViewedNow();
+ $userMessageView->setIp($metadata['client_ip'] ?? null);
+ $userMessageView->setData(serialize($data));
+
+ $this->entityManager->persist($userMessageView);
+ }
+}
diff --git a/src/Domain/Configuration/Service/Placeholder/UserTrackValueResolver.php b/src/Domain/Configuration/Service/Placeholder/UserTrackValueResolver.php
index 4983fc28..8a5b626d 100644
--- a/src/Domain/Configuration/Service/Placeholder/UserTrackValueResolver.php
+++ b/src/Domain/Configuration/Service/Placeholder/UserTrackValueResolver.php
@@ -13,7 +13,7 @@ final class UserTrackValueResolver implements PlaceholderValueResolverInterface
{
public function __construct(
private readonly ConfigProvider $config,
- #[Autowire('%rest_api_domain%')] private readonly string $restApiDomain,
+ #[Autowire('%app.rest_api_base_url%')] private readonly string $restApiBaseUrl,
) {
}
@@ -24,7 +24,7 @@ public function name(): string
public function __invoke(PlaceholderContext $ctx): string
{
- $base = $this->config->getValue(ConfigOption::Domain) ?? $this->restApiDomain;
+ $base = $this->config->getValue(ConfigOption::Domain) ?? $this->restApiBaseUrl;
if ($ctx->isText() || empty($base)) {
return '';
@@ -33,7 +33,7 @@ public function __invoke(PlaceholderContext $ctx): string
return '
';
+ $expected = '
';
// Normalize double quotes for comparison
$this->assertSame($expected, $result);
}
@@ -86,7 +86,7 @@ public function testHtmlFallsBackToRestApiDomainWhenConfigMissing(): void
$result = $resolver($ctx);
- $expected = '
';
+ $expected = '
';
$this->assertSame($expected, $result);
}
}
diff --git a/tests/Unit/Domain/Messaging/Service/ForwardingGuardTest.php b/tests/Unit/Domain/Messaging/Service/ForwardingGuardTest.php
index 8ac266f8..b1ee10b9 100644
--- a/tests/Unit/Domain/Messaging/Service/ForwardingGuardTest.php
+++ b/tests/Unit/Domain/Messaging/Service/ForwardingGuardTest.php
@@ -46,7 +46,7 @@ public function testAssertCanForwardReturnsSubscriber(): void
$subscriber = new Subscriber();
$this->subscriberRepo->method('findOneByUniqueId')->with($uid)->willReturn($subscriber);
- $this->userMessageRepo->method('findOneByUserAndMessage')->willReturn(
+ $this->userMessageRepo->method('findByUserAndMessage')->willReturn(
$this->createMock(UserMessage::class)
);
$this->forwardRepo->method('getCountByUserSince')->willReturn(1);
@@ -82,7 +82,7 @@ public function testAssertCanForwardThrowsWhenMessageNotReceived(): void
);
$this->subscriberRepo->method('findOneByUniqueId')->willReturn(new Subscriber());
- $this->userMessageRepo->method('findOneByUserAndMessage')->willReturn(null);
+ $this->userMessageRepo->method('findByUserAndMessage')->willReturn(null);
$this->expectException(MessageNotReceivedException::class);
$guard->assertCanForward('uid', $this->createMock(Message::class));
@@ -99,7 +99,7 @@ public function testAssertCanForwardThrowsWhenLimitExceeded(): void
);
$this->subscriberRepo->method('findOneByUniqueId')->willReturn(new Subscriber());
- $this->userMessageRepo->method('findOneByUserAndMessage')->willReturn($this->createMock(UserMessage::class));
+ $this->userMessageRepo->method('findByUserAndMessage')->willReturn($this->createMock(UserMessage::class));
$this->forwardRepo->method('getCountByUserSince')->willReturn(2);
$this->expectException(ForwardLimitExceededException::class);