Skip to content
Open
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
24 changes: 0 additions & 24 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,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\.$#'
identifier: missingType.parameter
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\.$#'
identifier: argument.type
count: 1
path: src/bundle/Controller/PasswordResetController.php

-
message: '#^Parameter \#1 \$user of method Ibexa\\Bundle\\User\\Controller\\PasswordResetController\:\:updateUserToken\(\) expects Ibexa\\Contracts\\Core\\Repository\\Values\\User\\User, Ibexa\\Contracts\\Core\\Repository\\Values\\User\\User\|false given\.$#'
identifier: argument.type
count: 1
path: src/bundle/Controller/PasswordResetController.php

-
message: '#^Parameter \#1 \$email of class Ibexa\\Contracts\\User\\Invitation\\InvitationCreateStruct constructor expects string, string\|null given\.$#'
identifier: argument.type
Expand Down Expand Up @@ -1284,12 +1266,6 @@ parameters:
count: 1
path: src/lib/Validator/Constraints/EmailInvitationValidator.php

-
message: '#^Method Ibexa\\User\\Validator\\Constraints\\Password\:\:getTargets\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: src/lib/Validator/Constraints/Password.php

-
message: '#^Access to an undefined property Symfony\\Component\\Validator\\Constraint\:\:\$contentType\.$#'
identifier: property.notFound
Expand Down
79 changes: 8 additions & 71 deletions src/bundle/Controller/PasswordResetController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@
use Ibexa\Contracts\Core\Repository\Values\User\User;
use Ibexa\Contracts\Core\Repository\Values\User\UserTokenUpdateStruct;
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\Notifications\Value\Recipent\UserRecipient;
use Ibexa\Contracts\User\Notification\UserPasswordReset;
use Ibexa\Contracts\User\PasswordReset\NotifierInterface;
use Ibexa\User\ExceptionHandler\ActionResultHandler;
use Ibexa\User\Form\Data\UserPasswordResetData;
use Ibexa\User\Form\Factory\FormFactory;
Expand All @@ -31,48 +27,37 @@
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;

class PasswordResetController extends Controller
{
private FormFactory $formFactory;

private UserService $userService;

private Swift_Mailer $mailer;

private Environment $twig;

private ActionResultHandler $actionResultHandler;

private PermissionResolver $permissionResolver;

private ConfigResolverInterface $configResolver;

private NotificationServiceInterface $notificationService;
private NotifierInterface $passwordResetMailer;

public function __construct(
FormFactory $formFactory,
UserService $userService,
Swift_Mailer $mailer,
Environment $twig,
ActionResultHandler $actionResultHandler,
PermissionResolver $permissionResolver,
ConfigResolverInterface $configResolver,
NotificationServiceInterface $notificationService
NotifierInterface $passwordResetMailer
) {
$this->formFactory = $formFactory;
$this->userService = $userService;
$this->mailer = $mailer;
$this->twig = $twig;
$this->actionResultHandler = $actionResultHandler;
$this->permissionResolver = $permissionResolver;
$this->configResolver = $configResolver;
$this->notificationService = $notificationService;
$this->passwordResetMailer = $passwordResetMailer;
}

/**
Expand All @@ -89,16 +74,17 @@ 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');
}

if (!empty($users)) {
/** @var \Ibexa\Contracts\Core\Repository\Values\User\User $user */
$user = reset($users);
$token = $this->updateUserToken($user);

$this->sendResetPasswordMessage($user, $token);
$this->passwordResetMailer->sendMessage($user, $token);
}

return new SuccessView(null);
Expand Down Expand Up @@ -138,7 +124,7 @@ public function userForgotPasswordLoginAction(Request $request)
}

$token = $this->updateUserToken($user);
$this->sendResetPasswordMessage($user, $token);
$this->passwordResetMailer->sendMessage($user, $token);

return new SuccessView(null);
}
Expand Down Expand Up @@ -231,55 +217,6 @@ private function updateUserToken(User $user): string

return $struct->hashKey;
}

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 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']);
}
}

class_alias(PasswordResetController::class, 'EzSystems\EzPlatformUserBundle\Controller\PasswordResetController');
1 change: 1 addition & 0 deletions src/bundle/Resources/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ imports:
- { resource: services/invitation.yaml }
- { resource: services/installer.yaml }
- { resource: services/twig.yaml }
- { resource: services/notifier.yaml }

parameters:
ibexa.user.content_type_identifier: user
Expand Down
9 changes: 9 additions & 0 deletions src/bundle/Resources/config/services/notifier.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

Ibexa\User\PasswordReset\Notifier: ~

Ibexa\Contracts\User\PasswordReset\NotifierInterface: '@Ibexa\User\PasswordReset\Notifier'
42 changes: 25 additions & 17 deletions src/bundle/Resources/translations/ibexa_forgot_password.en.xliff
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,6 @@
<target state="new">This email is connected with several accounts. Enter your username instead.</target>
<note>key: ezplatform.forgot_password.login</note>
</trans-unit>
<trans-unit id="1af697cb32b6eeeafbf4ca827e766829eac0e992" resname="ezplatform.forgot_password.message">
<source><![CDATA[Hello,
<br /><br />
We have received a request to reset the password for your account. Click “reset password” below to choose a new password:
<br /><br />
<a href="%reset_password%">Reset password<a/>
<br /><br />
If you did not request a password reset, please ignore this email, and your password will remain the same.]]></source>
<target state="new"><![CDATA[Hello,
<br /><br />
We have received a request to reset the password for your account. Click “reset password” below to choose a new password:
<br /><br />
<a href="%reset_password%">Reset password<a/>
<br /><br />
If you did not request a password reset, please ignore this email, and your password will remain the same.]]></target>
<note>key: ezplatform.forgot_password.message</note>
</trans-unit>
<trans-unit id="9d77404b1f40b0458d3b82757b067e15c7dc46e3" resname="ezplatform.forgot_password.reset_your_password">
<source>Reset your password</source>
<target state="new">Reset your password</target>
Expand All @@ -54,6 +37,31 @@
<p>If you reset your password multiple times, only the most recent password reset link will be valid.</p>]]></target>
<note>key: ezplatform.forgot_password.success</note>
</trans-unit>
<trans-unit id="3055d29b5833fba2c374b4a30fb66bf35e3df48a" resname="forgot_password.reset_your_password">
<source>Reset your password</source>
<target state="new">Reset your password</target>
<note>key: forgot_password.reset_your_password</note>
</trans-unit>
<trans-unit id="e7b58c781e23a49ce354cdb479f14d6f75ca6e4f" resname="forgot_user_password.mail.message">
<source>We have received a request to reset the password for your account. Click "reset password" below to choose a new password:</source>
<target state="new">We have received a request to reset the password for your account. Click "reset password" below to choose a new password:</target>
<note>key: forgot_user_password.mail.message</note>
</trans-unit>
<trans-unit id="26ccb574b6cd1e49d40d32d9183db89065138be2" resname="forgot_user_password.mail.message_footer">
<source>If you did not request a password reset, please ignore this email, and your password will remain the same.</source>
<target state="new">If you did not request a password reset, please ignore this email, and your password will remain the same.</target>
<note>key: forgot_user_password.mail.message_footer</note>
</trans-unit>
<trans-unit id="a5ba92910b3dc61efc12c4f42cc869975be98723" resname="forgot_user_password.mail.message_title">
<source>Hello,</source>
<target state="new">Hello,</target>
<note>key: forgot_user_password.mail.message_title</note>
</trans-unit>
<trans-unit id="b7293d1f766a95b50cf3e076c5ef4cd623dc542c" resname="forgot_user_password.mail.reset_password">
<source>Reset password</source>
<target state="new">Reset password</target>
<note>key: forgot_user_password.mail.reset_password</note>
</trans-unit>
</body>
</file>
</xliff>
10 changes: 10 additions & 0 deletions src/bundle/Resources/translations/ibexa_user_invitation.en.xliff
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
</header>
<body>
<trans-unit id="07c52e99431e40b768788c64536e4dc12ade0f03" resname="ibexa.user.invitation.mail.join">
<source>Join</source>
<target state="new">Join</target>
<note>key: ibexa.user.invitation.mail.join</note>
</trans-unit>
<trans-unit id="bc254dd11e21f88f3d7b2a1a9c8ab30bb6825702" resname="ibexa.user.invitation.mail.message">
<source xml:space="preserve">Hello,
Join us at: %invite_link%
Expand All @@ -15,6 +20,11 @@
</target>
<note>key: ibexa.user.invitation.mail.message</note>
</trans-unit>
<trans-unit id="56996e20d695f581a1344e83a8c542c7df1a04ec" resname="ibexa.user.invitation.mail.message_title">
<source>Hello,</source>
<target state="new">Hello,</target>
<note>key: ibexa.user.invitation.mail.message_title</note>
</trans-unit>
<trans-unit id="54fce872265c3912727c793b582ab71318d2294e" resname="ibexa.user.invitation.mail.subject">
<source>You are invited to join</source>
<target state="new">You are invited to join</target>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
{% trans_default_domain 'ibexa_forgot_password' %}
{% extends '@ibexadesign/ui/mail/base_mail_template.html.twig' %}

{%- block from -%}
{%- endblock from -%}
{% trans_default_domain 'ibexa_forgot_password' %}

{%- block subject -%}
{{ 'ezplatform.forgot_password.reset_your_password'|trans|desc('Reset your password') }}
{{ 'forgot_password.reset_your_password'|trans|desc('Reset your password') }}
{%- endblock subject -%}

{%- block body -%}
<p>
{{ 'ezplatform.forgot_password.message'|trans({ '%reset_password%': url('ibexa.user.reset_password', {'hashKey': hash_key}) })|raw
|desc('Hello,
<br /><br />
We have received a request to reset the password for your account. Click “reset password” below to choose a new password:
<br /><br />
<a href="%reset_password%">Reset password<a/>
<br /><br />
If you did not request a password reset, please ignore this email, and your password will remain the same.') }}
</p>
{%- endblock body -%}
{%- block mail_message_title_content -%}
{{ 'forgot_user_password.mail.message_title'|trans()|desc('Hello,') }}
{%- endblock mail_message_title_content -%}

{%- block mail_message_content %}
{{ 'forgot_user_password.mail.message'|trans()|desc('We have received a request to reset the password for your account. Click "reset password" below to choose a new password:') }}
{%- endblock mail_message_content %}

{%- block mail_actions_content -%}
{% include '@ibexadesign/ui/mail/components/action_btn.html.twig' with {
url: url('ibexa.user.reset_password', {'hashKey': hash_key}),
label: 'forgot_user_password.mail.reset_password'|trans()|desc('Reset password')
} only %}
{%- endblock mail_actions_content -%}

{%- block mail_footer_content -%}
{{ 'forgot_user_password.mail.message_footer'|trans()|desc('If you did not request a password reset, please ignore this email, and your password will remain the same.') }}
{%- endblock mail_footer_content -%}
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
{% trans_default_domain 'ibexa_user_invitation' %}
{% extends '@ibexadesign/ui/mail/base_mail_template.html.twig' %}

{%- block from -%}
{%- endblock from -%}
{% trans_default_domain 'ibexa_user_invitation' %}

{%- block subject -%}
{{ 'ibexa.user.invitation.mail.subject'|trans|desc('You are invited to join') }}
{%- endblock subject -%}

{%- block body -%}
<p>
{{ 'ibexa.user.invitation.mail.message'|trans({
'%invite_link%': url('ibexa.user.from_invite.register', {
'inviteHash': invite_hash,
'siteaccess': siteaccess
})
})|raw
|desc('Hello,
Join us at: %invite_link%
') }}
</p>
{%- endblock body -%}
{%- block mail_message_title_content -%}
{{ 'ibexa.user.invitation.mail.message_title'|trans()|desc('Hello,') }}
{%- endblock mail_message_title_content -%}

{%- block mail_message_content -%}
{{ 'ibexa.user.invitation.mail.message'|trans()|desc('Join us at:') }}
{%- endblock mail_message_content -%}

{%- block mail_actions_content -%}
{% include '@ibexadesign/ui/mail/components/action_btn.html.twig' with {
url: url('ibexa.user.from_invite.register', {
'inviteHash': invite_hash,
'siteaccess': siteaccess
}),
label: 'ibexa.user.invitation.mail.join'|trans()|desc('Join')
} %}
{%- endblock mail_actions_content -%}

{%- block mail_footer -%}{%- endblock mail_footer -%}
16 changes: 16 additions & 0 deletions src/contracts/PasswordReset/NotifierInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?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\PasswordReset;

use Ibexa\Contracts\Core\Repository\Values\User\User;

interface NotifierInterface
{
public function sendMessage(User $user, string $hashKey): void;
}
2 changes: 1 addition & 1 deletion src/lib/EventListener/ViewTemplatesListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function setViewTemplates(PreContentViewEvent $event): void
}

/**
* @return array<string, string>
* @return array<class-string, string>
*/
private function getTemplatesMap(): array
{
Expand Down
Loading
Loading