-
Notifications
You must be signed in to change notification settings - Fork 9.4k
createCustomer validation requirements #28888
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
1943018
887f191
b5208cd
0f7d805
592f5de
3a4cfa1
2e77e22
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\CustomerGraphQl\Model\Resolver; | ||
|
||
use Magento\CustomerGraphQl\Model\Customer\ExtractCustomerData; | ||
use Magento\CustomerGraphQl\Model\Customer\GetCustomer; | ||
use Magento\CustomerGraphQl\Model\Customer\UpdateCustomerAccount; | ||
use Magento\Framework\GraphQl\Config\Element\Field; | ||
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; | ||
use Magento\Framework\GraphQl\Query\ResolverInterface; | ||
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; | ||
use Magento\GraphQl\Model\Query\ContextInterface; | ||
|
||
/** | ||
* Customer email update, used for GraphQL request processing | ||
*/ | ||
class UpdateCustomerEmail implements ResolverInterface | ||
{ | ||
/** | ||
* @var GetCustomer | ||
*/ | ||
private $getCustomer; | ||
/** | ||
* @var UpdateCustomerAccount | ||
*/ | ||
private $updateCustomerAccount; | ||
/** | ||
* @var ExtractCustomerData | ||
*/ | ||
private $extractCustomerData; | ||
|
||
/** | ||
* @param GetCustomer $getCustomer | ||
* @param UpdateCustomerAccount $updateCustomerAccount | ||
* @param ExtractCustomerData $extractCustomerData | ||
*/ | ||
public function __construct( | ||
GetCustomer $getCustomer, | ||
UpdateCustomerAccount $updateCustomerAccount, | ||
ExtractCustomerData $extractCustomerData | ||
) { | ||
$this->getCustomer = $getCustomer; | ||
$this->updateCustomerAccount = $updateCustomerAccount; | ||
$this->extractCustomerData = $extractCustomerData; | ||
} | ||
|
||
/** | ||
* @inheritdoc | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you can add a proper description here |
||
*/ | ||
public function resolve( | ||
Field $field, | ||
$context, | ||
ResolveInfo $info, | ||
array $value = null, | ||
array $args = null | ||
) { | ||
/** @var ContextInterface $context */ | ||
if (false === $context->getExtensionAttributes()->getIsCustomer()) { | ||
throw new GraphQlAuthorizationException(__('The current customer isn\'t authorized.')); | ||
} | ||
|
||
$customer = $this->getCustomer->execute($context); | ||
$this->updateCustomerAccount->execute( | ||
$customer, | ||
['email' => $args['email'], 'password' => $args['password']], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unsafe array index, could cause an exception: |
||
$context->getExtensionAttributes()->getStore() | ||
); | ||
|
||
$data = $this->extractCustomerData->execute($customer); | ||
|
||
return ['customer' => $data]; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,14 +17,16 @@ type Query { | |
type Mutation { | ||
generateCustomerToken(email: String!, password: String!): CustomerToken @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\GenerateCustomerToken") @doc(description:"Retrieve the customer token") | ||
changeCustomerPassword(currentPassword: String!, newPassword: String!): Customer @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\ChangePassword") @doc(description:"Changes the password for the logged-in customer") | ||
createCustomer (input: CustomerInput!): CustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\CreateCustomer") @doc(description:"Create customer account") | ||
updateCustomer (input: CustomerInput!): CustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomer") @doc(description:"Update the customer's personal information") | ||
createCustomer (input: CustomerCreateInput!): CustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\CreateCustomer") @doc(description:"Create customer account") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can't change inputs on existing queries, so createCustomer (input: CustomerInput!): has to remain like this |
||
updateCustomer (input: CustomerInput!): CustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomer") @doc(description:"Deprecated. Use UpdateCustomerV2 instead.") | ||
updateCustomerV2 (input: CustomerUpdateInput!): CustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomer") @doc(description:"Update the customer's personal information") | ||
revokeCustomerToken: RevokeCustomerTokenOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\RevokeCustomerToken") @doc(description:"Revoke the customer token") | ||
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.") | ||
updateCustomerEmail(email: String!, password: String!): CustomerOutput @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\UpdateCustomerEmail") @doc(description: "") | ||
} | ||
|
||
input CustomerAddressInput { | ||
|
@@ -78,6 +80,34 @@ input CustomerInput { | |
is_subscribed: Boolean @doc(description: "Indicates whether the customer is subscribed to the company's newsletter") | ||
} | ||
|
||
input CustomerCreateInput { | ||
prefix: String @doc(description: "An honorific, such as Dr., Mr., or Mrs.") | ||
firstname: String! @doc(description: "The customer's first name") | ||
cpartica marked this conversation as resolved.
Show resolved
Hide resolved
|
||
middlename: String @doc(description: "The customer's middle name") | ||
lastname: String! @doc(description: "The customer's family name") | ||
suffix: String @doc(description: "A value such as Sr., Jr., or III") | ||
email: String! @doc(description: "The customer's email address. Required for customer creation") | ||
dob: String @doc(description: "Deprecated: Use `date_of_birth` instead") | ||
date_of_birth: String @doc(description: "The customer's date of birth") | ||
taxvat: String @doc(description: "The customer's Tax/VAT number (for corporate customers)") | ||
gender: Int @doc(description: "The customer's gender (Male - 1, Female - 2)") | ||
password: String @doc(description: "The customer's password") | ||
is_subscribed: Boolean @doc(description: "Indicates whether the customer is subscribed to the company's newsletter") | ||
} | ||
|
||
input CustomerUpdateInput { | ||
date_of_birth: String @doc(description: "The customer's date of birth") | ||
dob: String @doc(description: "Deprecated: Use `date_of_birth` instead") | ||
firstname: String @doc(description: "The customer's first name") | ||
gender: Int @doc(description: "The customer's gender (Male - 1, Female - 2)") | ||
is_subscribed: Boolean @doc(description: "Indicates whether the customer is subscribed to the company's newsletter") | ||
lastname: String @doc(description: "The customer's family name") | ||
middlename: String @doc(description: "The customer's middle name") | ||
prefix: String @doc(description: "An honorific, such as Dr., Mr., or Mrs.") | ||
suffix: String @doc(description: "A value such as Sr., Jr., or III") | ||
taxvat: String @doc(description: "The customer's Tax/VAT number (for corporate customers)") | ||
} | ||
|
||
type CustomerOutput { | ||
customer: Customer! | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -116,14 +116,18 @@ public function testCreateCustomerAccountWithoutPassword() | |
*/ | ||
public function testCreateCustomerIfInputDataIsEmpty() | ||
{ | ||
$exceptionMessage = 'Field CustomerCreateInput.email of required type String! was not provided. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a string either has "\n" or we can't do multi line strings like this. We usually don't add multi line exceptions |
||
Field CustomerCreateInput.firstname of required type String! was not provided. | ||
Field CustomerCreateInput.lastname of required type String! was not provided.'; | ||
|
||
$this->expectException(\Exception::class); | ||
$this->expectExceptionMessage('"input" value should be specified'); | ||
$this->expectExceptionMessage($exceptionMessage); | ||
|
||
$query = <<<QUERY | ||
mutation { | ||
createCustomer( | ||
input: { | ||
|
||
} | ||
) { | ||
customer { | ||
|
@@ -144,7 +148,7 @@ public function testCreateCustomerIfInputDataIsEmpty() | |
public function testCreateCustomerIfEmailMissed() | ||
{ | ||
$this->expectException(\Exception::class); | ||
$this->expectExceptionMessage('Required parameters are missing: Email'); | ||
$this->expectExceptionMessage('Field CustomerCreateInput.email of required type String! was not provided'); | ||
|
||
$newFirstname = 'Richard'; | ||
$newLastname = 'Rowe'; | ||
|
@@ -234,7 +238,7 @@ public function invalidEmailAddressDataProvider(): array | |
public function testCreateCustomerIfPassedAttributeDosNotExistsInCustomerInput() | ||
{ | ||
$this->expectException(\Exception::class); | ||
$this->expectExceptionMessage('Field "test123" is not defined by type CustomerInput.'); | ||
$this->expectExceptionMessage('Field "test123" is not defined by type CustomerCreateInput.'); | ||
|
||
$newFirstname = 'Richard'; | ||
$newLastname = 'Rowe'; | ||
|
@@ -339,7 +343,9 @@ public function testCreateCustomerSubscribed() | |
public function testCreateCustomerIfCustomerWithProvidedEmailAlreadyExists() | ||
{ | ||
$this->expectException(\Exception::class); | ||
$this->expectExceptionMessage('A customer with the same email address already exists in an associated website.'); | ||
$this->expectExceptionMessage( | ||
'A customer with the same email address already exists in an associated website.' | ||
); | ||
|
||
$existedEmail = 'customer@example.com'; | ||
$password = 'test123#'; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\GraphQl\Customer; | ||
|
||
use Exception; | ||
use Magento\Customer\Api\CustomerRepositoryInterface; | ||
use Magento\CustomerGraphQl\Model\Customer\UpdateCustomerAccount; | ||
use Magento\Framework\Exception\AuthenticationException; | ||
use Magento\Integration\Api\CustomerTokenServiceInterface; | ||
use Magento\Store\Api\StoreRepositoryInterface; | ||
use Magento\TestFramework\Helper\Bootstrap; | ||
use Magento\TestFramework\TestCase\GraphQlAbstract; | ||
|
||
/** | ||
* Test for update customer's email | ||
*/ | ||
class UpdateCustomerEmailTest extends GraphQlAbstract | ||
{ | ||
/** | ||
* @var CustomerTokenServiceInterface | ||
*/ | ||
private $customerTokenService; | ||
|
||
/** | ||
* @var CustomerRepositoryInterface | ||
*/ | ||
private $customerRepository; | ||
/** | ||
* @var UpdateCustomerAccount | ||
*/ | ||
private $updateCustomerAccount; | ||
/** | ||
* @var StoreRepositoryInterface | ||
*/ | ||
private $storeRepository; | ||
|
||
/** | ||
* Setting up tests | ||
*/ | ||
protected function setUp(): void | ||
{ | ||
parent::setUp(); | ||
|
||
$this->customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class); | ||
$this->customerRepository = Bootstrap::getObjectManager()->get(CustomerRepositoryInterface::class); | ||
$this->updateCustomerAccount = Bootstrap::getObjectManager()->get(UpdateCustomerAccount::class); | ||
$this->storeRepository = Bootstrap::getObjectManager()->get(StoreRepositoryInterface::class); | ||
} | ||
|
||
/** | ||
* @magentoApiDataFixture Magento/Customer/_files/customer.php | ||
*/ | ||
public function testUpdateCustomerEmail(): void | ||
{ | ||
$currentEmail = 'customer@example.com'; | ||
$currentPassword = 'password'; | ||
|
||
$newEmail = 'newcustomer@example.com'; | ||
|
||
$query = <<<QUERY | ||
mutation { | ||
updateCustomerEmail( | ||
email: "{$newEmail}" | ||
password: "{$currentPassword}" | ||
) { | ||
customer { | ||
} | ||
} | ||
} | ||
QUERY; | ||
|
||
$response = $this->graphQlMutation( | ||
$query, | ||
[], | ||
'', | ||
$this->getCustomerAuthHeaders($currentEmail, $currentPassword) | ||
); | ||
|
||
$this->assertEquals($newEmail, $response['updateCustomerEmail']['customer']['email']); | ||
|
||
/* $this->updateCustomerAccount->execute( | ||
$this->customerRepository->get($newEmail), | ||
['email' => $currentEmail, 'password' => $currentPassword], | ||
$this->storeRepository->getById(1) | ||
);*/ | ||
} | ||
|
||
/** | ||
* @magentoApiDataFixture Magento/Customer/_files/customer.php | ||
*/ | ||
public function testUpdateCustomerEmailIfPasswordIsWrong(): void | ||
{ | ||
$this->expectException(Exception::class); | ||
$this->expectExceptionMessage('Invalid login or password.'); | ||
|
||
$currentEmail = 'customer@example.com'; | ||
$currentPassword = 'password'; | ||
|
||
$newEmail = 'newcustomer@example.com'; | ||
$wrongPassword = 'wrongpassword'; | ||
|
||
$query = <<<QUERY | ||
mutation { | ||
updateCustomerEmail( | ||
email: "{$newEmail}" | ||
password: "{$wrongPassword}" | ||
) { | ||
customer { | ||
} | ||
} | ||
} | ||
QUERY; | ||
|
||
$this->graphQlMutation( | ||
$query, | ||
[], | ||
'', | ||
$this->getCustomerAuthHeaders($currentEmail, $currentPassword) | ||
); | ||
} | ||
|
||
/** | ||
* @magentoApiDataFixture Magento/Customer/_files/two_customers.php | ||
*/ | ||
public function testUpdateEmailIfEmailAlreadyExists() | ||
{ | ||
$this->expectException(Exception::class); | ||
$this->expectExceptionMessage( | ||
'A customer with the same email address already exists in an associated website.' | ||
); | ||
|
||
$currentEmail = 'customer@example.com'; | ||
$currentPassword = 'password'; | ||
$existedEmail = 'customer_two@example.com'; | ||
|
||
$query = <<<QUERY | ||
mutation { | ||
updateCustomerEmail( | ||
email: "{$existedEmail}" | ||
password: "{$currentPassword}" | ||
) { | ||
customer { | ||
firstname | ||
} | ||
} | ||
} | ||
QUERY; | ||
$this->graphQlMutation($query, [], '', $this->getCustomerAuthHeaders($currentEmail, $currentPassword)); | ||
} | ||
|
||
/** | ||
* Get customer authorization headers | ||
* | ||
* @param string $email | ||
* @param string $password | ||
* @return array | ||
* @throws AuthenticationException | ||
*/ | ||
private function getCustomerAuthHeaders(string $email, string $password): array | ||
{ | ||
$customerToken = $this->customerTokenService->createCustomerAccessToken($email, $password); | ||
return ['Authorization' => 'Bearer ' . $customerToken]; | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.