Skip to content

Commit e745e91

Browse files
Add change customer password mutation
1 parent a7893f9 commit e745e91

File tree

3 files changed

+225
-0
lines changed

3 files changed

+225
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CustomerGraphQl\Model\Resolver\Customer\Account;
9+
10+
use Magento\Authorization\Model\UserContextInterface;
11+
use Magento\Customer\Api\AccountManagementInterface;
12+
use Magento\Customer\Model\Customer;
13+
use Magento\CustomerGraphQl\Model\Resolver\Customer\CustomerDataProvider;
14+
use Magento\Framework\GraphQl\Config\Element\Field;
15+
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
16+
use Magento\Framework\GraphQl\Query\Resolver\Value;
17+
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory;
18+
use Magento\Framework\GraphQl\Query\ResolverInterface;
19+
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
20+
21+
/**
22+
* {@inheritdoc}
23+
*/
24+
class ChangePassword implements ResolverInterface
25+
{
26+
/**
27+
* @var UserContextInterface
28+
*/
29+
private $userContext;
30+
31+
/**
32+
* @var AccountManagementInterface
33+
*/
34+
private $accountManagement;
35+
36+
/**
37+
* @var CustomerDataProvider
38+
*/
39+
private $customerResolver;
40+
41+
/**
42+
* @var ValueFactory
43+
*/
44+
private $valueFactory;
45+
46+
/**
47+
* @param UserContextInterface $userContext
48+
* @param AccountManagementInterface $accountManagement
49+
* @param CustomerDataProvider $customerResolver
50+
* @param ValueFactory $valueFactory
51+
*/
52+
public function __construct(
53+
UserContextInterface $userContext,
54+
AccountManagementInterface $accountManagement,
55+
CustomerDataProvider $customerResolver,
56+
ValueFactory $valueFactory
57+
) {
58+
$this->userContext = $userContext;
59+
$this->accountManagement = $accountManagement;
60+
$this->customerResolver = $customerResolver;
61+
$this->valueFactory = $valueFactory;
62+
}
63+
64+
/**
65+
* @inheritdoc
66+
*/
67+
public function resolve(
68+
Field $field,
69+
$context,
70+
ResolveInfo $info,
71+
array $value = null,
72+
array $args = null
73+
): Value {
74+
$customerId = (int) $this->userContext->getUserId();
75+
76+
if ($customerId === 0) {
77+
throw new GraphQlAuthorizationException(
78+
__(
79+
'Current customer does not have access to the resource "%1"',
80+
[Customer::ENTITY]
81+
)
82+
);
83+
}
84+
85+
$this->accountManagement->changePasswordById($customerId, $args['currentPassword'], $args['newPassword']);
86+
$data = $this->customerResolver->getCustomerById($customerId);
87+
$result = function () use ($data) {
88+
return !empty($data) ? $data : [];
89+
};
90+
91+
return $this->valueFactory->create($result);
92+
}
93+
}

app/code/Magento/CustomerGraphQl/etc/schema.graphqls

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ type Query {
55
customer: Customer @resolver(class: "Magento\\CustomerGraphQl\\Model\\Resolver\\Customer") @doc(description: "The customer query returns information about a customer account")
66
}
77

8+
type Mutation {
9+
changePassword(currentPassword: String!, newPassword: String!): Customer @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\Customer\\Account\\ChangePassword") @doc(description:"Changes password for logged in customer")
10+
}
11+
812
type Customer @doc(description: "Customer defines the customer name and address and other details") {
913
created_at: String @doc(description: "Timestamp indicating when the account was created")
1014
group_id: Int @doc(description: "The group assigned to the user. Default values are 0 (Not logged in), 1 (General), 2 (Wholesale), and 3 (Retailer)")
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\GraphQl\Customer;
9+
10+
use Magento\Customer\Api\AccountManagementInterface;
11+
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\Integration\Api\CustomerTokenServiceInterface;
13+
use Magento\TestFramework\ObjectManager;
14+
use Magento\TestFramework\TestCase\GraphQlAbstract;
15+
16+
class CustomerChangePasswordTest extends GraphQlAbstract
17+
{
18+
/**
19+
* @var ObjectManager
20+
*/
21+
private $objectManager;
22+
23+
/**
24+
* @var AccountManagementInterface
25+
*/
26+
private $accountManagement;
27+
28+
/**
29+
* @magentoApiDataFixture Magento/Customer/_files/customer.php
30+
*/
31+
public function testCustomerChangeValidPassword()
32+
{
33+
$customerEmail = 'customer@example.com';
34+
$oldCustomerPassword = 'password';
35+
$newCustomerPassword = 'anotherPassword1';
36+
37+
$query = <<<QUERY
38+
mutation {
39+
changePassword(
40+
currentPassword: "$oldCustomerPassword",
41+
newPassword: "$newCustomerPassword"
42+
) {
43+
id
44+
email
45+
firstname
46+
lastname
47+
}
48+
}
49+
QUERY;
50+
51+
/** @var CustomerTokenServiceInterface $customerTokenService */
52+
$customerTokenService = $this->objectManager->create(CustomerTokenServiceInterface::class);
53+
$customerToken = $customerTokenService->createCustomerAccessToken($customerEmail, $oldCustomerPassword);
54+
$headerMap = ['Authorization' => 'Bearer ' . $customerToken];
55+
$response = $this->graphQlQuery($query, [], '', $headerMap);
56+
$this->assertEquals($customerEmail, $response['changePassword']['email']);
57+
58+
try {
59+
// registry contains the old password hash so needs to be reset
60+
$this->objectManager->get(\Magento\Customer\Model\CustomerRegistry::class)
61+
->removeByEmail($customerEmail);
62+
$this->accountManagement->authenticate($customerEmail, $newCustomerPassword);
63+
} catch (LocalizedException $e) {
64+
$this->fail('Password was not changed: ' . $e->getMessage());
65+
}
66+
}
67+
68+
public function testGuestUserCannotChangePassword()
69+
{
70+
$query = <<<QUERY
71+
mutation {
72+
changePassword(
73+
currentPassword: "currentpassword",
74+
newPassword: "newpassword"
75+
) {
76+
id
77+
email
78+
firstname
79+
lastname
80+
}
81+
}
82+
QUERY;
83+
$this->expectException(\Exception::class);
84+
$this->expectExceptionMessage('GraphQL response contains errors: Current customer' . ' ' .
85+
'does not have access to the resource "customer"');
86+
$this->graphQlQuery($query);
87+
}
88+
89+
/**
90+
* @magentoApiDataFixture Magento/Customer/_files/customer.php
91+
*/
92+
public function testChangeWeakPassword()
93+
{
94+
$customerEmail = 'customer@example.com';
95+
$oldCustomerPassword = 'password';
96+
$newCustomerPassword = 'weakpass';
97+
98+
$query = <<<QUERY
99+
mutation {
100+
changePassword(
101+
currentPassword: "$oldCustomerPassword",
102+
newPassword: "$newCustomerPassword"
103+
) {
104+
id
105+
email
106+
firstname
107+
lastname
108+
}
109+
}
110+
QUERY;
111+
112+
/** @var CustomerTokenServiceInterface $customerTokenService */
113+
$customerTokenService = $this->objectManager->create(CustomerTokenServiceInterface::class);
114+
$customerToken = $customerTokenService->createCustomerAccessToken($customerEmail, $oldCustomerPassword);
115+
$headerMap = ['Authorization' => 'Bearer ' . $customerToken];
116+
117+
$this->expectException(\Exception::class);
118+
$this->expectExceptionMessageRegExp('/Minimum of different classes of characters in password is.*/');
119+
120+
$this->graphQlQuery($query, [], '', $headerMap);
121+
}
122+
123+
protected function setUp()
124+
{
125+
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
126+
$this->accountManagement = $this->objectManager->get(AccountManagementInterface::class);
127+
}
128+
}

0 commit comments

Comments
 (0)