[Security][Notifier] Added integration of Login Link with the Notifier component
This commit is contained in:
parent
ffbb9883bd
commit
04ef565895
@ -10,6 +10,7 @@ CHANGELOG
|
||||
* added the `t()` function to easily create `TranslatableMessage` objects
|
||||
* Added support for extracting messages from the `t()` function
|
||||
* Added `field_*` Twig functions to access string values from Form fields
|
||||
* changed the `importance` context option of `NotificationEmail` to allow `null`
|
||||
|
||||
5.0.0
|
||||
-----
|
||||
|
@ -37,6 +37,7 @@ class NotificationEmail extends TemplatedEmail
|
||||
'action_url' => null,
|
||||
'markdown' => false,
|
||||
'raw' => false,
|
||||
'footer_text' => 'Notification e-mail sent by Symfony',
|
||||
];
|
||||
|
||||
public function __construct(Headers $headers = null, AbstractPart $body = null)
|
||||
@ -57,6 +58,18 @@ class NotificationEmail extends TemplatedEmail
|
||||
parent::__construct($headers, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a NotificationEmail instance that is appropriate to send to normal (non-admin) users.
|
||||
*/
|
||||
public static function asPublicEmail(Headers $headers = null, AbstractPart $body = null): self
|
||||
{
|
||||
$email = new static($headers, $body);
|
||||
$email->context['importance'] = null;
|
||||
$email->context['footer_text'] = null;
|
||||
|
||||
return $email;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
@ -166,7 +179,9 @@ class NotificationEmail extends TemplatedEmail
|
||||
|
||||
$importance = $this->context['importance'] ?? self::IMPORTANCE_LOW;
|
||||
$this->priority($this->determinePriority($importance));
|
||||
$headers->setHeaderBody('Text', 'Subject', sprintf('[%s] %s', strtoupper($importance), $this->getSubject()));
|
||||
if ($this->context['importance']) {
|
||||
$headers->setHeaderBody('Text', 'Subject', sprintf('[%s] %s', strtoupper($importance), $this->getSubject()));
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
<row>
|
||||
<columns large="12" small="12">
|
||||
{% block lead %}
|
||||
<small><strong>{{ importance|upper }}</strong></small>
|
||||
{% if importance is not null %}<small><strong>{{ importance|upper }}</strong></small>{% endif %}
|
||||
<p class="lead">
|
||||
{{ email.subject }}
|
||||
</p>
|
||||
@ -49,13 +49,15 @@
|
||||
<wrapper class="secondary">
|
||||
<spacer size="16"></spacer>
|
||||
{% block footer %}
|
||||
{% if footer_text is defined and footer_text is not null %}
|
||||
<row>
|
||||
<columns small="12" large="6">
|
||||
{% block footer_content %}
|
||||
<p><small>Notification e-mail sent by Symfony</small></p>
|
||||
<p><small>{{ footer_text }}</small></p>
|
||||
{% endblock %}
|
||||
</columns>
|
||||
</row>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</wrapper>
|
||||
</container>
|
||||
|
@ -26,6 +26,7 @@ class NotificationEmailTest extends TestCase
|
||||
'markdown' => true,
|
||||
'raw' => false,
|
||||
'a' => 'b',
|
||||
'footer_text' => 'Notification e-mail sent by Symfony',
|
||||
], $email->getContext());
|
||||
}
|
||||
|
||||
@ -47,6 +48,7 @@ class NotificationEmailTest extends TestCase
|
||||
'markdown' => false,
|
||||
'raw' => true,
|
||||
'a' => 'b',
|
||||
'footer_text' => 'Notification e-mail sent by Symfony',
|
||||
], $email->getContext());
|
||||
}
|
||||
|
||||
@ -63,4 +65,32 @@ class NotificationEmailTest extends TestCase
|
||||
$headers = $email->getPreparedHeaders();
|
||||
$this->assertSame('[LOW] Foo', $headers->get('Subject')->getValue());
|
||||
}
|
||||
|
||||
public function testPublicMail()
|
||||
{
|
||||
$email = NotificationEmail::asPublicEmail()
|
||||
->markdown('Foo')
|
||||
->action('Bar', 'http://example.com/')
|
||||
->context(['a' => 'b'])
|
||||
;
|
||||
|
||||
$this->assertEquals([
|
||||
'importance' => null,
|
||||
'content' => 'Foo',
|
||||
'exception' => false,
|
||||
'action_text' => 'Bar',
|
||||
'action_url' => 'http://example.com/',
|
||||
'markdown' => true,
|
||||
'raw' => false,
|
||||
'a' => 'b',
|
||||
'footer_text' => null,
|
||||
], $email->getContext());
|
||||
}
|
||||
|
||||
public function testPublicMailSubject()
|
||||
{
|
||||
$email = NotificationEmail::asPublicEmail()->from('me@example.com')->subject('Foo');
|
||||
$headers = $email->getPreparedHeaders();
|
||||
$this->assertSame('Foo', $headers->get('Subject')->getValue());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\LoginLink;
|
||||
|
||||
use Symfony\Bridge\Twig\Mime\NotificationEmail;
|
||||
use Symfony\Component\Notifier\Message\EmailMessage;
|
||||
use Symfony\Component\Notifier\Message\SmsMessage;
|
||||
use Symfony\Component\Notifier\Notification\EmailNotificationInterface;
|
||||
use Symfony\Component\Notifier\Notification\Notification;
|
||||
use Symfony\Component\Notifier\Notification\SmsNotificationInterface;
|
||||
use Symfony\Component\Notifier\Recipient\EmailRecipientInterface;
|
||||
use Symfony\Component\Notifier\Recipient\SmsRecipientInterface;
|
||||
|
||||
/**
|
||||
* Use this notification to ease sending login link
|
||||
* emails/SMS using the Notifier component.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @experimental in 5.2
|
||||
*/
|
||||
class LoginLinkNotification extends Notification implements EmailNotificationInterface, SmsNotificationInterface
|
||||
{
|
||||
private $loginLinkDetails;
|
||||
|
||||
public function __construct(LoginLinkDetails $loginLinkDetails, string $subject, array $channels = [])
|
||||
{
|
||||
parent::__construct($subject, $channels);
|
||||
|
||||
$this->loginLinkDetails = $loginLinkDetails;
|
||||
}
|
||||
|
||||
public function asEmailMessage(EmailRecipientInterface $recipient, string $transport = null): ?EmailMessage
|
||||
{
|
||||
if (!class_exists(NotificationEmail::class)) {
|
||||
throw new \LogicException(sprintf('The "%s" method requires "symfony/twig-bridge:>4.4".', __METHOD__));
|
||||
}
|
||||
|
||||
$email = NotificationEmail::asPublicEmail()
|
||||
->to($recipient->getEmail())
|
||||
->subject($this->getSubject())
|
||||
->content($this->getContent() ?: $this->getDefaultContent('button below'))
|
||||
->action('Sign in', $this->loginLinkDetails->getUrl())
|
||||
;
|
||||
|
||||
return new EmailMessage($email);
|
||||
}
|
||||
|
||||
public function asSmsMessage(SmsRecipientInterface $recipient, string $transport = null): ?SmsMessage
|
||||
{
|
||||
return new SmsMessage($recipient->getPhone(), $this->getDefaultContent('link').' '.$this->loginLinkDetails->getUrl());
|
||||
}
|
||||
|
||||
private function getDefaultContent(string $target): string
|
||||
{
|
||||
$duration = $this->loginLinkDetails->getExpiresAt()->getTimestamp() - time();
|
||||
$durationString = floor($duration / 60).' minute'.($duration > 60 ? 's' : '');
|
||||
if (($hours = $duration / 3600) >= 1) {
|
||||
$durationString = floor($hours).' hour'.($hours >= 2 ? 's' : '');
|
||||
}
|
||||
|
||||
return sprintf('Click on the %s to confirm you want to sign in. This link will expire in %s.', $target, $durationString);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user