Skip to content
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

LoginAsCustomer GraphQL #30130

Merged
merged 21 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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\LoginAsCustomerGraphQl\Model\LoginAsCustomer;

use Magento\Customer\Model\CustomerFactory;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Integration\Model\Oauth\TokenFactory;
use Magento\Store\Api\Data\StoreInterface;
use Exception;

/**
* Create customer token from customer email
*/
class CreateCustomerToken
{
/**
* @var CustomerFactory
*/
private $customerFactory;

/**
* @var TokenFactory
*/
private $tokenModelFactory;

/**
* @param TokenFactory $tokenModelFactory
* @param CustomerFactory $customerFactory
*/
public function __construct(
TokenFactory $tokenModelFactory,
CustomerFactory $customerFactory
) {
$this->tokenModelFactory = $tokenModelFactory;
$this->customerFactory= $customerFactory;
}

/**
* Get admin user token
*
* @param string $email
* @param StoreInterface $store
* @return array
* @throws GraphQlInputException
* @throws LocalizedException
*/
public function execute(string $email, StoreInterface $store): array
{
$customer = $this->customerFactory->create()->setWebsiteId((int)$store->getId())->loadByEmail($email);

/* Check if customer email exist */
if (!$customer->getId()) {
throw new GraphQlInputException(
__('Customer email provided does not exist')
);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to validate that the 'allow_remote_shopping_assistance' setting is enabled for the customer. See https://github.com/magento/architecture/pull/414/files#diff-ccdc60253a5ea983cb68248c51500c3cdc077232bd52ded6cb08d4af9cba8d2bR39

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

try {
return [
"customer_token" => $this->tokenModelFactory->create()
->createCustomerToken($customer->getId())->getToken()
];
} catch (Exception $e) {
throw new LocalizedException(
__(
'Unable to generate tokens. '
. 'Please wait and try again later.'
)
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\LoginAsCustomerGraphQl\Model\Resolver;

use Magento\Framework\AuthorizationInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Query\Resolver\Value;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
use Magento\LoginAsCustomerApi\Api\ConfigInterface as LoginAsCustomerConfig;
use Magento\LoginAsCustomerGraphQl\Model\LoginAsCustomer\CreateCustomerToken;

/**
* Gets customer token
*/
class RequestCustomerToken implements ResolverInterface
{
/**
* @var LoginAsCustomerConfig
*/
private $config;

/**
* @var AuthorizationInterface
*/
private $authorization;

/**
* @var CreateCustomerToken
*/
private $createCustomerToken;

/**
* @param AuthorizationInterface $authorization
* @param LoginAsCustomerConfig $config
* @param CreateCustomerToken $createCustomerToken
*/
public function __construct(
AuthorizationInterface $authorization,
LoginAsCustomerConfig $config,
CreateCustomerToken $createCustomerToken
) {
$this->authorization = $authorization;
$this->config = $config;
$this->createCustomerToken = $createCustomerToken;
}

/**
* Get Customer Token using email
*
* @param Field $field
* @param ContextInterface $context
* @param ResolveInfo $info
* @param array|null $value
* @param array|null $args
* @return Value|mixed|void
* @throws GraphQlAuthorizationException|GraphQlNoSuchEntityException|LocalizedException
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) {
$isAllowedLogin = $this->authorization->isAllowed('Magento_LoginAsCustomer::login');
$isAlllowedShoppingAssistance = $this->authorization->isAllowed('Magento_LoginAsCustomer::allow_shopping_assistance');
$isEnabled = $this->config->isEnabled();

/* Get input params */
try {
$args = $args['input'];
} catch (NoSuchEntityException $e) {
throw new GraphQlInputException(__('Check input params.'));
}

if (empty(trim($args['customer_email'], " "))) {
throw new GraphQlInputException(__('Specify the "customer email" value.'));
}

$this->validateUser($context);

if (!$isAllowedLogin || !$isEnabled) {
throw new GraphQlAuthorizationException(
__('Login as Customer is disabled.')
);
}

if (!$isAlllowedShoppingAssistance) {
throw new GraphQlAuthorizationException(
__('Allow remote shopping assistance is disabled.')
);
}

return $this->createCustomerToken->execute(
$args['customer_email'],
$context->getExtensionAttributes()->getStore()
);
}

/**
* Check if its an admin user
*
* @param ContextInterface $context
* @throws GraphQlAuthorizationException
*/
private function validateUser(ContextInterface $context): void
{
if ($context->getUserType() !== 2 || $context->getUserId() === 0) {
throw new GraphQlAuthorizationException(__('The current customer isn\'t authorized.'));
}
}
}
3 changes: 3 additions & 0 deletions app/code/Magento/LoginAsCustomerGraphQl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# LoginAsCustomerGraphQl

**LoginAsCustomerGraphQl** provides flexible login as a customer so a merchant or merchant admin can log into an end customer's account to assist them with their account.
28 changes: 28 additions & 0 deletions app/code/Magento/LoginAsCustomerGraphQl/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "magento/module-login-as-customer-graph-ql",
"description": "Flexible login as a customer so a merchant or merchant admin can log into an end customer's account to assist them with their account.",
"require": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, provide all the dependencies you use within the scope of the module. Like LoginAsCustomerApi, Customer, Store etc

"php": "~7.3.0||~7.4.0",
"magento/framework": "*",
"magento/module-login-as-customer-api": "*",
"magento/module-integration": "*",
"magento/module-store": "*",
"magento/module-customer": "*"
},
"suggest": {
"magento/module-login-as-customer": "*"
},
"type": "magento2-module",
"license": [
"OSL-3.0",
"AFL-3.0"
],
"autoload": {
"files": [
"registration.php"
],
"psr-4": {
"Magento\\LoginAsCustomerGraphQl\\": ""
}
}
}
17 changes: 17 additions & 0 deletions app/code/Magento/LoginAsCustomerGraphQl/etc/module.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" ?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Magento_LoginAsCustomerGraphQl">
<sequence>
<module name="Magento_LoginAsCustomerApi"/>
<module name="Magento_Customer"/>
<module name="Magento_Store"/>
<module name="Magento_CatalogGraphQl"/>
</sequence>
</module>
</config>
30 changes: 30 additions & 0 deletions app/code/Magento/LoginAsCustomerGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright © Magento, Inc. All rights reserved.
# See COPYING.txt for license details.

type Mutation {
generateCustomerTokenAsAdmin(
input: GenerateCustomerTokenAsAdminInput!
): GenerateCustomerTokenAsAdminOutput
@resolver(class: "Magento\\LoginAsCustomerGraphQl\\Model\\Resolver\\RequestCustomerToken")
@doc(description: "Request a customer token so that an administrator can perform remote shopping assistance")
}

input GenerateCustomerTokenAsAdminInput {
customer_email: String! @doc(description: "The email address of the customer requesting remote shopping assistance")
}

type GenerateCustomerTokenAsAdminOutput {
customer_token: String! @doc(description: "The generated customer token")
}

type Customer {
allow_remote_shopping_assistance: Boolean! @doc(description: "Indicates whether the customer has enabled remote shopping assistance")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetCustomer resolver will need to be updated to return this new value

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a new fixture for this with setAssistanceAllowed enabled

}

input CustomerCreateInput {
allow_remote_shopping_assistance: Boolean @doc(description: "Indicates whether the customer has enabled remote shopping assistance")
}

input CustomerUpdateInput {
allow_remote_shopping_assistance: Boolean @doc(description: "Indicates whether the customer has enabled remote shopping assistance")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolvers using these inputs will need to be updated to ensure allow_remote_shopping_assistance is persisted.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

@cspruiell cspruiell Dec 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the changes for this. The createCustomer & updateCustomer mutations need to be updated so that allow_remote_shopping_assistance is persisted

mutation { createCustomerV2(input: { email: "test@example.com" firstname: "Test" lastname: "Magento" password: "T3stP4ssw0rd" allow_remote_shopping_assistance: true}) { customer { firstname lastname email allow_remote_shopping_assistance } } }

14 changes: 14 additions & 0 deletions app/code/Magento/LoginAsCustomerGraphQl/registration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

use Magento\Framework\Component\ComponentRegistrar;

ComponentRegistrar::register(
ComponentRegistrar::MODULE,
'Magento_LoginAsCustomerGraphQl',
__DIR__
);
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@
"magento/module-integration": "*",
"magento/module-layered-navigation": "*",
"magento/module-login-as-customer": "*",
"magento/module-login-as-customer-graph-ql": "*",
"magento/module-login-as-customer-admin-ui": "*",
"magento/module-login-as-customer-api": "*",
"magento/module-login-as-customer-assistance": "*",
Expand Down
Loading