Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IBX-8137: Moved from swift mailer to symfony mailer #84

Merged
merged 6 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
"symfony/routing": "^5.0",
"symfony/security-core": "^5.0",
"symfony/security-http": "^5.0",
"symfony/swiftmailer-bundle": "^3.4",
"symfony/translation": "^5.0",
"symfony/validator": "^5.0",
"twig/twig": "^3.0"
Expand Down
15 changes: 0 additions & 15 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ parameters:
count: 1
path: src/bundle/Controller/PasswordChangeController.php

-
message: "#^Method Ibexa\\\\Bundle\\\\User\\\\Controller\\\\PasswordResetController\\:\\:sendNotification\\(\\) has parameter \\$user with no type specified\\.$#"
count: 1
path: src/bundle/Controller/PasswordResetController.php

-
message: "#^Parameter \\#1 \\$user of method Ibexa\\\\Bundle\\\\User\\\\Controller\\\\PasswordResetController\\:\\:sendResetPasswordMessage\\(\\) expects Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\User\\\\User, Ibexa\\\\Contracts\\\\Core\\\\Repository\\\\Values\\\\User\\\\User\\|false given\\.$#"
count: 1
Expand Down Expand Up @@ -985,16 +980,6 @@ parameters:
count: 1
path: tests/lib/Form/Type/ChoiceList/Loader/AvailableLocaleChoiceLoaderTest.php

-
message: "#^Access to an undefined property Ibexa\\\\Tests\\\\User\\\\Invitation\\\\InvitationServiceTest\\:\\:\\$configResolver\\.$#"
count: 2
path: tests/lib/Invitation/InvitationServiceTest.php

-
message: "#^Access to an undefined property Ibexa\\\\Tests\\\\User\\\\Invitation\\\\InvitationServiceTest\\:\\:\\$siteAccessService\\.$#"
count: 2
path: tests/lib/Invitation/InvitationServiceTest.php

-
message: "#^Method Ibexa\\\\Tests\\\\User\\\\Invitation\\\\InvitationServiceTest\\:\\:invitationProvider\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
Expand Down
49 changes: 2 additions & 47 deletions src/bundle/Controller/PasswordResetController.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@
use Ibexa\User\View\ResetPassword\FormView as UserResetPasswordFormView;
use Ibexa\User\View\ResetPassword\InvalidLinkView;
use Ibexa\User\View\ResetPassword\SuccessView as UserResetPasswordSuccessView;
use Swift_Mailer;
use Swift_Message;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;
Expand All @@ -43,8 +41,6 @@ class PasswordResetController extends Controller

private UserService $userService;

private Swift_Mailer $mailer;

private Environment $twig;

private ActionResultHandler $actionResultHandler;
Expand All @@ -58,7 +54,6 @@ class PasswordResetController extends Controller
public function __construct(
FormFactory $formFactory,
UserService $userService,
Swift_Mailer $mailer,
Environment $twig,
ActionResultHandler $actionResultHandler,
PermissionResolver $permissionResolver,
Expand All @@ -67,7 +62,6 @@ public function __construct(
) {
$this->formFactory = $formFactory;
$this->userService = $userService;
$this->mailer = $mailer;
$this->twig = $twig;
$this->actionResultHandler = $actionResultHandler;
$this->permissionResolver = $permissionResolver;
Expand All @@ -89,7 +83,7 @@ public function userForgotPasswordAction(Request $request, ?string $reason = nul
$data = $form->getData();
$users = $this->userService->loadUsersByEmail($data->getEmail());

/** Because is is possible to have multiple user accounts with same email address we must gain a user login. */
/** Because it is possible to have multiple user accounts with same email address we must gain a user login. */
if (\count($users) > 1) {
return $this->redirectToRoute('ibexa.user.forgot_password.login');
}
Expand Down Expand Up @@ -233,51 +227,12 @@ private function updateUserToken(User $user): string
}

private function sendResetPasswordMessage(User $user, string $hashKey): void
{
if ($this->isNotifierConfigured()) {
$this->sendNotification($user, $hashKey);

return;
}

// Swiftmailer delivery has to be kept to maintain backwards compatibility
$template = $this->twig->load($this->configResolver->getParameter('user_forgot_password.templates.mail'));

$senderAddress = $this->configResolver->hasParameter('sender_address', 'swiftmailer.mailer')
? $this->configResolver->getParameter('sender_address', 'swiftmailer.mailer')
: '';

$subject = $template->renderBlock('subject', []);
$from = $template->renderBlock('from', []) ?: $senderAddress;
$body = $template->renderBlock('body', ['hash_key' => $hashKey]);

$message = (new Swift_Message())
->setSubject($subject)
->setTo($user->email)
->setBody($body, 'text/html');

if (empty($from) === false) {
$message->setFrom($from);
}

$this->mailer->send($message);
}

private function sendNotification($user, string $token): void
{
$this->notificationService->send(
new SymfonyNotificationAdapter(
new UserPasswordReset($user, $token),
new UserPasswordReset($user, $hashKey, $this->configResolver, $this->twig),
),
[new SymfonyRecipientAdapter(new UserRecipient($user))],
);
}

private function isNotifierConfigured(): bool
{
$subscriptions = $this->configResolver->getParameter('notifications.subscriptions');

return array_key_exists(UserPasswordReset::class, $subscriptions)
&& !empty($subscriptions[UserPasswordReset::class]['channels']);
}
}
62 changes: 62 additions & 0 deletions src/contracts/Notification/UserInvitation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\User\Notification;

use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
use Ibexa\Contracts\User\Invitation\Invitation;
use Symfony\Bridge\Twig\Mime\NotificationEmail;
use Symfony\Component\Notifier\Message\EmailMessage;
use Symfony\Component\Notifier\Notification\EmailNotificationInterface;
use Symfony\Component\Notifier\Notification\Notification;
use Symfony\Component\Notifier\Recipient\EmailRecipientInterface;
use Twig\Environment;

final class UserInvitation extends Notification implements EmailNotificationInterface
{
public function __construct(
private readonly Invitation $invitation,
private readonly ConfigResolverInterface $configResolver,
private readonly Environment $twig
) {
parent::__construct();
}

public function asEmailMessage(EmailRecipientInterface $recipient, string $transport = null): ?EmailMessage
{
$templatePath = $this->twig->load(
$this->configResolver->getParameter(
'user_invitation.templates.mail',
null,
$this->invitation->getSiteAccessIdentifier()
)
);

$template = $this->twig->load($templatePath);

$subject = $template->renderBlock('subject');
$from = $template->renderBlock('from') ?: null;
$body = $template->renderBlock('body', [
'invite_hash' => $this->invitation->getHash(),
'siteaccess' => $this->invitation->getSiteAccessIdentifier(),
'invitation' => $this->invitation,
]);

$email = NotificationEmail::asPublicEmail()
->html($body)
->to($recipient->getEmail())
->subject($subject)
;

if ($from !== null) {
$email->from($from);
}

return new EmailMessage($email);
}
}
40 changes: 30 additions & 10 deletions src/contracts/Notification/UserPasswordReset.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,58 @@
namespace Ibexa\Contracts\User\Notification;

use Ibexa\Contracts\Core\Repository\Values\User\User;
use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
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 Twig\Environment;

final class UserPasswordReset extends Notification implements EmailNotificationInterface, SmsNotificationInterface, UserAwareNotificationInterface
final class UserPasswordReset extends Notification implements EmailNotificationInterface, UserAwareNotificationInterface
{
private User $user;

private string $token;

private ConfigResolverInterface $configResolver;

private Environment $twig;

public function __construct(
User $user,
string $token
string $token,
ConfigResolverInterface $configResolver,
Environment $twig
) {
parent::__construct();

$this->user = $user;
$this->token = $token;
$this->configResolver = $configResolver;
$this->twig = $twig;
}

public function asEmailMessage(EmailRecipientInterface $recipient, string $transport = null): ?EmailMessage
{
return null;
}
$templatePath = $this->configResolver->getParameter('user_forgot_password.templates.mail');
$template = $this->twig->load($templatePath);

public function asSmsMessage(SmsRecipientInterface $recipient, string $transport = null): ?SmsMessage
{
return null;
$subject = $template->renderBlock('subject');
$from = $template->renderBlock('from') ?: null;
$body = $template->renderBlock('body', ['hash_key' => $this->token]);

$email = NotificationEmail::asPublicEmail()
->html($body)
->to($recipient->getEmail())
->subject($subject)
;

if ($from !== null) {
$email->from($from);
}

return new EmailMessage($email);
}

public function getUser(): User
Expand Down
10 changes: 1 addition & 9 deletions src/contracts/Notification/UserRegister.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@

use Ibexa\Contracts\Core\Repository\Values\User\User;
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;

final class UserRegister extends Notification implements EmailNotificationInterface, SmsNotificationInterface, UserAwareNotificationInterface
final class UserRegister extends Notification implements EmailNotificationInterface, UserAwareNotificationInterface
{
private User $user;

Expand All @@ -33,11 +30,6 @@ public function asEmailMessage(EmailRecipientInterface $recipient, string $trans
return null;
}

public function asSmsMessage(SmsRecipientInterface $recipient, string $transport = null): ?SmsMessage
{
return null;
}

public function getUser(): User
{
return $this->user;
Expand Down
47 changes: 13 additions & 34 deletions src/lib/Invitation/MailSender.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
namespace Ibexa\User\Invitation;

use Ibexa\Contracts\Core\SiteAccess\ConfigResolverInterface;
use Ibexa\Contracts\Notifications\Service\NotificationServiceInterface;
use Ibexa\Contracts\Notifications\Value\Notification\SymfonyNotificationAdapter;
use Ibexa\Contracts\Notifications\Value\Recipent\SymfonyRecipientAdapter;
use Ibexa\Contracts\User\Invitation\Invitation;
use Ibexa\Contracts\User\Invitation\InvitationSender;
use Swift_Mailer;
use Swift_Message;
use Ibexa\Contracts\User\Notification\UserInvitation;
use Symfony\Component\Notifier\Recipient\Recipient;
use Twig\Environment;

final class MailSender implements InvitationSender
Expand All @@ -21,49 +24,25 @@ final class MailSender implements InvitationSender

private ConfigResolverInterface $configResolver;

private Swift_Mailer $mailer;
private NotificationServiceInterface $notificationService;

public function __construct(
Environment $twig,
ConfigResolverInterface $configResolver,
Swift_Mailer $mailer
NotificationServiceInterface $notificationService
) {
$this->twig = $twig;
$this->configResolver = $configResolver;
$this->mailer = $mailer;
$this->notificationService = $notificationService;
}

public function sendInvitation(Invitation $invitation): void
{
$template = $this->twig->load(
$this->configResolver->getParameter(
'user_invitation.templates.mail',
null,
$invitation->getSiteAccessIdentifier()
)
$this->notificationService->send(
new SymfonyNotificationAdapter(
new UserInvitation($invitation, $this->configResolver, $this->twig),
),
Steveb-p marked this conversation as resolved.
Show resolved Hide resolved
[new SymfonyRecipientAdapter(new Recipient($invitation->getEmail()))],
);

$senderAddress = $this->configResolver->hasParameter('sender_address', 'swiftmailer.mailer')
? $this->configResolver->getParameter('sender_address', 'swiftmailer.mailer')
: '';

$subject = $template->renderBlock('subject', []);
$from = $template->renderBlock('from', []) ?: $senderAddress;
$body = $template->renderBlock('body', [
'invite_hash' => $invitation->getHash(),
'siteaccess' => $invitation->getSiteAccessIdentifier(),
'invitation' => $invitation,
]);

$message = (new Swift_Message())
->setSubject($subject)
->setTo($invitation->getEmail())
->setBody($body, 'text/html');

if (empty($from) === false) {
$message->setFrom($from);
}

$this->mailer->send($message);
}
}
2 changes: 0 additions & 2 deletions tests/integration/IbexaTestKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Ibexa\Contracts\Core\Test\IbexaTestKernel as BaseIbexaTestKernel;
use Ibexa\Contracts\User\Invitation\InvitationService;
use LogicException;
use Swift_Mailer;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
Expand Down Expand Up @@ -55,7 +54,6 @@ public function registerContainerConfiguration(LoaderInterface $loader): void
$container->setParameter('locale_fallback', 'en');

self::createSyntheticService($container, UserDispatcher::class);
self::createSyntheticService($container, Swift_Mailer::class);

$container->loadFromExtension('framework', [
'router' => [
Expand Down
Loading
Loading