diff --git a/Classes/Controller/MailqueueModuleController.php b/Classes/Controller/MailqueueModuleController.php index d0fd774..990fcb9 100644 --- a/Classes/Controller/MailqueueModuleController.php +++ b/Classes/Controller/MailqueueModuleController.php @@ -62,6 +62,7 @@ public function __invoke(Message\ServerRequestInterface $request): Message\Respo $transport = $this->mailer->getTransport(); $page = (int)($request->getQueryParams()['page'] ?? $request->getParsedBody()['page'] ?? 1); $sendId = $request->getQueryParams()['send'] ?? null; + $deleteId = $request->getQueryParams()['delete'] ?? null; // Force redirect when page selector was used if ($request->getMethod() === 'POST' && !isset($request->getQueryParams()['page'])) { @@ -71,7 +72,7 @@ public function __invoke(Message\ServerRequestInterface $request): Message\Respo } if ($transport instanceof Mail\Transport\QueueableTransport) { - $templateVariables = $this->resolveTemplateVariables($transport, $page, $sendId); + $templateVariables = $this->resolveTemplateVariables($transport, $page, $sendId, $deleteId); } else { $templateVariables = [ 'unsupportedTransport' => $this->getTransportFromMailConfiguration(), @@ -100,6 +101,7 @@ public function __invoke(Message\ServerRequestInterface $request): Message\Respo /** * @return array{ * delayThreshold: positive-int, + * deleteResult: bool, * failing: bool, * longestPendingInterval: non-negative-int, * pagination: Core\Pagination\SimplePagination, @@ -112,16 +114,22 @@ private function resolveTemplateVariables( Mail\Transport\QueueableTransport $transport, int $currentPageNumber = 1, string $sendId = null, + string $deleteId = null, ): array { $failing = false; $longestPendingInterval = 0; $now = time(); $sendResult = null; + $deleteResult = false; if (is_string($sendId)) { $sendResult = $this->sendMail($transport, $sendId); } + if (is_string($deleteId)) { + $deleteResult = $this->deleteMail($transport, $deleteId); + } + foreach ($transport->getMailQueue() as $mailQueueItem) { if ($mailQueueItem->date !== null) { $longestPendingInterval = max($longestPendingInterval, $now - $mailQueueItem->date->getTimestamp()); @@ -142,6 +150,7 @@ private function resolveTemplateVariables( return [ 'delayThreshold' => $this->extensionConfiguration->getQueueDelayThreshold(), + 'deleteResult' => $deleteResult, 'failing' => $failing, 'longestPendingInterval' => $longestPendingInterval, 'pagination' => $pagination, @@ -153,14 +162,7 @@ private function resolveTemplateVariables( private function sendMail(Mail\Transport\QueueableTransport $transport, string $queueItemId): Enums\MailState { - $mailQueueItem = null; - - foreach ($transport->getMailQueue() as $item) { - if ($item->id === $queueItemId) { - $mailQueueItem = $item; - break; - } - } + $mailQueueItem = $this->getMailById($transport, $queueItemId); if ($mailQueueItem === null) { return Enums\MailState::AlreadySent; @@ -175,6 +177,30 @@ private function sendMail(Mail\Transport\QueueableTransport $transport, string $ return Enums\MailState::Sent; } + private function deleteMail(Mail\Transport\QueueableTransport $transport, string $queueItemId): bool + { + $mailQueueItem = $this->getMailById($transport, $queueItemId); + + if ($mailQueueItem === null) { + return false; + } + + return $transport->delete($mailQueueItem); + } + + private function getMailById( + Mail\Transport\QueueableTransport $transport, + string $queueItemId, + ): ?Mail\Queue\MailQueueItem { + foreach ($transport->getMailQueue() as $mailQueueItem) { + if ($mailQueueItem->id === $queueItemId) { + return $mailQueueItem; + } + } + + return null; + } + private function addLinkToConfigurationModule(Backend\Template\ModuleTemplate $template): void { $buttonBar = $template->getDocHeaderComponent()->getButtonBar(); diff --git a/Classes/Mail/Transport/QueueableFileTransport.php b/Classes/Mail/Transport/QueueableFileTransport.php index c0d55b5..0186a6c 100644 --- a/Classes/Mail/Transport/QueueableFileTransport.php +++ b/Classes/Mail/Transport/QueueableFileTransport.php @@ -166,6 +166,24 @@ public function dequeue(Mail\Queue\MailQueueItem $item, Mailer\Transport\Transpo return true; } + public function delete(Mail\Queue\MailQueueItem $item): bool + { + $path = $this->path . DIRECTORY_SEPARATOR . $item->id; + $failurePath = $this->getFileVariant($path, self::FILE_SUFFIX_FAILURE_DATA); + + // Early return if message no longer exists in queue + if (!file_exists($path)) { + return false; + } + + // Remove failure metadata + if (file_exists($failurePath)) { + unlink($failurePath); + } + + return unlink($path); + } + public function getMailQueue(): Mail\Queue\MailQueue { return new Mail\Queue\MailQueue( diff --git a/Classes/Mail/Transport/QueueableMemoryTransport.php b/Classes/Mail/Transport/QueueableMemoryTransport.php index e332ce8..f88f5f7 100644 --- a/Classes/Mail/Transport/QueueableMemoryTransport.php +++ b/Classes/Mail/Transport/QueueableMemoryTransport.php @@ -66,6 +66,17 @@ public function dequeue(Mail\Queue\MailQueueItem $item, Mailer\Transport\Transpo return true; } + public function delete(Mail\Queue\MailQueueItem $item): bool + { + if (!isset($this->queuedMessages[$item->id])) { + return false; + } + + unset($this->queuedMessages[$item->id]); + + return true; + } + public function getMailQueue(): Mail\Queue\MailQueue { return new Mail\Queue\MailQueue( diff --git a/Classes/Mail/Transport/QueueableTransport.php b/Classes/Mail/Transport/QueueableTransport.php index de2aa3f..671c2fc 100644 --- a/Classes/Mail/Transport/QueueableTransport.php +++ b/Classes/Mail/Transport/QueueableTransport.php @@ -47,4 +47,6 @@ public function enqueue(Mime\RawMessage $message, ?Mailer\Envelope $envelope = n * @throws Mailer\Exception\TransportExceptionInterface */ public function dequeue(Mail\Queue\MailQueueItem $item, Mailer\Transport\TransportInterface $transport): bool; + + public function delete(Mail\Queue\MailQueueItem $item): bool; } diff --git a/README.md b/README.md index be80a4a..3b1a785 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,12 @@ methods to enqueue and dequeue mails: with the difference that it only dequeues the given mail queue item and leaves the rest of the queue untouched. +* ```php + public function delete(Mail\Queue\MailQueueItem $item): bool + ``` + Deletes the message of a given mail queue item without sending it. The message is + also dequeued from the mail queue. + #### Recoverable transports Next to the `QueueableTransport` interface there exists an extended interface diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index c55c5f3..6908eef 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -79,6 +79,9 @@ The mail was successfully sent. + + The mail was successfully deleted. + Read the %s to learn more about mail spoolers in TYPO3. @@ -93,6 +96,12 @@ Transport failure details + + Delete this mail? + + + Are you sure you want to delete '%s'? + now @@ -150,6 +159,12 @@ View mail configuration + + Delete mail + + + Cancel + Mails %d - %d diff --git a/Resources/Private/Partials/List/Queue.html b/Resources/Private/Partials/List/Queue.html index c998743..ba4d026 100644 --- a/Resources/Private/Partials/List/Queue.html +++ b/Resources/Private/Partials/List/Queue.html @@ -3,6 +3,12 @@ {queue -> f:count() -> f:variable(name: 'count')} + + + + diff --git a/Resources/Private/Partials/List/QueueItem.html b/Resources/Private/Partials/List/QueueItem.html index 6b3c8c9..d54043b 100644 --- a/Resources/Private/Partials/List/QueueItem.html +++ b/Resources/Private/Partials/List/QueueItem.html @@ -5,6 +5,8 @@ + + {f:translate(key: 'queueItem.state.failed', extensionName: 'Mailqueue')} @@ -68,13 +70,20 @@
+ + diff --git a/Resources/Private/Partials/Modal/ConfirmDelete.html b/Resources/Private/Partials/Modal/ConfirmDelete.html new file mode 100644 index 0000000..4bc2de7 --- /dev/null +++ b/Resources/Private/Partials/Modal/ConfirmDelete.html @@ -0,0 +1,40 @@ + + + + + diff --git a/Resources/Private/Partials/Modal/TransportFailureDetails.html b/Resources/Private/Partials/Modal/TransportFailureDetails.html index 43de6e4..134e531 100644 --- a/Resources/Private/Partials/Modal/TransportFailureDetails.html +++ b/Resources/Private/Partials/Modal/TransportFailureDetails.html @@ -2,7 +2,7 @@ xmlns:c="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers" data-namespace-typo3-fluid="true"> -