Skip to content

Commit

Permalink
[API] Extract user context and revamp change password handler
Browse files Browse the repository at this point in the history
  • Loading branch information
lchrusciel committed Nov 3, 2020
1 parent 6c797d0 commit 207fc84
Show file tree
Hide file tree
Showing 16 changed files with 387 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Feature: Customer password validation
Then I should be notified that provided password is different than the current one

@ui @api
Scenario: Trying to change my password with a wrong confirmation password2
Scenario: Trying to change my password with a wrong confirmation password
When I want to change my password
And I specify the current password as "sylius"
And I specify the new password as "blackhouse"
Expand Down
14 changes: 7 additions & 7 deletions src/Sylius/Behat/Context/Api/Shop/CustomerContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,23 +130,23 @@ public function iSaveMyChanges(): void
*/
public function iSpecifyTheCurrentPasswordAs(string $password): void
{
$this->customerClient->addRequestData('oldPassword', $password);
$this->customerClient->addRequestData('currentPassword', $password);
}

/**
* @When I specify the new password as :password
*/
public function iSpecifyTheNewPasswordAs(string $password): void
{
$this->customerClient->addRequestData('password', $password);
$this->customerClient->addRequestData('newPassword', $password);
}

/**
* @When I confirm this password as :password
*/
public function iSpecifyTheConfirmationPasswordAs(string $password): void
{
$this->customerClient->addRequestData('confirmPassword', $password);
$this->customerClient->addRequestData('confirmNewPassword', $password);
}

/**
Expand All @@ -155,9 +155,9 @@ public function iSpecifyTheConfirmationPasswordAs(string $password): void
public function iChangePasswordTo(string $oldPassword, string $newPassword): void
{
$this->customerClient->setRequestData([
'oldPassword' => $oldPassword,
'password' => $newPassword,
'confirmPassword' => $newPassword
'currentPassword' => $oldPassword,
'newPassword' => $newPassword,
'confirmNewPassword' => $newPassword
]);
}

Expand Down Expand Up @@ -344,7 +344,7 @@ public function iShouldBeNotifiedThatTheEnteredPasswordsDoNotMatch(): void

Assert::contains(
$this->responseChecker->getError($this->customerClient->getLastResponse()),
'Your password and confirmation password does not match.'
'newPassword: The entered passwords don\'t match'
);
}

Expand Down
5 changes: 0 additions & 5 deletions src/Sylius/Behat/Resources/config/services/api.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,6 @@
<argument>shop</argument>
</service>

<service id="sylius.behat.api_platform_client.shop.user" class="Sylius\Behat\Client\ApiPlatformClient" parent="sylius.behat.api_platform_client">
<argument>users</argument>
<argument>shop</argument>
</service>

<service id="Sylius\Behat\Client\ResponseCheckerInterface" class="Sylius\Behat\Client\ResponseChecker">
<argument type="service" id="test.client" />
</service>
Expand Down
47 changes: 33 additions & 14 deletions src/Sylius/Bundle/ApiBundle/Command/ChangeShopUserPassword.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,44 @@

namespace Sylius\Bundle\ApiBundle\Command;

/**
* @experimental
* @psalm-immutable
*/
class ChangeShopUserPassword
/** @experimental */
class ChangeShopUserPassword implements ShopUserIdAwareInterface
{
/** @var string|null */
public $password;
/** @psalm-suppress MissingReturnType */
public $shopUserId;

/**
* @var string|null
* @psalm-immutable
*/
public $newPassword;

/** @var string|null */
/**
* @var string|null
* @psalm-immutable
*/
public $confirmPassword;

/** @var string|null */
public $oldPassword;
/**
* @var string|null
* @psalm-immutable
*/
public $currentPassword;

public function __construct(?string $newPassword, ?string $confirmNewPassword, ?string $currentPassword)
{
$this->newPassword = $newPassword;
$this->confirmPassword = $confirmNewPassword;
$this->currentPassword = $currentPassword;
}

public function getShopUserId()
{
return $this->shopUserId;
}

public function __construct(?string $password, ?string $confirmPassword, ?string $oldPassword)
public function setShopUserId($shopUserId): void
{
$this->password = $password;
$this->confirmPassword = $confirmPassword;
$this->oldPassword = $oldPassword;
$this->shopUserId = $shopUserId;
}
}
13 changes: 13 additions & 0 deletions src/Sylius/Bundle/ApiBundle/Command/ShopUserIdAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Sylius\Bundle\ApiBundle\Command;

/** @experimental */
interface ShopUserIdAwareInterface extends CommandAwareDataTransformerInterface
{
public function getShopUserId();

public function setShopUserId($shopUserId): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,49 +13,41 @@

namespace Sylius\Bundle\ApiBundle\CommandHandler;

use ApiPlatform\Core\DataPersister\DataPersisterInterface;
use Sylius\Bundle\ApiBundle\Command\ChangeShopUserPassword;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
use Sylius\Component\Core\Model\ShopUser;
use Sylius\Component\Core\Model\ShopUserInterface;
use Sylius\Component\User\Repository\UserRepositoryInterface;
use Sylius\Component\User\Security\PasswordUpdaterInterface;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Webmozart\Assert\Assert;

/** @experimental */
class ChangeShopUserPasswordHandler implements MessageHandlerInterface
final class ChangeShopUserPasswordHandler implements MessageHandlerInterface
{
/** @var DataPersisterInterface */
private $dataPersister;

/** @var PasswordUpdaterInterface */
private $passwordUpdater;

/** @var UserContextInterface */
private $userContext;
/** @var UserRepositoryInterface */
private $userRepository;

public function __construct(
DataPersisterInterface $dataPersister,
PasswordUpdaterInterface $passwordUpdater,
UserContextInterface $userContext
) {
$this->dataPersister = $dataPersister;
public function __construct(PasswordUpdaterInterface $passwordUpdater, UserRepositoryInterface $userRepository)
{
$this->passwordUpdater = $passwordUpdater;
$this->userContext = $userContext;
$this->userRepository = $userRepository;
}

public function __invoke(ChangeShopUserPassword $changePasswordShopUser){

if ($changePasswordShopUser->confirmPassword !== $changePasswordShopUser->password) {
throw new HttpException(400, "Your password and confirmation password does not match.");
public function __invoke(ChangeShopUserPassword $changeShopUserPassword)
{
if ($changeShopUserPassword->confirmPassword !== $changeShopUserPassword->newPassword) {
throw new \InvalidArgumentException('Passwords do not match.');
}

/** @var ShopUser $user */
$user = $this->userContext->getUser();
/** @var ShopUserInterface|null $user */
$user = $this->userRepository->find($changeShopUserPassword->getShopUserId());

if (in_array('ROLE_USER', $user->getRoles(), true)) {
$this->passwordUpdater->updatePassword($user);
$this->dataPersister->persist($user);
}
Assert::notNull($user);

$user->setPlainPassword($changeShopUserPassword->newPassword);

$this->passwordUpdater->updatePassword($user);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\ApiBundle\DataTransformer;

use Sylius\Bundle\ApiBundle\Command\ShopUserIdAwareInterface;
use Sylius\Bundle\ApiBundle\Context\UserContextInterface;
use Sylius\Component\Core\Model\ShopUserInterface;
use Sylius\Component\User\Model\UserInterface;

/** @experimental */
final class LoggedInShopUserIdAwareCommandDataTransformer implements CommandDataTransformerInterface
{
/** @var UserContextInterface */
private $userContext;

public function __construct(UserContextInterface $userContext)
{
$this->userContext = $userContext;
}

/**
* @param ShopUserIdAwareInterface $object
*/
public function transform($object, string $to, array $context = []): ShopUserIdAwareInterface
{
/** @var ShopUserInterface|UserInterface $user */
$user = $this->userContext->getUser();

if (!$user instanceof ShopUserInterface) {
return $object;
}

$object->setShopUserId($user->getId());

return $object;
}

public function supportsTransformation($object): bool
{
return $object instanceof ShopUserIdAwareInterface;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd"
>
<class name="Sylius\Bundle\ApiBundle\Command\ChangeShopUserPassword">
<attribute name="oldPassword">
<attribute name="currentPassword">
<group>customer:password:write</group>
</attribute>
<attribute name="password">
<attribute name="newPassword">
<group>customer:password:write</group>
</attribute>
<attribute name="confirmPassword">
<attribute name="confirmNewPassword">
<group>customer:password:write</group>
</attribute>
</class>
Expand Down
5 changes: 5 additions & 0 deletions src/Sylius/Bundle/ApiBundle/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@
<tag name="sylius.api.command_data_transformer" />
</service>

<service id="sylius.api.data_transformer.logged_in_shop_user_id_aware_input_data_transformer" class="Sylius\Bundle\ApiBundle\DataTransformer\LoggedInShopUserIdAwareCommandDataTransformer">
<argument type="service" id="sylius.api.context.user" />
<tag name="sylius.api.command_data_transformer" />
</service>

<service id="sylius.api.data_transformer.subresource_id_aware_data_transformer" class="Sylius\Bundle\ApiBundle\DataTransformer\SubresourceIdAwareCommandDataTransformer">
<argument type="service" id="request_stack" />
<tag name="sylius.api.command_data_transformer" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,8 @@
</service>

<service id="Sylius\Bundle\ApiBundle\CommandHandler\ChangeShopUserPasswordHandler">
<argument type="service" id="api_platform.doctrine.orm.data_persister" />
<argument type="service" id="sylius.security.password_updater" />
<argument type="service" id="sylius.api.context.user" />
<argument type="service" id="sylius.repository.shop_user" />
<tag name="messenger.message_handler" />
</service>
</services>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,9 @@
<argument type="service" id="sylius.repository.order" />
<tag name="validator.constraint_validator" alias="sylius_api_order_payment_method_eligibility" />
</service>

<service id="sylius.api.validator.correct_change_shop_user_confirm_password" class="Sylius\Bundle\ApiBundle\Validator\Constraints\CorrectChangeShopUserConfirmPasswordValidator">
<tag name="validator.constraint_validator" alias="sylius_api_correct_change_shop_user_confirm_password" />
</service>
</services>
</container>
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/services/constraint-mapping-1.0.xsd"
>
<class name="Sylius\Bundle\ApiBundle\Command\ChangePasswordShopUser">
<property name="oldPassword">
<class name="Sylius\Bundle\ApiBundle\Command\ChangeShopUserPassword">
<constraint name="Sylius\Bundle\ApiBundle\Validator\Constraints\CorrectChangeShopUserConfirmPassword">
<option name="groups">
<value>sylius</value>
</option>
</constraint>
<property name="currentPassword">
<constraint name="Symfony\Component\Security\Core\Validator\Constraints\UserPassword">
<option name="message">sylius.user.plainPassword.wrong_current</option>
<option name="groups">sylius</option>
Expand All @@ -29,7 +34,7 @@
<option name="groups">sylius</option>
</constraint>
</property>
<property name="password">
<property name="newPassword">
<constraint name="NotBlank">
<option name="groups">sylius</option>
</constraint>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\ApiBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;

/** @experimental */
final class CorrectChangeShopUserConfirmPassword extends Constraint
{
public function validatedBy(): string
{
return 'sylius_api_correct_change_shop_user_confirm_password';
}

public function getTargets(): string
{
return self::CLASS_CONSTRAINT;
}
}
Loading

0 comments on commit 207fc84

Please sign in to comment.