Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4cfede9

Browse files
authored
feature #12391 [API] reseting password with validation (arti0090)
This PR was merged into the 1.10-dev branch. Discussion ---------- | Q | A | --------------- | ----- | Branch? |master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | License | MIT Commits ------- d230f15 reseting password with validation ce84ee8 change endpoint from PATCH to POST 788a0f4 remove comments c39cdac improve handlers and add tests 8c87f04 update swagger doc c0a15e0 remove unused data transformer, change route to PATCH and fixes cdb7fd5 fix email by locale 2b369fa add phpspec for data provider 4816e27 add data provider spec 02212e4 remove empty line from resetPassword.xml
2 parents b8fd146 + 02212e4 commit 4cfede9

22 files changed

Lines changed: 642 additions & 71 deletions

features/account/resetting_password.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Feature: Resetting a password
2222
When I reset password for email "[email protected]" in "Polish (Poland)" locale
2323
Then an email with reset token should be sent to "[email protected]" in "Polish (Poland)" locale
2424

25-
@ui @email
25+
@ui @email @api
2626
Scenario: Changing my account password with token I received
2727
Given I have already received a resetting password email
2828
When I follow link on my email to reset my password

features/account/resetting_password_validation.feature

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Feature: Resetting a password validation
1515
And I try to reset it
1616
Then I should be notified that the email is required
1717

18-
@ui
18+
@ui @api
1919
Scenario: Trying to reset password with a wrong confirmation password
2020
Given I have already received a resetting password email
2121
When I follow link on my email to reset my password
@@ -24,7 +24,7 @@ Feature: Resetting a password validation
2424
And I try to reset it
2525
Then I should be notified that the entered passwords do not match
2626

27-
@ui
27+
@ui @api
2828
Scenario: Trying to reset my password with a too short password
2929
Given I have already received a resetting password email
3030
When I follow link on my email to reset my password

src/Sylius/Behat/Context/Api/Shop/LoginContext.php

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
use Sylius\Behat\Client\ApiClientInterface;
1818
use Sylius\Behat\Client\ApiSecurityClientInterface;
1919
use Sylius\Behat\Client\Request;
20-
use Sylius\Behat\Client\ResponseCheckerInterface;
20+
use Sylius\Component\User\Model\UserInterface;
21+
use Symfony\Component\HttpFoundation\Request as HTTPRequest;
2122
use Webmozart\Assert\Assert;
2223

2324
final class LoginContext implements Context
@@ -28,20 +29,15 @@ final class LoginContext implements Context
2829
/** @var ApiClientInterface */
2930
private $apiClient;
3031

31-
/** @var ResponseCheckerInterface */
32-
private $responseChecker;
33-
3432
/** @var Request|null */
3533
private $request;
3634

3735
public function __construct(
3836
ApiSecurityClientInterface $apiSecurityClient,
39-
ApiClientInterface $apiClient,
40-
ResponseCheckerInterface $responseChecker
37+
ApiClientInterface $apiClient
4138
) {
4239
$this->apiSecurityClient = $apiSecurityClient;
4340
$this->apiClient = $apiClient;
44-
$this->responseChecker = $responseChecker;
4541
}
4642

4743
/**
@@ -79,6 +75,17 @@ public function iResetPasswordForEmailInLocale(string $email, string $localeCode
7975
$this->iResetIt();
8076
}
8177

78+
/**
79+
* @When /^I follow link on (my) email to reset my password$/
80+
*/
81+
public function iFollowLinkOnMyEmailToResetPassword(UserInterface $user): void
82+
{
83+
$this->request = Request::custom(
84+
sprintf('api/v2/shop/reset-password/%s', $user->getPasswordResetToken()),
85+
HttpRequest::METHOD_PATCH
86+
);
87+
}
88+
8289
/**
8390
* @When I reset it
8491
* @When I try to reset it
@@ -102,7 +109,25 @@ public function iSpecifyTheUsername(string $username): void
102109
*/
103110
public function iSpecifyTheEmail(string $email = ''): void
104111
{
105-
$this->request->setContent(['email' => $email]);
112+
$this->request->updateContent(['email' => $email]);
113+
}
114+
115+
/**
116+
* @When I specify my new password as :password
117+
* @When I do not specify my new password
118+
*/
119+
public function iSpecifyMyNewPassword(?string $password = null): void
120+
{
121+
$this->request->updateContent(['newPassword' => $password]);
122+
}
123+
124+
/**
125+
* @When I confirm my new password as :password
126+
* @When I do not confirm my new password
127+
*/
128+
public function iConfirmMyNewPassword(?string $password = null): void
129+
{
130+
$this->request->updateContent(['confirmNewPassword' => $password]);
106131
}
107132

108133
/**
@@ -168,11 +193,22 @@ public function iShouldBeNotifiedAboutBadCredentials(): void
168193

169194
/**
170195
* @Then I should be notified that email with reset instruction has been sent
196+
* @Then I should be notified that my password has been successfully reset
171197
*/
172198
public function iShouldBeNotifiedThatEmailWithResetInstructionWasSent(): void
173199
{
174-
$response = $this->apiClient->getLastResponse();
175-
Assert::same($response->getStatusCode(), 202);
200+
Assert::same($this->apiClient->getLastResponse()->getStatusCode(), 202);
201+
}
202+
203+
/**
204+
* @Then I should be able to log in as :email with :password password
205+
* @Then the customer should be able to log in as :email with :password password
206+
*/
207+
public function iShouldBeAbleToLogInAsWithPassword(string $email, string $password): void
208+
{
209+
$this->iLogInAsWithPassword($email, $password);
210+
211+
$this->iShouldBeLoggedIn();
176212
}
177213

178214
private function addLocaleCode(string $localeCode): void

src/Sylius/Behat/Resources/config/services/contexts/api/shop.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@
7575
<service id="sylius.behat.context.api.shop.login" class="Sylius\Behat\Context\Api\Shop\LoginContext">
7676
<argument type="service" id="sylius.behat.client.shop_api_platform_security_client" />
7777
<argument type="service" id="sylius.behat.api_platform_client.shop.account" />
78-
<argument type="service" id="Sylius\Behat\Client\ResponseCheckerInterface" />
7978
</service>
8079

8180
<service id="sylius.behat.context.api.shop.product" class="Sylius\Behat\Context\Api\Shop\ProductContext">
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Paweł Jędrzejewski
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sylius\Bundle\ApiBundle\Command;
15+
16+
/** @experimental */
17+
class ResetPassword
18+
{
19+
/** @var string */
20+
public $newPassword;
21+
22+
/** @var string */
23+
public $confirmNewPassword;
24+
25+
/** @var string */
26+
public $resetPasswordToken;
27+
28+
public function __construct(string $resetPasswordToken)
29+
{
30+
$this->resetPasswordToken = $resetPasswordToken;
31+
}
32+
33+
public function getResetPasswordToken(): string
34+
{
35+
return $this->resetPasswordToken;
36+
}
37+
38+
public function setResetPasswordToken(string $token): void
39+
{
40+
$this->resetPasswordToken = $token;
41+
}
42+
}

src/Sylius/Bundle/ApiBundle/CommandHandler/RequestResetPasswordTokenHandler.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717
use Sylius\Bundle\ApiBundle\Command\SendResetPasswordEmail;
1818
use Sylius\Component\User\Repository\UserRepositoryInterface;
1919
use Sylius\Component\User\Security\Generator\GeneratorInterface;
20+
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
2021
use Symfony\Component\Messenger\MessageBusInterface;
2122
use Symfony\Component\Messenger\Stamp\DispatchAfterCurrentBusStamp;
2223
use Webmozart\Assert\Assert;
2324

2425
/** @experimental */
25-
final class RequestResetPasswordTokenHandler
26+
final class RequestResetPasswordTokenHandler implements MessageHandlerInterface
2627
{
2728
/** @var UserRepositoryInterface */
2829
private $userRepository;
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Paweł Jędrzejewski
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sylius\Bundle\ApiBundle\CommandHandler;
15+
16+
use Sylius\Bundle\ApiBundle\Command\ResetPassword;
17+
use Sylius\Component\Core\Model\ShopUserInterface;
18+
use Sylius\Component\Resource\Metadata\MetadataInterface;
19+
use Sylius\Component\User\Repository\UserRepositoryInterface;
20+
use Sylius\Component\User\Security\PasswordUpdaterInterface;
21+
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
22+
use Webmozart\Assert\Assert;
23+
24+
/** @experimental */
25+
final class ResetPasswordHandler implements MessageHandlerInterface
26+
{
27+
/** @var UserRepositoryInterface */
28+
private $userRepository;
29+
30+
/** @var MetadataInterface */
31+
private $metadata;
32+
33+
/** @var PasswordUpdaterInterface */
34+
private $passwordUpdater;
35+
36+
public function __construct(
37+
UserRepositoryInterface $userRepository,
38+
MetadataInterface $metadata,
39+
PasswordUpdaterInterface $passwordUpdater
40+
) {
41+
$this->userRepository = $userRepository;
42+
$this->metadata = $metadata;
43+
$this->passwordUpdater = $passwordUpdater;
44+
}
45+
46+
public function __invoke(ResetPassword $command): void
47+
{
48+
/** @var ShopUserInterface|null $user */
49+
$user = $this->userRepository->findOneBy(['passwordResetToken' => $command->getResetPasswordToken()]);
50+
51+
Assert::notNull($user);
52+
53+
$resetting = $this->metadata->getParameter('resetting');
54+
$lifetime = new \DateInterval($resetting['token']['ttl']);
55+
56+
if (!$user->isPasswordRequestNonExpired($lifetime)) {
57+
throw new \InvalidArgumentException('Password reset token has expired');
58+
}
59+
60+
if ($command->getResetPasswordToken() !== $user->getPasswordResetToken()) {
61+
throw new \InvalidArgumentException('Password reset token do not match.');
62+
}
63+
64+
$user->setPlainPassword($command->newPassword);
65+
66+
$this->passwordUpdater->updatePassword($user);
67+
}
68+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Sylius package.
5+
*
6+
* (c) Paweł Jędrzejewski
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace Sylius\Bundle\ApiBundle\DataProvider;
15+
16+
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
17+
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
18+
use Sylius\Bundle\ApiBundle\Command\ResetPassword;
19+
use Sylius\Component\User\Repository\UserRepositoryInterface;
20+
21+
/** @experimental */
22+
final class ResetPasswordItemDataProvider implements RestrictedDataProviderInterface, ItemDataProviderInterface
23+
{
24+
public function getItem(string $resourceClass, $id, string $operationName = null, array $context = [])
25+
{
26+
return new ResetPassword($id);
27+
}
28+
29+
public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
30+
{
31+
return is_a($resourceClass, ResetPassword::class, true);
32+
}
33+
}

src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/PasswordReset.xml

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)