Merge remote-tracking branch 'MyIgel/mailing'
This commit is contained in:
commit
6187eed3bb
|
@ -29,6 +29,7 @@
|
||||||
"psr/container": "^1.0",
|
"psr/container": "^1.0",
|
||||||
"psr/http-server-middleware": "^1.0",
|
"psr/http-server-middleware": "^1.0",
|
||||||
"psr/log": "^1.0",
|
"psr/log": "^1.0",
|
||||||
|
"swiftmailer/swiftmailer": "^6.1",
|
||||||
"symfony/http-foundation": "^3.3",
|
"symfony/http-foundation": "^3.3",
|
||||||
"symfony/psr-http-message-bridge": "^1.0",
|
"symfony/psr-http-message-bridge": "^1.0",
|
||||||
"twig/extensions": "^1.5",
|
"twig/extensions": "^1.5",
|
||||||
|
|
|
@ -5,9 +5,13 @@
|
||||||
return [
|
return [
|
||||||
// Service providers
|
// Service providers
|
||||||
'providers' => [
|
'providers' => [
|
||||||
|
|
||||||
|
// Application bootstrap
|
||||||
\Engelsystem\Logger\LoggerServiceProvider::class,
|
\Engelsystem\Logger\LoggerServiceProvider::class,
|
||||||
\Engelsystem\Exceptions\ExceptionsServiceProvider::class,
|
\Engelsystem\Exceptions\ExceptionsServiceProvider::class,
|
||||||
\Engelsystem\Config\ConfigServiceProvider::class,
|
\Engelsystem\Config\ConfigServiceProvider::class,
|
||||||
|
|
||||||
|
// Request handling
|
||||||
\Engelsystem\Http\UrlGeneratorServiceProvider::class,
|
\Engelsystem\Http\UrlGeneratorServiceProvider::class,
|
||||||
\Engelsystem\Renderer\RendererServiceProvider::class,
|
\Engelsystem\Renderer\RendererServiceProvider::class,
|
||||||
\Engelsystem\Database\DatabaseServiceProvider::class,
|
\Engelsystem\Database\DatabaseServiceProvider::class,
|
||||||
|
@ -19,13 +23,22 @@ return [
|
||||||
\Engelsystem\Renderer\TwigServiceProvider::class,
|
\Engelsystem\Renderer\TwigServiceProvider::class,
|
||||||
\Engelsystem\Middleware\RouteDispatcherServiceProvider::class,
|
\Engelsystem\Middleware\RouteDispatcherServiceProvider::class,
|
||||||
\Engelsystem\Middleware\RequestHandlerServiceProvider::class,
|
\Engelsystem\Middleware\RequestHandlerServiceProvider::class,
|
||||||
|
|
||||||
|
// Additional services
|
||||||
|
\Engelsystem\Mail\MailerServiceProvider::class,
|
||||||
],
|
],
|
||||||
|
|
||||||
// Application middleware
|
// Application middleware
|
||||||
'middleware' => [
|
'middleware' => [
|
||||||
|
|
||||||
|
// Basic initialization
|
||||||
\Engelsystem\Middleware\SendResponseHandler::class,
|
\Engelsystem\Middleware\SendResponseHandler::class,
|
||||||
\Engelsystem\Middleware\ExceptionHandler::class,
|
\Engelsystem\Middleware\ExceptionHandler::class,
|
||||||
|
|
||||||
|
// Changes of request/response parameters
|
||||||
\Engelsystem\Middleware\SetLocale::class,
|
\Engelsystem\Middleware\SetLocale::class,
|
||||||
|
|
||||||
|
// The application code
|
||||||
\Engelsystem\Middleware\ErrorHandler::class,
|
\Engelsystem\Middleware\ErrorHandler::class,
|
||||||
\Engelsystem\Middleware\RouteDispatcher::class,
|
\Engelsystem\Middleware\RouteDispatcher::class,
|
||||||
\Engelsystem\Middleware\RequestHandler::class,
|
\Engelsystem\Middleware\RequestHandler::class,
|
||||||
|
|
|
@ -26,8 +26,24 @@ return [
|
||||||
// Contact email address, linked on every page
|
// Contact email address, linked on every page
|
||||||
'contact_email' => env('CONTACT_EMAIL', 'mailto:ticket@c3heaven.de'),
|
'contact_email' => env('CONTACT_EMAIL', 'mailto:ticket@c3heaven.de'),
|
||||||
|
|
||||||
|
// Email config
|
||||||
|
'email' => [
|
||||||
|
// Can be mail, smtp, sendmail or log
|
||||||
|
'driver' => env('MAIL_DRIVER', 'smtp'),
|
||||||
|
'from' => [
|
||||||
// From address of all emails
|
// From address of all emails
|
||||||
'no_reply_email' => env('NO_REPLY_EMAIL', 'noreply@engelsystem.de'),
|
'address' => env('MAIL_FROM_ADDRESS', 'noreply@engelsystem.de'),
|
||||||
|
'name' => env('MAIL_FROM_NAME', 'Engelsystem')
|
||||||
|
],
|
||||||
|
|
||||||
|
'host' => env('MAIL_HOST', 'localhost'),
|
||||||
|
'port' => env('MAIL_PORT', 587),
|
||||||
|
// Transport encryption like tls
|
||||||
|
'encryption' => env('MAIL_ENCRYPTION', null),
|
||||||
|
'username' => env('MAIL_USERNAME'),
|
||||||
|
'password' => env('MAIL_PASSWORD'),
|
||||||
|
'sendmail' => env('MAIL_SENDMAIL', '/usr/sbin/sendmail -bs'),
|
||||||
|
],
|
||||||
|
|
||||||
// Default theme, 1=style1.css
|
// Default theme, 1=style1.css
|
||||||
'theme' => env('THEME', 1),
|
'theme' => env('THEME', 1),
|
||||||
|
@ -55,28 +71,27 @@ return [
|
||||||
// Only arrived angels can sign up for shifts
|
// Only arrived angels can sign up for shifts
|
||||||
'signup_requires_arrival' => false,
|
'signup_requires_arrival' => false,
|
||||||
|
|
||||||
// Anzahl Stunden bis zum Austragen eigener Schichten
|
// Number of hours that an angel has to sign out own shifts
|
||||||
'last_unsubscribe' => 3,
|
'last_unsubscribe' => 3,
|
||||||
|
|
||||||
// Setzt den zu verwendenden Crypto-Algorithmus (entsprechend der Dokumentation von crypt()).
|
// Define the algorithm to use for `crypt()` of passwords
|
||||||
// Falls ein Benutzerpasswort in einem anderen Format gespeichert ist,
|
// If the user uses an old algorithm the password will be converted to the new format
|
||||||
// wird es bei der ersten Benutzung des Klartext-Passworts in das neue Format
|
|
||||||
// konvertiert.
|
|
||||||
// MD5 '$1'
|
// MD5 '$1'
|
||||||
// Blowfish '$2y$13'
|
// Blowfish '$2y$13'
|
||||||
// SHA-256 '$5$rounds=5000'
|
// SHA-256 '$5$rounds=5000'
|
||||||
// SHA-512 '$6$rounds=5000'
|
// SHA-512 '$6$rounds=5000'
|
||||||
'crypt_alg' => '$6$rounds=5000',
|
'crypt_alg' => '$6$rounds=5000',
|
||||||
|
|
||||||
|
// The minimum length for passwords
|
||||||
'min_password_length' => 8,
|
'min_password_length' => 8,
|
||||||
|
|
||||||
// Wenn Engel beim Registrieren oder in ihrem Profil eine T-Shirt Größe angeben sollen, auf true setzen:
|
// Enables the T-Shirt configuration on signup and profile
|
||||||
'enable_tshirt_size' => true,
|
'enable_tshirt_size' => true,
|
||||||
|
|
||||||
// Number of shifts to freeload until angel is locked for shift signup.
|
// Number of shifts to freeload until angel is locked for shift signup.
|
||||||
'max_freeloadable_shifts' => 2,
|
'max_freeloadable_shifts' => 2,
|
||||||
|
|
||||||
// local timezone
|
// Local timezone
|
||||||
'timezone' => env('TIMEZONE', 'Europe/Berlin'),
|
'timezone' => env('TIMEZONE', 'Europe/Berlin'),
|
||||||
|
|
||||||
// Multiply 'night shifts' and freeloaded shifts (start or end between 2 and 6 exclusive) by 2
|
// Multiply 'night shifts' and freeloaded shifts (start or end between 2 and 6 exclusive) by 2
|
||||||
|
@ -99,6 +114,7 @@ return [
|
||||||
'en_US.UTF-8' => 'English',
|
'en_US.UTF-8' => 'English',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// The default locale to use
|
||||||
'default_locale' => env('DEFAULT_LOCALE', 'en_US.UTF-8'),
|
'default_locale' => env('DEFAULT_LOCALE', 'en_US.UTF-8'),
|
||||||
|
|
||||||
// Available T-Shirt sizes, set value to null if not available
|
// Available T-Shirt sizes, set value to null if not available
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Engelsystem\Mail\EngelsystemMailer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $recipient_user
|
* @param array $recipient_user
|
||||||
* @param string $title
|
* @param string $title
|
||||||
|
@ -18,38 +20,21 @@ function engelsystem_email_to_user($recipient_user, $title, $message, $not_if_it
|
||||||
/** @var \Engelsystem\Helpers\Translator $translator */
|
/** @var \Engelsystem\Helpers\Translator $translator */
|
||||||
$translator = app()->get('translator');
|
$translator = app()->get('translator');
|
||||||
$locale = $translator->getLocale();
|
$locale = $translator->getLocale();
|
||||||
|
/** @var EngelsystemMailer $mailer */
|
||||||
|
$mailer = app('mailer');
|
||||||
|
|
||||||
$translator->setLocale($recipient_user['Sprache']);
|
$translator->setLocale($recipient_user['Sprache']);
|
||||||
$message = sprintf(__('Hi %s,'), $recipient_user['Nick']) . "\n\n"
|
$status = $mailer->sendView(
|
||||||
. __('here is a message for you from the engelsystem:') . "\n\n"
|
$recipient_user['email'],
|
||||||
. $message . "\n\n"
|
$title,
|
||||||
. __('This email is autogenerated and has not been signed. You got this email because you are registered in the engelsystem.');
|
'emails/mail',
|
||||||
|
['user' => $recipient_user['Nick'], 'message' => $message]
|
||||||
|
);
|
||||||
$translator->setLocale($locale);
|
$translator->setLocale($locale);
|
||||||
|
|
||||||
return engelsystem_email($recipient_user['email'], $title, $message);
|
if (!$status) {
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $address
|
|
||||||
* @param string $title
|
|
||||||
* @param string $message
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
function engelsystem_email($address, $title, $message)
|
|
||||||
{
|
|
||||||
$result = mail(
|
|
||||||
$address,
|
|
||||||
$title,
|
|
||||||
$message,
|
|
||||||
sprintf(
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\r\nFrom: Engelsystem <%s>",
|
|
||||||
config('no_reply_email')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($result === false) {
|
|
||||||
engelsystem_error('Unable to send email.');
|
engelsystem_error('Unable to send email.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return (bool)$status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Mail;
|
||||||
|
|
||||||
|
use Engelsystem\Renderer\Renderer;
|
||||||
|
use Swift_Mailer as SwiftMailer;
|
||||||
|
|
||||||
|
class EngelsystemMailer extends Mailer
|
||||||
|
{
|
||||||
|
/** @var Renderer|null */
|
||||||
|
protected $view;
|
||||||
|
|
||||||
|
public function __construct(SwiftMailer $mailer, Renderer $view = null)
|
||||||
|
{
|
||||||
|
parent::__construct($mailer);
|
||||||
|
|
||||||
|
$this->view = $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a template
|
||||||
|
*
|
||||||
|
* @param string $to
|
||||||
|
* @param string $subject
|
||||||
|
* @param string $template
|
||||||
|
* @param array $data
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function sendView($to, $subject, $template, $data = []): int
|
||||||
|
{
|
||||||
|
$body = $this->view->render($template, $data);
|
||||||
|
|
||||||
|
return $this->send($to, $subject, $body);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Mail;
|
||||||
|
|
||||||
|
use Engelsystem\Renderer\Renderer;
|
||||||
|
use Swift_Mailer as SwiftMailer;
|
||||||
|
use Swift_Message as SwiftMessage;
|
||||||
|
|
||||||
|
class Mailer
|
||||||
|
{
|
||||||
|
/** @var SwiftMailer */
|
||||||
|
protected $mailer;
|
||||||
|
|
||||||
|
/** @var Renderer|null */
|
||||||
|
protected $view;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $fromAddress = '';
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $fromName = null;
|
||||||
|
|
||||||
|
public function __construct(SwiftMailer $mailer)
|
||||||
|
{
|
||||||
|
$this->mailer = $mailer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the mail
|
||||||
|
*
|
||||||
|
* @param string|string[] $to
|
||||||
|
* @param string $subject
|
||||||
|
* @param string $body
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function send($to, string $subject, string $body): int
|
||||||
|
{
|
||||||
|
/** @var SwiftMessage $message */
|
||||||
|
$message = $this->mailer->createMessage();
|
||||||
|
$message->setTo((array)$to)
|
||||||
|
->setFrom($this->fromAddress, $this->fromName)
|
||||||
|
->setSubject($subject)
|
||||||
|
->setBody($body);
|
||||||
|
|
||||||
|
return $this->mailer->send($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFromAddress(): string
|
||||||
|
{
|
||||||
|
return $this->fromAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $fromAddress
|
||||||
|
*/
|
||||||
|
public function setFromAddress(string $fromAddress)
|
||||||
|
{
|
||||||
|
$this->fromAddress = $fromAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getFromName(): string
|
||||||
|
{
|
||||||
|
return $this->fromName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $fromName
|
||||||
|
*/
|
||||||
|
public function setFromName(string $fromName)
|
||||||
|
{
|
||||||
|
$this->fromName = $fromName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Mail;
|
||||||
|
|
||||||
|
use Engelsystem\Config\Config;
|
||||||
|
use Engelsystem\Container\ServiceProvider;
|
||||||
|
use Engelsystem\Mail\Transport\LogTransport;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Swift_Mailer as SwiftMailer;
|
||||||
|
use Swift_SendmailTransport as SendmailTransport;
|
||||||
|
use Swift_SmtpTransport as SmtpTransport;
|
||||||
|
use Swift_Transport as Transport;
|
||||||
|
|
||||||
|
class MailerServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
/** @var Config $config */
|
||||||
|
$config = $this->app->get('config');
|
||||||
|
$mailConfig = $config->get('email');
|
||||||
|
|
||||||
|
$transport = $this->getTransport($mailConfig['driver'], $mailConfig);
|
||||||
|
$this->app->instance(Transport::class, $transport);
|
||||||
|
$this->app->instance('mailer.transport', $transport);
|
||||||
|
|
||||||
|
/** @var SwiftMailer $swiftMailer */
|
||||||
|
$swiftMailer = $this->app->make(SwiftMailer::class);
|
||||||
|
$this->app->instance(SwiftMailer::class, $swiftMailer);
|
||||||
|
$this->app->instance('mailer.swift', $swiftMailer);
|
||||||
|
|
||||||
|
/** @var Mailer $mailer */
|
||||||
|
$mailer = $this->app->make(EngelsystemMailer::class);
|
||||||
|
$mailer->setFromAddress($mailConfig['from']['address']);
|
||||||
|
if (!empty($mailConfig['from']['name'])) {
|
||||||
|
$mailer->setFromName($mailConfig['from']['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->app->instance(EngelsystemMailer::class, $mailer);
|
||||||
|
$this->app->instance(Mailer::class, $mailer);
|
||||||
|
$this->app->instance('mailer', $mailer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $transport
|
||||||
|
* @param array $config
|
||||||
|
* @return Transport
|
||||||
|
*/
|
||||||
|
protected function getTransport($transport, $config)
|
||||||
|
{
|
||||||
|
switch ($transport) {
|
||||||
|
case 'log':
|
||||||
|
return $this->app->make(LogTransport::class);
|
||||||
|
case 'mail':
|
||||||
|
case 'sendmail':
|
||||||
|
return $this->app->make(SendmailTransport::class, ['command' => $config['sendmail']]);
|
||||||
|
case 'smtp':
|
||||||
|
return $this->getSmtpTransport($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidArgumentException(sprintf('Mail driver "%s" not found', $transport));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $config
|
||||||
|
* @return SmtpTransport
|
||||||
|
*/
|
||||||
|
protected function getSmtpTransport(array $config)
|
||||||
|
{
|
||||||
|
/** @var SmtpTransport $transport */
|
||||||
|
$transport = $this->app->make(SmtpTransport::class, [
|
||||||
|
'host' => $config['host'],
|
||||||
|
'port' => $config['port'],
|
||||||
|
'encryption' => $config['encryption'],
|
||||||
|
// TODO: The security variable should be removed in the future
|
||||||
|
// https://github.com/swiftmailer/swiftmailer/commit/d3d6a98ab7dc155a04eb08273db7cd34606e7b5e#commitcomment-30462876
|
||||||
|
'security' => $config['encryption'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($config['username']) {
|
||||||
|
$transport->setUsername($config['username']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config['password']) {
|
||||||
|
$transport->setPassword($config['password']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transport;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Mail\Transport;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Swift_Mime_SimpleMessage as SimpleMessage;
|
||||||
|
|
||||||
|
class LogTransport extends Transport
|
||||||
|
{
|
||||||
|
/** @var LoggerInterface */
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
public function __construct(LoggerInterface $logger)
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the given Message.
|
||||||
|
*
|
||||||
|
* Recipient/sender data will be retrieved from the Message API.
|
||||||
|
* The return value is the number of recipients
|
||||||
|
*
|
||||||
|
* @param SimpleMessage $message
|
||||||
|
* @param string[] $failedRecipients An array of failures by-reference
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function send(
|
||||||
|
SimpleMessage $message,
|
||||||
|
&$failedRecipients = null
|
||||||
|
): int {
|
||||||
|
$this->logger->debug(
|
||||||
|
'Mail: Send mail "{title}" to "{recipients}":' . PHP_EOL . '{content}',
|
||||||
|
[
|
||||||
|
'title' => $message->getSubject(),
|
||||||
|
'recipients' => $this->getTo($message),
|
||||||
|
'content' => (string)$message->getHeaders() . PHP_EOL . PHP_EOL . $message->toString(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
return count($this->allRecipients($message));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Mail\Transport;
|
||||||
|
|
||||||
|
use Swift_Events_EventListener;
|
||||||
|
use Swift_Mime_SimpleMessage as SimpleMessage;
|
||||||
|
use Swift_Transport as SwiftTransport;
|
||||||
|
|
||||||
|
abstract class Transport implements SwiftTransport
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Test if this Transport mechanism has started.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isStarted(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start this Transport mechanism.
|
||||||
|
*/
|
||||||
|
public function start() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop this Transport mechanism.
|
||||||
|
*/
|
||||||
|
public function stop() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this Transport mechanism is alive.
|
||||||
|
*
|
||||||
|
* If a Transport mechanism session is no longer functional, the method
|
||||||
|
* returns FALSE. It is the responsibility of the developer to handle this
|
||||||
|
* case and restart the Transport mechanism manually.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* if (!$transport->ping()) {
|
||||||
|
* $transport->stop();
|
||||||
|
* $transport->start();
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* The Transport mechanism will be started, if it is not already.
|
||||||
|
*
|
||||||
|
* It is undefined if the Transport mechanism attempts to restart as long as
|
||||||
|
* the return value reflects whether the mechanism is now functional.
|
||||||
|
*
|
||||||
|
* @return bool TRUE if the transport is alive
|
||||||
|
*/
|
||||||
|
public function ping(): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a plugin in the Transport.
|
||||||
|
*
|
||||||
|
* @param Swift_Events_EventListener $plugin
|
||||||
|
*/
|
||||||
|
public function registerPlugin(Swift_Events_EventListener $plugin) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a unified list of all recipients
|
||||||
|
*
|
||||||
|
* @param SimpleMessage $message
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function allRecipients(SimpleMessage $message): array
|
||||||
|
{
|
||||||
|
return array_merge(
|
||||||
|
(array)$message->getTo(),
|
||||||
|
(array)$message->getCc(),
|
||||||
|
(array)$message->getBcc()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a concatenated list of mail recipients
|
||||||
|
*
|
||||||
|
* @param SimpleMessage $message
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getTo(SimpleMessage $message): string
|
||||||
|
{
|
||||||
|
return $this->formatTo($this->allRecipients($message));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $recipients
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function formatTo(array $recipients)
|
||||||
|
{
|
||||||
|
$list = [];
|
||||||
|
foreach ($recipients as $address => $name) {
|
||||||
|
$list[] = $name ? sprintf('%s <%s>', $name, $address) : $address;
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(',', $list);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{{ __('Hi %s,', [user]) }}
|
||||||
|
|
||||||
|
{{ __('here is a message for you from the engelsystem:') }}
|
||||||
|
{{ message|raw }}
|
||||||
|
|
||||||
|
{{ __('This email is autogenerated and has not been signed. You got this email because you are registered in the engelsystem.') }}
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Mail;
|
||||||
|
|
||||||
|
use Engelsystem\Mail\EngelsystemMailer;
|
||||||
|
use Engelsystem\Renderer\Renderer;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Swift_Mailer as SwiftMailer;
|
||||||
|
|
||||||
|
class EngelsystemMailerTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\EngelsystemMailer::__construct
|
||||||
|
* @covers \Engelsystem\Mail\EngelsystemMailer::sendView
|
||||||
|
*/
|
||||||
|
public function testSendView()
|
||||||
|
{
|
||||||
|
/** @var Renderer|MockObject $view */
|
||||||
|
$view = $this->createMock(Renderer::class);
|
||||||
|
/** @var SwiftMailer|MockObject $swiftMailer */
|
||||||
|
$swiftMailer = $this->createMock(SwiftMailer::class);
|
||||||
|
/** @var EngelsystemMailer|MockObject $mailer */
|
||||||
|
$mailer = $this->getMockBuilder(EngelsystemMailer::class)
|
||||||
|
->setConstructorArgs(['mailer' => $swiftMailer, 'view' => $view])
|
||||||
|
->setMethods(['send'])
|
||||||
|
->getMock();
|
||||||
|
$mailer->expects($this->once())
|
||||||
|
->method('send')
|
||||||
|
->with('foo@bar.baz', 'Lorem dolor', 'Rendered Stuff!')
|
||||||
|
->willReturn(1);
|
||||||
|
$view->expects($this->once())
|
||||||
|
->method('render')
|
||||||
|
->with('test/template.tpl', ['dev' => true])
|
||||||
|
->willReturn('Rendered Stuff!');
|
||||||
|
|
||||||
|
$return = $mailer->sendView('foo@bar.baz', 'Lorem dolor', 'test/template.tpl', ['dev' => true]);
|
||||||
|
$this->equalTo(1, $return);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Middleware;
|
||||||
|
|
||||||
|
use Engelsystem\Application;
|
||||||
|
use Engelsystem\Config\Config;
|
||||||
|
use Engelsystem\Mail\EngelsystemMailer;
|
||||||
|
use Engelsystem\Mail\Mailer;
|
||||||
|
use Engelsystem\Mail\MailerServiceProvider;
|
||||||
|
use Engelsystem\Mail\Transport\LogTransport;
|
||||||
|
use Engelsystem\Test\Unit\ServiceProviderTest;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Swift_Mailer as SwiftMailer;
|
||||||
|
use Swift_SendmailTransport as SendmailTransport;
|
||||||
|
use Swift_SmtpTransport as SmtpTransport;
|
||||||
|
use Swift_Transport as Transport;
|
||||||
|
|
||||||
|
class MailerServiceProviderTest extends ServiceProviderTest
|
||||||
|
{
|
||||||
|
/** @var array */
|
||||||
|
protected $defaultConfig = [
|
||||||
|
'email' => [
|
||||||
|
'driver' => 'mail',
|
||||||
|
'from' => [
|
||||||
|
'name' => 'Engelsystem',
|
||||||
|
'address' => 'foo@bar.batz',
|
||||||
|
],
|
||||||
|
'sendmail' => '/opt/bin/sendmail -bs',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $smtpConfig = [
|
||||||
|
'email' => [
|
||||||
|
'driver' => 'smtp',
|
||||||
|
'host' => 'mail.foo.bar',
|
||||||
|
'port' => 587,
|
||||||
|
'encryption' => 'tls',
|
||||||
|
'username' => 'foobar',
|
||||||
|
'password' => 'LoremIpsum123',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\MailerServiceProvider::register
|
||||||
|
*/
|
||||||
|
public function testRegister()
|
||||||
|
{
|
||||||
|
$app = $this->getApplication();
|
||||||
|
|
||||||
|
$serviceProvider = new MailerServiceProvider($app);
|
||||||
|
$serviceProvider->register();
|
||||||
|
|
||||||
|
$this->assertExistsInContainer(['mailer.transport', Transport::class], $app);
|
||||||
|
$this->assertExistsInContainer(['mailer.swift', SwiftMailer::class], $app);
|
||||||
|
$this->assertExistsInContainer(['mailer', EngelsystemMailer::class, Mailer::class], $app);
|
||||||
|
|
||||||
|
/** @var EngelsystemMailer $mailer */
|
||||||
|
$mailer = $app->get('mailer');
|
||||||
|
$this->assertEquals('Engelsystem', $mailer->getFromName());
|
||||||
|
$this->assertEquals('foo@bar.batz', $mailer->getFromAddress());
|
||||||
|
|
||||||
|
/** @var SendmailTransport $transport */
|
||||||
|
$transport = $app->get('mailer.transport');
|
||||||
|
$this->assertEquals($this->defaultConfig['email']['sendmail'], $transport->getCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function provideTransports()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[LogTransport::class, ['email' => ['driver' => 'log']]],
|
||||||
|
[SendmailTransport::class, ['email' => ['driver' => 'mail']]],
|
||||||
|
[SendmailTransport::class, ['email' => ['driver' => 'sendmail']]],
|
||||||
|
[
|
||||||
|
SmtpTransport::class,
|
||||||
|
$this->smtpConfig
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\MailerServiceProvider::getTransport
|
||||||
|
* @param string $class
|
||||||
|
* @param array $emailConfig
|
||||||
|
* @dataProvider provideTransports
|
||||||
|
*/
|
||||||
|
public function testGetTransport($class, $emailConfig = [])
|
||||||
|
{
|
||||||
|
$app = $this->getApplication($emailConfig);
|
||||||
|
|
||||||
|
$serviceProvider = new MailerServiceProvider($app);
|
||||||
|
$serviceProvider->register();
|
||||||
|
|
||||||
|
$transport = $app->get('mailer.transport');
|
||||||
|
$this->assertInstanceOf($class, $transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\MailerServiceProvider::getTransport
|
||||||
|
*/
|
||||||
|
public function testGetTransportNotFound()
|
||||||
|
{
|
||||||
|
$app = $this->getApplication(['email' => ['driver' => 'foo-bar-batz']]);
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
|
||||||
|
$serviceProvider = new MailerServiceProvider($app);
|
||||||
|
$serviceProvider->register();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\MailerServiceProvider::getSmtpTransport
|
||||||
|
*/
|
||||||
|
public function testGetSmtpTransport()
|
||||||
|
{
|
||||||
|
$app = $this->getApplication($this->smtpConfig);
|
||||||
|
|
||||||
|
$serviceProvider = new MailerServiceProvider($app);
|
||||||
|
$serviceProvider->register();
|
||||||
|
|
||||||
|
/** @var SmtpTransport $transport */
|
||||||
|
$transport = $app->get('mailer.transport');
|
||||||
|
|
||||||
|
$this->assertEquals($this->smtpConfig['email']['host'], $transport->getHost());
|
||||||
|
$this->assertEquals($this->smtpConfig['email']['port'], $transport->getPort());
|
||||||
|
$this->assertEquals($this->smtpConfig['email']['encryption'], $transport->getEncryption());
|
||||||
|
$this->assertEquals($this->smtpConfig['email']['username'], $transport->getUsername());
|
||||||
|
$this->assertEquals($this->smtpConfig['email']['password'], $transport->getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $configuration
|
||||||
|
* @return Application
|
||||||
|
*/
|
||||||
|
protected function getApplication($configuration = []): Application
|
||||||
|
{
|
||||||
|
$app = new Application();
|
||||||
|
|
||||||
|
$configuration = new Config(array_replace_recursive($this->defaultConfig, $configuration));
|
||||||
|
$app->instance('config', $configuration);
|
||||||
|
|
||||||
|
$logger = $this->getMockForAbstractClass(LoggerInterface::class);
|
||||||
|
$app->instance(LoggerInterface::class, $logger);
|
||||||
|
|
||||||
|
return $app;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[] $abstracts
|
||||||
|
* @param Application $container
|
||||||
|
*/
|
||||||
|
protected function assertExistsInContainer($abstracts, $container)
|
||||||
|
{
|
||||||
|
$first = array_shift($abstracts);
|
||||||
|
$this->assertContainerHas($first, $container);
|
||||||
|
|
||||||
|
foreach ($abstracts as $abstract) {
|
||||||
|
$this->assertContainerHas($abstract, $container);
|
||||||
|
$this->assertEquals($container->get($first), $container->get($abstract));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $abstract
|
||||||
|
* @param Application $container
|
||||||
|
*/
|
||||||
|
protected function assertContainerHas($abstract, $container)
|
||||||
|
{
|
||||||
|
$this->assertTrue(
|
||||||
|
$container->has($abstract) || $container->hasMethodBinding($abstract),
|
||||||
|
sprintf('Container does not contain abstract %s', $abstract)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Mail;
|
||||||
|
|
||||||
|
use Engelsystem\Mail\Mailer;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Swift_Mailer as SwiftMailer;
|
||||||
|
use Swift_Message as SwiftMessage;
|
||||||
|
|
||||||
|
class MailerTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\Mailer::__construct
|
||||||
|
* @covers \Engelsystem\Mail\Mailer::getFromAddress
|
||||||
|
* @covers \Engelsystem\Mail\Mailer::setFromAddress
|
||||||
|
* @covers \Engelsystem\Mail\Mailer::getFromName
|
||||||
|
* @covers \Engelsystem\Mail\Mailer::setFromName
|
||||||
|
*/
|
||||||
|
public function testInitAndSettersAndGetters()
|
||||||
|
{
|
||||||
|
/** @var SwiftMailer|MockObject $swiftMailer */
|
||||||
|
$swiftMailer = $this->createMock(SwiftMailer::class);
|
||||||
|
|
||||||
|
$mailer = new Mailer($swiftMailer);
|
||||||
|
|
||||||
|
$mailer->setFromName('From Name');
|
||||||
|
$this->assertEquals('From Name', $mailer->getFromName());
|
||||||
|
|
||||||
|
$mailer->setFromAddress('from@foo.bar');
|
||||||
|
$this->assertEquals('from@foo.bar', $mailer->getFromAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\Mailer::send
|
||||||
|
*/
|
||||||
|
public function testSend()
|
||||||
|
{
|
||||||
|
/** @var SwiftMessage|MockObject $message */
|
||||||
|
$message = $this->createMock(SwiftMessage::class);
|
||||||
|
/** @var SwiftMailer|MockObject $swiftMailer */
|
||||||
|
$swiftMailer = $this->createMock(SwiftMailer::class);
|
||||||
|
$swiftMailer->expects($this->once())
|
||||||
|
->method('createMessage')
|
||||||
|
->willReturn($message);
|
||||||
|
$swiftMailer->expects($this->once())
|
||||||
|
->method('send')
|
||||||
|
->willReturn(1);
|
||||||
|
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('setTo')
|
||||||
|
->with(['to@xam.pel'])
|
||||||
|
->willReturn($message);
|
||||||
|
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('setFrom')
|
||||||
|
->with('foo@bar.baz', 'Lorem Ipsum')
|
||||||
|
->willReturn($message);
|
||||||
|
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('setSubject')
|
||||||
|
->with('Foo Bar')
|
||||||
|
->willReturn($message);
|
||||||
|
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('setBody')
|
||||||
|
->with('Lorem Ipsum!')
|
||||||
|
->willReturn($message);
|
||||||
|
|
||||||
|
$mailer = new Mailer($swiftMailer);
|
||||||
|
$mailer->setFromAddress('foo@bar.baz');
|
||||||
|
$mailer->setFromName('Lorem Ipsum');
|
||||||
|
|
||||||
|
$return = $mailer->send('to@xam.pel', 'Foo Bar', 'Lorem Ipsum!');
|
||||||
|
$this->equalTo(1, $return);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Mail\Transport;
|
||||||
|
|
||||||
|
use Engelsystem\Mail\Transport\LogTransport;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Swift_Mime_SimpleMessage as SimpleMessage;
|
||||||
|
|
||||||
|
class LogTransportTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\Transport\LogTransport::__construct
|
||||||
|
* @covers \Engelsystem\Mail\Transport\LogTransport::send
|
||||||
|
*/
|
||||||
|
public function testSend()
|
||||||
|
{
|
||||||
|
/** @var LoggerInterface|MockObject $logger */
|
||||||
|
$logger = $this->getMockForAbstractClass(LoggerInterface::class);
|
||||||
|
/** @var SimpleMessage|MockObject $message */
|
||||||
|
$message = $this->createMock(SimpleMessage::class);
|
||||||
|
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('getSubject')
|
||||||
|
->willReturn('Some subject');
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('getHeaders')
|
||||||
|
->willReturn('Head: er');
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('toString')
|
||||||
|
->willReturn('Message body');
|
||||||
|
|
||||||
|
$logger->expects($this->once())
|
||||||
|
->method('debug')
|
||||||
|
->willReturnCallback(function ($message, $context = []) {
|
||||||
|
foreach (array_keys($context) as $key) {
|
||||||
|
$this->assertContains(sprintf('{%s}', $key), $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals('Some subject', $context['title']);
|
||||||
|
$this->assertEquals('foo@bar.batz,Lorem Ipsum <lor@em.ips>', $context['recipients']);
|
||||||
|
$this->assertContains('Head: er', $context['content']);
|
||||||
|
$this->assertContains('Message body', $context['content']);
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @var LogTransport|MockObject $transport */
|
||||||
|
$transport = $this->getMockBuilder(LogTransport::class)
|
||||||
|
->setConstructorArgs(['logger' => $logger])
|
||||||
|
->setMethods(['allRecipients'])
|
||||||
|
->getMock();
|
||||||
|
$transport->expects($this->exactly(2))
|
||||||
|
->method('allRecipients')
|
||||||
|
->with($message)
|
||||||
|
->willReturn(['foo@bar.batz' => null, 'lor@em.ips' => 'Lorem Ipsum']);
|
||||||
|
|
||||||
|
$return = $transport->send($message);
|
||||||
|
$this->equalTo(2, $return);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Mail\Transport\Stub;
|
||||||
|
|
||||||
|
use Engelsystem\Mail\Transport\Transport;
|
||||||
|
use Swift_Mime_SimpleMessage as SimpleMessage;
|
||||||
|
|
||||||
|
class TransportImplementation extends Transport
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function send(SimpleMessage $message, &$failedRecipients = null)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SimpleMessage $message
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllRecipients(SimpleMessage $message)
|
||||||
|
{
|
||||||
|
return $this->allRecipients($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SimpleMessage $message
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getGetTo(SimpleMessage $message)
|
||||||
|
{
|
||||||
|
return $this->getTo($message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Mail\Transport;
|
||||||
|
|
||||||
|
use Engelsystem\Test\Unit\Mail\Transport\Stub\TransportImplementation;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Swift_Mime_SimpleMessage as SimpleMessage;
|
||||||
|
|
||||||
|
class TransportTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\Transport\Transport::isStarted
|
||||||
|
* @covers \Engelsystem\Mail\Transport\Transport::ping
|
||||||
|
*/
|
||||||
|
public function testMethods()
|
||||||
|
{
|
||||||
|
$transport = new TransportImplementation();
|
||||||
|
|
||||||
|
$this->assertTrue($transport->isStarted());
|
||||||
|
$this->assertTrue($transport->ping());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\Transport\Transport::allRecipients
|
||||||
|
*/
|
||||||
|
public function testAllRecipients()
|
||||||
|
{
|
||||||
|
/** @var SimpleMessage|MockObject $message */
|
||||||
|
$message = $this->createMock(SimpleMessage::class);
|
||||||
|
$transport = new TransportImplementation();
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('getTo')
|
||||||
|
->willReturn([
|
||||||
|
'foo@bar.batz' => 'Foo Bar',
|
||||||
|
'lorem@ipsum.dolor' => null,
|
||||||
|
]);
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('getCc')
|
||||||
|
->willReturn([
|
||||||
|
'to@bar.batz' => null,
|
||||||
|
]);
|
||||||
|
$message->expects($this->once())
|
||||||
|
->method('getBcc')
|
||||||
|
->willReturn([
|
||||||
|
'secret@bar.batz' => 'I\'m secret!',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
[
|
||||||
|
'foo@bar.batz' => 'Foo Bar',
|
||||||
|
'lorem@ipsum.dolor' => null,
|
||||||
|
'to@bar.batz' => null,
|
||||||
|
'secret@bar.batz' => 'I\'m secret!',
|
||||||
|
],
|
||||||
|
$transport->getAllRecipients($message)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Mail\Transport\Transport::getTo
|
||||||
|
* @covers \Engelsystem\Mail\Transport\Transport::formatTo
|
||||||
|
*/
|
||||||
|
public function testGetTo()
|
||||||
|
{
|
||||||
|
/** @var SimpleMessage|MockObject $message */
|
||||||
|
$message = $this->createMock(SimpleMessage::class);
|
||||||
|
/** @var TransportImplementation|MockObject $transport */
|
||||||
|
$transport = $this->getMockBuilder(TransportImplementation::class)
|
||||||
|
->setMethods(['allRecipients'])
|
||||||
|
->getMock();
|
||||||
|
$transport->expects($this->once())
|
||||||
|
->method('allRecipients')
|
||||||
|
->with($message)
|
||||||
|
->willReturn([
|
||||||
|
'foo@bar.batz' => null,
|
||||||
|
'lorem@ipsum.dolor' => 'Developer',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$return = $transport->getGetTo($message);
|
||||||
|
$this->assertEquals('foo@bar.batz,Developer <lorem@ipsum.dolor>', $return);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue