Skip to content

Commit

Permalink
[TASK] Add API + rejecting
Browse files Browse the repository at this point in the history
  • Loading branch information
georgringer committed Feb 15, 2024
1 parent f936d75 commit decba35
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 8 deletions.
34 changes: 34 additions & 0 deletions Classes/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace StudioMitte\SentMails;

use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class Configuration
{

/** @var string[] */
public array $rejectBySearchTerms = [];

public int $mailInformationMaxTime = 60;

public string $mailAPIUsername = '';
public string $mailAPIPassword = '';

public function __construct()
{
try {
$settings = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('sent_mails');

$this->rejectBySearchTerms = GeneralUtility::trimExplode('|', $settings['rejectBySearchTerms'] ?? '', true);
$this->mailAPIUsername = $settings['mailAPIUsername'] ?? '';
$this->mailAPIPassword = $settings['mailAPIPassword'] ?? '';
} catch (\Exception $e) {
// do nothing
}
}

}
5 changes: 1 addition & 4 deletions Classes/EventListener/BeforeMailSentEventListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\StringUtility;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;

class BeforeMailSentEventListener
{
Expand All @@ -36,10 +35,8 @@ public function __invoke(BeforeMailerSentMessageEvent $event): void

$sentMessage->getHeaders()->addTextHeader('X-SentMail_Custom', $customId);

// $originalMessage = $sentMessage->getOriginalMessage();
$isReply = get_class($originalMessage) === RawMessage::class;
// DebuggerUtility::var_dump($isReply, '$isReply');
//

$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_sentmail_mail');
$connection->insert('tx_sentmail_mail', [
'crdate' => time(),
Expand Down
30 changes: 30 additions & 0 deletions Classes/EventListener/MailMessageListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);

namespace StudioMitte\SentMails\EventListener;


use StudioMitte\SentMails\Configuration;
use Symfony\Component\Mailer\Event\MessageEvent;

class MailMessageListener
{

public function __construct(
protected Configuration $configuration)
{
}

public function __invoke(MessageEvent $event): void
{
$message = $event->getMessage();

$messageAsString = $message->toString();
foreach ($this->configuration->rejectBySearchTerms as $searchTerm) {
if (preg_match(sprintf('/%s/i', $searchTerm), $messageAsString)) {
$event->reject();
return;
}
}
}
}
77 changes: 77 additions & 0 deletions Classes/Middleware/MailInformation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);

namespace StudioMitte\SentMails\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use StudioMitte\SentMails\Configuration;
use StudioMitte\SentMails\Repository\MailRepository;
use TYPO3\CMS\Core\Http\JsonResponse;

class MailInformation implements MiddlewareInterface
{

public function __construct(
protected readonly MailRepository $mailRepository,
protected readonly Configuration $configuration
)
{

}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
if (!$this->isValidRequest($request)) {
return $handler->handle($request);
}

$response = new JsonResponse();
if (!$this->validateBasicAuth($request)) {
$response = $response->withAddedHeader('WWW-Authenticate', 'Basic realm="Access check"');
}

try {
$searchParam = $this->getSearchParam($request);
$response->setPayload($this->mailRepository->getMailsBySearch($searchParam));
} catch (\Exception $e) {
$response = $response->withStatus(400);
$response->setPayload(['error' => $e->getMessage()]);
}
return $response;
}

protected function getSearchParam(ServerRequestInterface $request): string
{
$searchParams = trim($request->getQueryParams()['search'] ?? '');
if (mb_strlen($searchParams) < 10) {
throw new \InvalidArgumentException('Search parameter must be at least 10 characters long', 1627980733);
}
return $searchParams;
}

protected function isValidRequest(ServerRequestInterface $request): bool
{
if (!$request->getUri()) {
return false;
}
$uri = $request->getUri();

return $uri->getPath() === '/api/mailinformation';
}

protected function validateBasicAuth(ServerRequestInterface $request): bool
{
$username = $request->getServerParams()['PHP_AUTH_USER'] ?? false;
$password = $request->getServerParams()['PHP_AUTH_PW'] ?? false;

return
$this->configuration->mailAPIUsername &&
$this->configuration->mailAPIPassword &&
$username === $this->configuration->mailAPIUsername &&
$password === $this->configuration->mailAPIPassword;
}

}
23 changes: 23 additions & 0 deletions Classes/Repository/MailRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@

namespace StudioMitte\SentMails\Repository;

use StudioMitte\SentMails\Configuration;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class MailRepository
{

public function __construct(
protected readonly Configuration $configuration
)
{
}

public function getMails(): array
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_sentmail_mail');
Expand All @@ -26,5 +34,20 @@ public function getMailRow(int $id): array
return (array)$row;
}

public function getMailsBySearch(string $searchTerm): array
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_sentmail_mail');
return $queryBuilder
->select('is_sent')
->addSelectLiteral('count(*) as count')
->from('tx_sentmail_mail')
->where(
$queryBuilder->expr()->gte('crdate', $queryBuilder->createNamedParameter((time() - $this->configuration->mailInformationMaxTime ), Connection::PARAM_INT)),
$queryBuilder->expr()->like('message', $queryBuilder->createNamedParameter('%' . $queryBuilder->escapeLikeWildcards($searchTerm) . '%'))
)
->groupBy('is_sent')
->executeQuery()->fetchAllAssociative();
}


}
14 changes: 14 additions & 0 deletions Configuration/RequestMiddlewares.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

return [
'frontend' => [
'typo3/theme/logger' => [
'target' => \StudioMitte\SentMails\Middleware\MailInformation::class,
'before' => [
'typo3/cms-frontend/timetracker',
],
'after' => [
],
],
],
];
15 changes: 13 additions & 2 deletions Configuration/Services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,25 @@ services:
StudioMitte\SentMails\:
resource: '../Classes/*'

StudioMitte\SentMails\Repository\MailRepository:
public: true

StudioMitte\SentMails\EventListener\BeforeMailSentEventListener:
tags:
- name: event.listener
identifier: 'mail-sent-beforemailsent'
identifier: 'sent-mails/beforemailsent'
event: TYPO3\CMS\Core\Mail\Event\BeforeMailerSentMessageEvent

StudioMitte\SentMails\EventListener\AfterMailSentEventListener:
tags:
- name: event.listener
identifier: 'mail-sent-aftermailsent'
identifier: 'sent-mails/aftermailsent'
event: TYPO3\CMS\Core\Mail\Event\AfterMailerSentMessageEvent

StudioMitte\SentMails\EventListener\MailMessageListener:
tags:
- name: event.listener
identifier: 'sent-mails/symfony/mailmessage-listener'
event: Symfony\Component\Mailer\Event\MessageEvent


8 changes: 6 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# TYPO3 Extension `sent_mails`

This extension provides a simple way to persist **all** sent mails in the database.
Using a dedicated backend module an user can:
This extension provides a simple way to persist **all** sent mails in the database.
Using a dedicated backend module a user can:

* view the mail including plain & HTML view
* resend the mail
* forward the mail to a different email address
* reject mails with a specific content

## Installation

Expand All @@ -15,4 +16,7 @@ This extension requires the usage of composer!
composer req studiomitte/sent-mails
```

## Mail-Information API

Calling `/api/mailinformation?search=somecontent` will return a status information about the sent mails. Basic auth needs to be configured in the extension settings.

8 changes: 8 additions & 0 deletions ext_conf_template.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# cat=Feature; type=string; label=Search terms leading to rejection:List of search terms (separated by ###) which lead to rejecting the mail sending process
rejectBySearchTerms =

# cat=Feature; type=string; label=Mail API Username:Provide the username for the mail API
mailAPIUsername =

# cat=Feature; type=string; label=Mail API Password:Provide the password for the mail API
mailAPIPassword =

0 comments on commit decba35

Please sign in to comment.