mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
add validation, fix register customer route, add missing mail send
This commit is contained in:
parent
5ba7a4e2a0
commit
3272f454de
23 changed files with 378 additions and 64 deletions
|
|
@ -17,7 +17,7 @@ Feature: Verifying account's email address
|
|||
And I should be able to log in as "valkyrie@cain.com" with "sylius" password
|
||||
And my account should be verified
|
||||
|
||||
@ui
|
||||
@ui @api
|
||||
Scenario: Being unable to verify with invalid token
|
||||
When I try to verify using "twinklelittlestar" token
|
||||
Then I should be notified that the verification token is invalid
|
||||
|
|
@ -45,14 +45,14 @@ Feature: Verifying account's email address
|
|||
And I have already verified my account
|
||||
Then I should not be able to resend the verification email
|
||||
|
||||
@ui @email
|
||||
@ui @email @api
|
||||
Scenario: Receiving account verification email after registration
|
||||
When I register with email "ghastly@bespoke.com" and password "suitsarelife"
|
||||
Then I should be notified that my account has been created and the verification email has been sent
|
||||
And 2 emails should be sent to "ghastly@bespoke.com"
|
||||
But I should not be able to log in as "ghastly@bespoke.com" with "suitsarelife" password
|
||||
|
||||
@ui @email
|
||||
@ui @email @api
|
||||
Scenario: Do not send verification email when account verification on the channel is not required
|
||||
Given "United States" channel has account verification disabled
|
||||
When I register with email "ghastly@bespoke.com" and password "suitsarelife"
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@ final class EmailContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then :count email(s) should be sent to :recipient
|
||||
*/
|
||||
public function numberOfEmailsShouldBeSentTo(int $count, string $recipient): void
|
||||
{
|
||||
Assert::same($this->emailChecker->countMessagesTo($recipient), $count);
|
||||
}
|
||||
|
||||
private function assertEmailContainsMessageTo(string $message, string $recipient): void
|
||||
{
|
||||
Assert::true($this->emailChecker->hasMessageTo($message, $recipient));
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ final class CustomerContext implements Context
|
|||
/** @var ShopSecurityContext */
|
||||
private $shopApiSecurityContext;
|
||||
|
||||
/** @var string */
|
||||
private $verificationToken = '';
|
||||
|
||||
public function __construct(
|
||||
ApiClientInterface $customerClient,
|
||||
ApiClientInterface $orderShopClient,
|
||||
|
|
@ -186,12 +189,25 @@ final class CustomerContext implements Context
|
|||
*/
|
||||
public function iTryToVerifyMyAccountUsingTheLinkFromEmail(ShopUserInterface $user): void
|
||||
{
|
||||
$request = Request::custom(
|
||||
\sprintf('/api/v2/shop/account-verification-requests/%s', (string) $user->getEmailVerificationToken()),
|
||||
HttpRequest::METHOD_PATCH,
|
||||
);
|
||||
$this->verificationToken = $user->getEmailVerificationToken();
|
||||
$this->verifyAccount($this->verificationToken);
|
||||
}
|
||||
|
||||
$this->customerClient->executeCustomRequest($request);
|
||||
/**
|
||||
* @When I (try to )verify using :token token
|
||||
*/
|
||||
public function iTryToVerifyUsing(string $token): void
|
||||
{
|
||||
$this->verifyAccount($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I register with email :email and password :password
|
||||
*/
|
||||
public function iRegisterWithEmailAndPassword(string $email, string $password): void
|
||||
{
|
||||
$this->iRegisterThisAccount($email, $password);
|
||||
$this->loginContext->iLogInAsWithPassword($email, $password);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -287,6 +303,17 @@ final class CustomerContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that the verification token is invalid
|
||||
*/
|
||||
public function iShouldBeNotifiedThatTheVerificationTokenIsInvalid(): void
|
||||
{
|
||||
$this->isViolationWithMessageInResponse(
|
||||
$this->customerClient->getLastResponse(),
|
||||
sprintf('There is no shop user with %s email verification token.', $this->verificationToken)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I browse my orders
|
||||
*/
|
||||
|
|
@ -337,20 +364,10 @@ final class CustomerContext implements Context
|
|||
$this->responseChecker->isCreationSuccessful($this->customerClient->getLastResponse());
|
||||
}
|
||||
|
||||
private function isViolationWithMessageInResponse(Response $response, string $message): bool
|
||||
{
|
||||
$violations = $this->responseChecker->getResponseContent($response)['violations'];
|
||||
foreach ($violations as $violation) {
|
||||
if ($violation['message'] === $message) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that my password has been successfully changed
|
||||
* @Then I should be notified that new account has been successfully created
|
||||
* @Then I should be notified that my account has been created and the verification email has been sent
|
||||
*/
|
||||
public function iShouldBeNotifiedThatItHasBeenSuccessfullyChanged(): void
|
||||
{
|
||||
|
|
@ -408,8 +425,48 @@ final class CustomerContext implements Context
|
|||
$user = $this->sharedStorage->get('user');
|
||||
$this->loginContext->iLogInAsWithPassword($user->getEmail(), 'sylius');
|
||||
|
||||
$response = $this->customerClient->show((string) $user->getId());
|
||||
$response = $this->customerClient->show((string) $user->getCustomer()->getId());
|
||||
|
||||
Assert::true($this->responseChecker->getResponseContent($response)['user']['verified']);
|
||||
}
|
||||
|
||||
private function isViolationWithMessageInResponse(Response $response, string $message): bool
|
||||
{
|
||||
$violations = $this->responseChecker->getResponseContent($response)['violations'];
|
||||
foreach ($violations as $violation) {
|
||||
if ($violation['message'] === $message) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function verifyAccount(string $token): void
|
||||
{
|
||||
$request = Request::custom(
|
||||
\sprintf('/api/v2/shop/account-verification-requests/%s', $token),
|
||||
HttpRequest::METHOD_PATCH,
|
||||
);
|
||||
|
||||
$this->customerClient->executeCustomRequest($request);
|
||||
}
|
||||
|
||||
private function iRegisterThisAccount(?string $email = 'example@example.com', ?string $password = 'example'): void
|
||||
{
|
||||
$request = Request::create(
|
||||
'shop',
|
||||
'customers',
|
||||
'',
|
||||
);
|
||||
|
||||
$request->setContent([
|
||||
'firstName' => 'First',
|
||||
'lastName' => 'Last',
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
$this->customerClient->executeCustomRequest($request);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,16 @@ final class LoginContext implements Context
|
|||
$this->iShouldBeLoggedIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not be able to log in as :email with :password password
|
||||
*/
|
||||
public function iShouldNotBeAbleToLogInAsWithPassword(string $email, string $password): void
|
||||
{
|
||||
$this->iLogInAsWithPassword($email, $password);
|
||||
|
||||
$this->iShouldNotBeLoggedIn();
|
||||
}
|
||||
|
||||
private function addLocaleCode(string $localeCode): void
|
||||
{
|
||||
$this->request->updateContent(['localeCode' => $localeCode]);
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ final class RegistrationContext implements Context
|
|||
{
|
||||
$this->client->request(
|
||||
'POST',
|
||||
'/api/v2/shop/customers/',
|
||||
'/api/v2/shop/customers',
|
||||
[],
|
||||
[],
|
||||
['HTTP_ACCEPT' => 'application/ld+json', 'CONTENT_TYPE' => 'application/ld+json'],
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ default:
|
|||
- sylius.behat.context.setup.shop_api_security
|
||||
- sylius.behat.context.setup.user
|
||||
|
||||
- sylius.behat.context.api.email
|
||||
- sylius.behat.context.api.shop.customer
|
||||
- sylius.behat.context.api.shop.login
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ use Sylius\Component\Core\Model\ChannelInterface;
|
|||
use Sylius\Component\Core\Model\ShopUserInterface;
|
||||
use Sylius\Component\Resource\Factory\FactoryInterface;
|
||||
use Sylius\Component\User\Security\Generator\GeneratorInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
|
||||
|
|
@ -46,13 +48,17 @@ final class RegisterShopUserHandler implements MessageHandlerInterface
|
|||
/** @var MessageBusInterface */
|
||||
private $commandBus;
|
||||
|
||||
/** @var EventDispatcherInterface */
|
||||
private $eventDispatcher;
|
||||
|
||||
public function __construct(
|
||||
FactoryInterface $shopUserFactory,
|
||||
ObjectManager $shopUserManager,
|
||||
CustomerProviderInterface $customerProvider,
|
||||
ChannelRepositoryInterface $channelRepository,
|
||||
GeneratorInterface $tokenGenerator,
|
||||
MessageBusInterface $commandBus
|
||||
MessageBusInterface $commandBus,
|
||||
EventDispatcherInterface $eventDispatcher
|
||||
) {
|
||||
$this->shopUserFactory = $shopUserFactory;
|
||||
$this->shopUserManager = $shopUserManager;
|
||||
|
|
@ -60,6 +66,7 @@ final class RegisterShopUserHandler implements MessageHandlerInterface
|
|||
$this->channelRepository = $channelRepository;
|
||||
$this->tokenGenerator = $tokenGenerator;
|
||||
$this->commandBus = $commandBus;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
}
|
||||
|
||||
public function __invoke(RegisterShopUser $command): void
|
||||
|
|
@ -82,6 +89,11 @@ final class RegisterShopUserHandler implements MessageHandlerInterface
|
|||
/** @var ChannelInterface $channel */
|
||||
$channel = $this->channelRepository->findOneByCode($command->channelCode);
|
||||
|
||||
$this->shopUserManager->persist($user);
|
||||
$this->shopUserManager->flush();
|
||||
|
||||
$this->eventDispatcher->dispatch(new GenericEvent($customer), 'sylius.customer.post_register');
|
||||
|
||||
if ($channel->isAccountVerificationRequired()) {
|
||||
$token = $this->tokenGenerator->generate();
|
||||
$user->setEmailVerificationToken($token);
|
||||
|
|
@ -95,6 +107,5 @@ final class RegisterShopUserHandler implements MessageHandlerInterface
|
|||
$user->setEnabled(true);
|
||||
}
|
||||
|
||||
$this->shopUserManager->persist($user);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<collectionOperations>
|
||||
<collectionOperation name="shop_post">
|
||||
<attribute name="method">POST</attribute>
|
||||
<attribute name="path">/shop/customers/</attribute>
|
||||
<attribute name="path">/shop/customers</attribute>
|
||||
<attribute name="openapi_context">
|
||||
<attribute name="summary">Registers a new customer</attribute>
|
||||
</attribute>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
<resource class="Sylius\Bundle\ApiBundle\Command\VerifyCustomerAccount" shortName="VerifyCustomerAccount">
|
||||
<attribute name="route_prefix">shop</attribute>
|
||||
<attribute name="messenger">input</attribute>
|
||||
<attribute name="validation_groups">sylius</attribute>
|
||||
|
||||
<collectionOperations />
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
<argument type="service" id="sylius.repository.channel" />
|
||||
<argument type="service" id="sylius.shop_user.token_generator.email_verification" />
|
||||
<argument type="service" id="sylius_default.bus" />
|
||||
<argument type="service" id="event_dispatcher" />
|
||||
<tag name="messenger.message_handler" bus="sylius_default.bus"/>
|
||||
</service>
|
||||
|
||||
|
|
@ -154,5 +155,12 @@
|
|||
<argument type="service" id="sylius.email_sender" />
|
||||
<tag name="messenger.message_handler" bus="sylius_default.bus" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\ApiBundle\CommandHandler\SendUserRegistrationEmailHandler">
|
||||
<argument type="service" id="sylius.repository.shop_user" />
|
||||
<argument type="service" id="sylius.repository.channel" />
|
||||
<argument type="service" id="sylius.email_sender" />
|
||||
<tag name="messenger.message_handler" bus="sylius_default.bus" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
|
|||
|
|
@ -58,5 +58,10 @@
|
|||
<argument type="service" id="sylius.promotion_coupon_eligibility_checker" />
|
||||
<tag name="validator.constraint_validator" alias="sylius_api_promotion_coupon_eligibility" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.api.validator.account_verification_token_eligibility" class="Sylius\Bundle\ApiBundle\Validator\Constraints\AccountVerificationTokenEligibilityValidator">
|
||||
<argument type="service" id="sylius.repository.shop_user" />
|
||||
<tag name="validator.constraint_validator" alias="sylius_api_validator_account_verification_token_eligibility" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
|
||||
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" 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\VerifyCustomerAccount">
|
||||
<constraint name="Sylius\Bundle\ApiBundle\Validator\Constraints\AccountVerificationTokenEligibility">
|
||||
<option name="groups">
|
||||
<value>sylius</value>
|
||||
</option>
|
||||
</constraint>
|
||||
</class>
|
||||
</constraint-mapping>
|
||||
|
|
@ -1,3 +1,6 @@
|
|||
sylius:
|
||||
account:
|
||||
invalid_verification_token: 'There is no shop user with %verificationToken% email verification token.'
|
||||
order:
|
||||
not_empty: 'An empty order cannot be completed.'
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
|||
|
||||
final class SendAccountVerificationEmailHandlerTest extends KernelTestCase
|
||||
{
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function it_sends_account_verification_token_email_without_hostname(): void
|
||||
{
|
||||
$container = self::bootKernel()->getContainer();
|
||||
|
|
@ -78,6 +81,9 @@ final class SendAccountVerificationEmailHandlerTest extends KernelTestCase
|
|||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function it_sends_account_verification_token_email_with_hostname(): void
|
||||
{
|
||||
$container = self::bootKernel()->getContainer();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?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 AccountVerificationTokenEligibility extends Constraint
|
||||
{
|
||||
/** @var string */
|
||||
public $message = 'sylius.account.invalid_verification_token';
|
||||
|
||||
public function validatedBy(): string
|
||||
{
|
||||
return 'sylius_api_validator_account_verification_token_eligibility';
|
||||
}
|
||||
|
||||
public function getTargets(): string
|
||||
{
|
||||
return self::CLASS_CONSTRAINT;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?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 Sylius\Bundle\ApiBundle\Command\VerifyCustomerAccount;
|
||||
use Sylius\Component\Resource\Repository\RepositoryInterface;
|
||||
use Sylius\Component\User\Model\UserInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
||||
/** @experimental */
|
||||
final class AccountVerificationTokenEligibilityValidator extends ConstraintValidator
|
||||
{
|
||||
/** @var RepositoryInterface */
|
||||
private $shopUserRepository;
|
||||
|
||||
public function __construct(RepositoryInterface $shopUserRepository)
|
||||
{
|
||||
$this->shopUserRepository = $shopUserRepository;
|
||||
}
|
||||
|
||||
/** @param VerifyCustomerAccount|mixed $value */
|
||||
public function validate($value, Constraint $constraint)
|
||||
{
|
||||
/** @var UserInterface|null $user */
|
||||
$user = $this->shopUserRepository->findOneBy(['emailVerificationToken' => $value->token]);
|
||||
|
||||
if (null === $user) {
|
||||
$this->context->addViolation(
|
||||
$constraint->message,
|
||||
['%verificationToken%' => $value->token]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,8 @@ use Sylius\Component\Core\Model\CustomerInterface;
|
|||
use Sylius\Component\Core\Model\ShopUserInterface;
|
||||
use Sylius\Component\Resource\Factory\FactoryInterface;
|
||||
use Sylius\Component\User\Security\Generator\GeneratorInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
use Symfony\Component\Messenger\Envelope;
|
||||
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
|
|
@ -36,7 +38,8 @@ final class RegisterShopUserHandlerSpec extends ObjectBehavior
|
|||
CustomerProviderInterface $customerProvider,
|
||||
ChannelRepositoryInterface $channelRepository,
|
||||
GeneratorInterface $generator,
|
||||
MessageBusInterface $commandBus
|
||||
MessageBusInterface $commandBus,
|
||||
EventDispatcherInterface $eventDispatcher
|
||||
): void {
|
||||
$this->beConstructedWith(
|
||||
$shopUserFactory,
|
||||
|
|
@ -44,7 +47,8 @@ final class RegisterShopUserHandlerSpec extends ObjectBehavior
|
|||
$customerProvider,
|
||||
$channelRepository,
|
||||
$generator,
|
||||
$commandBus
|
||||
$commandBus,
|
||||
$eventDispatcher
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +66,8 @@ final class RegisterShopUserHandlerSpec extends ObjectBehavior
|
|||
ChannelRepositoryInterface $channelRepository,
|
||||
ChannelInterface $channel,
|
||||
GeneratorInterface $generator,
|
||||
MessageBusInterface $commandBus
|
||||
MessageBusInterface $commandBus,
|
||||
EventDispatcherInterface $eventDispatcher
|
||||
): void {
|
||||
$command = new RegisterShopUser('Will', 'Smith', 'WILL.SMITH@example.com', 'iamrobot', '+13104322400');
|
||||
$command->setChannelCode('CHANNEL_CODE');
|
||||
|
|
@ -85,10 +90,12 @@ final class RegisterShopUserHandlerSpec extends ObjectBehavior
|
|||
$generator->generate()->willReturn('TOKEN');
|
||||
$shopUser->setEmailVerificationToken('TOKEN')->shouldBeCalled();
|
||||
|
||||
$sendEmailCommand = new SendAccountVerificationEmail('WILL.SMITH@example.com', 'en_US', 'CHANNEL_CODE');
|
||||
$commandBus->dispatch($sendEmailCommand)->shouldBeCalled()->willReturn(new Envelope($sendEmailCommand));
|
||||
|
||||
$shopUserManager->persist($shopUser)->shouldBeCalled();
|
||||
$shopUserManager->flush()->shouldBeCalled();
|
||||
$eventDispatcher->dispatch(new GenericEvent($customer->getWrappedObject()), 'sylius.customer.post_register')->shouldBeCalled();
|
||||
|
||||
$sendVerificationEmailCommand = new SendAccountVerificationEmail('WILL.SMITH@example.com', 'en_US', 'CHANNEL_CODE');
|
||||
$commandBus->dispatch($sendVerificationEmailCommand)->shouldBeCalled()->willReturn(new Envelope($sendVerificationEmailCommand));
|
||||
|
||||
$this($command);
|
||||
}
|
||||
|
|
@ -100,7 +107,8 @@ final class RegisterShopUserHandlerSpec extends ObjectBehavior
|
|||
ShopUserInterface $shopUser,
|
||||
CustomerInterface $customer,
|
||||
ChannelRepositoryInterface $channelRepository,
|
||||
ChannelInterface $channel
|
||||
ChannelInterface $channel,
|
||||
EventDispatcherInterface $eventDispatcher
|
||||
): void {
|
||||
$command = new RegisterShopUser('Will', 'Smith', 'WILL.SMITH@example.com', 'iamrobot', '+13104322400');
|
||||
$command->setChannelCode('CHANNEL_CODE');
|
||||
|
|
@ -118,11 +126,14 @@ final class RegisterShopUserHandlerSpec extends ObjectBehavior
|
|||
$customer->setPhoneNumber('+13104322400')->shouldBeCalled();
|
||||
$customer->setUser($shopUser)->shouldBeCalled();
|
||||
|
||||
$shopUserManager->persist($shopUser)->shouldBeCalled();
|
||||
$shopUserManager->flush()->shouldBeCalled();
|
||||
$eventDispatcher->dispatch(new GenericEvent($customer->getWrappedObject()), 'sylius.customer.post_register')->shouldBeCalled();
|
||||
|
||||
$channelRepository->findOneByCode('CHANNEL_CODE')->willReturn($channel);
|
||||
$channel->isAccountVerificationRequired()->willReturn(false);
|
||||
$shopUser->setEnabled(true);
|
||||
|
||||
$shopUserManager->persist($shopUser)->shouldBeCalled();
|
||||
|
||||
$this($command);
|
||||
}
|
||||
|
|
@ -133,7 +144,8 @@ final class RegisterShopUserHandlerSpec extends ObjectBehavior
|
|||
CustomerProviderInterface $customerProvider,
|
||||
ShopUserInterface $shopUser,
|
||||
CustomerInterface $customer,
|
||||
ShopUserInterface $existingShopUser
|
||||
ShopUserInterface $existingShopUser,
|
||||
EventDispatcherInterface $eventDispatcher
|
||||
): void {
|
||||
$shopUserFactory->createNew()->willReturn($shopUser);
|
||||
$customerProvider->provide('WILL.SMITH@example.com')->willReturn($customer);
|
||||
|
|
@ -141,6 +153,8 @@ final class RegisterShopUserHandlerSpec extends ObjectBehavior
|
|||
$customer->getUser()->willReturn($existingShopUser);
|
||||
|
||||
$shopUserManager->persist($shopUser)->shouldNotBeCalled();
|
||||
$shopUserManager->flush()->shouldNotBeCalled();
|
||||
$eventDispatcher->dispatch(new GenericEvent($customer->getWrappedObject()), 'sylius.customer.post_register')->shouldNotBeCalled();
|
||||
|
||||
$this
|
||||
->shouldThrow(\DomainException::class)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
<?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 spec\Sylius\Bundle\ApiBundle\Validator\Constraints;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\ApiBundle\Command\VerifyCustomerAccount;
|
||||
use Sylius\Bundle\ApiBundle\Validator\Constraints\AccountVerificationTokenEligibility;
|
||||
use Sylius\Component\Core\Model\ShopUserInterface;
|
||||
use Sylius\Component\Resource\Repository\RepositoryInterface;
|
||||
use Symfony\Component\Validator\ConstraintValidatorInterface;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
|
||||
final class AccountVerificationTokenEligibilityValidatorSpec extends ObjectBehavior
|
||||
{
|
||||
function let(RepositoryInterface $shopUserRepository): void
|
||||
{
|
||||
$this->beConstructedWith($shopUserRepository);
|
||||
}
|
||||
|
||||
function it_is_a_constraint_validator(): void
|
||||
{
|
||||
$this->shouldImplement(ConstraintValidatorInterface::class);
|
||||
}
|
||||
|
||||
function it_adds_violation_if_account_is_null(
|
||||
RepositoryInterface $shopUserRepository,
|
||||
ExecutionContextInterface $executionContext
|
||||
): void {
|
||||
$constraint = new AccountVerificationTokenEligibility();
|
||||
$value = new VerifyCustomerAccount('TOKEN');
|
||||
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$shopUserRepository->findOneBy(['emailVerificationToken' => 'TOKEN'])->willReturn(null);
|
||||
|
||||
$executionContext
|
||||
->addViolation(
|
||||
'sylius.account.invalid_verification_token',
|
||||
['%verificationToken%' => 'TOKEN']
|
||||
)
|
||||
->shouldBeCalled()
|
||||
;
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
|
||||
function it_does_nothing_if_account_has_been_found(
|
||||
RepositoryInterface $shopUserRepository,
|
||||
ExecutionContextInterface $executionContext,
|
||||
ShopUserInterface $user
|
||||
): void {
|
||||
$constraint = new AccountVerificationTokenEligibility();
|
||||
$value = new VerifyCustomerAccount('TOKEN');
|
||||
|
||||
$this->initialize($executionContext);
|
||||
|
||||
$shopUserRepository->findOneBy(['emailVerificationToken' => 'TOKEN'])->willReturn($user);
|
||||
|
||||
$executionContext
|
||||
->addViolation(
|
||||
'sylius.account.invalid_verification_token',
|
||||
['%verificationToken%' => 'TOKEN']
|
||||
)
|
||||
->shouldNotBeCalled()
|
||||
;
|
||||
|
||||
$this->validate($value, $constraint);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,9 +9,12 @@ sylius_mailer:
|
|||
order_confirmation:
|
||||
subject: sylius.emails.order_confirmation.subject
|
||||
template: "@SyliusCore/Email/orderConfirmation.html.twig"
|
||||
user_registration:
|
||||
subject: sylius.emails.user_registration.subject
|
||||
template: "@SyliusCore/Email/userRegistration.html.twig"
|
||||
password_reset:
|
||||
subject: sylius.emails.user.password_reset.subject
|
||||
template: "@SyliusCore/Email/passwordReset.html.twig"
|
||||
account_verification_token:
|
||||
subject: sylius.emails.user.verification_token.subject
|
||||
template: "@SyliusShop/Email/verification.html.twig"
|
||||
template: "@SyliusCore/Email/accountVerification.html.twig"
|
||||
|
|
|
|||
|
|
@ -244,6 +244,14 @@ sylius:
|
|||
by_zones_and_channel: By zones and channel
|
||||
|
||||
email:
|
||||
account_verification_token:
|
||||
subject: Email address verification
|
||||
user_registration:
|
||||
start_shopping: 'Start shopping'
|
||||
subject: 'User registration'
|
||||
welcome_to_our_store: 'Welcome to our store!'
|
||||
you_have_just_been_registered: 'You have just been registered. Thank you'
|
||||
verification_token:
|
||||
hello: 'Hello'
|
||||
message: "Verify your account with token: "
|
||||
subject: 'Email address verification'
|
||||
to_verify_your_email_address: 'To verify your email address - click the link below'
|
||||
verify_your_email_address: 'Verify your email address'
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
{% extends '@SyliusCore/Email/layout.html.twig' %}
|
||||
|
||||
{% block subject %}
|
||||
{% if sylius_bundle_loaded_checker('SyliusShopBundle') %}
|
||||
{{ 'sylius.email.verification_token.subject'|trans({}, null, localeCode) }}
|
||||
{% else %}
|
||||
{{ 'sylius.email.account_verification_token.subject'|trans({}, null, localeCode) }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
|
@ -25,7 +21,7 @@
|
|||
</div>
|
||||
{% else %}
|
||||
<div style="text-align: center;">
|
||||
<span>{{ 'sylius.email.account_verification_token.message'|trans({}, null, localeCode) }}{{ user.emailVerificationToken }}</span>
|
||||
<span>{{ 'sylius.email.verification_token.message'|trans({}, null, localeCode) }}{{ user.emailVerificationToken }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
{% extends '@SyliusShop/Email/layout.html.twig' %}
|
||||
|
||||
{% block subject %}
|
||||
{{ 'sylius.email.user_registration.subject'|trans({}, null, localeCode) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if sylius_bundle_loaded_checker('SyliusShopBundle') %}
|
||||
{% set url = channel.hostname is not null ? 'http://' ~ channel.hostname ~ path('sylius_shop_homepage', {'_locale': localeCode}) : url('sylius_shop_homepage', {'_locale': localeCode}) %}
|
||||
{% endif %}
|
||||
<div style="text-align: center; margin-bottom: 30px;">
|
||||
<div style="font-size: 24px;">
|
||||
{{ 'sylius.email.user_registration.welcome_to_our_store'|trans({}, null, localeCode) }}<br>
|
||||
</div>
|
||||
{{ 'sylius.email.user_registration.you_have_just_been_registered'|trans({}, null, localeCode) }} {{ user.username }}.
|
||||
</div>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="{{ url|raw }}" style="display: inline-block; text-align: center; background: #1abb9c; padding: 18px 28px; color: #fff; text-decoration: none; border-radius: 3px;">
|
||||
{{ 'sylius.email.user_registration.start_shopping'|trans({}, null, localeCode) }}
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -1,22 +1 @@
|
|||
{% extends '@SyliusShop/Email/layout.html.twig' %}
|
||||
|
||||
{% block subject %}
|
||||
{{ 'sylius.email.user_registration.subject'|trans({}, null, localeCode) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% set url = channel.hostname is not null ? 'http://' ~ channel.hostname ~ path('sylius_shop_homepage', {'_locale': localeCode}) : url('sylius_shop_homepage', {'_locale': localeCode}) %}
|
||||
|
||||
<div style="text-align: center; margin-bottom: 30px;">
|
||||
<div style="font-size: 24px;">
|
||||
{{ 'sylius.email.user_registration.welcome_to_our_store'|trans({}, null, localeCode) }}<br>
|
||||
</div>
|
||||
{{ 'sylius.email.user_registration.you_have_just_been_registered'|trans({}, null, localeCode) }} {{ user.username }}.
|
||||
</div>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="{{ url|raw }}" style="display: inline-block; text-align: center; background: #1abb9c; padding: 18px 28px; color: #fff; text-decoration: none; border-radius: 3px;">
|
||||
{{ 'sylius.email.user_registration.start_shopping'|trans({}, null, localeCode) }}
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% extends '@SyliusCore/Email/userRegistration.html.twig' %}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue