Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions src/Domain/Analytics/Service/LinkTrackService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,10 @@

class LinkTrackService
{
private LinkTrackRepository $linkTrackRepository;
private ParameterProvider $paramProvider;

public function __construct(LinkTrackRepository $linkTrackRepository, ParameterProvider $paramProvider)
{
$this->linkTrackRepository = $linkTrackRepository;
$this->paramProvider = $paramProvider;
public function __construct(
private readonly LinkTrackRepository $linkTrackRepository,
private readonly ParameterProvider $paramProvider,
) {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

public function getUrlById(int $id): ?string
Expand Down Expand Up @@ -58,7 +55,6 @@ public function extractAndSaveLinks(MessagePrecacheDto $content, int $userId, ?i
$links = array_unique($links);

$savedLinks = [];

foreach ($links as $url) {
$existingLinkTrack = $this->linkTrackRepository->findByUrlUserIdAndMessageId($url, $userId, $messageId);
if ($existingLinkTrack !== null) {
Expand Down
5 changes: 2 additions & 3 deletions src/Domain/Identity/Service/PermissionChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpList\Core\Domain\Common\Model\Interfaces\OwnableInterface;
use PhpList\Core\Domain\Identity\Model\Administrator;
use PhpList\Core\Domain\Identity\Model\PrivilegeFlag;
use PhpList\Core\Domain\Messaging\Model\ListMessage;
use PhpList\Core\Domain\Messaging\Model\Message;
use PhpList\Core\Domain\Subscription\Model\Subscriber;
use PhpList\Core\Domain\Subscription\Model\SubscriberList;
Expand Down Expand Up @@ -70,9 +71,7 @@ private function resolveRelatedEntity(DomainModel $resource, string $relatedClas
}

if ($resource instanceof Message && $relatedClass === SubscriberList::class) {
// todo: check which one is correct
// return $resource->getListMessages()->map(fn(ListMessage $lm) => $lm->getList())->toArray();
return $resource->getListMessages()->map(fn($lm) => $lm->getSubscriberList())->toArray();
return $resource->getListMessages()->map(fn(ListMessage $lm) => $lm->getList())->toArray();
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,13 @@ private function handleEmailSending(
UserMessage $userMessage,
MessagePrecacheDto $precachedContent,
): void {
// todo: check at which point link tracking should be applied (maybe after constructing ful text?)
// todo: check at which point link tracking should be applied (maybe after constructing full text?)
$processed = $this->messagePreparator->processMessageLinks(
campaignId: $campaign->getId(),
cachedMessageDto: $precachedContent,
subscriber: $subscriber
);
$this->entityManager->flush();

try {
$result = $this->campaignEmailBuilder->buildCampaignEmail(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ class MessageFormatDto
public function __construct(
public readonly bool $htmlFormated,
public readonly string $sendFormat,
public readonly array $formatOptions,
) {
}
}
6 changes: 6 additions & 0 deletions src/Domain/Messaging/Model/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class Message implements DomainModel, Identity, ModificationDate, OwnableInterfa
#[ORM\JoinColumn(name: 'template', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')]
private ?Template $template = null;

/**
* @var Collection<int, ListMessage>
*/
#[ORM\OneToMany(targetEntity: ListMessage::class, mappedBy: 'message')]
private Collection $listMessages;

Expand Down Expand Up @@ -190,6 +193,9 @@ public function setOptions(MessageOptions $options): self
return $this;
}

/**
* @return Collection<int, ListMessage>
*/
public function getListMessages(): Collection
{
return $this->listMessages;
Expand Down
4 changes: 3 additions & 1 deletion src/Domain/Messaging/Model/Message/MessageMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ public function getStatus(): ?MessageStatus
public function setStatus(MessageStatus $status): self
{
if (!$this->getStatus()->canTransitionTo($status)) {
throw new InvalidArgumentException('Invalid status transition');
throw new InvalidArgumentException(
'Invalid status transition: ' . $this->status . ' -> ' . $status->value
);
}
$this->status = $status->value;

Expand Down
9 changes: 5 additions & 4 deletions src/Domain/Messaging/Model/Message/MessageStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ enum MessageStatus: string
public function allowedTransitions(): array
{
return match ($this) {
self::Draft, self::Suspended => [self::Submitted],
self::Submitted => [self::Prepared, self::InProcess],
self::Prepared => [self::InProcess],
self::Draft => [self::Prepared, self::Submitted],
self::Suspended => [self::Submitted, self::Requeued],
self::Submitted => [self::Prepared, self::InProcess, self::Suspended],
self::Prepared => [self::InProcess, self::Suspended],
self::InProcess => [self::Sent, self::Suspended, self::Submitted],
self::Requeued => [self::InProcess, self::Suspended],
self::Sent => [],
self::Sent => [self::Requeued],
};
}

Expand Down
33 changes: 26 additions & 7 deletions src/Domain/Messaging/Service/Manager/MessageManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,16 @@
use PhpList\Core\Domain\Messaging\Model\Dto\MessageContext;
use PhpList\Core\Domain\Messaging\Model\Dto\MessageDtoInterface;
use PhpList\Core\Domain\Messaging\Model\Message;
use PhpList\Core\Domain\Messaging\Model\Message\MessageMetadata;
use PhpList\Core\Domain\Messaging\Repository\MessageRepository;
use PhpList\Core\Domain\Messaging\Service\Builder\MessageBuilder;

class MessageManager
{
private MessageRepository $messageRepository;
private MessageBuilder $messageBuilder;

public function __construct(MessageRepository $messageRepository, MessageBuilder $messageBuilder)
{
$this->messageRepository = $messageRepository;
$this->messageBuilder = $messageBuilder;
public function __construct(
private readonly MessageRepository $messageRepository,
private readonly MessageBuilder $messageBuilder,
) {
}

public function createMessage(MessageDtoInterface $createMessageDto, Administrator $authUser): Message
Expand All @@ -31,6 +29,27 @@ public function createMessage(MessageDtoInterface $createMessageDto, Administrat
return $message;
}

public function copyAsDraftMessage(Message $message, Administrator $authUser): Message
{
$newMessage = new Message(
format: new Message\MessageFormat(
htmlFormatted: $message->getFormat()->isHtmlFormatted(),
sendFormat: $message->getFormat()->getSendFormat()
),
schedule: clone $message->getSchedule(),
metadata: new MessageMetadata(status: Message\MessageStatus::Draft),
content: clone $message->getContent(),
options: clone $message->getOptions(),
owner: $authUser,
template: $message->getTemplate(),
);
$newMessage->setUuid(bin2hex(random_bytes(18)));

$this->messageRepository->persist($newMessage);

return $newMessage;
}

public function updateMessage(
MessageDtoInterface $updateMessageDto,
Message $message,
Expand Down
2 changes: 1 addition & 1 deletion src/Domain/Messaging/Service/MessageDataLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ private function normaliseScheduleFields(array &$messageData): void
private function populateTargetLists(array &$messageData, Message $message): void
{
foreach ($message->getListMessages() as $listMessage) {
$messageData['targetlist'][$listMessage->getListId()] = 1;
$messageData['targetlist'][$listMessage->getList()->getId()] = 1;
}
}
Comment thread
TatevikGr marked this conversation as resolved.

Expand Down
2 changes: 1 addition & 1 deletion src/Domain/Messaging/Service/MessagePrecacheService.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public function precacheMessage(Message $campaign, array $loadedMessageData, ?bo
return false;
}

$messagePrecacheDto->googleTrack = $loadedMessageData['google_track'];
$messagePrecacheDto->googleTrack = (bool) $loadedMessageData['google_track'];

$this->applyBasicReplacements($messagePrecacheDto, $loadedMessageData);
$this->populateAdminAttributes($messagePrecacheDto, $campaign);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ private function createRequest(): CreateMessageDto
format: new MessageFormatDto(
htmlFormated: false,
sendFormat: 'text',
formatOptions: []
),
metadata: new MessageMetadataDto(
status: Message\MessageStatus::Draft
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ protected function setUp(): void

public function testBuildsMessageFormatSuccessfully(): void
{
$dto = new MessageFormatDto(htmlFormated: true, sendFormat: 'html', formatOptions: ['html', 'text']);
$dto = new MessageFormatDto(htmlFormated: true, sendFormat: 'html');
$messageFormat = $this->builder->build($dto);

$this->assertSame(true, $messageFormat->isHtmlFormatted());
Expand Down
47 changes: 45 additions & 2 deletions tests/Unit/Domain/Messaging/Service/Manager/MessageManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace PhpList\Core\Tests\Unit\Domain\Messaging\Service\Manager;

use DateTime;
use PhpList\Core\Domain\Identity\Model\Administrator;
use PhpList\Core\Domain\Messaging\Model\Dto\CreateMessageDto;
use PhpList\Core\Domain\Messaging\Model\Dto\Message\MessageContentDto;
Expand All @@ -13,6 +14,10 @@
use PhpList\Core\Domain\Messaging\Model\Dto\Message\MessageScheduleDto;
use PhpList\Core\Domain\Messaging\Model\Dto\UpdateMessageDto;
use PhpList\Core\Domain\Messaging\Model\Message;
use PhpList\Core\Domain\Messaging\Model\Message\MessageFormat;
use PhpList\Core\Domain\Messaging\Model\Message\MessageMetadata;
use PhpList\Core\Domain\Messaging\Model\Message\MessageOptions;
use PhpList\Core\Domain\Messaging\Model\Message\MessageSchedule;
use PhpList\Core\Domain\Messaging\Model\Message\MessageContent;
use PhpList\Core\Domain\Messaging\Repository\MessageRepository;
use PhpList\Core\Domain\Messaging\Service\Builder\MessageBuilder;
Expand All @@ -21,13 +26,51 @@

class MessageManagerTest extends TestCase
{
public function testCopyAsDraftMessagePersistsClonedDraftMessage(): void
{
$messageRepository = $this->createMock(MessageRepository::class);
$messageBuilder = $this->createMock(MessageBuilder::class);
$manager = new MessageManager($messageRepository, $messageBuilder);

$message = new Message(
format: new MessageFormat(true, 'html'),
schedule: new MessageSchedule(
repeatInterval: 0,
repeatUntil: null,
requeueInterval: 0,
requeueUntil: null,
embargo: new DateTime('2025-04-17T09:00:00+00:00')
),
metadata: new MessageMetadata(Message\MessageStatus::Submitted),
content: new MessageContent('Subject', 'Full text', 'Short text', 'Footer'),
options: new MessageOptions('from@example.com', 'to@example.com', 'reply@example.com', 'all-users'),
owner: null
);

$messageRepository->expects($this->once())
->method('persist')
->with($this->callback(function (Message $persistedMessage) use ($message): bool {
$this->assertNotSame($message, $persistedMessage);
$this->assertSame(Message\MessageStatus::Draft, $persistedMessage->getMetadata()->getStatus());
$this->assertTrue($persistedMessage->getFormat()->isHtmlFormatted());
$this->assertSame('html', $persistedMessage->getFormat()->getSendFormat());

return true;
}));

$result = $manager->copyAsDraftMessage($message, $this->createMock(Administrator::class));

$this->assertSame(Message\MessageStatus::Draft, $result->getMetadata()->getStatus());
$this->assertNotSame($message, $result);
}

public function testCreateMessageReturnsPersistedMessage(): void
{
$messageRepository = $this->createMock(MessageRepository::class);
$messageBuilder = $this->createMock(MessageBuilder::class);
$manager = new MessageManager($messageRepository, $messageBuilder);

$format = new MessageFormatDto(true, 'html', ['html']);
$format = new MessageFormatDto(true, 'html');
$schedule = new MessageScheduleDto(
embargo: '2025-04-17T09:00:00+00:00',
repeatInterval: 60 * 24,
Expand Down Expand Up @@ -81,7 +124,7 @@ public function testUpdateMessageReturnsUpdatedMessage(): void
$messageBuilder = $this->createMock(MessageBuilder::class);
$manager = new MessageManager($messageRepository, $messageBuilder);

$format = new MessageFormatDto(false, 'text', ['text']);
$format = new MessageFormatDto(false, 'text');
$schedule = new MessageScheduleDto(
embargo: '2025-04-17T09:00:00+00:00',
repeatInterval: 0,
Expand Down
18 changes: 8 additions & 10 deletions tests/Unit/Domain/Messaging/Service/MessageDataLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
use Doctrine\Common\Collections\ArrayCollection;
use PhpList\Core\Domain\Configuration\Model\ConfigOption;
use PhpList\Core\Domain\Configuration\Service\Provider\ConfigProvider;
use PhpList\Core\Domain\Messaging\Model\ListMessage;
use PhpList\Core\Domain\Messaging\Model\Message;
use PhpList\Core\Domain\Messaging\Model\MessageData;
use PhpList\Core\Domain\Messaging\Repository\MessageDataRepository;
use PhpList\Core\Domain\Messaging\Repository\MessageRepository;
use PhpList\Core\Domain\Messaging\Service\MessageDataLoader;
use PhpList\Core\Domain\Subscription\Model\SubscriberList;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
Expand Down Expand Up @@ -61,6 +63,11 @@ public function testLoadsMessageDataMergesAndParses(): void
$md2 = (new MessageData())->setId($messageId)->setName('criteria_match')->setData('any');
$md3 = (new MessageData())->setId($messageId)->setName('embargo')->setData('string');

$listMock = $this->createMock(SubscriberList::class);
$listMock->method('getId')->willReturn(42);
$listMessageMock = $this->createMock(ListMessage::class);
$listMessageMock->method('getList')->willReturn($listMock);

$this->messageDataRepository
->method('getForMessage')
->with($messageId)
Expand All @@ -69,16 +76,7 @@ public function testLoadsMessageDataMergesAndParses(): void
// Use a Message mock instead of an anonymous stub
$message = $this->createMock(Message::class);
$message->method('getId')->willReturn($messageId);
$message->method('getListMessages')->willReturn(
new ArrayCollection([
new class {
public function getListId(): int
{
return 42;
}
},
])
);
$message->method('getListMessages')->willReturn(new ArrayCollection([$listMessageMock]));

$loader = new MessageDataLoader(
configProvider: $this->config,
Expand Down
Loading