From 2bf0af8ff68d260bf20554ba3a63f203808b5fd8 Mon Sep 17 00:00:00 2001 From: Valerii Naida Date: Mon, 27 Apr 2020 16:51:09 -0500 Subject: [PATCH 1/2] Refactored Login model in LoginAsCustomer Extension # Conflicts: # app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Index.php # app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Login.php # app/code/Magento/LoginAsCustomer/Controller/Login/Index.php --- ...ngProductImportWithConfigTurnedOffTest.xml | 155 ------------------ 1 file changed, 155 deletions(-) delete mode 100644 app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCheckUrlRewritesCorrectlyGeneratedForMultipleStoreviewsDuringProductImportTest/AdminUrlRewriteGeneratedForMultipleStoreviewsDuringProductImportWithConfigTurnedOffTest.xml diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCheckUrlRewritesCorrectlyGeneratedForMultipleStoreviewsDuringProductImportTest/AdminUrlRewriteGeneratedForMultipleStoreviewsDuringProductImportWithConfigTurnedOffTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCheckUrlRewritesCorrectlyGeneratedForMultipleStoreviewsDuringProductImportTest/AdminUrlRewriteGeneratedForMultipleStoreviewsDuringProductImportWithConfigTurnedOffTest.xml deleted file mode 100644 index f9003ce8c0897..0000000000000 --- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCheckUrlRewritesCorrectlyGeneratedForMultipleStoreviewsDuringProductImportTest/AdminUrlRewriteGeneratedForMultipleStoreviewsDuringProductImportWithConfigTurnedOffTest.xml +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - - - <description value="Check Url Rewrites Correctly Generated for Multiple Storeviews During Product Import."/> - <severity value="CRITICAL"/> - <testCaseId value="MC-6802"/> - <group value="urlRewrite"/> - </annotations> - <before> - <!-- Set the configuration for Generate "category/product" URL Rewrites to Yes (default)--> - <comment userInput="Enable SEO configuration setting to generate category/product URL Rewrites" stepKey="commentEnableUrlRewriteConfig"/> - <magentoCLI command="config:set catalog/seo/generate_category_product_rewrites 1" stepKey="enableGenerateUrlRewrite"/> - <!--Flush cache--> - <magentoCLI command="cache:flush" stepKey="cleanCache1"/> - <createData entity="ApiCategory" stepKey="createCategory"> - <field key="name">category-admin</field> - </createData> - <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> - <!-- Create Store View EN --> - <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createStoreViewEn"> - <argument name="customStore" value="customStoreENNotUnique"/> - </actionGroup> - <!-- Create Store View NL --> - <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createStoreViewNl"> - <argument name="customStore" value="customStoreNLNotUnique"/> - </actionGroup> - <!-- Set the configuration for Generate "category/product" URL Rewrites to No--> - <comment userInput="Disable SEO configuration setting to generate category/product URL Rewrites" stepKey="commentDisableUrlRewriteConfig"/> - <magentoCLI command="config:set catalog/seo/generate_category_product_rewrites 0" stepKey="disableGenerateUrlRewrite"/> - <!--Flush cache--> - <magentoCLI command="cache:flush" stepKey="cleanCache"/> - </before> - <after> - <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> - <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreViewEn"> - <argument name="customStore" value="customStoreENNotUnique"/> - </actionGroup> - <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreViewNl"> - <argument name="customStore" value="customStoreNLNotUnique"/> - </actionGroup> - <actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearStoreGridFilters"/> - <actionGroup ref="DeleteProductByNameActionGroup" stepKey="deleteImportedProduct"> - <argument name="sku" value="productformagetwo68980"/> - <argument name="name" value="productformagetwo68980"/> - </actionGroup> - <actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearFiltersIfSet"/> - <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> - <magentoCLI command="config:set catalog/seo/generate_category_product_rewrites 1" stepKey="resetConfigurationSetting"/> - <!--Flush cache--> - <magentoCLI command="cache:flush" stepKey="cleanCache2"/> - </after> - <actionGroup ref="SwitchCategoryStoreViewActionGroup" stepKey="switchToStoreViewEn"> - <argument name="Store" value="customStoreENNotUnique.name"/> - <argument name="CatName" value="$$createCategory.name$$"/> - </actionGroup> - <uncheckOption selector="{{AdminCategoryBasicFieldSection.categoryNameUseDefault}}" stepKey="uncheckUseDefaultValueENStoreView"/> - <fillField selector="{{AdminCategoryBasicFieldSection.CategoryNameInput}}" userInput="category-english" stepKey="changeNameField"/> - <click selector="{{AdminCategorySEOSection.SectionHeader}}" stepKey="clickOnSectionHeader"/> - <actionGroup ref="ChangeSeoUrlKeyForSubCategoryActionGroup" stepKey="changeSeoUrlKeyENStoreView"> - <argument name="value" value="category-english"/> - </actionGroup> - <actionGroup ref="SwitchCategoryStoreViewActionGroup" stepKey="switchToStoreViewNl"> - <argument name="Store" value="customStoreNLNotUnique.name"/> - <argument name="CatName" value="$$createCategory.name$$"/> - </actionGroup> - <uncheckOption selector="{{AdminCategoryBasicFieldSection.categoryNameUseDefault}}" stepKey="uncheckUseDefaultValue1"/> - <fillField selector="{{AdminCategoryBasicFieldSection.CategoryNameInput}}" userInput="category-dutch" stepKey="changeNameFieldNLStoreView"/> - <click selector="{{AdminCategorySEOSection.SectionHeader}}" stepKey="clickOnSectionHeader2"/> - <actionGroup ref="ChangeSeoUrlKeyForSubCategoryActionGroup" stepKey="changeSeoUrlKeyNLStoreView"> - <argument name="value" value="category-dutch"/> - </actionGroup> - <amOnPage url="{{AdminImportIndexPage.url}}" stepKey="navigateToSystemImport"/> - <selectOption selector="{{AdminImportMainSection.entityType}}" userInput="Products" stepKey="selectProductsOption"/> - <waitForElementVisible selector="{{AdminImportMainSection.importBehavior}}" stepKey="waitForImportBehaviorElementVisible"/> - <selectOption selector="{{AdminImportMainSection.importBehavior}}" userInput="Add/Update" stepKey="selectAddUpdateOption"/> - <attachFile selector="{{AdminImportMainSection.selectFileToImport}}" userInput="import_updated.csv" stepKey="attachFileForImport"/> - <click selector="{{AdminImportHeaderSection.checkDataButton}}" stepKey="clickCheckDataButton"/> - <see selector="{{AdminImportValidationMessagesSection.notice}}" userInput="Checked rows: 3, checked entities: 1, invalid rows: 0, total errors: 0" stepKey="assertNotice"/> - <see selector="{{AdminImportValidationMessagesSection.success}}" userInput="File is valid! To start import process press "Import" button" stepKey="assertSuccessMessage"/> - <click selector="{{AdminImportMainSection.importButton}}" stepKey="clickImportButton"/> - <see selector="{{AdminImportValidationMessagesSection.success}}" userInput="Import successfully done" stepKey="assertSuccessMessage1"/> - <see selector="{{AdminImportValidationMessagesSection.notice}}" userInput="Created: 1, Updated: 0, Deleted: 0" stepKey="assertNotice1"/> - <actionGroup ref="SearchForProductOnBackendByNameActionGroup" stepKey="searchForProductOnBackend"> - <argument name="productName" value="productformagetwo68980"/> - </actionGroup> - <click selector="{{AdminProductGridSection.productRowBySku('productformagetwo68980')}}" stepKey="clickOnProductRow"/> - <grabFromCurrentUrl regex="~/id/(\d+)/~" stepKey="grabProductIdFromUrl"/> - <amOnPage url="{{AdminUrlRewriteIndexPage.url}}" stepKey="goToUrlRewritesIndexPage"/> - - <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openUrlRewriteGridFilters"/> - <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('request_path')}}" userInput="category-english.html" stepKey="inputCategoryUrlForENStoreView"/> - <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickOrderApplyFilters"/> - <waitForPageLoad stepKey="waitForPageToLoad"/> - <seeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Request Path', 'category-english.html')}}" stepKey="seeUrlInRequestPathColumn"/> - <seeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Target Path', catalog/category/view/id/$$createCategory.id$$)}}" stepKey="seeUrlInTargetPathColumn"/> - - <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openUrlRewriteGridFilters1"/> - <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('request_path')}}" userInput="category-dutch.html" stepKey="inputCategoryUrlForNLStoreView"/> - <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickOrderApplyFilters1"/> - <waitForPageLoad stepKey="waitForPageToLoad1"/> - <seeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Request Path', 'category-dutch.html')}}" stepKey="seeUrlInRequestPathColumn1"/> - <seeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Target Path', catalog/category/view/id/$$createCategory.id$$)}}" stepKey="seeUrlInTargetPathColumn1"/> - - <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openUrlRewriteGridFilters2"/> - <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('request_path')}}" userInput="productformagetwo68980-english.html" stepKey="inputProductUrlForENStoreView"/> - <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickOrderApplyFilters2"/> - <waitForPageLoad stepKey="waitForPageToLoad2"/> - <seeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Request Path', 'productformagetwo68980-english.html')}}" stepKey="seeUrlInRequestPathColumn2"/> - <seeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Target Path', 'catalog/product/view/id/$grabProductIdFromUrl')}}" stepKey="seeUrlInTargetPathColumn2"/> - <dontSeeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Request Path', 'category-english/productformagetwo68980-english.html')}}" stepKey="seeUrlInRequestPathColumn4"/> - <dontSeeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Target Path', catalog/product/view/id/$grabProductIdFromUrl/category/$$createCategory.id$$)}}" stepKey="seeUrlInTargetPathColumn4"/> - - <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openUrlRewriteGridFilters3"/> - <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('request_path')}}" userInput="productformagetwo68980-dutch.html" stepKey="inputProductUrlForENStoreView1"/> - <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickOrderApplyFilters3"/> - <waitForPageLoad stepKey="waitForPageToLoad3"/> - <seeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Request Path', 'productformagetwo68980-dutch.html')}}" stepKey="seeUrlInRequestPathColumn3"/> - <seeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Target Path', 'catalog/product/view/id/$grabProductIdFromUrl')}}" stepKey="seeUrlInTargetPathColumn3"/> - <dontSeeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Request Path', 'category-dutch/productformagetwo68980-dutch.html')}}" stepKey="seeUrlInRequestPathColumn5"/> - <dontSeeElement selector="{{AdminUrlRewriteIndexSection.gridCellByColumnValue('Target Path', catalog/product/view/id/$grabProductIdFromUrl/category/$$createCategory.id$$)}}" stepKey="seeUrlInTargetPathColumn5"/> - - <!-- Switch StoreView --> - <amOnPage url="{{StorefrontHomePage.url}}" stepKey="amOnProduct4Page"/> - <actionGroup ref="StorefrontSwitchStoreViewActionGroup" stepKey="switchToCustomStoreView"> - <argument name="storeView" value="customStoreENNotUnique"/> - </actionGroup> - - <amOnPage url="/productformagetwo68980-english.html" stepKey="navigateToProductPage"/> - <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="productformagetwo68980-english" stepKey="seeProductName"/> - <amOnPage url="/category-english/productformagetwo68980-english.html" stepKey="navigateToProductPage2"/> - <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="productformagetwo68980-english" stepKey="seeProductName2"/> - - <!-- Switch StoreView --> - <amOnPage url="{{StorefrontHomePage.url}}" stepKey="amOnProduct4Page2"/> - <actionGroup ref="StorefrontSwitchStoreViewActionGroup" stepKey="switchToCustomStoreView2"> - <argument name="storeView" value="customStoreNLNotUnique"/> - </actionGroup> - - <amOnPage url="/productformagetwo68980-dutch.html" stepKey="navigateToProductPage3"/> - <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="productformagetwo68980-dutch" stepKey="seeProductName3"/> - <amOnPage url="/category-dutch/productformagetwo68980-dutch.html" stepKey="navigateToProductPage4"/> - <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="productformagetwo68980-dutch" stepKey="seeProductName4"/> - </test> -</tests> From bcf441f791a79ca1b1778048dbecdaf6e1212b48 Mon Sep 17 00:00:00 2001 From: Ihor Vansach <ihor@magefan.com> Date: Sat, 25 Apr 2020 18:33:06 +0300 Subject: [PATCH 2/2] Refactored Login model in LoginAsCustomer Extension --- .../Api/AuthenticateCustomerInterface.php | 23 ++ .../Api/CreateSecretInterface.php | 22 ++ .../Api/DeleteOldSecretsInterface.php | 19 ++ .../Api/DeleteSecretInterface.php | 19 ++ .../Api/GetAuthenticateDataInterface.php | 19 ++ .../Controller/Adminhtml/Login/Index.php | 21 -- .../Controller/Adminhtml/Login/Login.php | 66 +++--- .../Controller/Login/Index.php | 92 +++++--- .../LoginAsCustomer/Cron/DeleteOldSecrets.php | 50 ++++ .../Model/AuthenticateCustomer.php | 85 +++++++ .../Magento/LoginAsCustomer/Model/Config.php | 2 + .../Magento/LoginAsCustomer/Model/Login.php | 216 ------------------ .../Model/ResourceModel/CreateSecret.php | 73 ++++++ .../Model/ResourceModel/DeleteOldSecrets.php | 58 +++++ .../Model/ResourceModel/DeleteSecret.php | 47 ++++ .../ResourceModel/GetAuthenticateData.php | 70 ++++++ .../Model/ResourceModel/Login.php | 2 +- .../Magento/LoginAsCustomer/etc/crontab.xml | 14 ++ .../Magento/LoginAsCustomer/etc/db_schema.xml | 3 +- .../etc/db_schema_whitelist.json | 5 +- app/code/Magento/LoginAsCustomer/etc/di.xml | 14 ++ 21 files changed, 617 insertions(+), 303 deletions(-) create mode 100644 app/code/Magento/LoginAsCustomer/Api/AuthenticateCustomerInterface.php create mode 100644 app/code/Magento/LoginAsCustomer/Api/CreateSecretInterface.php create mode 100644 app/code/Magento/LoginAsCustomer/Api/DeleteOldSecretsInterface.php create mode 100644 app/code/Magento/LoginAsCustomer/Api/DeleteSecretInterface.php create mode 100644 app/code/Magento/LoginAsCustomer/Api/GetAuthenticateDataInterface.php create mode 100644 app/code/Magento/LoginAsCustomer/Cron/DeleteOldSecrets.php create mode 100644 app/code/Magento/LoginAsCustomer/Model/AuthenticateCustomer.php create mode 100644 app/code/Magento/LoginAsCustomer/Model/ResourceModel/CreateSecret.php create mode 100644 app/code/Magento/LoginAsCustomer/Model/ResourceModel/DeleteOldSecrets.php create mode 100644 app/code/Magento/LoginAsCustomer/Model/ResourceModel/DeleteSecret.php create mode 100644 app/code/Magento/LoginAsCustomer/Model/ResourceModel/GetAuthenticateData.php create mode 100644 app/code/Magento/LoginAsCustomer/etc/crontab.xml create mode 100755 app/code/Magento/LoginAsCustomer/etc/di.xml diff --git a/app/code/Magento/LoginAsCustomer/Api/AuthenticateCustomerInterface.php b/app/code/Magento/LoginAsCustomer/Api/AuthenticateCustomerInterface.php new file mode 100644 index 0000000000000..da3c519064995 --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Api/AuthenticateCustomerInterface.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Api; + +/** + * @api + */ +interface AuthenticateCustomerInterface +{ + /** + * Authenticate a customer by customer ID + * + * @return bool + * @param int $customerId + * @param int $adminId + */ + public function execute(int $customerId, int $adminId):bool; +} diff --git a/app/code/Magento/LoginAsCustomer/Api/CreateSecretInterface.php b/app/code/Magento/LoginAsCustomer/Api/CreateSecretInterface.php new file mode 100644 index 0000000000000..3a0ebbbc79685 --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Api/CreateSecretInterface.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Api; + +/** + * @api + */ +interface CreateSecretInterface +{ + /** + * Create a new secret key + * @return string + * @param int $customerId + * @param int $adminId + */ + public function execute(int $customerId, int $adminId):string; +} diff --git a/app/code/Magento/LoginAsCustomer/Api/DeleteOldSecretsInterface.php b/app/code/Magento/LoginAsCustomer/Api/DeleteOldSecretsInterface.php new file mode 100644 index 0000000000000..396be1e05891a --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Api/DeleteOldSecretsInterface.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Api; + +/** + * @api + */ +interface DeleteOldSecretsInterface +{ + /** + * Delete old secret key records + */ + public function execute():void; +} diff --git a/app/code/Magento/LoginAsCustomer/Api/DeleteSecretInterface.php b/app/code/Magento/LoginAsCustomer/Api/DeleteSecretInterface.php new file mode 100644 index 0000000000000..d4d83aa91bc08 --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Api/DeleteSecretInterface.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Api; + +/** + * @api + */ +interface DeleteSecretInterface +{ + /** + * Delete secret key + */ + public function execute(string $secretKey):void; +} diff --git a/app/code/Magento/LoginAsCustomer/Api/GetAuthenticateDataInterface.php b/app/code/Magento/LoginAsCustomer/Api/GetAuthenticateDataInterface.php new file mode 100644 index 0000000000000..0a8da079155bf --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Api/GetAuthenticateDataInterface.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Api; + +/** + * @api + */ +interface GetAuthenticateDataInterface +{ + /** + * Load login details based on secret key + */ + public function execute(string $secretKey):array; +} diff --git a/app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Index.php b/app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Index.php index 55d89dedf09f1..4bfe58849c471 100755 --- a/app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Index.php +++ b/app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Index.php @@ -7,14 +7,12 @@ namespace Magento\LoginAsCustomer\Controller\Adminhtml\Login; -use Magento\Backend\App\Action\Context; use Magento\Backend\Model\View\Result\Page; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Controller\ResultInterface; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Backend\App\Action; -use Magento\LoginAsCustomer\Model\Login; /** * Login As Customer log grid action @@ -29,23 +27,6 @@ class Index extends Action implements HttpGetActionInterface, HttpPostActionInte */ const ADMIN_RESOURCE = 'Magento_LoginAsCustomer::login_log'; - /** - * @var Login - */ - private $loginModel; - - /** - * @param Context $context - * @param Login $loginModel - */ - public function __construct( - Context $context, - Login $loginModel - ) { - parent::__construct($context); - $this->loginModel = $loginModel; - } - /** * Login As Customer log grid action * @@ -59,8 +40,6 @@ public function execute():ResultInterface return $resultForward; } - $this->loginModel->deleteNotUsed(); - /** @var Page $resultPage */ $resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE); $resultPage->setActiveMenu('Magento_LoginAsCustomer::login_log') diff --git a/app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Login.php b/app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Login.php index 8c3f0969cfbe6..a260000237f9e 100755 --- a/app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Login.php +++ b/app/code/Magento/LoginAsCustomer/Controller/Adminhtml/Login/Login.php @@ -11,6 +11,9 @@ use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Backend\App\Action; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\LoginAsCustomer\Api\CreateSecretInterface; /** * Login as customer action @@ -27,11 +30,6 @@ class Login extends Action implements HttpGetActionInterface, HttpPostActionInte */ const ADMIN_RESOURCE = 'Magento_LoginAsCustomer::login_button'; - /** - * @var \Magento\LoginAsCustomer\Model\Login - */ - private $loginModel; - /** * @var \Magento\Backend\Model\Auth\Session */ @@ -47,34 +45,47 @@ class Login extends Action implements HttpGetActionInterface, HttpPostActionInte */ private $url; + /** + * @var CustomerRepositoryInterface + */ + private $customerRepository; + /** * @var \Magento\LoginAsCustomer\Model\Config */ private $config; + /** + * @var CreateSecretInterface + */ + private $createSecretProcessor; + /** * Login constructor. * @param \Magento\Backend\App\Action\Context $context - * @param \Magento\LoginAsCustomer\Model\Login $loginModel * @param \Magento\Backend\Model\Auth\Session $authSession * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Framework\Url $url - * @param \Magento\LoginAsCustomer\Model\Config $config + * @param CustomerRepositoryInterface $customerRepository + * @param \Magento\LoginAsCustomer\Model\Config $config, + * @param CreateSecretInterface $createSecretProcessor */ public function __construct( \Magento\Backend\App\Action\Context $context, - \Magento\LoginAsCustomer\Model\Login $loginModel, \Magento\Backend\Model\Auth\Session $authSession, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Framework\Url $url, - \Magento\LoginAsCustomer\Model\Config $config + CustomerRepositoryInterface $customerRepository, + \Magento\LoginAsCustomer\Model\Config $config, + CreateSecretInterface $createSecretProcessor ) { parent::__construct($context); - $this->loginModel = $loginModel; $this->authSession = $authSession; $this->storeManager = $storeManager; $this->url = $url; + $this->customerRepository = $customerRepository; $this->config = $config; + $this->createSecretProcessor = $createSecretProcessor; } /** @@ -84,48 +95,45 @@ public function __construct( */ public function execute(): ResultInterface { + /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + + if (!$this->config->isEnabled()) { + $this->messageManager->addErrorMessage(__('Login As Customer is disabled.')); + return $resultRedirect->setPath('customer/index/index'); + } + $request = $this->getRequest(); + $customerId = (int) $request->getParam('customer_id'); if (!$customerId) { $customerId = (int) $request->getParam('entity_id'); } - /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultRedirectFactory->create(); - - if (!$this->config->isEnabled()) { - $this->messageManager->addErrorMessage(__('Login As Customer is disabled.')); + try { + $customer = $this->customerRepository->getById($customerId); + } catch (NoSuchEntityException $e) { + $this->messageManager->addErrorMessage(__('Customer with this ID are no longer exist.')); return $resultRedirect->setPath('customer/index/index'); } $customerStoreId = $request->getParam('store_id'); - if (!isset($customerStoreId) && $this->config->isManualChoiceEnabled()) { $this->messageManager->addNoticeMessage(__('Please select a Store View to login in.')); return $resultRedirect->setPath('loginascustomer/login/manual', ['entity_id' => $customerId ]); } - $login = $this->loginModel->setCustomerId($customerId); - - $login->deleteNotUsed(); - - $customer = $login->getCustomer(); - - if (!$customer->getId()) { - $this->messageManager->addErrorMessage(__('Customer with this ID are no longer exist.')); - return $resultRedirect->setPath('customer/index/index'); - } $user = $this->authSession->getUser(); - $login->generate($user->getId()); - $store = $this->storeManager->getStore(); + $secret = $this->createSecretProcessor->execute($customerId, (int)$user->getId()); + $store = $this->storeManager->getStore(); if (null === $store) { $store = $this->storeManager->getDefaultStoreView(); } $redirectUrl = $this->url->setScope($store) - ->getUrl('loginascustomer/login/index', ['secret' => $login->getSecret(), '_nosid' => true]); + ->getUrl('loginascustomer/login/index', ['secret' => $secret, '_nosid' => true]); return $resultRedirect->setUrl($redirectUrl); } diff --git a/app/code/Magento/LoginAsCustomer/Controller/Login/Index.php b/app/code/Magento/LoginAsCustomer/Controller/Login/Index.php index dc3affa70e3a2..9fc30ac277cfe 100755 --- a/app/code/Magento/LoginAsCustomer/Controller/Login/Index.php +++ b/app/code/Magento/LoginAsCustomer/Controller/Login/Index.php @@ -11,11 +11,15 @@ use Magento\Framework\Controller\Result\Redirect; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Controller\ResultInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\App\Action\HttpGetActionInterface; use Magento\Framework\Message\ManagerInterface; -use Magento\LoginAsCustomer\Model\Login; use Psr\Log\LoggerInterface; +use Magento\LoginAsCustomer\Api\GetAuthenticateDataInterface; +use Magento\LoginAsCustomer\Api\AuthenticateCustomerInterface; +use Magento\LoginAsCustomer\Api\DeleteSecretInterface; /** * Login As Customer storefront login action @@ -33,9 +37,24 @@ class Index implements HttpGetActionInterface private $request; /** - * @var Login + * @var CustomerRepositoryInterface */ - private $loginModel; + private $customerRepository; + + /** + * @var GetAuthenticateDataInterface + */ + private $getAuthenticateDataProcessor; + + /** + * @var AuthenticateCustomerInterface + */ + private $authenticateCustomerProcessor; + + /** + * @var DeleteSecretInterface + */ + private $deleteSecretProcessor; /** * @var ManagerInterface @@ -50,20 +69,29 @@ class Index implements HttpGetActionInterface /** * @param ResultFactory $resultFactory * @param RequestInterface $request - * @param Login $loginModel + * @param CustomerRepositoryInterface $customerRepository + * @param GetAuthenticateDataInterface $getAuthenticateDataProcessor + * @param AuthenticateCustomerInterface $authenticateCustomerProcessor + * @param DeleteSecretInterface $deleteSecretProcessor * @param ManagerInterface $messageManager * @param LoggerInterface $logger */ public function __construct( ResultFactory $resultFactory, RequestInterface $request, - Login $loginModel, + CustomerRepositoryInterface $customerRepository, + GetAuthenticateDataInterface $getAuthenticateDataProcessor, + AuthenticateCustomerInterface $authenticateCustomerProcessor, + DeleteSecretInterface $deleteSecretProcessor, ManagerInterface $messageManager, LoggerInterface $logger ) { $this->resultFactory = $resultFactory; $this->request = $request; - $this->loginModel = $loginModel; + $this->customerRepository = $customerRepository; + $this->getAuthenticateDataProcessor = $getAuthenticateDataProcessor; + $this->authenticateCustomerProcessor = $authenticateCustomerProcessor; + $this->deleteSecretProcessor = $deleteSecretProcessor; $this->messageManager = $messageManager; $this->logger = $logger; } @@ -79,11 +107,35 @@ public function execute(): ResultInterface $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); try { - $login = $this->initLogin(); - $login->authenticateCustomer(); + $secret = $this->request->getParam('secret'); + if (!$secret || !is_string($secret)) { + throw new LocalizedException(__('Cannot login to account. No secret key provided.')); + } + + /* Can throw LocalizedException */ + $authenticateData = $this->getAuthenticateDataProcessor->execute($secret); + + $this->deleteSecretProcessor->execute($secret); + + try { + $customer = $this->customerRepository->getById($authenticateData['customer_id']); + } catch (NoSuchEntityException $e) { + throw new LocalizedException(__('Customer are no longer exist.')); + } + + $loggedIn = $this->authenticateCustomerProcessor->execute( + (int)$authenticateData['customer_id'], + (int)$authenticateData['admin_id'] + ); + + + if (!$loggedIn) { + throw new LocalizedException(__('Login was not successful.')); + } + $this->messageManager->addSuccessMessage( - __('You are logged in as customer: %1', $login->getCustomer()->getName()) + __('You are logged in as customer: %1', $customer->getFirstname() . ' ' . $customer->getLastname()) ); $resultRedirect->setPath('*/*/proceed'); @@ -98,26 +150,4 @@ public function execute(): ResultInterface } return $resultRedirect; } - - /** - * Init login info - * - * @return Login - * @throws LocalizedException - */ - private function initLogin(): Login - { - $secret = $this->request->getParam('secret'); - if (!$secret) { - throw new LocalizedException(__('Cannot login to account. No secret key provided.')); - } - - $login = $this->loginModel->loadNotUsed($secret); - - if ($login->getId()) { - return $login; - } else { - throw new LocalizedException(__('Cannot login to account. Secret key is not valid')); - } - } } diff --git a/app/code/Magento/LoginAsCustomer/Cron/DeleteOldSecrets.php b/app/code/Magento/LoginAsCustomer/Cron/DeleteOldSecrets.php new file mode 100644 index 0000000000000..b832b45c63b48 --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Cron/DeleteOldSecrets.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Cron; + +use Magento\LoginAsCustomer\Api\DeleteOldSecretsInterface; +use Magento\LoginAsCustomer\Model\Config; + +/** + * @api + */ +class DeleteOldSecrets implements DeleteOldSecretsInterface +{ + /** + * @var DeleteOldSecretsInterface + */ + private $deleteOldSecretsProcessor; + + /** + * @var Config + */ + private $config; + + /** + * DeleteOldSecrets constructor. + * @param DeleteOldSecretsInterface $deleteOldSecretsProcessor + * @param Config $config + */ + public function __construct( + DeleteOldSecretsInterface $deleteOldSecretsProcessor, + Config $config + ) { + $this->deleteOldSecretsProcessor = $deleteOldSecretsProcessor; + $this->config = $config; + } + + /** + * Delete old secret key records + */ + public function execute():void + { + if ($this->config->isEnabled()) { + $this->deleteOldSecretsProcessor->execute(); + } + } +} diff --git a/app/code/Magento/LoginAsCustomer/Model/AuthenticateCustomer.php b/app/code/Magento/LoginAsCustomer/Model/AuthenticateCustomer.php new file mode 100644 index 0000000000000..4a9aca6f4decf --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Model/AuthenticateCustomer.php @@ -0,0 +1,85 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Model; + +use Magento\Customer\Model\Session; +use Magento\LoginAsCustomer\Api\AuthenticateCustomerInterface; + +/** + * @api + */ +class AuthenticateCustomer implements AuthenticateCustomerInterface +{ + /** + * @var Session + */ + private $customerSession; + + /** + * @var \Magento\Checkout\Model\Cart + */ + private $cart; + + /** + * @var \Magento\Checkout\Model\Session + */ + private $checkoutSession; + + /** + * AuthenticateCustomer constructor. + * @param Session $customerSession + * @param \Magento\Checkout\Model\Cart $cart + * @param \Magento\Checkout\Model\Session $checkoutSession + */ + public function __construct( + Session $customerSession, + \Magento\Checkout\Model\Cart $cart, + \Magento\Checkout\Model\Session $checkoutSession + ) { + $this->customerSession = $customerSession; + $this->cart = $cart; + $this->checkoutSession = $checkoutSession; + } + + /** + * Authenticate a customer by customer ID + * + * @return bool + * @param int $customerId + * @param int $adminId + */ + public function execute(int $customerId, int $adminId):bool + { + if ($this->customerSession->getId()) { + /* Logout if logged in */ + $this->customerSession->logout(); + } else { + $quote = $this->cart->getQuote(); + /* Remove items from guest cart */ + foreach ($quote->getAllVisibleItems() as $item) { + $this->cart->removeItem($item->getId()); + } + $this->cart->save(); + } + + $loggedIn = $this->customerSession->loginById($customerId); + if ($loggedIn) { + $this->customerSession->regenerateId(); + $this->customerSession->setLoggedAsCustomerAdmindId($adminId); + } + + /* Load Customer Quote */ + $this->checkoutSession->loadCustomerQuote(); + + $quote = $this->checkoutSession->getQuote(); + $quote->setCustomerIsGuest(0); + $quote->save(); + + return $loggedIn; + } +} diff --git a/app/code/Magento/LoginAsCustomer/Model/Config.php b/app/code/Magento/LoginAsCustomer/Model/Config.php index 7b34cc8dcfd7c..85ea8a42c9b57 100644 --- a/app/code/Magento/LoginAsCustomer/Model/Config.php +++ b/app/code/Magento/LoginAsCustomer/Model/Config.php @@ -22,6 +22,8 @@ class Config private const XML_PATH_EXTENSION_ENABLED = 'loginascustomer/general/enabled'; private const ENABLE_STORE_VIEW_MANUAL_CHOICE = 'loginascustomer/general/enable_store_view_manual_choice'; + public const TIME_FRAME = 60; + /** * @var ScopeConfigInterface */ diff --git a/app/code/Magento/LoginAsCustomer/Model/Login.php b/app/code/Magento/LoginAsCustomer/Model/Login.php index e4c1e55b30a27..847c6cc61a506 100755 --- a/app/code/Magento/LoginAsCustomer/Model/Login.php +++ b/app/code/Magento/LoginAsCustomer/Model/Login.php @@ -12,108 +12,6 @@ */ class Login extends \Magento\Framework\Model\AbstractModel { - /** - * Login tome frame - */ - const TIME_FRAME = 60; - - /** - * Prefix of model events names - * - * @var string - */ - protected $_eventPrefix = 'login_as_customer_log'; - - /** - * Parameter name in event - * - * In observe method you can use $observer->getEvent()->getObject() in this case - * - * @var string - */ - protected $_eventObject = 'loginascustomer_login'; - - /** - * @var \Magento\Customer\Model\CustomerFactory - */ - private $_customerFactory; - - /** - * @var \Magento\Customer\Model\Customer - */ - private $_customer; - - /** - * @var \Magento\Customer\Model\Session - */ - private $_customerSession; - - /** - * @var \Magento\Checkout\Model\Session - */ - private $_checkoutSession; - - /** - * @var \Magento\Framework\Stdlib\DateTime\DateTime - */ - private $_dateTime; - - /** - * @var \Magento\Framework\Math\Random - */ - private $_random; - - /** - * @var \Magento\Checkout\Model\Cart - */ - private $cart; - - /** - * @var \Magento\Framework\App\Config\ScopeConfigInterface - */ - private $scopeConfig; - - /** - * Initialize dependencies. - * @param \Magento\Framework\Model\Context $context - * @param \Magento\Framework\Registry $registry - * @param \Magento\Customer\Model\CustomerFactory $customerFactory - * @param \Magento\Customer\Model\Session $customerSession - * @param \Magento\Framework\Stdlib\DateTime\DateTime $dateTime - * @param \Magento\Framework\Math\Random $random - * @param \Magento\Checkout\Model\Cart $cart - * @param \Magento\Checkout\Model\Session $checkoutSession - * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig - * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource - * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection - * @param array $data - */ - public function __construct( - \Magento\Framework\Model\Context $context, - \Magento\Framework\Registry $registry, - \Magento\Customer\Model\CustomerFactory $customerFactory, - \Magento\Customer\Model\Session $customerSession, - \Magento\Framework\Stdlib\DateTime\DateTime $dateTime, - \Magento\Framework\Math\Random $random, - \Magento\Checkout\Model\Cart $cart, - \Magento\Checkout\Model\Session $checkoutSession, - \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, - \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, - \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] - ) { - $this->_customerFactory = $customerFactory; - $this->_customerSession = $customerSession; - $this->_checkoutSession = $checkoutSession; - $this->_dateTime = $dateTime; - $this->_random = $random; - $this->cart = $cart; - $this->_checkoutSession = $checkoutSession; - $this->scopeConfig = $scopeConfig; - - parent::__construct($context, $registry, $resource, $resourceCollection, $data); - } - /** * Initialize resource model * @@ -123,118 +21,4 @@ protected function _construct() { $this->_init(\Magento\LoginAsCustomer\Model\ResourceModel\Login::class); } - - /** - * Retrieve not used admin login - * @param string $secret - * @return self - */ - public function loadNotUsed($secret): self - { - return $this->getCollection() - ->addFieldToFilter('secret', $secret) - ->addFieldToFilter('used', 0) - ->addFieldToFilter('created_at', ['gt' => $this->getDateTimePoint()]) - ->setPageSize(1) - ->getFirstItem(); - } - - /** - * Delete not used credentials - * @return void - */ - public function deleteNotUsed(): void - { - $resource = $this->getResource(); - $resource->getConnection()->delete( - $resource->getTable('login_as_customer_log'), - [ - 'created_at < ?' => $this->getDateTimePoint(), - 'used = ?' => 0, - ] - ); - } - - /** - * Retrieve login datetime point - * @return string - */ - private function getDateTimePoint(): string - { - return date('Y-m-d H:i:s', $this->_dateTime->gmtTimestamp() - self::TIME_FRAME); - } - - /** - * Retrieve customer - * @return \Magento\Customer\Model\Customer - */ - public function getCustomer(): \Magento\Customer\Model\Customer - { - if (is_null($this->_customer)) { - $this->_customer = $this->_customerFactory->create() - ->load($this->getCustomerId()); - } - return $this->_customer; - } - - /** - * Login Customer - * @return \Magento\Customer\Model\Customer - */ - public function authenticateCustomer(): \Magento\Customer\Model\Customer - { - if ($this->_customerSession->getId()) { - /* Logout if logged in */ - $this->_customerSession->logout(); - } else { - $quote = $this->cart->getQuote(); - /* Remove items from guest cart */ - foreach ($quote->getAllVisibleItems() as $item) { - $this->cart->removeItem($item->getId()); - } - $this->cart->save(); - } - - $customer = $this->getCustomer(); - - if (!$customer->getId()) { - throw new \Exception(__("Customer are no longer exist."), 1); - } - - if ($this->_customerSession->loginById($customer->getId())) { - $this->_customerSession->regenerateId(); - $this->_customerSession->setLoggedAsCustomerAdmindId( - $this->getAdminId() - ); - } else { - throw new \Exception(__("Cannot login customer."), 1); - } - - /* Load Customer Quote */ - $this->_checkoutSession->loadCustomerQuote(); - - $quote = $this->_checkoutSession->getQuote(); - $quote->setCustomerIsGuest(0); - $quote->save(); - - $this->setUsed(1)->save(); - - return $customer; - } - - /** - * Generate new login credentials - * @param int $adminId - * @return $this - */ - public function generate($adminId): self - { - return $this->setData([ - 'customer_id' => $this->getCustomerId(), - 'admin_id' => $adminId, - 'secret' => $this->_random->getRandomString(64), - 'used' => 0, - 'created_at' => $this->_dateTime->gmtTimestamp(), - ])->save(); - } } diff --git a/app/code/Magento/LoginAsCustomer/Model/ResourceModel/CreateSecret.php b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/CreateSecret.php new file mode 100644 index 0000000000000..c17c080320abb --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/CreateSecret.php @@ -0,0 +1,73 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Model\ResourceModel; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Stdlib\DateTime\DateTime; +use Magento\Framework\Math\Random; +use Magento\LoginAsCustomer\Api\CreateSecretInterface; + +/** + * @api + */ +class CreateSecret implements CreateSecretInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var DateTime + */ + private $dateTime; + + /** + * @var Random + */ + private $random; + + /** + * @param ResourceConnection $resourceConnection + */ + public function __construct( + ResourceConnection $resourceConnection, + DateTime $dateTime, + Random $random + ) { + $this->resourceConnection = $resourceConnection; + $this->dateTime = $dateTime; + $this->random = $random; + } + + /** + * Create a new secret key + * @return string + * @param int $customerId + * @param int $adminId + */ + public function execute(int $customerId, int $adminId):string + { + $connection = $this->resourceConnection->getConnection(); + $tableName = $this->resourceConnection->getTableName('login_as_customer'); + + $secret = $this->random->getRandomString(64); + + $connection->insert( + $tableName, + [ + 'customer_id' => $customerId, + 'admin_id' => $adminId, + 'secret' => $secret, + 'created_at' => $this->dateTime->gmtDate(), + ] + ); + + return $secret; + } +} diff --git a/app/code/Magento/LoginAsCustomer/Model/ResourceModel/DeleteOldSecrets.php b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/DeleteOldSecrets.php new file mode 100644 index 0000000000000..92a9223c1a822 --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/DeleteOldSecrets.php @@ -0,0 +1,58 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Model\ResourceModel; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Stdlib\DateTime\DateTime; +use Magento\LoginAsCustomer\Api\DeleteOldSecretsInterface; +use Magento\LoginAsCustomer\Model\Config; + +/** + * @api + */ +class DeleteOldSecrets implements DeleteOldSecretsInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var DateTime + */ + private $dateTime; + + /** + * @param ResourceConnection $resourceConnection + */ + public function __construct( + ResourceConnection $resourceConnection, + DateTime $dateTime + ) { + $this->resourceConnection = $resourceConnection; + $this->dateTime = $dateTime; + } + + /** + * Delete old secret key records + */ + public function execute():void + { + $connection = $this->resourceConnection->getConnection(); + $tableName = $this->resourceConnection->getTableName('login_as_customer'); + + $timePoint = date('Y-m-d H:i:s', $this->dateTime->gmtTimestamp() - Config::TIME_FRAME); + + $connection->delete( + $tableName, + [ + 'created_at < ?' => $timePoint + ] + ); + } +} diff --git a/app/code/Magento/LoginAsCustomer/Model/ResourceModel/DeleteSecret.php b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/DeleteSecret.php new file mode 100644 index 0000000000000..0fb5f6a70214c --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/DeleteSecret.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Model\ResourceModel; + +use Magento\Framework\App\ResourceConnection; +use Magento\LoginAsCustomer\Api\DeleteSecretInterface; + +/** + * @api + */ +class DeleteSecret implements DeleteSecretInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @param ResourceConnection $resourceConnection + */ + public function __construct( + ResourceConnection $resourceConnection + ) { + $this->resourceConnection = $resourceConnection; + } + + /** + * Delete old secret key records + */ + public function execute(string $secretKey):void + { + $connection = $this->resourceConnection->getConnection(); + $tableName = $this->resourceConnection->getTableName('login_as_customer'); + + $connection->delete( + $tableName, + [ + 'secret = ?' => $secretKey + ] + ); + } +} diff --git a/app/code/Magento/LoginAsCustomer/Model/ResourceModel/GetAuthenticateData.php b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/GetAuthenticateData.php new file mode 100644 index 0000000000000..59ab0f11d6ba7 --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/GetAuthenticateData.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\LoginAsCustomer\Model\ResourceModel; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Stdlib\DateTime\DateTime; +use Magento\Framework\Exception\LocalizedException; +use Magento\LoginAsCustomer\Api\GetAuthenticateDataInterface; +use Magento\LoginAsCustomer\Model\Config; + +/** + * @api + */ +class GetAuthenticateData implements GetAuthenticateDataInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var DateTime + */ + private $dateTime; + + /** + * @param ResourceConnection $resourceConnection + */ + public function __construct( + ResourceConnection $resourceConnection, + DateTime $dateTime + ) { + $this->resourceConnection = $resourceConnection; + $this->dateTime = $dateTime; + } + + /** + * Load logic details based on secret key + * @return array + * @throws LocalizedException + * @param string $secretKey + */ + public function execute(string $secretKey):array + { + $connection = $this->resourceConnection->getConnection(); + $tableName = $this->resourceConnection->getTableName('login_as_customer'); + + $timePoint = date('Y-m-d H:i:s', $this->dateTime->gmtTimestamp() - Config::TIME_FRAME); + + $select = $connection->select() + ->from(['main_table' => $tableName]) + ->where('main_table.secret = ?', $secretKey) + ->where('main_table.created_at > ?', $timePoint) + ->limit(1); + + $data = $connection->fetchRow($select); + + if (!$data) { + throw new LocalizedException(__('Secret key is not valid.')); + } + + + return $data; + } +} diff --git a/app/code/Magento/LoginAsCustomer/Model/ResourceModel/Login.php b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/Login.php index b61e595a29212..aa8d4dc554894 100755 --- a/app/code/Magento/LoginAsCustomer/Model/ResourceModel/Login.php +++ b/app/code/Magento/LoginAsCustomer/Model/ResourceModel/Login.php @@ -20,6 +20,6 @@ class Login extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb */ protected function _construct() { - $this->_init('login_as_customer_log', 'login_id'); + $this->_init('login_as_customer', 'login_id'); } } diff --git a/app/code/Magento/LoginAsCustomer/etc/crontab.xml b/app/code/Magento/LoginAsCustomer/etc/crontab.xml new file mode 100644 index 0000000000000..b2fa75253f241 --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/etc/crontab.xml @@ -0,0 +1,14 @@ +<?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:module:Magento_Cron:etc/crontab.xsd"> + <group id="default"> + <job instance="Magento\LoginAsCustomer\Cron\DeleteOldSecrets" method="execute" name="login_as_customer_delete_old_secrets"> + <schedule>15 * * * *</schedule> + </job> + </group> +</config> diff --git a/app/code/Magento/LoginAsCustomer/etc/db_schema.xml b/app/code/Magento/LoginAsCustomer/etc/db_schema.xml index c4c8e8f01a1da..1b457fc2ddcb8 100644 --- a/app/code/Magento/LoginAsCustomer/etc/db_schema.xml +++ b/app/code/Magento/LoginAsCustomer/etc/db_schema.xml @@ -7,7 +7,7 @@ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> - <table name="login_as_customer_log" resource="default" engine="innodb" comment="Magento Login As Customer Table"> + <table name="login_as_customer" resource="default" engine="innodb" comment="Magento Login As Customer Table"> <column xsi:type="int" name="login_id" nullable="false" identity="true" comment="Admin Login ID"/> <column xsi:type="int" name="customer_id" nullable="true" identity="false" @@ -15,7 +15,6 @@ <column xsi:type="int" name="admin_id" nullable="true" identity="false" comment="Admin ID"/> <column xsi:type="varchar" name="secret" length="64" nullable="true" comment="Login Secret"/> - <column xsi:type="smallint" name="used" padding="6" nullable="false" default="1" comment="Is Login Used"/> <column xsi:type="timestamp" name="created_at" comment="Creation Time"/> <constraint xsi:type="primary" referenceId="PRIMARY"> <column name="login_id"/> diff --git a/app/code/Magento/LoginAsCustomer/etc/db_schema_whitelist.json b/app/code/Magento/LoginAsCustomer/etc/db_schema_whitelist.json index bb05d8fbb5a0b..e723c1c73b6ff 100644 --- a/app/code/Magento/LoginAsCustomer/etc/db_schema_whitelist.json +++ b/app/code/Magento/LoginAsCustomer/etc/db_schema_whitelist.json @@ -1,11 +1,10 @@ { - "login_as_customer_log": { + "login_as_customer": { "column": { "login_id": true, "customer_id": true, "admin_id": true, "secret": true, - "used": true, "created_at": true }, "index": { @@ -17,4 +16,4 @@ "PRIMARY": true } } -} \ No newline at end of file +} diff --git a/app/code/Magento/LoginAsCustomer/etc/di.xml b/app/code/Magento/LoginAsCustomer/etc/di.xml new file mode 100755 index 0000000000000..4eb46a8be7e53 --- /dev/null +++ b/app/code/Magento/LoginAsCustomer/etc/di.xml @@ -0,0 +1,14 @@ +<?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:ObjectManager/etc/config.xsd"> + <preference for="Magento\LoginAsCustomer\Api\CreateSecretInterface" type="Magento\LoginAsCustomer\Model\ResourceModel\CreateSecret" /> + <preference for="Magento\LoginAsCustomer\Api\GetAuthenticateDataInterface" type="Magento\LoginAsCustomer\Model\ResourceModel\GetAuthenticateData" /> + <preference for="Magento\LoginAsCustomer\Api\AuthenticateCustomerInterface" type="Magento\LoginAsCustomer\Model\AuthenticateCustomer" /> + <preference for="Magento\LoginAsCustomer\Api\DeleteSecretInterface" type="Magento\LoginAsCustomer\Model\ResourceModel\DeleteSecret" /> + <preference for="Magento\LoginAsCustomer\Api\DeleteOldSecretsInterface" type="Magento\LoginAsCustomer\Model\ResourceModel\DeleteOldSecrets" /> +</config>