Skip to content

Commit

Permalink
ENGCOM-7473: Feature 259 Add GraphQL mutations for Reset password for…
Browse files Browse the repository at this point in the history
… MyAccount #27876
  • Loading branch information
lenaorobei authored May 11, 2020
2 parents f2fd3e5 + 14db001 commit aa01211
Show file tree
Hide file tree
Showing 7 changed files with 672 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CustomerGraphQl\Model\Resolver;

use Magento\Customer\Api\AccountManagementInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Model\AccountManagement;
use Magento\Customer\Model\AuthenticationInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
use Magento\Framework\GraphQl\Query\Resolver\Value;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\Validator\EmailAddress as EmailValidator;

/**
* Class Resolver for RequestPasswordResetEmail
*/
class RequestPasswordResetEmail implements ResolverInterface
{
/**
* @var AuthenticationInterface
*/
private $authentication;

/**
* @var CustomerRepositoryInterface
*/
private $customerRepository;

/**
* @var AccountManagementInterface
*/
private $customerAccountManagement;

/**
* @var EmailValidator
*/
private $emailValidator;

/**
* RequestPasswordResetEmail constructor.
*
* @param AuthenticationInterface $authentication
* @param CustomerRepositoryInterface $customerRepository
* @param AccountManagementInterface $customerAccountManagement
* @param EmailValidator $emailValidator
*/
public function __construct(
AuthenticationInterface $authentication,
CustomerRepositoryInterface $customerRepository,
AccountManagementInterface $customerAccountManagement,
EmailValidator $emailValidator
) {
$this->authentication = $authentication;
$this->customerRepository = $customerRepository;
$this->customerAccountManagement = $customerAccountManagement;
$this->emailValidator = $emailValidator;
}

/**
* Send password email request
*
* @param Field $field
* @param ContextInterface $context
* @param ResolveInfo $info
* @param array|null $value
* @param array|null $args
*
* @return bool|Value|mixed
*
* @throws GraphQlInputException
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) {
if (empty($args['email'])) {
throw new GraphQlInputException(__('You must specify an email address.'));
}

if (!$this->emailValidator->isValid($args['email'])) {
throw new GraphQlInputException(__('The email address has an invalid format.'));
}

try {
$customer = $this->customerRepository->get($args['email']);
} catch (LocalizedException $e) {
throw new GraphQlInputException(__('Cannot reset the customer\'s password'), $e);
}

if (true === $this->authentication->isLocked($customer->getId())) {
throw new GraphQlInputException(__('The account is locked'));
}

try {
return $this->customerAccountManagement->initiatePasswordReset(
$args['email'],
AccountManagement::EMAIL_RESET
);
} catch (LocalizedException $e) {
throw new GraphQlInputException(__('Cannot reset the customer\'s password'), $e);
}
}
}
124 changes: 124 additions & 0 deletions app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CustomerGraphQl\Model\Resolver;

use Magento\Customer\Api\AccountManagementInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Model\AuthenticationInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
use Magento\Framework\GraphQl\Query\Resolver\Value;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\Validator\EmailAddress as EmailValidator;

/**
* Class Resolver for ResetPassword
*/
class ResetPassword implements ResolverInterface
{
/**
* @var AccountManagementInterface
*/
private $customerAccountManagement;

/**
* @var EmailValidator
*/
private $emailValidator;

/**
* @var AuthenticationInterface
*/
private $authentication;

/**
* @var CustomerRepositoryInterface
*/
private $customerRepository;

/**
* ResetPassword constructor.
*
* @param AuthenticationInterface $authentication
* @param CustomerRepositoryInterface $customerRepository
* @param AccountManagementInterface $customerAccountManagement
* @param EmailValidator $emailValidator
*/
public function __construct(
AuthenticationInterface $authentication,
CustomerRepositoryInterface $customerRepository,
AccountManagementInterface $customerAccountManagement,
EmailValidator $emailValidator
) {
$this->authentication = $authentication;
$this->customerRepository = $customerRepository;
$this->customerAccountManagement = $customerAccountManagement;
$this->emailValidator = $emailValidator;
}

/**
* Reset old password and set new
*
* @param Field $field
* @param ContextInterface $context
* @param ResolveInfo $info
* @param array|null $value
* @param array|null $args
*
* @return bool|Value|mixed
*
* @throws GraphQlInputException
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) {
if (empty($args['email'])) {
throw new GraphQlInputException(__('You must specify an email address.'));
}

if (!$this->emailValidator->isValid($args['email'])) {
throw new GraphQlInputException(__('The email address has an invalid format.'));
}

if (empty($args['resetPasswordToken'])) {
throw new GraphQlInputException(__('resetPasswordToken must be specified'));
}

if (empty($args['newPassword'])) {
throw new GraphQlInputException(__('newPassword must be specified'));
}

try {
$customer = $this->customerRepository->get($args['email']);
} catch (LocalizedException $e) {
throw new GraphQlInputException(__('Cannot set the customer\'s password'), $e);
}

if (true === $this->authentication->isLocked($customer->getId())) {
throw new GraphQlInputException(__('The account is locked'));
}

try {
return $this->customerAccountManagement->resetPassword(
$args['email'],
$args['resetPasswordToken'],
$args['newPassword']
);
} catch (LocalizedException $e) {
throw new GraphQlInputException(__('Cannot set the customer\'s password'), $e);
}
}
}
9 changes: 9 additions & 0 deletions app/code/Magento/CustomerGraphQl/etc/graphql/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,13 @@
</argument>
</arguments>
</type>
<type name="Magento\StoreGraphQl\Model\Resolver\Store\StoreConfigDataProvider">
<arguments>
<argument name="extendedConfigData" xsi:type="array">
<item name="required_character_classes_number" xsi:type="string">customer/password/required_character_classes_number</item>
<item name="minimum_password_length" xsi:type="string">customer/password/minimum_password_length</item>
<item name="autocomplete_on_storefront" xsi:type="string">customer/password/autocomplete_on_storefront</item>
</argument>
</arguments>
</type>
</config>
8 changes: 8 additions & 0 deletions app/code/Magento/CustomerGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Copyright © Magento, Inc. All rights reserved.
# See COPYING.txt for license details.

type StoreConfig {
required_character_classes_number : String @doc(description: "The number of different character classes required in a password (lowercase, uppercase, digits, special characters).")
minimum_password_length : String @doc(description: "The minimum number of characters required for a valid password.")
autocomplete_on_storefront : Boolean @doc(description: "Enable autocomplete on login and forgot password forms")
}

type Query {
customer: Customer @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\Customer") @doc(description: "The customer query returns information about a customer account") @cache(cacheable: false)
isEmailAvailable (
Expand All @@ -17,6 +23,8 @@ type Mutation {
createCustomerAddress(input: CustomerAddressInput!): CustomerAddress @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\CreateCustomerAddress") @doc(description: "Create customer address")
updateCustomerAddress(id: Int!, input: CustomerAddressInput): CustomerAddress @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomerAddress") @doc(description: "Update customer address")
deleteCustomerAddress(id: Int!): Boolean @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\DeleteCustomerAddress") @doc(description: "Delete customer address")
requestPasswordResetEmail(email: String!): Boolean @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\RequestPasswordResetEmail") @doc(description: "Request an email with a reset password token for the registered customer identified by the specified email.")
resetPassword(email: String!, resetPasswordToken: String!, newPassword: String!): Boolean @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\ResetPassword") @doc(description: "Reset a customer's password using the reset password token that the customer received in an email after requesting it using requestPasswordResetEmail.")
}

input CustomerAddressInput {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\GraphQl\Customer;

use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;

class RequestPasswordResetEmailTest extends GraphQlAbstract
{
/**
* @var LockCustomer
*/
private $lockCustomer;

protected function setUp(): void
{
parent::setUp();

$this->lockCustomer = Bootstrap::getObjectManager()->get(LockCustomer::class);
}
/**
* @magentoApiDataFixture Magento/Customer/_files/customer.php
*/
public function testCustomerAccountWithEmailAvailable()
{
$query =
<<<QUERY
mutation {
requestPasswordResetEmail(email: "customer@example.com")
}
QUERY;
$response = $this->graphQlMutation($query);

self::assertArrayHasKey('requestPasswordResetEmail', $response);
self::assertTrue($response['requestPasswordResetEmail']);
}

/**
* Check if customer account is not available
*
* @expectedException \Exception
* @expectedExceptionMessage Cannot reset the customer's password
*/
public function testCustomerAccountWithEmailNotAvailable()
{
$query =
<<<QUERY
mutation {
requestPasswordResetEmail(email: "customerNotAvalible@example.com")
}
QUERY;
$this->graphQlMutation($query);
}

/**
* Check if email value empty
*
* @expectedException \Exception
* @expectedExceptionMessage You must specify an email address.
*/
public function testEmailAvailableEmptyValue()
{
$query = <<<QUERY
mutation {
requestPasswordResetEmail(email: "")
}
QUERY;
$this->graphQlMutation($query);
}

/**
* Check if email is invalid
*
* @expectedException \Exception
* @expectedExceptionMessage The email address has an invalid format.
*/
public function testEmailAvailableInvalidValue()
{
$query = <<<QUERY
mutation {
requestPasswordResetEmail(email: "invalid-email")
}
QUERY;
$this->graphQlMutation($query);
}

/**
* Check if email was sent for lock customer
*
* @magentoApiDataFixture Magento/Customer/_files/customer.php
*
* @expectedException \Exception
* @expectedExceptionMessage The account is locked
*/
public function testRequestPasswordResetEmailForLockCustomer()
{
$this->lockCustomer->execute(1);
$query =
<<<QUERY
mutation {
requestPasswordResetEmail(email: "customer@example.com")
}
QUERY;

$this->graphQlMutation($query);
}
}
Loading

0 comments on commit aa01211

Please sign in to comment.