diff --git a/.gitignore b/.gitignore index 7d89a98..7be8ae8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ /.project frosh-platform-mail-archive.css frosh-platform-mail-archive.js +/vendor/ +/src/Resources/public/ +/composer.lock diff --git a/src/Content/MailArchive/MailArchiveDefinition.php b/src/Content/MailArchive/MailArchiveDefinition.php index 450409b..7c0a725 100644 --- a/src/Content/MailArchive/MailArchiveDefinition.php +++ b/src/Content/MailArchive/MailArchiveDefinition.php @@ -46,6 +46,7 @@ protected function defineFields(): FieldCollection (new LongTextField('htmlText', 'htmlText'))->addFlags(new AllowHtml(), new SearchRanking(SearchRanking::LOW_SEARCH_RANKING)), (new LongTextField('eml', 'eml'))->addFlags(new AllowHtml()), (new StringField('eml_path', 'emlPath', 2048)), + (new StringField('transport_state', 'transportState'))->addFlags(new Required()), (new OneToManyAssociationField('attachments', MailArchiveAttachmentDefinition::class, 'mail_archive_id', 'id'))->addFlags(new CascadeDelete()), @@ -54,6 +55,9 @@ protected function defineFields(): FieldCollection new FkField('customerId', 'customerId', CustomerDefinition::class), new ManyToOneAssociationField('customer', 'customerId', CustomerDefinition::class, 'id', true), + + new FkField('source_mail_id', 'sourceMailId', self::class), + new ManyToOneAssociationField('sourceMail', 'source_mail_id', self::class, 'id', false), ]); } } diff --git a/src/Content/MailArchive/MailArchiveEntity.php b/src/Content/MailArchive/MailArchiveEntity.php index 531fb62..854aec2 100644 --- a/src/Content/MailArchive/MailArchiveEntity.php +++ b/src/Content/MailArchive/MailArchiveEntity.php @@ -24,6 +24,8 @@ class MailArchiveEntity extends Entity protected ?string $htmlText; + protected ?string $transportState; + /** * @deprecated will not be filled anyone. Use emlPath instead */ @@ -42,6 +44,11 @@ class MailArchiveEntity extends Entity /** @var EntityCollection|null $attachments */ protected ?EntityCollection $attachments = null; + protected ?string $sourceMailId; + + protected ?MailArchiveEntity $sourceMail; + + /** * @return array */ @@ -185,4 +192,35 @@ public function setAttachments(EntityCollection $attachments): void { $this->attachments = $attachments; } + + public function getSourceMailId(): ?string + { + return $this->sourceMailId; + } + + public function setSourceMailId(?string $sourceMailId): void + { + $this->sourceMailId = $sourceMailId; + } + + public function getSourceMail(): ?MailArchiveEntity + { + return $this->sourceMail; + } + + public function setSourceMail(?MailArchiveEntity $sourceMail): void + { + $this->sourceMail = $sourceMail; + } + + public function getTransportState(): ?string + { + return $this->transportState; + } + + public function setTransportState(string $transportState): void + { + $this->transportState = $transportState; + } + } diff --git a/src/Controller/Api/MailArchiveController.php b/src/Controller/Api/MailArchiveController.php index fd4f93a..9abb7e8 100644 --- a/src/Controller/Api/MailArchiveController.php +++ b/src/Controller/Api/MailArchiveController.php @@ -7,11 +7,13 @@ use Frosh\MailArchive\Content\MailArchive\MailArchiveException; use Frosh\MailArchive\Services\EmlFileManager; use Frosh\MailArchive\Services\MailSender; +use Shopware\Core\Content\Mail\Service\AbstractMailSender; use Shopware\Core\Framework\Context; use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository; use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria; use Shopware\Core\PlatformRequest; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; @@ -29,13 +31,14 @@ class MailArchiveController extends AbstractController public function __construct( private readonly EntityRepository $froshMailArchiveRepository, private readonly EntityRepository $froshMailArchiveAttachmentRepository, - private readonly MailSender $mailSender, + #[Autowire(service: MailSender::class)] + private readonly AbstractMailSender $mailSender, private readonly RequestStack $requestStack, private readonly EmlFileManager $emlFileManager ) { } - #[Route(path: '/api/_action/frosh-mail-archive/resend-mail')] + #[Route(path: '/api/_action/frosh-mail-archive/resend-mail', name: 'api.action.frosh-mail-archive.resend-mail')] public function resend(Request $request): JsonResponse { $mailId = $request->request->get('mailId'); diff --git a/src/FroshPlatformMailArchive.php b/src/FroshPlatformMailArchive.php index 49c0522..1c3000d 100644 --- a/src/FroshPlatformMailArchive.php +++ b/src/FroshPlatformMailArchive.php @@ -21,11 +21,11 @@ public function uninstall(UninstallContext $uninstallContext): void $connection = $container->get(Connection::class); if (!$connection instanceof Connection) { - return; + return; } - $connection->executeStatement('DROP TABLE IF EXISTS frosh_mail_archive'); $connection->executeStatement('DROP TABLE IF EXISTS frosh_mail_archive_attachment'); + $connection->executeStatement('DROP TABLE IF EXISTS frosh_mail_archive'); } public function executeComposerCommands(): bool diff --git a/src/Migration/Migration1694604822AddSourceMailId.php b/src/Migration/Migration1694604822AddSourceMailId.php new file mode 100644 index 0000000..5d2357b --- /dev/null +++ b/src/Migration/Migration1694604822AddSourceMailId.php @@ -0,0 +1,25 @@ +executeStatement("ALTER TABLE `frosh_mail_archive` ADD `source_mail_id` BINARY(16) NULL;"); + } + + public function updateDestructive(Connection $connection): void + { + } +} diff --git a/src/Migration/Migration1694714751TransportInfo.php b/src/Migration/Migration1694714751TransportInfo.php new file mode 100644 index 0000000..5ab0912 --- /dev/null +++ b/src/Migration/Migration1694714751TransportInfo.php @@ -0,0 +1,25 @@ +executeStatement("ALTER TABLE `frosh_mail_archive` ADD `transport_state` VARCHAR(255) NULL;"); + } + + public function updateDestructive(Connection $connection): void + { + } +} diff --git a/src/Resources/app/administration/src/main.js b/src/Resources/app/administration/src/main.js index 0099d6f..0c80a41 100644 --- a/src/Resources/app/administration/src/main.js +++ b/src/Resources/app/administration/src/main.js @@ -1,3 +1,4 @@ import './init/api.init'; import './module/frosh-mail-archive'; import './component/notification-sw-admin'; + diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/component/frosh-mail-resend-history/frosh-mail-resend-history.html.twig b/src/Resources/app/administration/src/module/frosh-mail-archive/component/frosh-mail-resend-history/frosh-mail-resend-history.html.twig new file mode 100644 index 0000000..3c0113c --- /dev/null +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/component/frosh-mail-resend-history/frosh-mail-resend-history.html.twig @@ -0,0 +1,59 @@ + + + diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/component/frosh-mail-resend-history/index.js b/src/Resources/app/administration/src/module/frosh-mail-archive/component/frosh-mail-resend-history/index.js new file mode 100644 index 0000000..9020dcf --- /dev/null +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/component/frosh-mail-resend-history/index.js @@ -0,0 +1,57 @@ +const {Criteria} = Shopware.Data; +import template from './frosh-mail-resend-history.html.twig'; + +Shopware.Component.register('frosh-mail-resend-history', { + props: { + sourceMailId: { + required: true, + type: String + }, + currentMailId: { + required: true, + type: String + } + }, + template, + data() { + return { + resentMails: [], + isLoading: false, + columns: [{ + property: 'createdAt', + label: this.$tc('frosh-mail-archive.detail.resend-grid.column-created-at'), + primary: true, + }, { + property: 'success', + label: this.$tc('frosh-mail-archive.detail.resend-grid.column-state'), + sortable: false, + }] + } + }, + inject: ['repositoryFactory'], + computed: { + mailArchiveRepository() { + return this.repositoryFactory.create('frosh_mail_archive'); + } + }, + async created() { + this.isLoading = true; + await this.loadMails(); + this.isLoading = false; + }, + methods: { + async loadMails() { + const criteria = new Criteria(); + criteria.addFilter(Criteria.multi('OR', [ + Criteria.equals('id', this.sourceMailId), + Criteria.equals('sourceMailId', this.sourceMailId) + ])); + criteria.addSorting(Criteria.sort('createdAt', 'DESC')); + + this.resentMails = await this.mailArchiveRepository.search(criteria, Shopware.Context.api); + }, + navigateToDetailPage(id) { + this.$router.push({name: 'frosh.mail.archive.detail', params: {id}}) + } + } +}); diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/index.js b/src/Resources/app/administration/src/module/frosh-mail-archive/index.js index 411ec2f..c8fcd76 100644 --- a/src/Resources/app/administration/src/module/frosh-mail-archive/index.js +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/index.js @@ -1,5 +1,6 @@ import './page/frosh-mail-archive-index/index'; import './page/frosh-mail-archive-detail/index'; +import './component/frosh-mail-resend-history' Shopware.Module.register('frosh-mail-archive', { type: 'plugin', @@ -20,7 +21,12 @@ Shopware.Module.register('frosh-mail-archive', { path: 'detail/:id', meta: { parentPath: 'frosh.mail.archive.list' - } + }, + props: { + default: ($route) => { + return { archiveId: $route.params.id }; + }, + }, } }, diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/frosh-mail-archive-detail.scss b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/frosh-mail-archive-detail.scss index fa1c2c9..6dda079 100644 --- a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/frosh-mail-archive-detail.scss +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/frosh-mail-archive-detail.scss @@ -9,3 +9,7 @@ white-space: pre-line; } } + +.frosh-mail-archive__detail-alert { + max-width: 960px; +} diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/frosh-mail-archive-detail.twig b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/frosh-mail-archive-detail.twig index 9fe8850..5d02165 100644 --- a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/frosh-mail-archive-detail.twig +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/frosh-mail-archive-detail.twig @@ -8,30 +8,47 @@ {{ $tc('frosh-mail-archive.detail.toolbar.customer') }} - + {{ $tc('frosh-mail-archive.detail.toolbar.downloadEml') }} - + {{ $tc('frosh-mail-archive.detail.toolbar.resend') }} diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/index.js b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/index.js index 314725e..2c401c6 100644 --- a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/index.js +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-detail/index.js @@ -1,5 +1,5 @@ -const { Component } = Shopware; -const { Criteria } = Shopware.Data; +const {Component, Mixin} = Shopware; +const {Criteria} = Shopware.Data; import template from './frosh-mail-archive-detail.twig'; import './frosh-mail-archive-detail.scss'; @@ -14,20 +14,36 @@ Component.register('frosh-mail-archive-detail', { resendIsSuccessful: false, downloadIsLoading: false, downloadIsSuccessful: false, + resendCounter: 0 } }, - created() { - this.repository = this.repositoryFactory.create('frosh_mail_archive'); + props: { + archiveId: { + type: String, + required: true + } + }, - const criteria = new Criteria(); - criteria.addAssociation('attachments'); + mixins: [ + Mixin.getByName('notification') + ], - this.repository.get(this.$route.params.id, Shopware.Context.api, criteria).then(archive => { - this.archive = archive; - }) + created() { + this.loadMail(); + }, + watch: { + archiveId() { + this.loadMail(); + } }, computed: { + resendKey() { + return this.archive.id + this.resendCounter; + }, + repository() { + return this.repositoryFactory.create('frosh_mail_archive'); + }, createdAtDate() { const locale = Shopware.State.getters.adminLocaleLanguage || 'en'; const options = { @@ -87,37 +103,60 @@ Component.register('frosh-mail-archive-detail', { }, methods: { + loadMail() { + const criteria = new Criteria(); + criteria.addAssociation('attachments'); + + this.repository.get(this.archiveId, Shopware.Context.api, criteria).then(archive => { + this.archive = archive; + }) + }, getContent(html) { - return 'data:text/html;base64,' + btoa(unescape(encodeURIComponent(html.replace(/[\u00A0-\u2666]/g, function(c) { + return 'data:text/html;base64,' + btoa(unescape(encodeURIComponent(html.replace(/[\u00A0-\u2666]/g, function (c) { return '&#' + c.charCodeAt(0) + ';'; })))); }, openCustomer() { this.$router.push({ name: 'sw.customer.detail', - params: { id: this.archive.customer.id } + params: {id: this.archive.customer.id} }); }, + resendFinish() { + this.resendIsSuccessful = false; + }, + downloadFinish() { + this.downloadIsSuccessful = false; + }, resendMail() { this.resendIsLoading = true; this.froshMailArchiveService.resendMail(this.archive.id).then(() => { - this.resendIsLoading = false; this.resendIsSuccessful = true; + this.createNotificationSuccess({ + title: this.$tc('frosh-mail-archive.detail.resend-success-notification.title'), + message: this.$tc('frosh-mail-archive.detail.resend-success-notification.message') + }); }).catch(() => { - this.resendIsLoading = false; this.resendIsSuccessful = false; + this.createNotificationError({ + title: this.$tc('frosh-mail-archive.detail.resend-error-notification.title'), + message: this.$tc('frosh-mail-archive.detail.resend-error-notification.message') + }); + }).finally(() => { + this.resendIsLoading = false; + this.resendCounter++; }); }, downloadMail() { this.downloadIsLoading = true; this.froshMailArchiveService.downloadMail(this.archive.id).then(() => { - this.downloadIsLoading = false; this.downloadIsSuccessful = true; }).catch(() => { - this.downloadIsLoading = false; this.downloadIsSuccessful = false; + }).finally(() => { + this.downloadIsLoading = false; }); }, downloadAttachment(attachmentId) { @@ -134,7 +173,7 @@ Component.register('frosh-mail-archive-detail', { const units = ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; let index = -1; - const reach = 10**dp; + const reach = 10 ** dp; do { formatted /= thresh; diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/frosh-mail-archive-index.scss b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/frosh-mail-archive-index.scss index 50db991..de12052 100644 --- a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/frosh-mail-archive-index.scss +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/frosh-mail-archive-index.scss @@ -1,3 +1,8 @@ .sw-sidebar-item__scrollable-container { padding: 10px; } + +.frosh-mail-archive__data-grid-danger-icon { + margin-left: 10px; + color: #f00; +} diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/frosh-mail-archive-index.twig b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/frosh-mail-archive-index.twig index e0f978c..5081408 100644 --- a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/frosh-mail-archive-index.twig +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/frosh-mail-archive-index.twig @@ -25,10 +25,21 @@ @@ -44,7 +55,8 @@ - + diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/index.js b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/index.js index a042149..03fad76 100644 --- a/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/index.js +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/page/frosh-mail-archive-index/index.js @@ -1,5 +1,5 @@ -const { Component, Mixin } = Shopware; -const { Criteria } = Shopware.Data; +const {Component, Mixin} = Shopware; +const {Criteria} = Shopware.Data; const utils = Shopware.Utils; import template from './frosh-mail-archive-index.twig'; import './frosh-mail-archive-index.scss'; diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/snippet/de-DE.json b/src/Resources/app/administration/src/module/frosh-mail-archive/snippet/de-DE.json index a97c8c0..eaebadf 100644 --- a/src/Resources/app/administration/src/module/frosh-mail-archive/snippet/de-DE.json +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/snippet/de-DE.json @@ -6,7 +6,8 @@ "sentDate": "Versanddatum", "subject": "Betreff", "receiver": "Empfänger", - "action": "Anzeigen" + "action": "Anzeigen", + "transportFailed": "Versand der E-Mail fehlgeschlagen" }, "sidebar": { "refresh": "Neuladen", @@ -35,6 +36,28 @@ }, "content": { "title": "Inhalt" + }, + "alert": { + "transportFailed": "E-Mail-Versand fehlgeschlagen. Bitte überprüfe deine Mailer-Einstellungen und versuche es erneut." + }, + "resend-success-notification": { + "message": "Der E-Mail-Versand wurde gestartet.", + "title": "Mail Archiv" + }, + "resend-error-notification": { + "title": "Mail Archiv", + "message": "Fehler beim Senden der E-Mail" + }, + "resend-grid": { + "navigate": "Anzeigen", + "success-label": "erfolgreich", + "failed-label": "fehlgeschlagen", + "column-created-at": "Gesendet am", + "column-state": "Status", + "currently-selected": "ausgewählt", + "title": "Sendeverlauf", + "pending-label": "ausstehend", + "unknown-label": "unbekannt" } }, "missingMigration": { diff --git a/src/Resources/app/administration/src/module/frosh-mail-archive/snippet/en-GB.json b/src/Resources/app/administration/src/module/frosh-mail-archive/snippet/en-GB.json index e01f837..6d4e778 100644 --- a/src/Resources/app/administration/src/module/frosh-mail-archive/snippet/en-GB.json +++ b/src/Resources/app/administration/src/module/frosh-mail-archive/snippet/en-GB.json @@ -6,7 +6,8 @@ "sentDate": "Sent date", "subject": "Subject", "receiver": "Recipients", - "action": "Show" + "action": "Show", + "transportFailed": "Mail delivery failed." }, "sidebar": { "refresh": "Refresh", @@ -35,6 +36,28 @@ }, "content": { "title": "Content" + }, + "alert": { + "transportFailed": "Mail delivery failed. Please check mailer settings and try again." + }, + "resend-success-notification": { + "message": "Mail dispatch has started.", + "title": "Mail Archive" + }, + "resend-error-notification": { + "title": "Mail Archive", + "message": "Mail could not be delivered" + }, + "resend-grid": { + "navigate": "Show", + "success-label": "success", + "failed-label": "failed", + "column-created-at": "Sent at", + "column-state": "State", + "currently-selected": "this", + "title": "Resend history", + "pending-label": "pending", + "unknown-label": "unknown" } }, "missingMigration": { diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml index a59ab8d..61f706a 100644 --- a/src/Resources/config/services.xml +++ b/src/Resources/config/services.xml @@ -6,6 +6,6 @@ - + diff --git a/src/Services/MailSender.php b/src/Services/MailSender.php index 8ff6a78..15dbd66 100644 --- a/src/Services/MailSender.php +++ b/src/Services/MailSender.php @@ -2,6 +2,8 @@ namespace Frosh\MailArchive\Services; +use Frosh\MailArchive\Content\MailArchive\MailArchiveEntity; +use Frosh\MailArchive\Content\MailArchive\MailArchiveException; use Shopware\Core\Content\Mail\Service\AbstractMailSender; use Shopware\Core\Framework\Context; use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository; @@ -17,21 +19,33 @@ #[AsDecorator(decorates: \Shopware\Core\Content\Mail\Service\MailSender::class)] class MailSender extends AbstractMailSender { + + public const TRANSPORT_STATE_PENDING = 'pending'; + public const TRANSPORT_STATE_FAILED = 'failed'; + public const TRANSPORT_STATE_SENT = 'sent'; + + public const FROSH_MESSAGE_ID_HEADER = 'Frosh-Message-ID'; + public function __construct( private readonly AbstractMailSender $mailSender, - private readonly RequestStack $requestStack, - private readonly EntityRepository $froshMailArchiveRepository, - private readonly EntityRepository $customerRepository, - private readonly EmlFileManager $emlFileManager - ) { + private readonly RequestStack $requestStack, + private readonly EntityRepository $froshMailArchiveRepository, + private readonly EntityRepository $customerRepository, + private readonly EmlFileManager $emlFileManager + ) + { } public function send(Email $email, ?Envelope $envelope = null): void { - // let first send the mail itself, to see if it was really sent or entered error state + $id = Uuid::randomHex(); + $email->getHeaders()->remove(self::FROSH_MESSAGE_ID_HEADER); + $email->getHeaders()->addHeader(self::FROSH_MESSAGE_ID_HEADER, $id); + + // save the mail first, to make sure it exists in the database when we want to update its state + $this->saveMail($id, $email); $this->mailSender->send($email, $envelope); - $this->saveMail($email); } public function getDecorated(): AbstractMailSender @@ -39,10 +53,8 @@ public function getDecorated(): AbstractMailSender return $this->mailSender; } - private function saveMail(Email $message): void + private function saveMail(string $id, Email $message): void { - $id = Uuid::randomHex(); - $emlPath = $this->emlFileManager->writeFile($id, $message->toString()); $attachments = []; @@ -55,20 +67,23 @@ private function saveMail(Email $message): void ]; } + $context = Context::createDefaultContext(); $this->froshMailArchiveRepository->create([ [ 'id' => $id, 'sender' => [$message->getFrom()[0]->getAddress() => $message->getFrom()[0]->getName()], 'receiver' => $this->convertAddress($message->getTo()), 'subject' => $message->getSubject(), - 'plainText' => nl2br((string) $message->getTextBody()), + 'plainText' => nl2br((string)$message->getTextBody()), 'htmlText' => $message->getHtmlBody(), 'emlPath' => $emlPath, 'salesChannelId' => $this->getCurrentSalesChannelId(), 'customerId' => $this->getCustomerIdByMail($message->getTo()), 'attachments' => $attachments, + 'sourceMailId' => $this->getSourceMailId($context), + 'transportState' => self::TRANSPORT_STATE_PENDING, ], - ], Context::createDefaultContext()); + ], $context); } private function getCurrentSalesChannelId(): ?string @@ -85,6 +100,31 @@ private function getCurrentSalesChannelId(): ?string return $salesChannelId; } + private function getSourceMailId(Context $context): ?string + { + $request = $this->requestStack->getMainRequest(); + if ($request === null) { + return null; + } + + $route = $request->attributes->get('_route'); + if ($route !== 'api.action.frosh-mail-archive.resend-mail') { + return null; + } + + $sourceMailId = $request->request->get('mailId'); + + if (!\is_string($sourceMailId)) { + throw MailArchiveException::parameterMissing('mailId in request'); + } + + /** @var MailArchiveEntity|null $sourceMail */ + $sourceMail = $this->froshMailArchiveRepository->search(new Criteria([$sourceMailId]), $context)->first(); + + // In case the source Mail is a resend, we want to save the original source mail id + return $sourceMail?->getSourceMailId() ?? $sourceMailId; + } + /** * @param Address[] $to */ diff --git a/src/Subscriber/MailArchiveDeleteSubscriber.php b/src/Subscriber/MailArchiveDeleteSubscriber.php index be2df42..3c18330 100644 --- a/src/Subscriber/MailArchiveDeleteSubscriber.php +++ b/src/Subscriber/MailArchiveDeleteSubscriber.php @@ -14,8 +14,9 @@ class MailArchiveDeleteSubscriber implements EventSubscriberInterface { public function __construct( private readonly EntityRepository $froshMailArchiveRepository, - private readonly EmlFileManager $emlFileManager - ) { + private readonly EmlFileManager $emlFileManager + ) + { } public static function getSubscribedEvents(): array diff --git a/src/Subscriber/MailTransportSubscriber.php b/src/Subscriber/MailTransportSubscriber.php new file mode 100644 index 0000000..caea347 --- /dev/null +++ b/src/Subscriber/MailTransportSubscriber.php @@ -0,0 +1,76 @@ + 'onMessageFailed', + SentMessageEvent::class => 'onMessageSent' + ]; + } + + public function onMessageFailed(FailedMessageEvent $e): void + { + $message = $e->getMessage(); + $this->updateArchiveState($message, MailSender::TRANSPORT_STATE_FAILED); + } + + public function onMessageSent(SentMessageEvent $event): void + { + $message = $event->getMessage()->getOriginalMessage(); + $this->updateArchiveState($message, MailSender::TRANSPORT_STATE_SENT); + } + + private function updateArchiveState(RawMessage $message, string $newState): void + { + $context = Context::createDefaultContext(); + $archiveId = $this->getArchiveIdByMessage($message, $context); + + if ($archiveId) { + $this->froshMailArchiveRepository->update([[ + 'id' => $archiveId, + 'transportState' => $newState + ]], $context); + } + } + + private function getArchiveIdByMessage(RawMessage $message, Context $context): ?string + { + if (!($message instanceof Email)) { + return null; + } + + $messageIdHeader = $message->getHeaders()->get(MailSender::FROSH_MESSAGE_ID_HEADER); + + if (!$messageIdHeader) { + return null; + } + + $messageId = $messageIdHeader->getBody(); + + if (\is_string($messageId)) { + return $messageId; + } + + return null; + } +}