Skip to content

Commit

Permalink
[FEATURE] Add two basic events to LUXletter
Browse files Browse the repository at this point in the history
1) to stop testmails and implement own testmail service
2) to set own bodytext for newsletter mails

Related: https://github.com/in2code-de/luxletter/pull/205/files
  • Loading branch information
einpraegsam committed Feb 2, 2024
1 parent 9ecde16 commit b16c18f
Show file tree
Hide file tree
Showing 9 changed files with 290 additions and 16 deletions.
78 changes: 68 additions & 10 deletions Classes/Controller/NewsletterController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);
namespace In2code\Luxletter\Controller;

use Doctrine\DBAL\Driver\Exception as ExceptionDbalDriver;
use In2code\Lux\Domain\Repository\VisitorRepository;
use In2code\Luxletter\Domain\Model\Dto\Filter;
use In2code\Luxletter\Domain\Model\Newsletter;
Expand All @@ -11,15 +12,23 @@
use In2code\Luxletter\Domain\Service\PreviewUrlService;
use In2code\Luxletter\Domain\Service\QueueService;
use In2code\Luxletter\Domain\Service\ReceiverAnalysisService;
use In2code\Luxletter\Events\AfterTestMailButtonClickedEvent;
use In2code\Luxletter\Exception\ApiConnectionException;
use In2code\Luxletter\Exception\AuthenticationFailedException;
use In2code\Luxletter\Exception\InvalidUrlException;
use In2code\Luxletter\Exception\MisconfigurationException;
use In2code\Luxletter\Mail\TestMail;
use In2code\Luxletter\Utility\BackendUserUtility;
use In2code\Luxletter\Utility\ConfigurationUtility;
use In2code\Luxletter\Utility\LocalizationUtility;
use In2code\Luxletter\Utility\ObjectUtility;
use JsonException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationExtensionNotConfiguredException;
use TYPO3\CMS\Core\Configuration\Exception\ExtensionConfigurationPathDoesNotExistException;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\Exception\InvalidConfigurationTypeException;
use TYPO3\CMS\Fluid\View\StandaloneView;

class NewsletterController extends AbstractNewsletterController
Expand Down Expand Up @@ -220,36 +229,80 @@ public function wizardUserPreviewAjax(ServerRequestInterface $request): Response
return $response;
}

/**
* @param ServerRequestInterface $request
* @return ResponseInterface
* @throws AuthenticationFailedException
* @throws ExceptionDbalDriver
* @throws ApiConnectionException
* @throws InvalidUrlException
* @throws MisconfigurationException
* @throws JsonException
* @throws ExtensionConfigurationExtensionNotConfiguredException
* @throws ExtensionConfigurationPathDoesNotExistException
* @throws InvalidConfigurationTypeException
*/
public function testMailAjax(ServerRequestInterface $request): ResponseInterface
{
if (BackendUserUtility::isBackendUserAuthenticated() === false) {
throw new AuthenticationFailedException('You are not authenticated to send mails', 1560872725);
}
$testMail = GeneralUtility::makeInstance(TestMail::class);
$status = $testMail->preflight(
$request->getQueryParams()['origin'],
$request->getQueryParams()['layout'],
(int)$request->getQueryParams()['configuration'],
$request->getQueryParams()['subject'],
$request->getQueryParams()['email']
);
$status = null;

/**
* This event can be used for sending the Test-email with external logic
* @see Documentation/Tech/Events.md
*/
$event = GeneralUtility::makeInstance(AfterTestMailButtonClickedEvent::class, $request);
$this->eventDispatcher->dispatch($event);

if ($event->isTestMailIsSendExternal() === false) {
$testMail = GeneralUtility::makeInstance(TestMail::class);
$status = $testMail->preflight(
$request->getQueryParams()['origin'],
$request->getQueryParams()['layout'],
(int)$request->getQueryParams()['configuration'],
$request->getQueryParams()['subject'],
$request->getQueryParams()['email']
);
}
$responseData = [
'status' => $status ?? $event->getStatus(),
];
if ($event->isTestMailIsSendExternal()) {
$responseData += $event->getStatusResponse();
}
$response = ObjectUtility::getJsonResponse();
$response->getBody()->write(json_encode(['status' => $status]));
$response->getBody()->write(json_encode($responseData, JSON_THROW_ON_ERROR));
return $response;
}

/**
* @param ServerRequestInterface $request
* @return ResponseInterface
* @throws AuthenticationFailedException
* @throws ExceptionDbalDriver
* @throws ExtensionConfigurationExtensionNotConfiguredException
* @throws ExtensionConfigurationPathDoesNotExistException
* @throws InvalidConfigurationTypeException
* @throws MisconfigurationException
*/
public function previewSourcesAjax(ServerRequestInterface $request): ResponseInterface
{
if (BackendUserUtility::isBackendUserAuthenticated() === false) {
throw new AuthenticationFailedException('You are not authenticated to send mails', 1645707268);
}
$previewUrlService = GeneralUtility::makeInstance(PreviewUrlService::class);
$response = ObjectUtility::getJsonResponse();
$content = $previewUrlService->get($request->getQueryParams()['origin'], $request->getQueryParams()['layout']);
$response = ObjectUtility::getJsonResponse();
$response->getBody()->write(json_encode($content));
return $response;
}

/**
* @param ServerRequestInterface $request
* @return ResponseInterface
*/
public function receiverDetailAjax(ServerRequestInterface $request): ResponseInterface
{
$userRepository = GeneralUtility::makeInstance(UserRepository::class);
Expand All @@ -270,6 +323,11 @@ public function receiverDetailAjax(ServerRequestInterface $request): ResponseInt
return $response;
}

/**
* @return void
* @throws ExtensionConfigurationExtensionNotConfiguredException
* @throws ExtensionConfigurationPathDoesNotExistException
*/
protected function addDocumentHeaderForNewsletterController(): void
{
$menuConfiguration = [
Expand Down
9 changes: 6 additions & 3 deletions Classes/Domain/Repository/LogRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,14 @@ public function findRawByUser(User $user, array $statusWhitelist = [], array $st
}

/**
* @param User $user
* @return QueryResultInterface
* @param ?User $user
* @return ?QueryResultInterface
*/
public function findByUser(User $user): QueryResultInterface
public function findByUser(?User $user): ?QueryResultInterface
{
if ($user === null) {
return null;
}
$query = $this->createQuery();
$query->matching($query->equals('user', $user));
$query->setLimit(100);
Expand Down
96 changes: 96 additions & 0 deletions Classes/Events/AfterTestMailButtonClickedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

declare(strict_types=1);
namespace In2code\Luxletter\Events;

use Psr\Http\Message\ServerRequestInterface;

final class AfterTestMailButtonClickedEvent
{
public const STATUS_SEVERITY_SUCCESS = 'alert-success';
public const STATUS_SEVERITY_WARNING = 'alert-warning';
public const STATUS_SEVERITY_ERROR = 'alert-danger';

protected ServerRequestInterface $request;

protected bool $testMailIsSendExternal = false;
protected bool $status = false;

protected string $statusTitle = '';
protected string $statusMessage = '';
protected string $statusSeverity = self::STATUS_SEVERITY_ERROR;

public function __construct(ServerRequestInterface $request)
{
$this->request = $request;
}

public function getRequest(): ServerRequestInterface
{
return $this->request;
}

public function isTestMailIsSendExternal(): bool
{
return $this->testMailIsSendExternal;
}

public function setTestMailIsSendExternal(): self
{
$this->testMailIsSendExternal = true;
return $this;
}

public function getStatus(): bool
{
return $this->status;
}

public function setStatus(bool $status): self
{
$this->status = $status;
return $this;
}

public function getStatusTitle(): string
{
return $this->statusTitle;
}

public function setStatusTitle(string $statusTitle): self
{
$this->statusTitle = $statusTitle;
return $this;
}

public function getStatusMessage(): string
{
return $this->statusMessage;
}

public function setStatusMessage(string $statusMessage): self
{
$this->statusMessage = $statusMessage;
return $this;
}

public function getStatusSeverity(): string
{
return $this->statusSeverity;
}

public function setStatusSeverity(string $statusSeverity): self
{
$this->statusSeverity = $statusSeverity;
return $this;
}

public function getStatusResponse(): array
{
return [
'statusTitle' => $this->getStatusTitle(),
'statusMessage' => $this->getStatusMessage(),
'statusSeverity' => $this->getStatusSeverity(),
];
}
}
35 changes: 35 additions & 0 deletions Classes/Events/BeforeBodytextIsParsedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);
namespace In2code\Luxletter\Events;

use In2code\Luxletter\Domain\Model\Queue;

final class BeforeBodytextIsParsedEvent
{
protected Queue $queue;

protected string $bodytext = '';

public function __construct(Queue $queue)
{
$this->queue = $queue;
$this->bodytext = $queue->getNewsletter()->getBodytext();
}

public function getQueue(): Queue
{
return $this->queue;
}

public function getBodytext(): string
{
return $this->bodytext;
}

public function setBodytext(string $bodytext): self
{
$this->bodytext = $bodytext;
return $this;
}
}
6 changes: 5 additions & 1 deletion Classes/Mail/ProgressQueue.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use In2code\Luxletter\Domain\Service\BodytextManipulation\LinkHashing;
use In2code\Luxletter\Domain\Service\LogService;
use In2code\Luxletter\Domain\Service\Parsing\Newsletter;
use In2code\Luxletter\Events\BeforeBodytextIsParsedEvent;
use In2code\Luxletter\Events\ProgressQueueEvent;
use In2code\Luxletter\Exception\ArgumentMissingException;
use In2code\Luxletter\Exception\MisconfigurationException;
Expand Down Expand Up @@ -181,8 +182,11 @@ protected function getSubject(Queue $queue): string
*/
protected function getBodyText(Queue $queue): string
{
$event = GeneralUtility::makeInstance(BeforeBodytextIsParsedEvent::class, $queue);
$this->eventDispatcher->dispatch($event);

$bodytext = $this->parseService->parseBodytext(
$queue->getNewsletter()->getBodytext(),
$event->getBodytext(),
[
'user' => $queue->getUser(),
'newsletter' => $queue->getNewsletter(),
Expand Down
1 change: 1 addition & 0 deletions Documentation/Index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Send newsletters the easy way
### Tech corner and FAQ

[Tech corner and FAQ](Tech/Index.md)
[Events](Tech/Events.md)

### Changelog and breaking changes

Expand Down
70 changes: 70 additions & 0 deletions Documentation/Tech/Events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<img align="left" src="../../Resources/Public/Icons/lux.svg" width="50" />

# Luxletter - Email marketing in TYPO3. Send newsletters the easy way.

## Events

There are some events that can be used to extend Luxletter.
This documentation is under construction and not all events are documented yet.

### AfterTestMailButtonClickedEvent

This event can be used to deactivate the internal sending of test emails and implement your own logic, e.g. sending test newsletters via a separate queue.

To deactivate the internal logic, the `$testMailIsSendExternal` property of the event must be set to true.
If the general status `$status` is set to `false`, no message is shown.
If the general status `$status` is set to `true`, a message with the properties `$statusTitle`, `$statusMessage` and `$statusSeverity` is shown.
The values for `$statusSeverity` should be `AfterTestMailButtonClickedEvent::STATUS_SEVERITY_SUCCESS`, `AfterTestMailButtonClickedEvent::STATUS_SEVERITY_WARNING` and `AfterTestMailButtonClickedEvent::STATUS_SEVERITY_ERROR`, the default value is `AfterTestMailButtonClickedEvent::STATUS_SEVERITY_ERROR`.

The `$request` property is available in the event, from which all necessary data can be obtained to send the test e-mail.

Sample Eventlistener:

```
<?php
declare(strict_types=1);
namespace Vendor\Extension\EventListener;
use In2code\Luxletter\Events\AfterTestMailButtonClickedEvent;
final class DemoEventlistener
{
public function __invoke(AfterTestMailButtonClickedEvent $event): void
{
$event->setTestMailIsSendExternal(true);
// ... handle email sending
$event->setStatus(true);
$event->setStatusSeverity(AfterTestMailButtonClickedEvent::STATUS_SEVERITY_SUCCESS);
$event->setStatusTitle('Success');
$event->setStatusMessage('The test email is successfully added to the queue');
}
}
```

### BeforeBodytextIsParsedEvent

This event is executed before the body text for the individual newsletter is processed. The event can be used to change or reset the body text that is used for parsing.

The `$queue` property is available in the event, which can be used to access all relevant data for the newsletter.
If the `$bodytext` property is set via an event listener, the content of this property is used for further processing. If there is no content in the property, the standard text from the newsletter is used.

Sample Eventlistener:

```
<?php
declare(strict_types=1);
namespace Vendor\Extension\EventListener;
use In2code\Luxletter\Events\AfterTestMailButtonClickedEvent;
use In2code\Luxletter\Events\BeforeBodytextIsParsedEvent;
final class DemoEventlistener
{
public function __invoke(BeforeBodytextIsParsedEvent $event): void
{
$event->setBodytext('<h1>I am the new body</h1>');
}
}
```
Loading

0 comments on commit b16c18f

Please sign in to comment.