generated from flo/template-backend
changes to mail
This commit is contained in:
parent
6d97fc24c4
commit
ed03bb79d6
@ -20,7 +20,8 @@ INIT_USER_PASSWORD=password
|
||||
INIT_USER_MAIL=admin@test.com
|
||||
|
||||
# Mail
|
||||
MAIL_DEFAULT_SENDER=info@bee.local
|
||||
MAIL_DEFAULT_SENDER=beekeeper@stack-up.de
|
||||
MAIL_DEFAULT_SENDER_NAME=Beekeeper
|
||||
SMTP_USERNAME=smtp@stack-up.de
|
||||
SMTP_PASSWORD=
|
||||
SMTP_HOST= #srv-mail-01.lab.jonasf.de
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
return [
|
||||
'mail' => [
|
||||
'default' => [
|
||||
'sender' => $_ENV['MAIL_DEFAULT_SENDER']
|
||||
'sender' => $_ENV['MAIL_DEFAULT_SENDER'],
|
||||
'senderName' => $_ENV['MAIL_DEFAULT_SENDER_NAME']
|
||||
],
|
||||
'smtp-server' => [
|
||||
'host' => $_ENV['SMTP_HOST'],
|
||||
|
||||
40
data/migrations/business/Version20240911191301.php
Normal file
40
data/migrations/business/Version20240911191301.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Bee\Migrations\Bee;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20240911191301 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return "Create Table 'mail'";
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$sql = "CREATE TABLE mail (
|
||||
id binary(16) NOT NULL,
|
||||
template varchar(255) NOT NULL,
|
||||
data json NOT NULL,
|
||||
recipient varchar(255) NOT NULL,
|
||||
sender varchar(255) NULL,
|
||||
sender_name varchar(255) NULL,
|
||||
created_at datetime NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
);";
|
||||
|
||||
$this->addSql($sql);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql("DROP TABLE mail;");
|
||||
}
|
||||
}
|
||||
@ -2,10 +2,12 @@
|
||||
|
||||
use Bee\API\Console\Command\InitializeDataCommand;
|
||||
use Bee\API\Console\Command\RbacUpdateCommand;
|
||||
use Bee\API\Console\Command\SendMailsCommand;
|
||||
|
||||
return [
|
||||
'commands' => [
|
||||
InitializeDataCommand::class,
|
||||
RbacUpdateCommand::class,
|
||||
SendMailsCommand::class,
|
||||
]
|
||||
];
|
||||
|
||||
@ -2,11 +2,13 @@
|
||||
|
||||
use Bee\API\Console\Command\InitializeDataCommand;
|
||||
use Bee\API\Console\Command\RbacUpdateCommand;
|
||||
use Bee\API\Console\Command\SendMailsCommand;
|
||||
use Reinfi\DependencyInjection\Factory\AutoWiringFactory;
|
||||
|
||||
return [
|
||||
'factories' => [
|
||||
InitializeDataCommand::class => AutoWiringFactory::class,
|
||||
RbacUpdateCommand::class => AutoWiringFactory::class,
|
||||
SendMailsCommand::class => AutoWiringFactory::class,
|
||||
],
|
||||
];
|
||||
|
||||
@ -75,6 +75,7 @@ class InitializeDataCommand extends Command
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->success("Done");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,6 +93,7 @@ class RbacUpdateCommand extends Command
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->success("Done");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
43
src/ApiDomain/Console/src/Command/SendMailsCommand.php
Normal file
43
src/ApiDomain/Console/src/Command/SendMailsCommand.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\API\Console\Command;
|
||||
|
||||
use Bee\Infrastructure\Logging\Logger\Logger;
|
||||
use Bee\Infrastructure\Mail\Service\MailService;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(name: 'mails:send', description: 'Sends all mails left in the mail queue')]
|
||||
class SendMailsCommand extends Command
|
||||
{
|
||||
|
||||
public function __construct(
|
||||
private readonly MailService $service,
|
||||
private readonly Logger $logger,
|
||||
) {
|
||||
parent::__construct($this->getName());
|
||||
}
|
||||
|
||||
protected function execute(
|
||||
InputInterface $input,
|
||||
OutputInterface $output
|
||||
): int {
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
try {
|
||||
$this->service->send();
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
$io->error($e->getMessage());
|
||||
$io->error($e->getTraceAsString());
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$io->success("Done");
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Bee\API\External\Health\Handler;
|
||||
|
||||
use Bee\Infrastructure\Mail\Service\MailService;
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
@ -11,7 +12,8 @@ use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class HealthHandler implements RequestHandlerInterface
|
||||
{
|
||||
public function __construct() {
|
||||
public function __construct(
|
||||
) {
|
||||
}
|
||||
|
||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||
@ -19,5 +21,3 @@ class HealthHandler implements RequestHandlerInterface
|
||||
return new JsonResponse("I'm fine. :)");
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
112
src/DataDomain/Business/src/Entity/Mail.php
Normal file
112
src/DataDomain/Business/src/Entity/Mail.php
Normal file
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\Data\Business\Entity;
|
||||
|
||||
use DateTime;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Bee\Infrastructure\UuidGenerator\UuidGenerator;
|
||||
use Ramsey\Uuid\UuidInterface;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass="Bee\Data\Business\Repository\MailRepository")
|
||||
* @ORM\Table(name="mail")
|
||||
*/
|
||||
class Mail {
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(name="id", type="uuid_binary_ordered_time")
|
||||
*/
|
||||
private UuidInterface $id;
|
||||
|
||||
/** @ORM\Column(name="template", type="string") */
|
||||
private string $template;
|
||||
|
||||
/** @ORM\Column(name="data", type="json") */
|
||||
private array $data;
|
||||
|
||||
/** @ORM\Column(name="recipient", type="string") */
|
||||
private string $recipient;
|
||||
|
||||
/** @ORM\Column(name="sender", type="string", nullable="true") */
|
||||
private ?string $sender;
|
||||
|
||||
/** @ORM\Column(name="sender_name", type="string", nullable="true") */
|
||||
private ?string $senderName;
|
||||
|
||||
/** @ORM\Column(name="created_at", type="datetime") */
|
||||
private DateTime $createdAt;
|
||||
|
||||
public function __construct() {
|
||||
$this->id = UuidGenerator::generate();
|
||||
|
||||
$now = new DateTime();
|
||||
$this->setCreatedAt($now);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ORM\PrePersist
|
||||
* @ORM\PreUpdate
|
||||
*/
|
||||
public function updateTimestamps(): void {
|
||||
$now = new DateTime();
|
||||
//$this->setUpdatedAt($now);
|
||||
}
|
||||
|
||||
|
||||
public function getId(): UuidInterface {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getTemplate(): string
|
||||
{
|
||||
return $this->template;
|
||||
}
|
||||
public function setTemplate(string $template): void
|
||||
{
|
||||
$this->template = $template;
|
||||
}
|
||||
|
||||
public function getData(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
public function setData(array $data): void
|
||||
{
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function getRecipient(): string
|
||||
{
|
||||
return $this->recipient;
|
||||
}
|
||||
public function setRecipient(string $recipient): void
|
||||
{
|
||||
$this->recipient = $recipient;
|
||||
}
|
||||
|
||||
public function getSender(): ?string
|
||||
{
|
||||
return $this->sender;
|
||||
}
|
||||
public function setSender(?string $sender): void
|
||||
{
|
||||
$this->sender = $sender;
|
||||
}
|
||||
|
||||
public function getSenderName(): ?string
|
||||
{
|
||||
return $this->senderName;
|
||||
}
|
||||
public function setSenderName(?string $senderName): void
|
||||
{
|
||||
$this->senderName = $senderName;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): DateTime {
|
||||
return $this->createdAt;
|
||||
}
|
||||
public function setCreatedAt(DateTime $createdAt): void {
|
||||
$this->createdAt = $createdAt;
|
||||
}
|
||||
}
|
||||
10
src/DataDomain/Business/src/Repository/MailRepository.php
Normal file
10
src/DataDomain/Business/src/Repository/MailRepository.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Bee\Data\Business\Repository;
|
||||
|
||||
use Bee\Data\Business\Entity\User;
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
class MailRepository extends EntityRepository {
|
||||
|
||||
}
|
||||
@ -29,7 +29,7 @@ class SendMailStep implements TaskInterface
|
||||
$command = $payload->getCommand();
|
||||
$registration = $payload->getRegistration();
|
||||
|
||||
$this->mailService->send(
|
||||
$this->mailService->enqueue(
|
||||
template: 'registration',
|
||||
templateData: [
|
||||
'username' => $command->getUsername(),
|
||||
@ -40,9 +40,7 @@ class SendMailStep implements TaskInterface
|
||||
$registration->getId()->toString()
|
||||
)
|
||||
],
|
||||
recipient: $command->getMail(),
|
||||
sender: 'beekeeper@stack-up.de',
|
||||
senderName: "Beekeeper"
|
||||
recipient: $command->getMail()
|
||||
);
|
||||
|
||||
$pipeline->next()($payload, $pipeline);
|
||||
|
||||
@ -50,7 +50,7 @@ class ForgotPasswordCommandHandler
|
||||
$this->entityManager->persist($passwordToken);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->mailService->send(
|
||||
$this->mailService->enqueue(
|
||||
'reset-password',
|
||||
templateData: [
|
||||
'username' => $user->getUsername(),
|
||||
@ -61,8 +61,6 @@ class ForgotPasswordCommandHandler
|
||||
)
|
||||
],
|
||||
recipient: $mail,
|
||||
sender: 'beekeeper@stack-up.de',
|
||||
senderName: 'Beekeeper'
|
||||
);
|
||||
|
||||
return new ForgotPasswordCommandResult();
|
||||
|
||||
@ -4,6 +4,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace Bee\Infrastructure\Mail\Service;
|
||||
|
||||
use Bee\Data\Business\Entity\Mail;
|
||||
use Bee\Data\Business\Manager\EntityManager;
|
||||
use Bee\Data\Business\Repository\MailRepository;
|
||||
use Exception;
|
||||
use Latte\Engine;
|
||||
use Nette\Mail\Mailer;
|
||||
@ -18,18 +21,70 @@ class MailService
|
||||
{
|
||||
private const TEMPLATE_PATH = APP_ROOT . '/data/mails/';
|
||||
private readonly Engine $engine;
|
||||
private readonly MailRepository $mailRepository;
|
||||
|
||||
public function __construct(
|
||||
private readonly EntityManager $entityManager,
|
||||
private readonly ConfigService $configService,
|
||||
private readonly Logger $logger,
|
||||
) {
|
||||
$this->engine = new Engine();
|
||||
|
||||
$this->mailRepository = $this->entityManager->getRepository(Mail::class);
|
||||
}
|
||||
|
||||
public function enqueue(
|
||||
string $template,
|
||||
array $templateData,
|
||||
string $recipient,
|
||||
?string $sender = null,
|
||||
?string $senderName = null
|
||||
): void {
|
||||
$mail = new Mail();
|
||||
$mail->setTemplate($template);
|
||||
$mail->setData($templateData);
|
||||
$mail->setRecipient($recipient);
|
||||
$mail->setSender($sender);
|
||||
$mail->setSenderName($senderName);
|
||||
|
||||
$this->entityManager->persist($mail);
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
public function send(?int $count = null): void {
|
||||
$qb = $this->mailRepository->createQueryBuilder('m');
|
||||
$qb->orderBy('m.createdAt', 'asc');
|
||||
|
||||
if ($count !== null) {
|
||||
$qb->setMaxResults($count);
|
||||
}
|
||||
|
||||
$mailsToSend = $qb->getQuery()->execute();
|
||||
|
||||
/** @var Mail $mailToSend */
|
||||
foreach ($mailsToSend as $mailToSend) {
|
||||
|
||||
try {
|
||||
$this->sendMail(
|
||||
$mailToSend->getTemplate(),
|
||||
$mailToSend->getData(),
|
||||
$mailToSend->getRecipient(),
|
||||
$mailToSend->getSender(),
|
||||
$mailToSend->getSenderName(),
|
||||
);
|
||||
|
||||
$this->entityManager->remove($mailToSend);
|
||||
} catch (SendMailFailedException $e) {
|
||||
// log is done withing sendMail
|
||||
}
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SendMailFailedException
|
||||
*/
|
||||
public function send(
|
||||
private function sendMail(
|
||||
string $template,
|
||||
array $templateData,
|
||||
string $recipient,
|
||||
@ -112,9 +167,7 @@ class MailService
|
||||
$defaultConfig = $this->configService->resolve('mail.default');
|
||||
|
||||
$from = $sender ?? $defaultConfig['sender'] ?? throw new Exception('Could not determine Sender');
|
||||
if ($senderName !== null) {
|
||||
$from = sprintf('%s <%s>', $senderName, $from);
|
||||
}
|
||||
return $from;
|
||||
$name =$sender ?? $defaultConfig['senderName'] ?? throw new Exception('Could not determine Sender Name');
|
||||
return sprintf('%s <%s>', $name, $from);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user