From 89a0a09f2b843948b1f784d077506dcee834efd9 Mon Sep 17 00:00:00 2001 From: Ricards Z Date: Mon, 12 Mar 2018 18:55:08 +0200 Subject: [PATCH 001/529] Correctly convert config integration api resources --- .../Integration/Model/Config/Consolidated/Converter.php | 6 ++++++ .../Test/Unit/Model/Config/Consolidated/_files/acl.php | 2 ++ .../Unit/Model/Config/Consolidated/_files/integration.php | 6 +++++- .../Unit/Model/Config/Consolidated/_files/integration.xml | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Integration/Model/Config/Consolidated/Converter.php b/app/code/Magento/Integration/Model/Config/Consolidated/Converter.php index 674a97a68d065..2c5bf5fd4ac82 100644 --- a/app/code/Magento/Integration/Model/Config/Consolidated/Converter.php +++ b/app/code/Magento/Integration/Model/Config/Consolidated/Converter.php @@ -80,6 +80,12 @@ public function convert($source) $result[$integrationName][self::API_RESOURCES][] = $name; } } + + // Add root resource if any child has been added + if (! empty($result[$integrationName][self::API_RESOURCES])) { + array_unshift($result[$integrationName][self::API_RESOURCES], $allResources[1]['id']); + } + // Remove any duplicates added parents $result[$integrationName][self::API_RESOURCES] = array_values(array_unique($result[$integrationName][self::API_RESOURCES])); diff --git a/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/acl.php b/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/acl.php index 5b7bbace5a65d..42b62acaba5b4 100644 --- a/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/acl.php +++ b/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/acl.php @@ -6,6 +6,8 @@ return [ [], [ + 'id' => 'Magento_Backend::admin', + 'title' => 'Magento Admin (Root)', 'children' => [ [ diff --git a/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/integration.php b/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/integration.php index 54e05d5ef9017..0293492c77658 100644 --- a/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/integration.php +++ b/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/integration.php @@ -9,6 +9,7 @@ 'endpoint_url' => 'http://endpoint.com', 'identity_link_url' => 'http://www.example.com/identity', 'resource' => [ + 'Magento_Backend::admin', 'Magento_Customer::manageParent', 'Magento_Customer::manage', 'Magento_SalesRule::quoteParent', @@ -17,6 +18,9 @@ ], 'TestIntegration2' => [ 'email' => 'test-integration2@magento.com', - 'resource' => ['Magento_Sales::sales'] + 'resource' => [ + 'Magento_Backend::admin', + 'Magento_Sales::sales' + ] ] ]; diff --git a/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/integration.xml b/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/integration.xml index 585fabc24299d..f8bcf3fc4a2ce 100644 --- a/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/integration.xml +++ b/app/code/Magento/Integration/Test/Unit/Model/Config/Consolidated/_files/integration.xml @@ -18,6 +18,7 @@ test-integration2@magento.com + From 5815a2073d4703eccbb12100e1bbe7dc48bb79bb Mon Sep 17 00:00:00 2001 From: Ricards Z Date: Tue, 13 Mar 2018 10:07:52 +0200 Subject: [PATCH 002/529] Fixed broken integration test and added additional integration test --- .../Consolidated/_files/integration.php | 3 + .../ConfigBasedIntegrationManagerTest.php | 110 ++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Consolidated/_files/integration.php b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Consolidated/_files/integration.php index cc2841f1acf2c..d72a1359dfa52 100644 --- a/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Consolidated/_files/integration.php +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/Config/Consolidated/_files/integration.php @@ -9,6 +9,7 @@ 'endpoint_url' => 'http://example.com/endpoint1', 'identity_link_url' => 'http://www.example.com/identity1', 'resource' => [ + 'Magento_Backend::admin', 'Magento_Customer::customer', 'Magento_Customer::manage', 'Magento_Sales::sales', @@ -26,6 +27,7 @@ 'endpoint_url' => 'http://example.com/integration2', 'identity_link_url' => 'http://www.example.com/identity2', 'resource' => [ + 'Magento_Backend::admin', 'Magento_Sales::sales', 'Magento_Sales::sales_operation', 'Magento_Sales::sales_order', @@ -40,6 +42,7 @@ 'TestIntegration3' => [ 'email' => 'test-integration3@example.com', 'resource' => [ + 'Magento_Backend::admin', 'Magento_Sales::sales', 'Magento_Sales::sales_operation', 'Magento_Sales::sales_order', diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php b/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php new file mode 100644 index 0000000000000..b45b9906e2844 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php @@ -0,0 +1,110 @@ +consolidatedConfigMock = $this->createMock(\Magento\Integration\Model\ConsolidatedConfig::class); + $objectManager->addSharedInstance( + $this->consolidatedConfigMock, + \Magento\Integration\Model\ConsolidatedConfig::class + ); + $this->integrationManager = $objectManager->create( + \Magento\Integration\Model\ConfigBasedIntegrationManager::class, + [] + ); + $this->integrationService = $objectManager->create( + \Magento\Integration\Api\IntegrationServiceInterface::class, + [] + ); + } + + /** + * @magentoDbIsolation enabled + */ + public function testProcessConfigBasedIntegrations() + { + $newIntegrations = require __DIR__ . '/Config/Consolidated/_files/integration.php'; + $this->consolidatedConfigMock + ->expects($this->any()) + ->method('getIntegrations') + ->willReturn($newIntegrations); + + // Check that the integrations do not exist already + foreach ($newIntegrations as $integrationName => $integrationData) { + $integration = $this->integrationService->findByName($integrationName); + $this->assertEquals(null, $integration->getId(), 'Integration already exists'); + } + + // Create new integrations + $this->assertEquals( + $newIntegrations, + $this->integrationManager->processConfigBasedIntegrations($newIntegrations), + 'Error processing config based integrations.' + ); + $createdIntegrations = []; + + // Check that the integrations are new with "inactive" status + foreach ($newIntegrations as $integrationName => $integrationData) { + $integration = $this->integrationService->findByName($integrationName); + $this->assertNotEmpty($integration->getId(), 'Integration was not created'); + $this->assertEquals( + $integration::STATUS_INACTIVE, + $integration->getStatus(), + 'Integration is not created with "inactive" status' + ); + $createdIntegrations[$integrationName] = $integration; + } + + // Rerun integration creation + $this->assertEquals( + $newIntegrations, + $this->integrationManager->processConfigBasedIntegrations($newIntegrations), + 'Error processing config based integrations.' + ); + + // Check that the integrations are not recreated when data has not actually changed + foreach ($newIntegrations as $integrationName => $integrationData) { + $integration = $this->integrationService->findByName($integrationName); + $this->assertEquals( + $createdIntegrations[$integrationName]->getId(), + $integration->getId(), + 'Integration ID has changed' + ); + $this->assertEquals( + $createdIntegrations[$integrationName]->getStatus(), + $integration->getStatus(), + 'Integration status has changed' + ); + } + } +} From 406935b76fc45ad326e0001d6afa3df9e478dfaf Mon Sep 17 00:00:00 2001 From: Ricards Z Date: Tue, 13 Mar 2018 10:11:14 +0200 Subject: [PATCH 003/529] Updated comment --- .../Integration/Model/ConfigBasedIntegrationManagerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php b/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php index b45b9906e2844..9042354fabb5d 100644 --- a/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php @@ -85,7 +85,7 @@ public function testProcessConfigBasedIntegrations() $createdIntegrations[$integrationName] = $integration; } - // Rerun integration creation + // Rerun integration creation with the same data (data has not changed) $this->assertEquals( $newIntegrations, $this->integrationManager->processConfigBasedIntegrations($newIntegrations), From 3868e814def1b8886c2c33a191f7e0ff306a2172 Mon Sep 17 00:00:00 2001 From: Ricards Z Date: Wed, 14 Mar 2018 09:23:14 +0200 Subject: [PATCH 004/529] Minor refactoring to update code quality --- .../ConfigBasedIntegrationManagerTest.php | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php b/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php index 9042354fabb5d..af1ee643866f6 100644 --- a/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Integration/Model/ConfigBasedIntegrationManagerTest.php @@ -14,7 +14,7 @@ class ConfigBasedIntegrationManagerTest extends \PHPUnit\Framework\TestCase /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $consolidatedConfigMock; + protected $consolidatedMock; /** * @var \Magento\Integration\Model\ConfigBasedIntegrationManager @@ -26,35 +26,49 @@ class ConfigBasedIntegrationManagerTest extends \PHPUnit\Framework\TestCase */ protected $integrationService; + /** + * @var \Magento\TestFramework\ObjectManager + */ + protected $objectManager; + + /** + * @inheritdoc + */ protected function setUp() { parent::setUp(); - /** - * @var $objectManager \Magento\TestFramework\ObjectManager - */ - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->consolidatedConfigMock = $this->createMock(\Magento\Integration\Model\ConsolidatedConfig::class); - $objectManager->addSharedInstance( - $this->consolidatedConfigMock, + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->consolidatedMock = $this->createMock(\Magento\Integration\Model\ConsolidatedConfig::class); + $this->objectManager->addSharedInstance( + $this->consolidatedMock, \Magento\Integration\Model\ConsolidatedConfig::class ); - $this->integrationManager = $objectManager->create( + $this->integrationManager = $this->objectManager->create( \Magento\Integration\Model\ConfigBasedIntegrationManager::class, [] ); - $this->integrationService = $objectManager->create( + $this->integrationService = $this->objectManager->create( \Magento\Integration\Api\IntegrationServiceInterface::class, [] ); } + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->objectManager->removeSharedInstance(\Magento\Integration\Model\ConsolidatedConfig::class); + parent::tearDown(); + } + /** * @magentoDbIsolation enabled */ public function testProcessConfigBasedIntegrations() { $newIntegrations = require __DIR__ . '/Config/Consolidated/_files/integration.php'; - $this->consolidatedConfigMock + $this->consolidatedMock ->expects($this->any()) ->method('getIntegrations') ->willReturn($newIntegrations); From dc97cf4b135bb7eb6cbc0f97f2c787e58fa89ace Mon Sep 17 00:00:00 2001 From: Tom Erskine Date: Wed, 14 Mar 2018 09:56:44 -0500 Subject: [PATCH 005/529] MQE-801:Allow Test Generation of a single test via arg Modified RoboFile.php to allow generation of single or specified set of tests --- dev/tests/acceptance/RoboFile.php | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/dev/tests/acceptance/RoboFile.php b/dev/tests/acceptance/RoboFile.php index be9be5a2cc878..861b901599f96 100644 --- a/dev/tests/acceptance/RoboFile.php +++ b/dev/tests/acceptance/RoboFile.php @@ -38,22 +38,32 @@ function buildProject() } /** - * Generate all Tests in PHP. + * Generate all Tests in PHP OR Generate set of tests via passing array of tests * + * @param array $tests * @param array $opts * @return void */ - function generateTests($opts = ['config' => null, 'force' => false, 'nodes' => null]) + + function generateTests(array $tests, $opts = ['config' => null, 'force' => false, 'nodes' => null]) + { $GLOBALS['GENERATE_TESTS'] = true; - + require 'tests'. DIRECTORY_SEPARATOR . 'functional' . DIRECTORY_SEPARATOR . '_bootstrap.php'; + $testsObjects = []; + if (!empty($tests)) + { + foreach ($tests as $test) + { + $testsObjects[] = Magento\FunctionalTestingFramework\Test\Handlers\TestObjectHandler::getInstance()->getObject($test); + } + } if ($opts['force']) { $GLOBALS['FORCE_PHP_GENERATE'] = true; } - require 'tests'. DIRECTORY_SEPARATOR . 'functional' . DIRECTORY_SEPARATOR . '_bootstrap.php'; - \Magento\FunctionalTestingFramework\Util\TestGenerator::getInstance()->createAllTestFiles($opts['config'], $opts['nodes']); + \Magento\FunctionalTestingFramework\Util\TestGenerator::getInstance(null, $testsObjects)->createAllTestFiles($opts['config'], $opts['nodes']); $this->say("Generate Tests Command Run"); } @@ -197,4 +207,6 @@ function preInstall() { $this->_exec('php pre-install.php'); } + + } From 7a23bd3d6363494089bf3a67381bac0d08e7a460 Mon Sep 17 00:00:00 2001 From: Kevin Kozan Date: Tue, 27 Mar 2018 23:06:48 +0300 Subject: [PATCH 006/529] MQE-830: Output error details about test failure - Added TestContextExtension to enabled module list --- dev/tests/acceptance/codeception.dist.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/acceptance/codeception.dist.yml b/dev/tests/acceptance/codeception.dist.yml index 207671b27a153..0e4c6cadd9f81 100644 --- a/dev/tests/acceptance/codeception.dist.yml +++ b/dev/tests/acceptance/codeception.dist.yml @@ -15,6 +15,7 @@ extensions: enabled: - Codeception\Extension\RunFailed - Yandex\Allure\Adapter\AllureAdapter + - Magento\FunctionalTestingFramework\Extension\TestContextExtension config: Yandex\Allure\Adapter\AllureAdapter: deletePreviousResults: true From d900236a01400a5a48464b5ab9bf590c83c61629 Mon Sep 17 00:00:00 2001 From: Tom Reece Date: Wed, 4 Apr 2018 16:38:12 -0500 Subject: [PATCH 007/529] MQE-912: AdminCreateCustomerTest fails randomly --- .../FunctionalTest/Customer/Test/AdminCreateCustomerTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/AdminCreateCustomerTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/AdminCreateCustomerTest.xml index b678528409501..acc7120c1c039 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/AdminCreateCustomerTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/AdminCreateCustomerTest.xml @@ -26,6 +26,7 @@ + From 30bc2d1c3e9d8d29c9a07927db4c8758f7de9899 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Mon, 16 Apr 2018 16:21:40 +0300 Subject: [PATCH 008/529] MAGETWO-72982: Reset Password --- .../Api/AccountManagementInterface.php | 11 ++- .../Controller/Account/CreatePassword.php | 15 ++-- .../Controller/Account/ResetPasswordPost.php | 34 ++++----- .../Customer/Model/AccountManagement.php | 72 ++++++++++++++++--- .../email/password_reset_confirmation.html | 2 +- .../form/resetforgottenpassword.phtml | 2 +- .../Customer/Model/AccountManagementTest.php | 63 +++++++++++++++- .../Magento/Framework/Math/Random.php | 62 +++++----------- 8 files changed, 178 insertions(+), 83 deletions(-) diff --git a/app/code/Magento/Customer/Api/AccountManagementInterface.php b/app/code/Magento/Customer/Api/AccountManagementInterface.php index d2f9fb7ebc420..0bda1fc4bb815 100644 --- a/app/code/Magento/Customer/Api/AccountManagementInterface.php +++ b/app/code/Magento/Customer/Api/AccountManagementInterface.php @@ -7,6 +7,8 @@ namespace Magento\Customer\Api; +use Magento\Framework\Exception\InputException; + /** * Interface for managing customers accounts. * @api @@ -144,19 +146,24 @@ public function initiatePasswordReset($email, $template, $websiteId = null); /** * Reset customer password. * - * @param string $email + * @param string $email If empty value given then the customer + * will be matched by the RP token. * @param string $resetToken * @param string $newPassword + * * @return bool true on success * @throws \Magento\Framework\Exception\LocalizedException + * @throws InputException */ public function resetPassword($email, $resetToken, $newPassword); /** * Check if password reset token is valid. * - * @param int $customerId + * @param int $customerId If 0 is given then a customer + * will be matched by the RP token. * @param string $resetPasswordLinkToken + * * @return bool True if the token is valid * @throws \Magento\Framework\Exception\State\InputMismatchException If token is mismatched * @throws \Magento\Framework\Exception\State\ExpiredException If token is expired diff --git a/app/code/Magento/Customer/Controller/Account/CreatePassword.php b/app/code/Magento/Customer/Controller/Account/CreatePassword.php index fb2e3dd42908b..a86f42c14a027 100644 --- a/app/code/Magento/Customer/Controller/Account/CreatePassword.php +++ b/app/code/Magento/Customer/Controller/Account/CreatePassword.php @@ -54,27 +54,30 @@ public function __construct( public function execute() { $resetPasswordToken = (string)$this->getRequest()->getParam('token'); - $customerId = (int)$this->getRequest()->getParam('id'); - $isDirectLink = $resetPasswordToken != '' && $customerId != 0; + $isDirectLink = $resetPasswordToken != ''; if (!$isDirectLink) { $resetPasswordToken = (string)$this->session->getRpToken(); - $customerId = (int)$this->session->getRpCustomerId(); } try { - $this->accountManagement->validateResetPasswordLinkToken($customerId, $resetPasswordToken); + $this->accountManagement->validateResetPasswordLinkToken( + 0, + $resetPasswordToken + ); if ($isDirectLink) { $this->session->setRpToken($resetPasswordToken); - $this->session->setRpCustomerId($customerId); $resultRedirect = $this->resultRedirectFactory->create(); $resultRedirect->setPath('*/*/createpassword'); + return $resultRedirect; } else { /** @var \Magento\Framework\View\Result\Page $resultPage */ $resultPage = $this->resultPageFactory->create(); - $resultPage->getLayout()->getBlock('resetPassword')->setCustomerId($customerId) + $resultPage->getLayout() + ->getBlock('resetPassword') ->setResetPasswordLinkToken($resetPasswordToken); + return $resultPage; } } catch (\Exception $exception) { diff --git a/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php b/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php index 3de44e35d2447..7a59ad507aaeb 100644 --- a/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php +++ b/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php @@ -12,7 +12,6 @@ use Magento\Framework\App\Action\Context; use Magento\Framework\Exception\InputException; use Magento\Customer\Model\Customer\CredentialsValidator; -use Magento\Framework\App\ObjectManager; class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount { @@ -31,11 +30,6 @@ class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount */ protected $session; - /** - * @var CredentialsValidator - */ - private $credentialsValidator; - /** * @param Context $context * @param Session $customerSession @@ -53,8 +47,6 @@ public function __construct( $this->session = $customerSession; $this->accountManagement = $accountManagement; $this->customerRepository = $customerRepository; - $this->credentialsValidator = $credentialsValidator ?: ObjectManager::getInstance() - ->get(CredentialsValidator::class); parent::__construct($context); } @@ -70,27 +62,33 @@ public function execute() /** @var \Magento\Framework\Controller\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); $resetPasswordToken = (string)$this->getRequest()->getQuery('token'); - $customerId = (int)$this->getRequest()->getQuery('id'); $password = (string)$this->getRequest()->getPost('password'); $passwordConfirmation = (string)$this->getRequest()->getPost('password_confirmation'); if ($password !== $passwordConfirmation) { $this->messageManager->addError(__("New Password and Confirm New Password values didn't match.")); - $resultRedirect->setPath('*/*/createPassword', ['id' => $customerId, 'token' => $resetPasswordToken]); + $resultRedirect->setPath( + '*/*/createPassword', + ['token' => $resetPasswordToken] + ); return $resultRedirect; } if (iconv_strlen($password) <= 0) { $this->messageManager->addError(__('Please enter a new password.')); - $resultRedirect->setPath('*/*/createPassword', ['id' => $customerId, 'token' => $resetPasswordToken]); + $resultRedirect->setPath( + '*/*/createPassword', + ['token' => $resetPasswordToken] + ); return $resultRedirect; } try { - $customerEmail = $this->customerRepository->getById($customerId)->getEmail(); - $this->credentialsValidator->checkPasswordDifferentFromEmail($customerEmail, $password); - $this->accountManagement->resetPassword($customerEmail, $resetPasswordToken, $password); + $this->accountManagement->resetPassword( + '', + $resetPasswordToken, + $password + ); $this->session->unsRpToken(); - $this->session->unsRpCustomerId(); $this->messageManager->addSuccess(__('You updated your password.')); $resultRedirect->setPath('*/*/login'); return $resultRedirect; @@ -102,7 +100,11 @@ public function execute() } catch (\Exception $exception) { $this->messageManager->addError(__('Something went wrong while saving the new password.')); } - $resultRedirect->setPath('*/*/createPassword', ['id' => $customerId, 'token' => $resetPasswordToken]); + + $resultRedirect->setPath( + '*/*/createPassword', + ['token' => $resetPasswordToken] + ); return $resultRedirect; } } diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index fa209cf1e865b..77da5505b0770 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -19,6 +19,7 @@ use Magento\Customer\Model\Metadata\Validator; use Magento\Eav\Model\Validator\Attribute\Backend; use Magento\Framework\Api\ExtensibleDataObjectConverter; +use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\App\Area; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\ObjectManager; @@ -40,6 +41,7 @@ use Magento\Framework\Intl\DateTimeFactory; use Magento\Framework\Mail\Template\TransportBuilder; use Magento\Framework\Math\Random; +use Magento\Framework\Phrase; use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Framework\Registry; use Magento\Framework\Stdlib\DateTime; @@ -325,6 +327,11 @@ class AccountManagement implements AccountManagementInterface */ private $accountConfirmation; + /** + * @var SearchCriteriaBuilder + */ + private $searchCriteriaBuilder; + /** * @param CustomerFactory $customerFactory * @param ManagerInterface $eventManager @@ -356,6 +363,7 @@ class AccountManagement implements AccountManagementInterface * @param SessionManagerInterface|null $sessionManager * @param SaveHandlerInterface|null $saveHandler * @param CollectionFactory|null $visitorCollectionFactory + * @param SearchCriteriaBuilder|null $searchCriteriaBuilder * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -387,7 +395,8 @@ public function __construct( AccountConfirmation $accountConfirmation = null, SessionManagerInterface $sessionManager = null, SaveHandlerInterface $saveHandler = null, - CollectionFactory $visitorCollectionFactory = null + CollectionFactory $visitorCollectionFactory = null, + SearchCriteriaBuilder $searchCriteriaBuilder = null ) { $this->customerFactory = $customerFactory; $this->eventManager = $eventManager; @@ -423,6 +432,8 @@ public function __construct( ?: ObjectManager::getInstance()->get(SaveHandlerInterface::class); $this->visitorCollectionFactory = $visitorCollectionFactory ?: ObjectManager::getInstance()->get(CollectionFactory::class); + $this->searchCriteriaBuilder = $searchCriteriaBuilder + ?: ObjectManager::getInstance()->get(SearchCriteriaBuilder::class); } /** @@ -596,14 +607,62 @@ public function initiatePasswordReset($email, $template, $websiteId = null) return false; } + /** + * Match a customer by their RP token. + * + * @param string $rpToken + * @throws ExpiredException + * @throws NoSuchEntityException + * + * @return CustomerInterface + */ + private function matchCustomerByRpToken(string $rpToken): CustomerInterface + { + + $this->searchCriteriaBuilder->addFilter( + 'rp_token', + $rpToken + ); + $this->searchCriteriaBuilder->setPageSize(1); + $found = $this->customerRepository->getList( + $this->searchCriteriaBuilder->create() + ); + + if ($found->getTotalCount() > 1) { + //Failed to generated unique RP token + throw new ExpiredException( + new Phrase('Reset password token expired.') + ); + } + if ($found->getTotalCount() === 0) { + //Customer with such token not found. + throw NoSuchEntityException::singleField( + 'rp_token', + $rpToken + ); + } + + //Unique customer found. + return $found->getItems()[0]; + } + /** * {@inheritdoc} */ public function resetPassword($email, $resetToken, $newPassword) { - $customer = $this->customerRepository->get($email); + if (!$email) { + $customer = $this->matchCustomerByRpToken($resetToken); + $email = $customer->getEmail(); + } else { + $customer = $this->customerRepository->get($email); + } //Validate Token and new password strength $this->validateResetPasswordToken($customer->getId(), $resetToken); + $this->credentialsValidator->checkPasswordDifferentFromEmail( + $email, + $newPassword + ); $this->checkPasswordStrength($newPassword); //Update secure data $customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId()); @@ -1011,12 +1070,9 @@ public function isCustomerInStore($customerWebsiteId, $storeId) private function validateResetPasswordToken($customerId, $resetPasswordLinkToken) { if (empty($customerId) || $customerId < 0) { - throw new InputException( - __( - 'Invalid value of "%value" provided for the %fieldName field.', - ['value' => $customerId, 'fieldName' => 'customerId'] - ) - ); + //Looking for the customer. + $customerId = $this->matchCustomerByRpToken($resetPasswordLinkToken) + ->getId(); } if (!is_string($resetPasswordLinkToken) || empty($resetPasswordLinkToken)) { $params = ['fieldName' => 'resetPasswordLinkToken']; diff --git a/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html b/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html index 6c17762a88227..59e7f16adfd51 100644 --- a/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html +++ b/app/code/Magento/Customer/view/frontend/email/password_reset_confirmation.html @@ -21,7 +21,7 @@
- {{trans "Set a New Password"}} + {{trans "Set a New Password"}}
diff --git a/app/code/Magento/Customer/view/frontend/templates/form/resetforgottenpassword.phtml b/app/code/Magento/Customer/view/frontend/templates/form/resetforgottenpassword.phtml index 15e570da04beb..e79cea80ac838 100644 --- a/app/code/Magento/Customer/view/frontend/templates/form/resetforgottenpassword.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/form/resetforgottenpassword.phtml @@ -8,7 +8,7 @@ /** @var \Magento\Customer\Block\Account\Resetpassword $block */ ?> -
isAutocompleteDisabled()) :?> autocomplete="off" id="form-validate" diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php index 865a190f077b2..2e132d27f5cb1 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php @@ -357,6 +357,32 @@ public function testValidateResetPasswordLinkTokenNull() } } + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testValidateResetPasswordLinkTokenWithoutId() + { + $token = 'randomStr123'; + $this->setResetPasswordData($token, 'Y-m-d H:i:s'); + + $this->assertTrue( + $this->accountManagement->validateResetPasswordLinkToken(0, $token) + ); + } + + /** + * @magentoDataFixture Magento/Customer/_files/two_customers.php + * @expectedException \Magento\Framework\Exception\State\ExpiredException + */ + public function testValidateResetPasswordLinkTokenAmbiguous() + { + $token = 'randomStr123'; + $this->setResetPasswordData($token, 'Y-m-d H:i:s', 1); + $this->setResetPasswordData($token, 'Y-m-d H:i:s', 2); + + $this->accountManagement->validateResetPasswordLinkToken(0, $token); + } + /** * @magentoAppArea frontend * @magentoDataFixture Magento/Customer/_files/customer.php @@ -512,6 +538,34 @@ public function testResetPasswordTokenInvalidUserEmail() } } + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + */ + public function testResetPasswordWithoutEmail() + { + $resetToken = 'lsdj579slkj5987slkj595lkj'; + $password = 'new_Password123'; + + $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s'); + $this->assertTrue( + $this->accountManagement->resetPassword('', $resetToken, $password) + ); + } + + /** + * @magentoDataFixture Magento/Customer/_files/two_customers.php + * @expectedException \Magento\Framework\Exception\State\ExpiredException + */ + public function testResetPasswordAmbiguousToken() + { + $resetToken = 'lsdj579slkj5987slkj595lkj'; + $password = 'new_Password123'; + + $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s', 1); + $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s', 2); + $this->accountManagement->resetPassword('', $resetToken, $password); + } + /** * @magentoAppArea frontend * @magentoAppIsolation enabled @@ -960,10 +1014,13 @@ public function testGetDefaultAddressesForNonExistentAddress() * * @param $resetToken * @param $date + * @param int $customerIdFromFixture Which customer to use. */ - protected function setResetPasswordData($resetToken, $date) - { - $customerIdFromFixture = 1; + protected function setResetPasswordData( + $resetToken, + $date, + int $customerIdFromFixture = 1 + ) { /** @var \Magento\Customer\Model\Customer $customerModel */ $customerModel = $this->objectManager->create(\Magento\Customer\Model\Customer::class); $customerModel->load($customerIdFromFixture); diff --git a/lib/internal/Magento/Framework/Math/Random.php b/lib/internal/Magento/Framework/Math/Random.php index 7cb70c9a822cc..ffab4181c1e94 100644 --- a/lib/internal/Magento/Framework/Math/Random.php +++ b/lib/internal/Magento/Framework/Math/Random.php @@ -5,6 +5,9 @@ */ namespace Magento\Framework\Math; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; + /** * Random data generator * @@ -24,41 +27,24 @@ class Random /**#@-*/ /** - * Get random string + * Get random string. * * @param int $length * @param null|string $chars + * * @return string - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ public function getRandomString($length, $chars = null) { $str = ''; if (null === $chars) { - $chars = self::CHARS_LOWERS . self::CHARS_UPPERS . self::CHARS_DIGITS; + $chars = self::CHARS_LOWERS.self::CHARS_UPPERS.self::CHARS_DIGITS; } - if (function_exists('openssl_random_pseudo_bytes')) { - // use openssl lib if it is installed - for ($i = 0, $lc = strlen($chars) - 1; $i < $length; $i++) { - $bytes = openssl_random_pseudo_bytes(PHP_INT_SIZE); - $hex = bin2hex($bytes); // hex() doubles the length of the string - $rand = abs(hexdec($hex) % $lc); // random integer from 0 to $lc - $str .= $chars[$rand]; // random character in $chars - } - } elseif ($fp = @fopen('/dev/urandom', 'rb')) { - // attempt to use /dev/urandom if it exists but openssl isn't available - for ($i = 0, $lc = strlen($chars) - 1; $i < $length; $i++) { - $bytes = @fread($fp, PHP_INT_SIZE); - $hex = bin2hex($bytes); // hex() doubles the length of the string - $rand = abs(hexdec($hex) % $lc); // random integer from 0 to $lc - $str .= $chars[$rand]; // random character in $chars - } - fclose($fp); - } else { - throw new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase("Please make sure you have 'openssl' extension installed") - ); + $charsMaxKey = mb_strlen($chars) - 1; + for ($i = 0; $i < $length; $i++) { + $str .= $chars[self::getRandomNumber(0, $charsMaxKey)]; } return $str; @@ -70,44 +56,28 @@ public function getRandomString($length, $chars = null) * @param $min [optional] * @param $max [optional] * @return int A random integer value between min (or 0) and max - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ public static function getRandomNumber($min = 0, $max = null) { if (null === $max) { $max = mt_getrandmax(); } - $range = $max - $min + 1; - $offset = 0; - - if (function_exists('openssl_random_pseudo_bytes')) { - // use openssl lib if it is installed - $bytes = openssl_random_pseudo_bytes(PHP_INT_SIZE); - $hex = bin2hex($bytes); // hex() doubles the length of the string - $offset = abs(hexdec($hex) % $range); // random integer from 0 to $range - } elseif ($fp = @fopen('/dev/urandom', 'rb')) { - // attempt to use /dev/urandom if it exists but openssl isn't available - $bytes = @fread($fp, PHP_INT_SIZE); - $hex = bin2hex($bytes); // hex() doubles the length of the string - $offset = abs(hexdec($hex) % $range); // random integer from 0 to $range - fclose($fp); - } else { - throw new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase("Please make sure you have 'openssl' extension installed") - ); + if ($max < $min) { + throw new LocalizedException(new Phrase('Invalid range given.')); } - return $min + $offset; // random integer from $min to $max + return random_int($min, $max); } /** - * Generate a hash from unique ID + * Generate a hash from unique ID. * * @param string $prefix * @return string */ public function getUniqueHash($prefix = '') { - return $prefix . md5(uniqid(microtime() . self::getRandomNumber(), true)); + return $prefix . $this->getRandomString(64); } } From f8c2e49ef507b1fa6191d0dd86832253ea89b696 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Mon, 16 Apr 2018 17:50:02 +0300 Subject: [PATCH 009/529] MAGETWO-72982: Reset Password --- .../Controller/Account/CreatePasswordTest.php | 233 -- .../Account/ResetPasswordPostTest.php | 379 ---- .../Test/Unit/Model/AccountManagementTest.php | 1983 ----------------- 3 files changed, 2595 deletions(-) delete mode 100644 app/code/Magento/Customer/Test/Unit/Controller/Account/CreatePasswordTest.php delete mode 100644 app/code/Magento/Customer/Test/Unit/Controller/Account/ResetPasswordPostTest.php delete mode 100644 app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/CreatePasswordTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/CreatePasswordTest.php deleted file mode 100644 index 77f41024ba02f..0000000000000 --- a/app/code/Magento/Customer/Test/Unit/Controller/Account/CreatePasswordTest.php +++ /dev/null @@ -1,233 +0,0 @@ -sessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) - ->disableOriginalConstructor() - ->setMethods(['setRpToken', 'setRpCustomerId', 'getRpToken', 'getRpCustomerId']) - ->getMock(); - $this->pageFactoryMock = $this->getMockBuilder(\Magento\Framework\View\Result\PageFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->accountManagementMock = $this->getMockBuilder(\Magento\Customer\Api\AccountManagementInterface::class) - ->getMockForAbstractClass(); - $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) - ->getMockForAbstractClass(); - $this->redirectFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\RedirectFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class) - ->getMockForAbstractClass(); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->model = $this->objectManagerHelper->getObject( - \Magento\Customer\Controller\Account\CreatePassword::class, - [ - 'customerSession' => $this->sessionMock, - 'resultPageFactory' => $this->pageFactoryMock, - 'accountManagement' => $this->accountManagementMock, - 'request' => $this->requestMock, - 'resultRedirectFactory' => $this->redirectFactoryMock, - 'messageManager' => $this->messageManagerMock, - ] - ); - } - - public function testExecuteWithLink() - { - $token = 'token'; - $customerId = '11'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getParam') - ->willReturnMap( - [ - ['token', null, $token], - ['id', null, $customerId], - ] - ); - - $this->accountManagementMock->expects($this->once()) - ->method('validateResetPasswordLinkToken') - ->with($customerId, $token) - ->willReturn(true); - - $this->sessionMock->expects($this->once()) - ->method('setRpToken') - ->with($token); - $this->sessionMock->expects($this->once()) - ->method('setRpCustomerId') - ->with($customerId); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createpassword', []) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - public function testExecuteWithSession() - { - $token = 'token'; - $customerId = '11'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getParam') - ->willReturnMap( - [ - ['token', null, null], - ['id', null, $customerId], - ] - ); - - $this->sessionMock->expects($this->once()) - ->method('getRpToken') - ->willReturn($token); - $this->sessionMock->expects($this->once()) - ->method('getRpCustomerId') - ->willReturn($customerId); - - $this->accountManagementMock->expects($this->once()) - ->method('validateResetPasswordLinkToken') - ->with($customerId, $token) - ->willReturn(true); - - /** @var \Magento\Framework\View\Result\Page|\PHPUnit_Framework_MockObject_MockObject $pageMock */ - $pageMock = $this->getMockBuilder(\Magento\Framework\View\Result\Page::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->pageFactoryMock->expects($this->once()) - ->method('create') - ->with(false, []) - ->willReturn($pageMock); - - /** @var \Magento\Framework\View\Layout|\PHPUnit_Framework_MockObject_MockObject $layoutMock */ - $layoutMock = $this->getMockBuilder(\Magento\Framework\View\Layout::class) - ->disableOriginalConstructor() - ->getMock(); - - $pageMock->expects($this->once()) - ->method('getLayout') - ->willReturn($layoutMock); - - /** @var \Magento\Customer\Block\Account\Resetpassword|\PHPUnit_Framework_MockObject_MockObject $layoutMock */ - $blockMock = $this->getMockBuilder(\Magento\Customer\Block\Account\Resetpassword::class) - ->disableOriginalConstructor() - ->setMethods(['setCustomerId', 'setResetPasswordLinkToken']) - ->getMock(); - - $layoutMock->expects($this->once()) - ->method('getBlock') - ->with('resetPassword') - ->willReturn($blockMock); - - $blockMock->expects($this->once()) - ->method('setCustomerId') - ->with($customerId) - ->willReturnSelf(); - $blockMock->expects($this->once()) - ->method('setResetPasswordLinkToken') - ->with($token) - ->willReturnSelf(); - - $this->assertEquals($pageMock, $this->model->execute()); - } - - public function testExecuteWithException() - { - $token = 'token'; - $customerId = '11'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getParam') - ->willReturnMap( - [ - ['token', null, $token], - ['id', null, null], - ] - ); - - $this->sessionMock->expects($this->once()) - ->method('getRpToken') - ->willReturn($token); - $this->sessionMock->expects($this->once()) - ->method('getRpCustomerId') - ->willReturn($customerId); - - $this->accountManagementMock->expects($this->once()) - ->method('validateResetPasswordLinkToken') - ->with($customerId, $token) - ->willThrowException(new \Exception('Exception.')); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('Your password reset link has expired.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/forgotpassword', []) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } -} diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Account/ResetPasswordPostTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Account/ResetPasswordPostTest.php deleted file mode 100644 index b79ad008e5e44..0000000000000 --- a/app/code/Magento/Customer/Test/Unit/Controller/Account/ResetPasswordPostTest.php +++ /dev/null @@ -1,379 +0,0 @@ -sessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) - ->disableOriginalConstructor() - ->setMethods(['unsRpToken', 'unsRpCustomerId']) - ->getMock(); - $this->pageFactoryMock = $this->getMockBuilder(\Magento\Framework\View\Result\PageFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->accountManagementMock = $this->getMockBuilder(\Magento\Customer\Api\AccountManagementInterface::class) - ->getMockForAbstractClass(); - $this->customerRepositoryMock = $this->getMockBuilder(\Magento\Customer\Api\CustomerRepositoryInterface::class) - ->getMockForAbstractClass(); - $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) - ->setMethods(['getQuery', 'getPost']) - ->getMockForAbstractClass(); - $this->redirectFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\RedirectFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class) - ->getMockForAbstractClass(); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->model = $this->objectManagerHelper->getObject( - \Magento\Customer\Controller\Account\ResetPasswordPost::class, - [ - 'customerSession' => $this->sessionMock, - 'resultPageFactory' => $this->pageFactoryMock, - 'accountManagement' => $this->accountManagementMock, - 'customerRepository' => $this->customerRepositoryMock, - 'request' => $this->requestMock, - 'resultRedirectFactory' => $this->redirectFactoryMock, - 'messageManager' => $this->messageManagerMock, - ] - ); - } - - public function testExecute() - { - $token = 'token'; - $customerId = '11'; - $password = 'password'; - $passwordConfirmation = 'password'; - $email = 'email@email.com'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */ - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - - $this->customerRepositoryMock->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customerMock); - - $customerMock->expects($this->once()) - ->method('getEmail') - ->willReturn($email); - - $this->accountManagementMock->expects($this->once()) - ->method('resetPassword') - ->with($email, $token, $password) - ->willReturn(true); - - $this->sessionMock->expects($this->once()) - ->method('unsRpToken'); - $this->sessionMock->expects($this->once()) - ->method('unsRpCustomerId'); - - $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') - ->with(__('You updated your password.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/login', []) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - public function testExecuteWithException() - { - $token = 'token'; - $customerId = '11'; - $password = 'password'; - $passwordConfirmation = 'password'; - $email = 'email@email.com'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */ - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - - $this->customerRepositoryMock->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customerMock); - - $customerMock->expects($this->once()) - ->method('getEmail') - ->willReturn($email); - - $this->accountManagementMock->expects($this->once()) - ->method('resetPassword') - ->with($email, $token, $password) - ->willThrowException(new \Exception('Exception.')); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('Something went wrong while saving the new password.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createPassword', ['id' => $customerId, 'token' => $token]) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - /** - * Test for InputException - */ - public function testExecuteWithInputException() - { - $token = 'token'; - $customerId = '11'; - $password = 'password'; - $passwordConfirmation = 'password'; - $email = 'email@email.com'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - /** @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject $customerMock */ - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - - $this->customerRepositoryMock->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customerMock); - - $customerMock->expects($this->once()) - ->method('getEmail') - ->willReturn($email); - - $this->accountManagementMock->expects($this->once()) - ->method('resetPassword') - ->with($email, $token, $password) - ->willThrowException(new \Magento\Framework\Exception\InputException(__('InputException.'))); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('InputException.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createPassword', ['id' => $customerId, 'token' => $token]) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - public function testExecuteWithWrongConfirmation() - { - $token = 'token'; - $customerId = '11'; - $password = 'password'; - $passwordConfirmation = 'wrong_password'; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('New Password and Confirm New Password values didn\'t match.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createPassword', ['id' => $customerId, 'token' => $token]) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } - - public function testExecuteWithEmptyPassword() - { - $token = 'token'; - $customerId = '11'; - $password = ''; - $passwordConfirmation = ''; - - $this->requestMock->expects($this->exactly(2)) - ->method('getQuery') - ->willReturnMap( - [ - ['token', $token], - ['id', $customerId], - ] - ); - $this->requestMock->expects($this->exactly(2)) - ->method('getPost') - ->willReturnMap( - [ - ['password', $password], - ['password_confirmation', $passwordConfirmation], - ] - ); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with(__('Please enter a new password.')) - ->willReturnSelf(); - - /** @var Redirect|\PHPUnit_Framework_MockObject_MockObject $redirectMock */ - $redirectMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->redirectFactoryMock->expects($this->once()) - ->method('create') - ->with([]) - ->willReturn($redirectMock); - - $redirectMock->expects($this->once()) - ->method('setPath') - ->with('*/*/createPassword', ['id' => $customerId, 'token' => $token]) - ->willReturnSelf(); - - $this->assertEquals($redirectMock, $this->model->execute()); - } -} diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php deleted file mode 100644 index 9d32065c6b64b..0000000000000 --- a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php +++ /dev/null @@ -1,1983 +0,0 @@ -customerFactory = $this->createPartialMock(\Magento\Customer\Model\CustomerFactory::class, ['create']); - $this->manager = $this->createMock(\Magento\Framework\Event\ManagerInterface::class); - $this->store = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->disableOriginalConstructor() - ->getMock(); - $this->storeManager = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); - $this->random = $this->createMock(\Magento\Framework\Math\Random::class); - $this->validator = $this->createMock(\Magento\Customer\Model\Metadata\Validator::class); - $this->validationResultsInterfaceFactory = $this->createMock( - \Magento\Customer\Api\Data\ValidationResultsInterfaceFactory::class - ); - $this->addressRepository = $this->createMock(\Magento\Customer\Api\AddressRepositoryInterface::class); - $this->customerMetadata = $this->createMock(\Magento\Customer\Api\CustomerMetadataInterface::class); - $this->customerRegistry = $this->createMock(\Magento\Customer\Model\CustomerRegistry::class); - $this->logger = $this->createMock(\Psr\Log\LoggerInterface::class); - $this->encryptor = $this->getMockBuilder(\Magento\Framework\Encryption\EncryptorInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->share = $this->createMock(\Magento\Customer\Model\Config\Share::class); - $this->string = $this->createMock(\Magento\Framework\Stdlib\StringUtils::class); - $this->customerRepository = $this->createMock(\Magento\Customer\Api\CustomerRepositoryInterface::class); - $this->scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->transportBuilder = $this->createMock(\Magento\Framework\Mail\Template\TransportBuilder::class); - $this->dataObjectProcessor = $this->createMock(\Magento\Framework\Reflection\DataObjectProcessor::class); - $this->registry = $this->createMock(\Magento\Framework\Registry::class); - $this->customerViewHelper = $this->createMock(\Magento\Customer\Helper\View::class); - $this->dateTime = $this->createMock(\Magento\Framework\Stdlib\DateTime::class); - $this->customer = $this->createMock(\Magento\Customer\Model\Customer::class); - $this->objectFactory = $this->createMock(\Magento\Framework\DataObjectFactory::class); - $this->extensibleDataObjectConverter = $this->createMock( - \Magento\Framework\Api\ExtensibleDataObjectConverter::class - ); - $this->authenticationMock = $this->getMockBuilder(AuthenticationInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->emailNotificationMock = $this->getMockBuilder(EmailNotificationInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'addData', 'setRpTokenCreatedAt', 'setData', 'getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - - $this->visitorCollectionFactory = $this->getMockBuilder( - \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->sessionManager = $this->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->saveHandler = $this->getMockBuilder(\Magento\Framework\Session\SaveHandlerInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->dateTimeFactory = $this->createMock(DateTimeFactory::class); - $this->accountConfirmation = $this->createMock(AccountConfirmation::class); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->accountManagement = $this->objectManagerHelper->getObject( - \Magento\Customer\Model\AccountManagement::class, - [ - 'customerFactory' => $this->customerFactory, - 'eventManager' => $this->manager, - 'storeManager' => $this->storeManager, - 'mathRandom' => $this->random, - 'validator' => $this->validator, - 'validationResultsDataFactory' => $this->validationResultsInterfaceFactory, - 'addressRepository' => $this->addressRepository, - 'customerMetadataService' => $this->customerMetadata, - 'customerRegistry' => $this->customerRegistry, - 'logger' => $this->logger, - 'encryptor' => $this->encryptor, - 'configShare' => $this->share, - 'stringHelper' => $this->string, - 'customerRepository' => $this->customerRepository, - 'scopeConfig' => $this->scopeConfig, - 'transportBuilder' => $this->transportBuilder, - 'dataProcessor' => $this->dataObjectProcessor, - 'registry' => $this->registry, - 'customerViewHelper' => $this->customerViewHelper, - 'dateTime' => $this->dateTime, - 'customerModel' => $this->customer, - 'objectFactory' => $this->objectFactory, - 'extensibleDataObjectConverter' => $this->extensibleDataObjectConverter, - 'dateTimeFactory' => $this->dateTimeFactory, - 'accountConfirmation' => $this->accountConfirmation, - 'sessionManager' => $this->sessionManager, - 'saveHandler' => $this->saveHandler, - 'visitorCollectionFactory' => $this->visitorCollectionFactory, - ] - ); - $reflection = new \ReflectionClass(get_class($this->accountManagement)); - $reflectionProperty = $reflection->getProperty('authentication'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->accountManagement, $this->authenticationMock); - $reflectionProperty = $reflection->getProperty('emailNotification'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->accountManagement, $this->emailNotificationMock); - } - - /** - * @expectedException \Magento\Framework\Exception\InputException - */ - public function testCreateAccountWithPasswordHashWithExistingCustomer() - { - $websiteId = 1; - $storeId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->once()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->once()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager - ->expects($this->once()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->accountManagement->createAccountWithPasswordHash($customer, $hash); - } - - /** - * @expectedException \Magento\Framework\Exception\State\InputMismatchException - */ - public function testCreateAccountWithPasswordHashWithCustomerWithoutStoreId() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer - ->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer - ->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $exception = new \Magento\Framework\Exception\AlreadyExistsException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customer, $hash) - ->willThrowException($exception); - - $this->accountManagement->createAccountWithPasswordHash($customer, $hash); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountWithPasswordHashWithLocalizedException() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer - ->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer - ->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $exception = new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customer, $hash) - ->willThrowException($exception); - - $this->accountManagement->createAccountWithPasswordHash($customer, $hash); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountWithPasswordHashWithAddressException() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->once()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer - ->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer - ->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share - ->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customer, $hash) - ->willReturn($customer); - $exception = new \Magento\Framework\Exception\InputException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->addressRepository - ->expects($this->atLeastOnce()) - ->method('save') - ->with($address) - ->willThrowException($exception); - $this->customerRepository - ->expects($this->once()) - ->method('delete') - ->with($customer); - - $this->accountManagement->createAccountWithPasswordHash($customer, $hash); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountWithPasswordHashWithNewCustomerAndLocalizedException() - { - $storeId = 1; - $storeName = 'store_name'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - - $customerMock->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn(null); - $customerMock->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customerMock->expects($this->once()) - ->method('setCreatedIn') - ->with($storeName) - ->willReturnSelf(); - $customerMock->expects($this->once()) - ->method('getAddresses') - ->willReturn([]); - $customerMock->expects($this->once()) - ->method('setAddresses') - ->with(null) - ->willReturnSelf(); - - $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->disableOriginalConstructor() - ->getMock(); - - $storeMock->expects($this->once()) - ->method('getName') - ->willReturn($storeName); - - $this->storeManager->expects($this->exactly(2)) - ->method('getStore') - ->with($storeId) - ->willReturn($storeMock); - $exception = new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customerMock, $hash) - ->willThrowException($exception); - - $this->accountManagement->createAccountWithPasswordHash($customerMock, $hash); - } - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testCreateAccountWithoutPassword() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $newLinkToken = '2jh43j5h2345jh23lh452h345hfuzasd96ofu'; - - $datetime = $this->prepareDateTimeFactory(); - - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->atLeastOnce()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->atLeastOnce()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->customerRepository->expects($this->atLeastOnce()) - ->method('save') - ->willReturn($customer); - $this->addressRepository->expects($this->atLeastOnce()) - ->method('save') - ->with($address); - $this->customerRepository->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customer); - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($newLinkToken); - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->any()) - ->method('setRpToken') - ->with($newLinkToken); - $customerSecure->expects($this->any()) - ->method('setRpTokenCreatedAt') - ->with($datetime) - ->willReturnSelf(); - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn(null); - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($customerSecure); - $this->emailNotificationMock->expects($this->once()) - ->method('newAccount') - ->willReturnSelf(); - - $this->accountManagement->createAccount($customer); - } - - /** - * Data provider for testCreateAccountWithPasswordInputException test - * - * @return array - */ - public function dataProviderCheckPasswordStrength() - { - return [ - [ - 'testNumber' => 1, - 'password' => 'qwer', - 'minPasswordLength' => 5, - 'minCharacterSetsNum' => 1 - ], - [ - 'testNumber' => 2, - 'password' => 'wrfewqedf1', - 'minPasswordLength' => 5, - 'minCharacterSetsNum' => 3 - ] - ]; - } - - /** - * @param int $testNumber - * @param string $password - * @param int $minPasswordLength - * @param int $minCharacterSetsNum - * @dataProvider dataProviderCheckPasswordStrength - */ - public function testCreateAccountWithPasswordInputException( - $testNumber, - $password, - $minPasswordLength, - $minCharacterSetsNum - ) { - $this->scopeConfig->expects($this->any()) - ->method('getValue') - ->will( - $this->returnValueMap( - [ - [ - AccountManagement::XML_PATH_MINIMUM_PASSWORD_LENGTH, - 'default', - null, - $minPasswordLength, - ], - [ - AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER, - 'default', - null, - $minCharacterSetsNum], - ] - ) - ); - - $this->string->expects($this->any()) - ->method('strlen') - ->with($password) - ->willReturn(iconv_strlen($password, 'UTF-8')); - - if ($testNumber == 1) { - $this->expectException( - \Magento\Framework\Exception\InputException::class, - 'Please enter a password with at least ' . $minPasswordLength . ' characters.' - ); - } - - if ($testNumber == 2) { - $this->expectException( - \Magento\Framework\Exception\InputException::class, - 'Minimum of different classes of characters in password is ' . $minCharacterSetsNum . - '. Classes of characters: Lower Case, Upper Case, Digits, Special Characters.' - ); - } - - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $this->accountManagement->createAccount($customer, $password); - } - - public function testCreateAccountInputExceptionExtraLongPassword() - { - $password = '257*chars*************************************************************************************' - . '****************************************************************************************************' - . '***************************************************************'; - - $this->string->expects($this->any()) - ->method('strlen') - ->with($password) - ->willReturn(iconv_strlen($password, 'UTF-8')); - - $this->expectException( - \Magento\Framework\Exception\InputException::class, - 'Please enter a password with at most 256 characters.' - ); - - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $this->accountManagement->createAccount($customer, $password); - } - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testCreateAccountWithPassword() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - $newLinkToken = '2jh43j5h2345jh23lh452h345hfuzasd96ofu'; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - $password = 'wrfewqedf1'; - $minPasswordLength = 5; - $minCharacterSetsNum = 2; - - $datetime = $this->prepareDateTimeFactory(); - - $this->scopeConfig->expects($this->any()) - ->method('getValue') - ->willReturnMap( - [ - [ - AccountManagement::XML_PATH_MINIMUM_PASSWORD_LENGTH, - 'default', - null, - $minPasswordLength, - ], - [ - AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER, - 'default', - null, - $minCharacterSetsNum], - [ - AccountManagement::XML_PATH_REGISTER_EMAIL_TEMPLATE, - ScopeInterface::SCOPE_STORE, - $defaultStoreId, - $templateIdentifier, - ], - [ - AccountManagement::XML_PATH_REGISTER_EMAIL_IDENTITY, - ScopeInterface::SCOPE_STORE, - 1, - $sender - ] - ] - ); - $this->string->expects($this->any()) - ->method('strlen') - ->with($password) - ->willReturn(iconv_strlen($password, 'UTF-8')); - $this->encryptor->expects($this->once()) - ->method('getHash') - ->with($password, true) - ->willReturn($hash); - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId); - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->getMockBuilder(\Magento\Store\Model\Website::class)->disableOriginalConstructor()->getMock(); - $website->expects($this->atLeastOnce()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->atLeastOnce()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->customerRepository->expects($this->atLeastOnce()) - ->method('save') - ->willReturn($customer); - $this->addressRepository->expects($this->atLeastOnce()) - ->method('save') - ->with($address); - $this->customerRepository->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customer); - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($newLinkToken); - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->any()) - ->method('setRpToken') - ->with($newLinkToken); - $customerSecure->expects($this->any()) - ->method('setRpTokenCreatedAt') - ->with($datetime) - ->willReturnSelf(); - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn($hash); - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($customerSecure); - $this->emailNotificationMock->expects($this->once()) - ->method('newAccount') - ->willReturnSelf(); - - $this->accountManagement->createAccount($customer, $password); - } - - /** - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testSendPasswordReminderEmail() - { - $customerId = 1; - $customerStoreId = 2; - $customerEmail = 'email@email.com'; - $customerData = ['key' => 'value']; - $customerName = 'Customer Name'; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMock(); - $customer->expects($this->any()) - ->method('getStoreId') - ->willReturn($customerStoreId); - $customer->expects($this->any()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->any()) - ->method('getEmail') - ->willReturn($customerEmail); - - $this->store->expects($this->any()) - ->method('getId') - ->willReturn($customerStoreId); - - $this->storeManager->expects($this->at(0)) - ->method('getStore') - ->willReturn($this->store); - - $this->storeManager->expects($this->at(1)) - ->method('getStore') - ->with($customerStoreId) - ->willReturn($this->store); - - $this->customerRegistry->expects($this->once()) - ->method('retrieveSecureData') - ->with($customerId) - ->willReturn($this->customerSecure); - - $this->dataObjectProcessor->expects($this->once()) - ->method('buildOutputDataArray') - ->with($customer, \Magento\Customer\Api\Data\CustomerInterface::class) - ->willReturn($customerData); - - $this->customerViewHelper->expects($this->any()) - ->method('getCustomerName') - ->with($customer) - ->willReturn($customerName); - - $this->customerSecure->expects($this->once()) - ->method('addData') - ->with($customerData) - ->willReturnSelf(); - $this->customerSecure->expects($this->once()) - ->method('setData') - ->with('name', $customerName) - ->willReturnSelf(); - - $this->scopeConfig->expects($this->at(0)) - ->method('getValue') - ->with(AccountManagement::XML_PATH_REMIND_EMAIL_TEMPLATE, ScopeInterface::SCOPE_STORE, $customerStoreId) - ->willReturn($templateIdentifier); - $this->scopeConfig->expects($this->at(1)) - ->method('getValue') - ->with(AccountManagement::XML_PATH_FORGOT_EMAIL_IDENTITY, ScopeInterface::SCOPE_STORE, $customerStoreId) - ->willReturn($sender); - - $transport = $this->getMockBuilder(\Magento\Framework\Mail\TransportInterface::class) - ->getMock(); - - $this->transportBuilder->expects($this->once()) - ->method('setTemplateIdentifier') - ->with($templateIdentifier) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('setTemplateOptions') - ->with(['area' => Area::AREA_FRONTEND, 'store' => $customerStoreId]) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('setTemplateVars') - ->with(['customer' => $this->customerSecure, 'store' => $this->store]) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('setFrom') - ->with($sender) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('addTo') - ->with($customerEmail, $customerName) - ->willReturnSelf(); - $this->transportBuilder->expects($this->once()) - ->method('getTransport') - ->willReturn($transport); - - $transport->expects($this->once()) - ->method('sendMessage'); - - $this->assertEquals($this->accountManagement, $this->accountManagement->sendPasswordReminderEmail($customer)); - } - - /** - * @param string $email - * @param string $templateIdentifier - * @param string $sender - * @param int $storeId - * @param int $customerId - * @param string $hash - */ - protected function prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash) - { - $websiteId = 1; - - $datetime = $this->prepareDateTimeFactory(); - - $customerData = ['key' => 'value']; - $customerName = 'Customer Name'; - - $this->store->expects($this->once()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $this->store->expects($this->any()) - ->method('getId') - ->willReturn($storeId); - - $this->storeManager->expects($this->any()) - ->method('getStore') - ->willReturn($this->store); - - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMock(); - $customer->expects($this->any()) - ->method('getEmail') - ->willReturn($email); - $customer->expects($this->any()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->any()) - ->method('getStoreId') - ->willReturn($storeId); - - $this->customerRepository->expects($this->once()) - ->method('get') - ->with($email, $websiteId) - ->willReturn($customer); - $this->customerRepository->expects($this->once()) - ->method('save') - ->with($customer) - ->willReturnSelf(); - - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($hash); - - $this->customerViewHelper->expects($this->any()) - ->method('getCustomerName') - ->with($customer) - ->willReturn($customerName); - - $this->customerSecure->expects($this->any()) - ->method('setRpToken') - ->with($hash) - ->willReturnSelf(); - $this->customerSecure->expects($this->any()) - ->method('setRpTokenCreatedAt') - ->with($datetime) - ->willReturnSelf(); - $this->customerSecure->expects($this->any()) - ->method('addData') - ->with($customerData) - ->willReturnSelf(); - $this->customerSecure->expects($this->any()) - ->method('setData') - ->with('name', $customerName) - ->willReturnSelf(); - - $this->customerRegistry->expects($this->any()) - ->method('retrieveSecureData') - ->with($customerId) - ->willReturn($this->customerSecure); - - $this->dataObjectProcessor->expects($this->any()) - ->method('buildOutputDataArray') - ->with($customer, \Magento\Customer\Api\Data\CustomerInterface::class) - ->willReturn($customerData); - - $this->prepareEmailSend($email, $templateIdentifier, $sender, $storeId, $customerName); - } - - /** - * @param $email - * @param $templateIdentifier - * @param $sender - * @param $storeId - * @param $customerName - */ - protected function prepareEmailSend($email, $templateIdentifier, $sender, $storeId, $customerName) - { - $transport = $this->getMockBuilder(\Magento\Framework\Mail\TransportInterface::class) - ->getMock(); - - $this->transportBuilder->expects($this->any()) - ->method('setTemplateIdentifier') - ->with($templateIdentifier) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('setTemplateOptions') - ->with(['area' => Area::AREA_FRONTEND, 'store' => $storeId]) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('setTemplateVars') - ->with(['customer' => $this->customerSecure, 'store' => $this->store]) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('setFrom') - ->with($sender) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('addTo') - ->with($email, $customerName) - ->willReturnSelf(); - $this->transportBuilder->expects($this->any()) - ->method('getTransport') - ->willReturn($transport); - - $transport->expects($this->any()) - ->method('sendMessage'); - } - - public function testInitiatePasswordResetEmailReminder() - { - $customerId = 1; - - $email = 'test@example.com'; - $template = AccountManagement::EMAIL_REMINDER; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - - $storeId = 1; - - mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX); - $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true)); - - $this->emailNotificationMock->expects($this->once()) - ->method('passwordReminder') - ->willReturnSelf(); - - $this->prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash); - - $this->assertTrue($this->accountManagement->initiatePasswordReset($email, $template)); - } - - public function testInitiatePasswordResetEmailReset() - { - $storeId = 1; - $customerId = 1; - - $email = 'test@example.com'; - $template = AccountManagement::EMAIL_RESET; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - - mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX); - $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true)); - - $this->emailNotificationMock->expects($this->once()) - ->method('passwordResetConfirmation') - ->willReturnSelf(); - - $this->prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash); - - $this->assertTrue($this->accountManagement->initiatePasswordReset($email, $template)); - } - - public function testInitiatePasswordResetNoTemplate() - { - $storeId = 1; - $customerId = 1; - - $email = 'test@example.com'; - $template = null; - $templateIdentifier = 'Template Identifier'; - $sender = 'Sender'; - - mt_srand(mt_rand() + (100000000 * (float)microtime()) % PHP_INT_MAX); - $hash = md5(uniqid(microtime() . mt_rand(0, mt_getrandmax()), true)); - - $this->prepareInitiatePasswordReset($email, $templateIdentifier, $sender, $storeId, $customerId, $hash); - - $this->expectException(\Magento\Framework\Exception\InputException::class); - $this->expectExceptionMessage( - 'Invalid value of "" provided for the template field. Possible values: email_reminder or email_reset.' - ); - $this->accountManagement->initiatePasswordReset($email, $template); - } - - /** - * @expectedException \Magento\Framework\Exception\InputException - * @expectedExceptionMessage Invalid value of "" provided for the customerId field - */ - public function testValidateResetPasswordTokenBadCustomerId() - { - $this->accountManagement->validateResetPasswordLinkToken(null, ''); - } - - /** - * @expectedException \Magento\Framework\Exception\InputException - * @expectedExceptionMessage resetPasswordLinkToken is a required field - */ - public function testValidateResetPasswordTokenBadResetPasswordLinkToken() - { - $this->accountManagement->validateResetPasswordLinkToken(22, null); - } - - /** - * @expectedException \Magento\Framework\Exception\State\InputMismatchException - * @expectedExceptionMessage Reset password token mismatch - */ - public function testValidateResetPasswordTokenTokenMismatch() - { - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($this->customerSecure); - - $this->accountManagement->validateResetPasswordLinkToken(22, 'newStringToken'); - } - - /** - * @expectedException \Magento\Framework\Exception\State\ExpiredException - * @expectedExceptionMessage Reset password token expired - */ - public function testValidateResetPasswordTokenTokenExpired() - { - $this->reInitModel(); - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($this->customerSecure); - - $this->accountManagement->validateResetPasswordLinkToken(22, 'newStringToken'); - } - - /** - * return bool - */ - public function testValidateResetPasswordToken() - { - $this->reInitModel(); - - $this->customer - ->expects($this->once()) - ->method('getResetPasswordLinkExpirationPeriod') - ->willReturn(100000); - - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($this->customerSecure); - - $this->assertTrue($this->accountManagement->validateResetPasswordLinkToken(22, 'newStringToken')); - } - - /** - * reInit $this->accountManagement object - */ - private function reInitModel() - { - $this->customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->disableOriginalConstructor() - ->setMethods( - [ - 'getRpToken', - 'getRpTokenCreatedAt', - 'getPasswordHash', - 'setPasswordHash', - 'setRpToken', - 'setRpTokenCreatedAt', - ] - ) - ->getMock(); - - $this->customerSecure - ->expects($this->any()) - ->method('getRpToken') - ->willReturn('newStringToken'); - - $pastDateTime = '2016-10-25 00:00:00'; - - $this->customerSecure - ->expects($this->any()) - ->method('getRpTokenCreatedAt') - ->willReturn($pastDateTime); - - $this->customer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) - ->disableOriginalConstructor() - ->setMethods(['getResetPasswordLinkExpirationPeriod']) - ->getMock(); - - $this->prepareDateTimeFactory(); - - $this->sessionManager = $this->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) - ->disableOriginalConstructor() - ->setMethods(['destroy', 'start', 'writeClose']) - ->getMockForAbstractClass(); - $this->visitorCollectionFactory = $this->getMockBuilder( - \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class - ) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->saveHandler = $this->getMockBuilder(\Magento\Framework\Session\SaveHandlerInterface::class) - ->disableOriginalConstructor() - ->setMethods(['destroy']) - ->getMockForAbstractClass(); - - $dateTime = '2017-10-25 18:57:08'; - $timestamp = '1508983028'; - $dateTimeMock = $this->createMock(\DateTime::class); - $dateTimeMock->expects($this->any()) - ->method('format') - ->with(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT) - ->willReturn($dateTime); - - $dateTimeMock - ->expects($this->any()) - ->method('getTimestamp') - ->willReturn($timestamp); - - $dateTimeMock - ->expects($this->any()) - ->method('setTimestamp') - ->willReturnSelf(); - - $dateTimeFactory = $this->createMock(DateTimeFactory::class); - $dateTimeFactory->expects($this->any())->method('create')->willReturn($dateTimeMock); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->accountManagement = $this->objectManagerHelper->getObject( - \Magento\Customer\Model\AccountManagement::class, - [ - 'customerFactory' => $this->customerFactory, - 'customerRegistry' => $this->customerRegistry, - 'customerRepository' => $this->customerRepository, - 'customerModel' => $this->customer, - 'dateTimeFactory' => $dateTimeFactory, - 'stringHelper' => $this->string, - 'scopeConfig' => $this->scopeConfig, - 'sessionManager' => $this->sessionManager, - 'visitorCollectionFactory' => $this->visitorCollectionFactory, - 'saveHandler' => $this->saveHandler, - 'encryptor' => $this->encryptor, - 'dataProcessor' => $this->dataObjectProcessor, - 'storeManager' => $this->storeManager, - 'transportBuilder' => $this->transportBuilder, - ] - ); - $reflection = new \ReflectionClass(get_class($this->accountManagement)); - $reflectionProperty = $reflection->getProperty('authentication'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->accountManagement, $this->authenticationMock); - } - - /** - * @return void - */ - public function testChangePassword() - { - $customerId = 7; - $email = 'test@example.com'; - $currentPassword = '1234567'; - $newPassword = 'abcdefg'; - $passwordHash = '1a2b3f4c'; - - $this->reInitModel(); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMock(); - $customer->expects($this->any()) - ->method('getId') - ->willReturn($customerId); - - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($email) - ->willReturn($customer); - - $this->authenticationMock->expects($this->once()) - ->method('authenticate'); - - $this->customerSecure->expects($this->once()) - ->method('setRpToken') - ->with(null); - $this->customerSecure->expects($this->once()) - ->method('setRpTokenCreatedAt') - ->willReturnSelf(); - $this->customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn($passwordHash); - - $this->customerRegistry->expects($this->any()) - ->method('retrieveSecureData') - ->with($customerId) - ->willReturn($this->customerSecure); - - $this->scopeConfig->expects($this->any()) - ->method('getValue') - ->willReturnMap( - [ - [ - AccountManagement::XML_PATH_MINIMUM_PASSWORD_LENGTH, - 'default', - null, - 7, - ], - [ - AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER, - 'default', - null, - 1 - ], - ] - ); - $this->string->expects($this->any()) - ->method('strlen') - ->with($newPassword) - ->willReturn(7); - - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customer); - - $this->sessionManager->expects($this->atLeastOnce())->method('start'); - $this->sessionManager->expects($this->atLeastOnce())->method('writeClose'); - $this->sessionManager->expects($this->atLeastOnce())->method('getSessionId'); - - $visitor = $this->getMockBuilder(\Magento\Customer\Model\Visitor::class) - ->disableOriginalConstructor() - ->setMethods(['getSessionId']) - ->getMock(); - $visitor->expects($this->at(0))->method('getSessionId')->willReturn('session_id_1'); - $visitor->expects($this->at(1))->method('getSessionId')->willReturn('session_id_2'); - $visitorCollection = $this->getMockBuilder( - \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class - ) - ->disableOriginalConstructor()->setMethods(['addFieldToFilter', 'getItems'])->getMock(); - $visitorCollection->expects($this->atLeastOnce())->method('addFieldToFilter')->willReturnSelf(); - $visitorCollection->expects($this->atLeastOnce())->method('getItems')->willReturn([$visitor, $visitor]); - $this->visitorCollectionFactory->expects($this->atLeastOnce())->method('create') - ->willReturn($visitorCollection); - $this->saveHandler->expects($this->at(0))->method('destroy')->with('session_id_1'); - $this->saveHandler->expects($this->at(1))->method('destroy')->with('session_id_2'); - - $this->assertTrue($this->accountManagement->changePassword($email, $currentPassword, $newPassword)); - } - - public function testResetPassword() - { - $customerEmail = 'customer@example.com'; - $customerId = '1'; - $resetToken = 'newStringToken'; - $newPassword = 'new_password'; - - $this->reInitModel(); - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer->expects($this->any())->method('getId')->willReturn($customerId); - $this->customerRepository->expects($this->atLeastOnce())->method('get')->with($customerEmail) - ->willReturn($customer); - $this->customer->expects($this->atLeastOnce())->method('getResetPasswordLinkExpirationPeriod') - ->willReturn(100000); - $this->string->expects($this->any())->method('strlen')->willReturnCallback( - function ($string) { - return strlen($string); - } - ); - $this->customerRegistry->expects($this->atLeastOnce())->method('retrieveSecureData') - ->willReturn($this->customerSecure); - - $this->customerSecure->expects($this->once()) - ->method('setRpToken') - ->with(null); - $this->customerSecure->expects($this->once()) - ->method('setRpTokenCreatedAt') - ->with(null); - $this->customerSecure->expects($this->any()) - ->method('setPasswordHash') - ->willReturn(null); - - $this->sessionManager->expects($this->atLeastOnce())->method('destroy'); - $this->sessionManager->expects($this->atLeastOnce())->method('start'); - $this->sessionManager->expects($this->atLeastOnce())->method('writeClose'); - $this->sessionManager->expects($this->atLeastOnce())->method('getSessionId'); - $visitor = $this->getMockBuilder(\Magento\Customer\Model\Visitor::class) - ->disableOriginalConstructor() - ->setMethods(['getSessionId']) - ->getMock(); - $visitor->expects($this->at(0))->method('getSessionId')->willReturn('session_id_1'); - $visitor->expects($this->at(1))->method('getSessionId')->willReturn('session_id_2'); - $visitorCollection = $this->getMockBuilder( - \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class - ) - ->disableOriginalConstructor()->setMethods(['addFieldToFilter', 'getItems'])->getMock(); - $visitorCollection->expects($this->atLeastOnce())->method('addFieldToFilter')->willReturnSelf(); - $visitorCollection->expects($this->atLeastOnce())->method('getItems')->willReturn([$visitor, $visitor]); - $this->visitorCollectionFactory->expects($this->atLeastOnce())->method('create') - ->willReturn($visitorCollection); - $this->saveHandler->expects($this->at(0))->method('destroy')->with('session_id_1'); - $this->saveHandler->expects($this->at(1))->method('destroy')->with('session_id_2'); - $this->assertTrue($this->accountManagement->resetPassword($customerEmail, $resetToken, $newPassword)); - } - - /** - * @return void - */ - public function testChangePasswordException() - { - $email = 'test@example.com'; - $currentPassword = '1234567'; - $newPassword = 'abcdefg'; - - $exception = new NoSuchEntityException( - new \Magento\Framework\Phrase('Exception message') - ); - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($email) - ->willThrowException($exception); - - $this->expectException( - \Magento\Framework\Exception\InvalidEmailOrPasswordException::class, - 'Invalid login or password.' - ); - - $this->accountManagement->changePassword($email, $currentPassword, $newPassword); - } - - /** - * @return void - */ - public function testAuthenticate() - { - $username = 'login'; - $password = '1234567'; - $passwordHash = '1a2b3f4c'; - - $customerData = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMock(); - - $customerModel = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) - ->disableOriginalConstructor() - ->getMock(); - $customerModel->expects($this->once()) - ->method('updateData') - ->willReturn($customerModel); - - $this->customerRepository - ->expects($this->once()) - ->method('get') - ->with($username) - ->willReturn($customerData); - - $this->authenticationMock->expects($this->once()) - ->method('authenticate'); - - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn($passwordHash); - - $this->customerRegistry->expects($this->any()) - ->method('retrieveSecureData') - ->willReturn($customerSecure); - - $this->customerFactory->expects($this->once()) - ->method('create') - ->willReturn($customerModel); - - $this->manager->expects($this->exactly(2)) - ->method('dispatch') - ->withConsecutive( - [ - 'customer_customer_authenticated', - ['model' => $customerModel, 'password' => $password] - ], - [ - 'customer_data_object_login', ['customer' => $customerData] - ] - ); - - $this->assertEquals($customerData, $this->accountManagement->authenticate($username, $password)); - } - - /** - * @param int $isConfirmationRequired - * @param string|null $confirmation - * @param string $expected - * @dataProvider dataProviderGetConfirmationStatus - */ - public function testGetConfirmationStatus( - $isConfirmationRequired, - $confirmation, - $expected - ) { - $websiteId = 1; - $customerId = 1; - $customerEmail = 'test1@example.com'; - - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $customerMock->expects($this->once()) - ->method('getId') - ->willReturn($customerId); - $customerMock->expects($this->any()) - ->method('getConfirmation') - ->willReturn($confirmation); - $customerMock->expects($this->once()) - ->method('getEmail') - ->willReturn($customerEmail); - $customerMock->expects($this->once()) - ->method('getWebsiteId') - ->willReturn($websiteId); - - $this->accountConfirmation->expects($this->once()) - ->method('isConfirmationRequired') - ->with($websiteId, $customerId, $customerEmail) - ->willReturn($isConfirmationRequired); - - $this->customerRepository->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customerMock); - - $this->assertEquals($expected, $this->accountManagement->getConfirmationStatus($customerId)); - } - - /** - * @return array - */ - public function dataProviderGetConfirmationStatus() - { - return [ - [0, null, AccountManagement::ACCOUNT_CONFIRMATION_NOT_REQUIRED], - [0, null, AccountManagement::ACCOUNT_CONFIRMATION_NOT_REQUIRED], - [0, null, AccountManagement::ACCOUNT_CONFIRMATION_NOT_REQUIRED], - [1, null, AccountManagement::ACCOUNT_CONFIRMED], - [1, 'test', AccountManagement::ACCOUNT_CONFIRMATION_REQUIRED], - ]; - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - */ - public function testCreateAccountWithPasswordHashForGuest() - { - $storeId = 1; - $storeName = 'store_name'; - $websiteId = 1; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $storeMock = $this->getMockBuilder(\Magento\Store\Model\Store::class) - ->disableOriginalConstructor() - ->getMock(); - $storeMock->expects($this->once()) - ->method('getId') - ->willReturn($storeId); - $storeMock->expects($this->once()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $storeMock->expects($this->once()) - ->method('getName') - ->willReturn($storeName); - - $this->storeManager->expects($this->exactly(3)) - ->method('getStore') - ->willReturn($storeMock); - - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - $customerMock->expects($this->exactly(2)) - ->method('getId') - ->willReturn(null); - $customerMock->expects($this->exactly(3)) - ->method('getStoreId') - ->willReturn(null); - $customerMock->expects($this->exactly(2)) - ->method('getWebsiteId') - ->willReturn(null); - $customerMock->expects($this->once()) - ->method('setStoreId') - ->with($storeId) - ->willReturnSelf(); - $customerMock->expects($this->once()) - ->method('setWebsiteId') - ->with($websiteId) - ->willReturnSelf(); - $customerMock->expects($this->once()) - ->method('setCreatedIn') - ->with($storeName) - ->willReturnSelf(); - $customerMock->expects($this->once()) - ->method('getAddresses') - ->willReturn(null); - $customerMock->expects($this->once()) - ->method('setAddresses') - ->with(null) - ->willReturnSelf(); - - $this->customerRepository - ->expects($this->once()) - ->method('save') - ->with($customerMock, $hash) - ->willThrowException(new \Magento\Framework\Exception\LocalizedException(__('Exception message'))); - - $this->accountManagement->createAccountWithPasswordHash($customerMock, $hash); - } - - public function testCreateAccountWithPasswordHashWithCustomerAddresses() - { - $websiteId = 1; - $addressId = 2; - $customerId = null; - $storeId = 1; - $hash = '4nj54lkj5jfi03j49f8bgujfgsd'; - - $this->prepareDateTimeFactory(); - - //Handle store - $store = $this->getMockBuilder(\Magento\Store\Model\Store::class)->disableOriginalConstructor()->getMock(); - $store->expects($this->any()) - ->method('getWebsiteId') - ->willReturn($websiteId); - //Handle address - existing and non-existing. Non-Existing should return null when call getId method - $existingAddress = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $nonExistingAddress = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - //Ensure that existing address is not in use - $this->addressRepository - ->expects($this->atLeastOnce()) - ->method("save") - ->withConsecutive( - [$this->logicalNot($this->identicalTo($existingAddress))], - [$this->identicalTo($nonExistingAddress)] - ); - - $existingAddress - ->expects($this->any()) - ->method("getId") - ->willReturn($addressId); - //Expects that id for existing address should be unset - $existingAddress - ->expects($this->once()) - ->method("setId") - ->with(null); - //Handle Customer calls - $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); - $customer - ->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer - ->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer - ->expects($this->any()) - ->method("getId") - ->willReturn($customerId); - //Return Customer from customer repository - $this->customerRepository - ->expects($this->atLeastOnce()) - ->method('save') - ->willReturn($customer); - $this->customerRepository - ->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customer); - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->once()) - ->method('setRpToken') - ->with($hash); - - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn($hash); - - $this->customerRegistry->expects($this->any()) - ->method('retrieveSecureData') - ->with($customerId) - ->willReturn($customerSecure); - - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($hash); - - $customer - ->expects($this->atLeastOnce()) - ->method('getAddresses') - ->willReturn([$existingAddress, $nonExistingAddress]); - - $this->storeManager - ->expects($this->atLeastOnce()) - ->method('getStore') - ->willReturn($store); - - $this->assertSame($customer, $this->accountManagement->createAccountWithPasswordHash($customer, $hash)); - } - - /** - * @return string - */ - private function prepareDateTimeFactory() - { - $dateTime = '2017-10-25 18:57:08'; - $timestamp = '1508983028'; - $dateTimeMock = $this->createMock(\DateTime::class); - $dateTimeMock->expects($this->any()) - ->method('format') - ->with(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT) - ->willReturn($dateTime); - - $dateTimeMock - ->expects($this->any()) - ->method('getTimestamp') - ->willReturn($timestamp); - - $this->dateTimeFactory - ->expects($this->any()) - ->method('create') - ->willReturn($dateTimeMock); - - return $dateTime; - } - - public function testCreateAccountUnexpectedValueException() - { - $websiteId = 1; - $storeId = null; - $defaultStoreId = 1; - $customerId = 1; - $customerEmail = 'email@email.com'; - $newLinkToken = '2jh43j5h2345jh23lh452h345hfuzasd96ofu'; - $exception = new \UnexpectedValueException('Template file was not found'); - - $datetime = $this->prepareDateTimeFactory(); - - $address = $this->createMock(\Magento\Customer\Api\Data\AddressInterface::class); - $address->expects($this->once()) - ->method('setCustomerId') - ->with($customerId); - $store = $this->createMock(\Magento\Store\Model\Store::class); - $store->expects($this->once()) - ->method('getId') - ->willReturn($defaultStoreId); - $website = $this->createMock(\Magento\Store\Model\Website::class); - $website->expects($this->atLeastOnce()) - ->method('getStoreIds') - ->willReturn([1, 2, 3]); - $website->expects($this->once()) - ->method('getDefaultStore') - ->willReturn($store); - $customer = $this->createMock(\Magento\Customer\Api\Data\CustomerInterface::class); - $customer->expects($this->atLeastOnce()) - ->method('getId') - ->willReturn($customerId); - $customer->expects($this->atLeastOnce()) - ->method('getEmail') - ->willReturn($customerEmail); - $customer->expects($this->atLeastOnce()) - ->method('getWebsiteId') - ->willReturn($websiteId); - $customer->expects($this->atLeastOnce()) - ->method('getStoreId') - ->willReturn($storeId); - $customer->expects($this->once()) - ->method('setStoreId') - ->with($defaultStoreId); - $customer->expects($this->once()) - ->method('getAddresses') - ->willReturn([$address]); - $customer->expects($this->once()) - ->method('setAddresses') - ->with(null); - $this->customerRepository->expects($this->once()) - ->method('get') - ->with($customerEmail) - ->willReturn($customer); - $this->share->expects($this->once()) - ->method('isWebsiteScope') - ->willReturn(true); - $this->storeManager->expects($this->atLeastOnce()) - ->method('getWebsite') - ->with($websiteId) - ->willReturn($website); - $this->customerRepository->expects($this->atLeastOnce()) - ->method('save') - ->willReturn($customer); - $this->addressRepository->expects($this->atLeastOnce()) - ->method('save') - ->with($address); - $this->customerRepository->expects($this->once()) - ->method('getById') - ->with($customerId) - ->willReturn($customer); - $this->random->expects($this->once()) - ->method('getUniqueHash') - ->willReturn($newLinkToken); - $customerSecure = $this->createPartialMock( - \Magento\Customer\Model\Data\CustomerSecure::class, - ['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash'] - ); - $customerSecure->expects($this->any()) - ->method('setRpToken') - ->with($newLinkToken); - $customerSecure->expects($this->any()) - ->method('setRpTokenCreatedAt') - ->with($datetime) - ->willReturnSelf(); - $customerSecure->expects($this->any()) - ->method('getPasswordHash') - ->willReturn(null); - $this->customerRegistry->expects($this->atLeastOnce()) - ->method('retrieveSecureData') - ->willReturn($customerSecure); - $this->emailNotificationMock->expects($this->once()) - ->method('newAccount') - ->willThrowException($exception); - $this->logger->expects($this->once())->method('error')->with($exception); - - $this->accountManagement->createAccount($customer); - } -} From ae65683c9878accbec2050fae1854418dab9cb6c Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Mon, 16 Apr 2018 17:54:57 +0300 Subject: [PATCH 010/529] MAGETWO-72982: Reset Password --- lib/internal/Magento/Framework/Math/Random.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Math/Random.php b/lib/internal/Magento/Framework/Math/Random.php index ffab4181c1e94..d2f9b30344225 100644 --- a/lib/internal/Magento/Framework/Math/Random.php +++ b/lib/internal/Magento/Framework/Math/Random.php @@ -78,6 +78,6 @@ public static function getRandomNumber($min = 0, $max = null) */ public function getUniqueHash($prefix = '') { - return $prefix . $this->getRandomString(64); + return $prefix . $this->getRandomString(32); } } From 9f7f90857fd2fd166b65539ed7faee1ffe9d5967 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Tue, 17 Apr 2018 17:51:54 +0300 Subject: [PATCH 011/529] MAGETWO-88598: Varnish Config Access List --- .../System/Config/Backend/AccessList.php | 38 ++++++++ .../System/Config/Backend/AccessListTest.php | 90 +++++++++++++++++++ .../PageCache/etc/adminhtml/system.xml | 2 +- 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/PageCache/Model/System/Config/Backend/AccessList.php create mode 100644 app/code/Magento/PageCache/Test/Unit/Model/System/Config/Backend/AccessListTest.php diff --git a/app/code/Magento/PageCache/Model/System/Config/Backend/AccessList.php b/app/code/Magento/PageCache/Model/System/Config/Backend/AccessList.php new file mode 100644 index 0000000000000..a9a4d4a87022b --- /dev/null +++ b/app/code/Magento/PageCache/Model/System/Config/Backend/AccessList.php @@ -0,0 +1,38 @@ +getValue(); + if (!is_string($value) || !preg_match('/^[\w\s\.\-\,\:]+$/', $value)) { + throw new LocalizedException( + new Phrase( + 'Access List value "%1" is not valid. ' + .'Please use only IP addresses and host names.', + [$value] + ) + ); + } + } + +} diff --git a/app/code/Magento/PageCache/Test/Unit/Model/System/Config/Backend/AccessListTest.php b/app/code/Magento/PageCache/Test/Unit/Model/System/Config/Backend/AccessListTest.php new file mode 100644 index 0000000000000..1c4f279917c68 --- /dev/null +++ b/app/code/Magento/PageCache/Test/Unit/Model/System/Config/Backend/AccessListTest.php @@ -0,0 +1,90 @@ +getMockForAbstractClass( + ScopeConfigInterface::class + ); + $configMock->expects($this->any()) + ->method('getValue') + ->with('system/full_page_cache/default') + ->willReturn(['access_list' => 'localhost']); + $this->accessList = $objectManager->getObject( + AccessList::class, + [ + 'config' => $configMock, + 'data' => ['field' => 'access_list'] + ] + ); + } + + /** + * @return array + */ + public function getValidValues(): array + { + return [ + ['localhost', 'localhost'], + [null, 'localhost'], + ['127.0.0.1', '127.0.0.1'], + ['127.0.0.1, localhost, ::2', '127.0.0.1, localhost, ::2'], + ]; + } + + /** + * @param mixed $value + * @param mixed $expectedValue + * @dataProvider getValidValues + */ + public function testBeforeSave($value, $expectedValue) + { + $this->accessList->setValue($value); + $this->accessList->beforeSave(); + $this->assertEquals($expectedValue, $this->accessList->getValue()); + } + + /** + * @return array + */ + public function getInvalidValues(): array + { + return [ + ['\\bull val\\'], + ['{*I am not an IP*}'], + ['{*I am not an IP*}, 127.0.0.1'], + ]; + } + + /** + * @param mixed $value + * @expectedException \Magento\Framework\Exception\LocalizedException + * @dataProvider getInvalidValues + */ + public function testBeforeSaveInvalid($value) + { + $this->accessList->setValue($value); + $this->accessList->beforeSave(); + } +} diff --git a/app/code/Magento/PageCache/etc/adminhtml/system.xml b/app/code/Magento/PageCache/etc/adminhtml/system.xml index 1d6c0d890737b..7282a2608496f 100644 --- a/app/code/Magento/PageCache/etc/adminhtml/system.xml +++ b/app/code/Magento/PageCache/etc/adminhtml/system.xml @@ -20,7 +20,7 @@ IPs access list separated with ',' that can purge Varnish configuration for config file generation. If field is empty default value localhost will be saved. - Magento\PageCache\Model\System\Config\Backend\Varnish + Magento\PageCache\Model\System\Config\Backend\AccessList 1 From 8831db69b1308673354b44ea239b8aebf1b64052 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Tue, 17 Apr 2018 18:03:02 +0300 Subject: [PATCH 012/529] MAGETWO-88598: Varnish Config Access List --- .../Magento/PageCache/Model/System/Config/Backend/AccessList.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/PageCache/Model/System/Config/Backend/AccessList.php b/app/code/Magento/PageCache/Model/System/Config/Backend/AccessList.php index a9a4d4a87022b..e16584b0b17f8 100644 --- a/app/code/Magento/PageCache/Model/System/Config/Backend/AccessList.php +++ b/app/code/Magento/PageCache/Model/System/Config/Backend/AccessList.php @@ -34,5 +34,4 @@ public function beforeSave() ); } } - } From e7a8f8bfe7ddee29ff2a17d1a1c4b3465b82f5eb Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Thu, 19 Apr 2018 11:59:20 +0300 Subject: [PATCH 013/529] MAGETWO-88604: Invalid Video Uploader Link --- .../view/adminhtml/web/js/new-video-dialog.js | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/ProductVideo/view/adminhtml/web/js/new-video-dialog.js b/app/code/Magento/ProductVideo/view/adminhtml/web/js/new-video-dialog.js index 1ab10c95a51bc..c2b824a27b347 100644 --- a/app/code/Magento/ProductVideo/view/adminhtml/web/js/new-video-dialog.js +++ b/app/code/Magento/ProductVideo/view/adminhtml/web/js/new-video-dialog.js @@ -99,21 +99,17 @@ define([ this.element.find(this.options.metaData.DOM.uploaded).text(this.options.metaData.data.uploaded); this.element.find(this.options.metaData.DOM.duration).text(this.options.metaData.data.duration); + let uploaderLinkUrl = ""; if (this.options.videoProvider === 'youtube') { - this.element.find(this.options.metaData.DOM.uploader).html( - '' + - this.options.metaData.data.uploader + - '' - ); + uploaderLinkUrl = 'https://youtube.com/channel/' + this.options.metaData.data.uploaderUrl; } else if (this.options.videoProvider === 'vimeo') { - this.element.find(this.options.metaData.DOM.uploader).html( - '' + this.options.metaData.data.uploader + - ''); + uploaderLinkUrl = this.options.metaData.data.uploaderUrl; } + let uploaderLink = document.createElement('a'); + uploaderLink.setAttribute('href', uploaderLinkUrl); + uploaderLink.setAttribute('target', '_blank'); + uploaderLink.innerText = this.options.metaData.data.uploader; + this.element.find(this.options.metaData.DOM.uploader)[0].appendChild(uploaderLink); this.element.find('.' + this.options.videoClass).productVideoLoader(); }, From df0d60324c5f643ea312b46b5b55602202cd0b5e Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Thu, 19 Apr 2018 13:56:56 +0300 Subject: [PATCH 014/529] MAGETWO-88604: Invalid Video Uploader Link --- .../ProductVideo/view/adminhtml/web/js/new-video-dialog.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ProductVideo/view/adminhtml/web/js/new-video-dialog.js b/app/code/Magento/ProductVideo/view/adminhtml/web/js/new-video-dialog.js index c2b824a27b347..f575f28a5c737 100644 --- a/app/code/Magento/ProductVideo/view/adminhtml/web/js/new-video-dialog.js +++ b/app/code/Magento/ProductVideo/view/adminhtml/web/js/new-video-dialog.js @@ -86,6 +86,9 @@ define([ * @private */ _doUpdate: function () { + var uploaderLinkUrl, + uploaderLink; + this.reset(); this.element.find(this.options.container).append('
Date: Mon, 23 Apr 2018 14:06:20 +0300 Subject: [PATCH 015/529] MAGETWO-72982: Reset Password --- .../Customer/Controller/Account/ResetPasswordPost.php | 2 ++ .../testsuite/Magento/Customer/Controller/AccountTest.php | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php b/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php index 7a59ad507aaeb..ab6944a995d84 100644 --- a/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php +++ b/app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php @@ -36,6 +36,8 @@ class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount * @param AccountManagementInterface $accountManagement * @param CustomerRepositoryInterface $customerRepository * @param CredentialsValidator|null $credentialsValidator + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( Context $context, diff --git a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php index a01006a06a2e3..6f5f6e4e2c661 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Controller/AccountTest.php @@ -128,7 +128,6 @@ public function testCreatepasswordActionWithDirectLink() $customer->save(); $this->getRequest()->setParam('token', $token); - $this->getRequest()->setParam('id', $customer->getId()); $this->dispatch('customer/account/createPassword'); @@ -136,12 +135,13 @@ public function testCreatepasswordActionWithDirectLink() $this->assertEquals(302, $response->getHttpResponseCode()); $text = $response->getBody(); $this->assertFalse((bool)preg_match('/' . $token . '/m', $text)); - $this->assertRedirect($this->stringContains('customer/account/createpassword')); + $this->assertRedirect( + $this->stringContains('customer/account/createpassword') + ); /** @var Session $customer */ $session = Bootstrap::getObjectManager()->get(Session::class); $this->assertEquals($token, $session->getRpToken()); - $this->assertEquals($customer->getId(), $session->getRpCustomerId()); $this->assertNotContains($token, $response->getHeader('Location')->getFieldValue()); } From 199b7d00121541c9e3ac7dbb7e006b2fd4cb73c1 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Tue, 15 May 2018 15:32:21 +0300 Subject: [PATCH 016/529] MAGETWO-88592: [Backport for 2.2.x] Deleting Stores --- .../System/Store/DeleteGroupPost.php | 16 ++++++++++++--- .../System/Store/DeleteStorePost.php | 17 +++++++++++++--- .../System/Store/DeleteWebsitePost.php | 20 ++++++++++++++----- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php index b6fbd88c7669c..c2456d969f720 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php @@ -7,6 +7,7 @@ namespace Magento\Backend\Controller\Adminhtml\System\Store; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\App\Request\Http as HttpRequest; class DeleteGroupPost extends \Magento\Backend\Controller\Adminhtml\System\Store { @@ -15,11 +16,20 @@ class DeleteGroupPost extends \Magento\Backend\Controller\Adminhtml\System\Store */ public function execute() { - $itemId = $this->getRequest()->getParam('item_id'); - + /** @var HttpRequest $request */ + $request = $this->getRequest(); /** @var \Magento\Backend\Model\View\Result\Redirect $redirectResult */ - $redirectResult = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + $redirectResult = $this->resultFactory->create( + ResultFactory::TYPE_REDIRECT + ); + if (!$request->isPost()) { + $this->messageManager->addErrorMessage( + __('Something went wrong. Please try again.') + ); + return $redirectResult->setPath('adminhtml/*/'); + } + $itemId = $request->getParam('item_id'); if (!($model = $this->_objectManager->create(\Magento\Store\Model\Group::class)->load($itemId))) { $this->messageManager->addError(__('Something went wrong. Please try again.')); return $redirectResult->setPath('adminhtml/*/'); diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php index ac470238e588f..10f6b86ec7064 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php @@ -6,6 +6,7 @@ */ namespace Magento\Backend\Controller\Adminhtml\System\Store; +use Magento\Framework\App\Request\Http as HttpRequest; use Magento\Framework\Controller\ResultFactory; class DeleteStorePost extends \Magento\Backend\Controller\Adminhtml\System\Store @@ -17,10 +18,20 @@ class DeleteStorePost extends \Magento\Backend\Controller\Adminhtml\System\Store */ public function execute() { - $itemId = $this->getRequest()->getParam('item_id'); - + /** @var HttpRequest $request */ + $request = $this->getRequest(); /** @var \Magento\Backend\Model\View\Result\Redirect $redirectResult */ - $redirectResult = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + $redirectResult = $this->resultFactory->create( + ResultFactory::TYPE_REDIRECT + ); + if (!$request->isPost()) { + $this->messageManager->addErrorMessage( + __('Something went wrong. Please try again.') + ); + return $redirectResult->setPath('adminhtml/*/'); + } + + $itemId = $request->getParam('item_id'); if (!($model = $this->_objectManager->create(\Magento\Store\Model\Store::class)->load($itemId))) { $this->messageManager->addError(__('Something went wrong. Please try again.')); return $redirectResult->setPath('adminhtml/*/'); diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php index c2d24b8c41a8c..877bee1a2b3aa 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php @@ -7,6 +7,7 @@ namespace Magento\Backend\Controller\Adminhtml\System\Store; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\App\Request\Http as HttpRequest; class DeleteWebsitePost extends \Magento\Backend\Controller\Adminhtml\System\Store { @@ -15,13 +16,22 @@ class DeleteWebsitePost extends \Magento\Backend\Controller\Adminhtml\System\Sto */ public function execute() { - $itemId = $this->getRequest()->getParam('item_id'); - $model = $this->_objectManager->create(\Magento\Store\Model\Website::class); - $model->load($itemId); - + /** @var HttpRequest $request */ + $request = $this->getRequest(); /** @var \Magento\Backend\Model\View\Result\Redirect $redirectResult */ - $redirectResult = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); + $redirectResult = $this->resultFactory->create( + ResultFactory::TYPE_REDIRECT + ); + if (!$request->isPost()) { + $this->messageManager->addErrorMessage( + __('Something went wrong. Please try again.') + ); + return $redirectResult->setPath('adminhtml/*/'); + } + $itemId = $request->getParam('item_id'); + $model = $this->_objectManager->create(\Magento\Store\Model\Website::class); + $model->load($itemId); if (!$model) { $this->messageManager->addError(__('Something went wrong. Please try again.')); return $redirectResult->setPath('adminhtml/*/'); From 97b37853ec1b1458fb6bc10e65e1932a52439bf8 Mon Sep 17 00:00:00 2001 From: Dmytro Voskoboinikov Date: Tue, 15 May 2018 16:27:27 +0300 Subject: [PATCH 017/529] MAGETWO-72024: Wysiwyg editor incorrectly processes attributes of HTML5 tags --- .../adminhtml/wysiwyg/tiny_mce/html5-schema.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js index 48960ed3403c0..234c27edf6de2 100644 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js @@ -186,11 +186,18 @@ define([ }); _.each(compiled, function (node, nodeName) { - var attributes = node.attributes.join('|'), - children = node.children.join('|'); + var filteredAttributes = []; - validElements.push(nodeName + '[' + attributes + ']'); - validChildren.push(nodeName + '[' + children + ']'); + _.each(node.attributes, function (attribute) { + if (!/^on/.test(attribute)) { + filteredAttributes.push(attribute) + } + }); + + node.attributes = filteredAttributes; + + validElements.push(nodeName + '[' + node.attributes.join('|') + ']'); + validChildren.push(nodeName + '[' + node.children.join('|') + ']'); }); return { From f75520f2878455a31a9be8bcd591a166cae6fab4 Mon Sep 17 00:00:00 2001 From: Dmytro Voskoboinikov Date: Thu, 17 May 2018 15:26:39 +0300 Subject: [PATCH 018/529] MAGETWO-72024: Wysiwyg editor incorrectly processes attributes of HTML5 tags --- lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js index 234c27edf6de2..7760562fb34aa 100644 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js @@ -189,6 +189,7 @@ define([ var filteredAttributes = []; _.each(node.attributes, function (attribute) { + // Disallowing usage of 'on*' attributes. if (!/^on/.test(attribute)) { filteredAttributes.push(attribute) } From 274fee981c33ee22b296f99e1ca6cc009d7abaa2 Mon Sep 17 00:00:00 2001 From: Sunil Patel Date: Sat, 19 May 2018 15:50:34 +0530 Subject: [PATCH 019/529] 15259 : Unable to disable without providing Industry value --- app/code/Magento/Analytics/etc/adminhtml/system.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Analytics/etc/adminhtml/system.xml b/app/code/Magento/Analytics/etc/adminhtml/system.xml index 889517e629e04..5d80917fc4daa 100644 --- a/app/code/Magento/Analytics/etc/adminhtml/system.xml +++ b/app/code/Magento/Analytics/etc/adminhtml/system.xml @@ -36,6 +36,9 @@ Magento\Analytics\Model\Config\Source\Vertical Magento\Analytics\Model\Config\Backend\Vertical Magento\Analytics\Block\Adminhtml\System\Config\Vertical + + 1 + From 380edb9b39a121b4444e833e366227806876a030 Mon Sep 17 00:00:00 2001 From: Dmytro Voskoboinikov Date: Mon, 21 May 2018 17:44:50 +0300 Subject: [PATCH 020/529] MAGETWO-72024: Wysiwyg editor incorrectly processes attributes of HTML5 tags --- lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js index 7760562fb34aa..98ce6a005db04 100644 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js @@ -188,10 +188,10 @@ define([ _.each(compiled, function (node, nodeName) { var filteredAttributes = []; - _.each(node.attributes, function (attribute) { + _.each(node.attributes, function (attribute) { //eslint-disable-line max-nested-callbacks // Disallowing usage of 'on*' attributes. if (!/^on/.test(attribute)) { - filteredAttributes.push(attribute) + filteredAttributes.push(attribute); } }); From 594689b19a142836e43e31d1265f7212c08c445a Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Wed, 23 May 2018 14:43:16 +0300 Subject: [PATCH 021/529] MAGETWO-81470: [Backport for 2.2.x] Cached Config is Different From DB --- .../Magento/Config/App/Config/Type/System.php | 21 ++++-- .../Test/Unit/App/Config/Type/SystemTest.php | 65 +++++-------------- .../Serialize/Serializer/Sensitive.php | 63 ++++++++++++++++++ 3 files changed, 97 insertions(+), 52 deletions(-) create mode 100644 lib/internal/Magento/Framework/Serialize/Serializer/Sensitive.php diff --git a/app/code/Magento/Config/App/Config/Type/System.php b/app/code/Magento/Config/App/Config/Type/System.php index 4f6d9c14346f0..f18a9f9d34c6f 100644 --- a/app/code/Magento/Config/App/Config/Type/System.php +++ b/app/code/Magento/Config/App/Config/Type/System.php @@ -8,6 +8,8 @@ use Magento\Framework\App\Config\ConfigTypeInterface; use Magento\Framework\App\ObjectManager; use Magento\Config\App\Config\Type\System\Reader; +use Magento\Framework\Serialize\Serializer\Sensitive as SensitiveSerializer; +use Magento\Framework\Serialize\Serializer\SensitiveFactory as SensitiveSerializerFactory; /** * System configuration type @@ -56,7 +58,7 @@ class System implements ConfigTypeInterface private $fallback; /** - * @var \Magento\Framework\Serialize\SerializerInterface + * @var SensitiveSerializer */ private $serializer; @@ -91,6 +93,9 @@ class System implements ConfigTypeInterface * @param int $cachingNestedLevel * @param string $configType * @param Reader $reader + * @param SensitiveSerializerFactory|null $sensitiveFactory + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( \Magento\Framework\App\Config\ConfigSourceInterface $source, @@ -101,7 +106,8 @@ public function __construct( \Magento\Framework\App\Config\Spi\PreProcessorInterface $preProcessor, $cachingNestedLevel = 1, $configType = self::CONFIG_TYPE, - Reader $reader = null + Reader $reader = null, + SensitiveSerializerFactory $sensitiveFactory = null ) { $this->source = $source; $this->postProcessor = $postProcessor; @@ -109,9 +115,16 @@ public function __construct( $this->cache = $cache; $this->cachingNestedLevel = $cachingNestedLevel; $this->fallback = $fallback; - $this->serializer = $serializer; $this->configType = $configType; - $this->reader = $reader ?: ObjectManager::getInstance()->get(Reader::class); + $this->reader = $reader ?: ObjectManager::getInstance() + ->get(Reader::class); + $sensitiveFactory = $sensitiveFactory ?? ObjectManager::getInstance() + ->get(SensitiveSerializerFactory::class); + //Using sensitive serializer because any kind of information may + //be stored in configs. + $this->serializer = $sensitiveFactory->create( + ['serializer' => $serializer] + ); } /** diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php index 40aa110382ede..9ca4e6138babe 100644 --- a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php +++ b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php @@ -11,6 +11,8 @@ use Magento\Framework\App\Config\Spi\PostProcessorInterface; use Magento\Framework\App\Config\Spi\PreProcessorInterface; use Magento\Framework\Cache\FrontendInterface; +use Magento\Framework\Serialize\Serializer\Sensitive; +use Magento\Framework\Serialize\Serializer\SensitiveFactory; use Magento\Framework\Serialize\SerializerInterface; use Magento\Store\Model\Config\Processor\Fallback; use Magento\Config\App\Config\Type\System\Reader; @@ -74,22 +76,34 @@ public function setUp() ->getMockForAbstractClass(); $this->preProcessor = $this->getMockBuilder(PreProcessorInterface::class) ->getMockForAbstractClass(); - $this->serializer = $this->getMockBuilder(SerializerInterface::class) + $this->serializer = $this->getMockBuilder(Sensitive::class) + ->disableOriginalConstructor() ->getMock(); $this->reader = $this->getMockBuilder(Reader::class) ->disableOriginalConstructor() ->getMock(); + $sensitiveFactory = $this->getMockBuilder(SensitiveFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $sensitiveFactory->expects($this->any()) + ->method('create') + ->willReturn($this->serializer); + /** @var SerializerInterface|\PHPUnit_Framework_MockObject_MockObject $serializerMock */ + $serializerMock = $this->getMockBuilder(SerializerInterface::class) + ->disableOriginalConstructor() + ->getMock(); $this->configType = new System( $this->source, $this->postProcessor, $this->fallback, $this->cache, - $this->serializer, + $serializerMock, $this->preProcessor, 1, 'system', - $this->reader + $this->reader, + $sensitiveFactory ); } @@ -133,49 +147,4 @@ public function testGetCachedWithLoadAllData() ->willReturn($data); $this->assertEquals($data, $this->configType->get('')); } - - public function testGetNotCached() - { - $path = 'stores/default/dev/unsecure/url'; - $url = 'http://magento.test/'; - - $dataToCache = [ - 'unsecure' => [ - 'url' => $url - ] - ]; - $data = [ - 'default' => [], - 'websites' => [], - 'stores' => [ - 'default' => [ - 'dev' => [ - 'unsecure' => [ - 'url' => $url - ] - ] - ] - ] - ]; - $this->cache->expects($this->any()) - ->method('load') - ->willReturnOnConsecutiveCalls(false, false); - - $this->serializer->expects($this->atLeastOnce()) - ->method('serialize') - ->willReturn(serialize($dataToCache)); - $this->cache->expects($this->atLeastOnce()) - ->method('save') - ->willReturnSelf(); - $this->reader->expects($this->once()) - ->method('read') - ->willReturn($data); - $this->postProcessor->expects($this->once()) - ->method('process') - ->with($data) - ->willReturn($data); - - $this->assertEquals($url, $this->configType->get($path)); - $this->assertEquals($url, $this->configType->get($path)); - } } diff --git a/lib/internal/Magento/Framework/Serialize/Serializer/Sensitive.php b/lib/internal/Magento/Framework/Serialize/Serializer/Sensitive.php new file mode 100644 index 0000000000000..248800ccf2baf --- /dev/null +++ b/lib/internal/Magento/Framework/Serialize/Serializer/Sensitive.php @@ -0,0 +1,63 @@ +encryptor = $encryptor; + $this->serializer = $serializer; + } + + /** + * @inheritDoc + */ + public function serialize($data) + { + $serialized = $this->serializer->serialize($data); + if (is_string($serialized)) { + $serialized = $this->encryptor->encrypt($serialized); + } + + return $serialized; + } + + /** + * @inheritDoc + */ + public function unserialize($string) + { + $string = $this->encryptor->decrypt($string); + + return $this->serializer->unserialize($string); + } +} From f1554d42e7824ea9149d20142a0178f7a7d31f90 Mon Sep 17 00:00:00 2001 From: Michiel Gerritsen Date: Sat, 2 Jun 2018 11:20:25 +0200 Subject: [PATCH 022/529] Added checks to see if the payment is available --- .../Observer/SalesOrderBeforeSaveObserver.php | 2 +- .../SalesOrderBeforeSaveObserverTest.php | 28 ++++++++++++++++--- .../Magento/Paypal/Plugin/OrderCanInvoice.php | 4 +++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php index ed8185e6dedeb..465c4916d8abb 100644 --- a/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php +++ b/app/code/Magento/Payment/Observer/SalesOrderBeforeSaveObserver.php @@ -21,7 +21,7 @@ public function execute(\Magento\Framework\Event\Observer $observer) /** @var \Magento\Sales\Model\Order $order */ $order = $observer->getEvent()->getOrder(); - if ($order->getPayment()->getMethodInstance()->getCode() != 'free') { + if ($order->getPayment() && $order->getPayment()->getMethodInstance()->getCode() != 'free') { return $this; } diff --git a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php index b86fbc6b18263..47af32d554b68 100644 --- a/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php +++ b/app/code/Magento/Payment/Test/Unit/Observer/SalesOrderBeforeSaveObserverTest.php @@ -61,7 +61,7 @@ public function testSalesOrderBeforeSaveCantUnhold() $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); @@ -86,7 +86,7 @@ public function testSalesOrderBeforeSaveIsCanceled() $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); @@ -114,7 +114,7 @@ public function testSalesOrderBeforeSaveIsClosed() $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); @@ -156,6 +156,26 @@ public function testSalesOrderBeforeSaveSetForced() $this->salesOrderBeforeSaveObserver->execute($this->observerMock); } + /** + * The method should check that the payment is available, as this is not always the case. + */ + public function testDoesNothingWhenNoPaymentIsAvailable() + { + $this->_prepareEventMockWithMethods(['getOrder']); + + $order = $this->getMockBuilder(\Magento\Sales\Model\Order::class)->disableOriginalConstructor()->setMethods( + array_merge(['__wakeup', 'getPayment']) + )->getMock(); + + $this->eventMock->expects($this->once())->method('getOrder')->will( + $this->returnValue($order) + ); + + $order->expects($this->exactly(1))->method('getPayment')->willReturn(null); + + $this->salesOrderBeforeSaveObserver->execute($this->observerMock); + } + /** * Prepares EventMock with set of methods * @@ -184,7 +204,7 @@ private function _getPreparedOrderMethod($methodCode, $orderMethods = []) $paymentMock = $this->getMockBuilder( \Magento\Sales\Model\Order\Payment::class )->disableOriginalConstructor()->setMethods([])->getMock(); - $order->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock)); + $order->method('getPayment')->will($this->returnValue($paymentMock)); $methodInstance = $this->getMockBuilder( \Magento\Payment\Model\MethodInterface::class )->getMockForAbstractClass(); diff --git a/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php b/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php index 8393b756be364..434082728513d 100644 --- a/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php +++ b/app/code/Magento/Paypal/Plugin/OrderCanInvoice.php @@ -38,6 +38,10 @@ public function __construct(Express $express) */ public function afterCanInvoice(Order $order, $result): bool { + if (!$order->getPayment()) { + return false; + } + if ($this->express->isOrderAuthorizationAllowed($order->getPayment())) { return false; } From 6ea9da7c7c89ee260410ce6365cf5a8df119abd5 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Tue, 5 Jun 2018 15:07:43 +0300 Subject: [PATCH 023/529] MAGETWO-88592: [Backport for 2.2.x] Deleting Stores --- .../Controller/Adminhtml/System/Store/DeleteGroupPost.php | 7 +++---- .../Controller/Adminhtml/System/Store/DeleteStorePost.php | 7 +++---- .../Adminhtml/System/Store/DeleteWebsitePost.php | 7 +++---- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php index c2456d969f720..5c0a2681c81a2 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteGroupPost.php @@ -8,11 +8,13 @@ use Magento\Framework\Controller\ResultFactory; use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\Exception\NotFoundException; class DeleteGroupPost extends \Magento\Backend\Controller\Adminhtml\System\Store { /** * @return \Magento\Backend\Model\View\Result\Redirect + * @throws NotFoundException */ public function execute() { @@ -23,10 +25,7 @@ public function execute() ResultFactory::TYPE_REDIRECT ); if (!$request->isPost()) { - $this->messageManager->addErrorMessage( - __('Something went wrong. Please try again.') - ); - return $redirectResult->setPath('adminhtml/*/'); + throw new NotFoundException(__('Page not found.')); } $itemId = $request->getParam('item_id'); diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php index 10f6b86ec7064..3cf0554cdf705 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteStorePost.php @@ -8,6 +8,7 @@ use Magento\Framework\App\Request\Http as HttpRequest; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\Exception\NotFoundException; class DeleteStorePost extends \Magento\Backend\Controller\Adminhtml\System\Store { @@ -15,6 +16,7 @@ class DeleteStorePost extends \Magento\Backend\Controller\Adminhtml\System\Store * Delete store view post action * * @return \Magento\Backend\Model\View\Result\Redirect + * @throws NotFoundException */ public function execute() { @@ -25,10 +27,7 @@ public function execute() ResultFactory::TYPE_REDIRECT ); if (!$request->isPost()) { - $this->messageManager->addErrorMessage( - __('Something went wrong. Please try again.') - ); - return $redirectResult->setPath('adminhtml/*/'); + throw new NotFoundException(__('Page not found.')); } $itemId = $request->getParam('item_id'); diff --git a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php index 877bee1a2b3aa..5b578ad3876d1 100644 --- a/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php +++ b/app/code/Magento/Backend/Controller/Adminhtml/System/Store/DeleteWebsitePost.php @@ -8,11 +8,13 @@ use Magento\Framework\Controller\ResultFactory; use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\Exception\NotFoundException; class DeleteWebsitePost extends \Magento\Backend\Controller\Adminhtml\System\Store { /** * @return \Magento\Backend\Model\View\Result\Redirect + * @throws NotFoundException */ public function execute() { @@ -23,10 +25,7 @@ public function execute() ResultFactory::TYPE_REDIRECT ); if (!$request->isPost()) { - $this->messageManager->addErrorMessage( - __('Something went wrong. Please try again.') - ); - return $redirectResult->setPath('adminhtml/*/'); + throw new NotFoundException(__('Page not found.')); } $itemId = $request->getParam('item_id'); From a8e36c907b878f02d9c12e29df58bfa58d84c566 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Tue, 12 Jun 2018 13:05:36 +0300 Subject: [PATCH 024/529] MAGETWO-88655: [Backport for 2.2.x] Sales Rule Widget Label --- .../Magento/SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php b/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php index b4be904223aac..6a54404e1865e 100644 --- a/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php +++ b/app/code/Magento/SalesRule/Block/Adminhtml/Promo/Widget/Chooser.php @@ -87,7 +87,7 @@ public function prepareElementHtml(\Magento\Framework\Data\Form\Element\Abstract if ($element->getValue()) { $rule = $this->ruleFactory->create()->load((int)$element->getValue()); if ($rule->getId()) { - $chooser->setLabel($rule->getName()); + $chooser->setLabel($this->escapeHtml($rule->getName())); } } From f969b9d93dc984db4e87d8a774abfa6832c79c2a Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Wed, 13 Jun 2018 11:04:04 +0300 Subject: [PATCH 025/529] MAGETWO-92162: [Backport for 2.2.x] Log File Validation --- dev/tests/functional/utils/log.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dev/tests/functional/utils/log.php b/dev/tests/functional/utils/log.php index b6c19458b10b9..c61a8b8c2f5a4 100644 --- a/dev/tests/functional/utils/log.php +++ b/dev/tests/functional/utils/log.php @@ -9,6 +9,11 @@ } $name = urldecode($_GET['name']); -$file = file_get_contents('../../../../var/log/' . $name); +$logDir = realpath('../../../../var/log'); +$logFile = realpath($logDir .'/' .$name); +if (!$logFile || !$logDir || mb_strpos($logFile, $logDir .'/') !== 0) { + throw new \InvalidArgumentException('Invalid log file name'); +} +$file = file_get_contents($logFile); echo serialize($file); From 7a8c24b2efd9d2e59bf9efac016a9e656b0b4067 Mon Sep 17 00:00:00 2001 From: Vinai Kopp Date: Thu, 14 Jun 2018 09:48:26 +0200 Subject: [PATCH 026/529] Fix typehint of customer-data updateSectionId parameters The typehint wrongly indicates the parameter should be a number, where in fact it is a boolean. It is passed through to the server side to the controller action \Magento\Customer\Controller\Section\Load::execute() where it is cast to a boolean and passed as the $updateIds parameter to \Magento\Customer\CustomerData\SectionPool::getSectionsData() and from there as the boolean parameter $forceUpdate to the \Magento\Customer\CustomerData\Section\Identifier::initMark() method. This PR introduces no backward incompatibilities, it only fixes the type hint to make the code more readable and improve compatibility with static code analysis tools. --- .../Magento/Customer/view/frontend/web/js/customer-data.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js index 15df80f360bf7..56ee437d9704f 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js +++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js @@ -74,7 +74,7 @@ define([ /** * @param {Object} sectionNames - * @param {Number} updateSectionId + * @param {Boolean} updateSectionId * @return {*} */ getFromServer: function (sectionNames, updateSectionId) { @@ -324,7 +324,7 @@ define([ /** * @param {Array} sectionNames - * @param {Number} updateSectionId + * @param {Boolean} updateSectionId * @return {*} */ reload: function (sectionNames, updateSectionId) { From 19ddf6592393fc3235266703d506aa2ba367a114 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Fri, 15 Jun 2018 14:21:29 +0300 Subject: [PATCH 027/529] MAGETWO-92197: [Backport for 2.2.x] Mass Action Wrong Requests --- .../Controller/Adminhtml/Order/MassCancel.php | 16 ++++++++++++++++ .../Controller/Adminhtml/Order/MassHold.php | 16 ++++++++++++++++ .../Controller/Adminhtml/Order/MassUnhold.php | 16 ++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassCancel.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassCancel.php index 2ba8467ff6864..5d7a55bc4a56c 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassCancel.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassCancel.php @@ -5,10 +5,12 @@ */ namespace Magento\Sales\Controller\Adminhtml\Order; +use Magento\Framework\Exception\NotFoundException; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Magento\Sales\Model\ResourceModel\Order\CollectionFactory; +use Magento\Framework\App\Request\Http as HttpRequest; class MassCancel extends \Magento\Sales\Controller\Adminhtml\Order\AbstractMassAction { @@ -28,6 +30,20 @@ public function __construct(Context $context, Filter $filter, CollectionFactory $this->collectionFactory = $collectionFactory; } + /** + * @inheritDoc + */ + public function execute() + { + /** @var HttpRequest $request */ + $request = $this->getRequest(); + if (!$request->isPost()) { + throw new NotFoundException(__('Page not found.')); + } + + return parent::execute(); + } + /** * Cancel selected orders * diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php index e894957dc8b6c..67263028d51a9 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassHold.php @@ -5,11 +5,13 @@ */ namespace Magento\Sales\Controller\Adminhtml\Order; +use Magento\Framework\Exception\NotFoundException; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Magento\Sales\Model\ResourceModel\Order\CollectionFactory; use Magento\Sales\Api\OrderManagementInterface; +use Magento\Framework\App\Request\Http as HttpRequest; /** * Class MassHold @@ -43,6 +45,20 @@ public function __construct( $this->orderManagement = $orderManagement; } + /** + * @inheritDoc + */ + public function execute() + { + /** @var HttpRequest $request */ + $request = $this->getRequest(); + if (!$request->isPost()) { + throw new NotFoundException(__('Page not found.')); + } + + return parent::execute(); + } + /** * Hold selected orders * diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php index 2eb54c9814ef7..68090d7a75239 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/MassUnhold.php @@ -5,11 +5,13 @@ */ namespace Magento\Sales\Controller\Adminhtml\Order; +use Magento\Framework\Exception\NotFoundException; use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Magento\Sales\Model\ResourceModel\Order\CollectionFactory; use Magento\Sales\Api\OrderManagementInterface; +use Magento\Framework\App\Request\Http as HttpRequest; class MassUnhold extends AbstractMassAction { @@ -42,6 +44,20 @@ public function __construct( ); } + /** + * @inheritDoc + */ + public function execute() + { + /** @var HttpRequest $request */ + $request = $this->getRequest(); + if (!$request->isPost()) { + throw new NotFoundException(__('Page not found.')); + } + + return parent::execute(); + } + /** * Unhold selected orders * From e60509efca9b07f1405d4e1107d514dfd02b358d Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Fri, 15 Jun 2018 15:44:19 +0300 Subject: [PATCH 028/529] MAGETWO-92197: [Backport for 2.2.x] Mass Action Wrong Requests --- .../Adminhtml/Order/MassCancelTest.php | 280 ------------------ .../Adminhtml/Order/MassHoldTest.php | 253 ---------------- .../Adminhtml/Order/MassUnholdTest.php | 252 ---------------- 3 files changed, 785 deletions(-) delete mode 100644 app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php delete mode 100644 app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php delete mode 100644 app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php deleted file mode 100644 index 569a210d993f0..0000000000000 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassCancelTest.php +++ /dev/null @@ -1,280 +0,0 @@ -contextMock = $this->createMock(\Magento\Backend\App\Action\Context::class); - $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\Manager::class); - $this->responseMock = $this->createMock(\Magento\Framework\App\ResponseInterface::class); - $this->requestMock = $this->createMock(\Magento\Framework\App\Request\Http::class); - $this->objectManagerMock = $this->createMock(\Magento\Framework\ObjectManager\ObjectManager::class); - - $resultRedirectFactory = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); - - $this->orderCollectionMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Collection::class) - ->disableOriginalConstructor() - ->getMock(); - - $resourceCollection = \Magento\Sales\Model\ResourceModel\Order\CollectionFactory::class; - $this->orderCollectionFactoryMock = $this->getMockBuilder($resourceCollection) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $this->sessionMock = $this->createPartialMock(\Magento\Backend\Model\Session::class, ['setIsUrlNotice']); - $this->actionFlagMock = $this->createPartialMock(\Magento\Framework\App\ActionFlag::class, ['get', 'set']); - $this->helperMock = $this->createPartialMock(\Magento\Backend\Helper\Data::class, ['getUrl']); - $this->resultRedirectMock = $this->createMock(\Magento\Backend\Model\View\Result\Redirect::class); - $resultRedirectFactory->expects($this->any())->method('create')->willReturn($this->resultRedirectMock); - - $redirectMock = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $resultFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $resultFactoryMock->expects($this->any()) - ->method('create') - ->with(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) - ->willReturn($redirectMock); - - $this->contextMock->expects($this->once())->method('getMessageManager')->willReturn($this->messageManagerMock); - $this->contextMock->expects($this->once())->method('getRequest')->willReturn($this->requestMock); - $this->contextMock->expects($this->once())->method('getResponse')->willReturn($this->responseMock); - $this->contextMock->expects($this->once())->method('getObjectManager')->willReturn($this->objectManagerMock); - $this->contextMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); - $this->contextMock->expects($this->once())->method('getActionFlag')->willReturn($this->actionFlagMock); - $this->contextMock->expects($this->once())->method('getHelper')->willReturn($this->helperMock); - $this->contextMock->expects($this->once()) - ->method('getResultRedirectFactory') - ->willReturn($resultRedirectFactory); - $this->contextMock->expects($this->any()) - ->method('getResultFactory') - ->willReturn($resultFactoryMock); - $this->filterMock = $this->createMock(\Magento\Ui\Component\MassAction\Filter::class); - $this->filterMock->expects($this->once()) - ->method('getCollection') - ->with($this->orderCollectionMock) - ->willReturn($this->orderCollectionMock); - $this->orderCollectionFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->orderCollectionMock); - $this->massAction = $objectManagerHelper->getObject( - \Magento\Sales\Controller\Adminhtml\Order\MassCancel::class, - [ - 'context' => $this->contextMock, - 'filter' => $this->filterMock, - 'collectionFactory' => $this->orderCollectionFactoryMock - ] - ); - } - - /** - * Test for selected orders - * Two orders, only $order1 can be canceled - */ - public function testExecuteCanCancelOneOrder() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $orders = [$order1, $order2]; - $countOrders = count($orders); - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('canCancel') - ->willReturn(true); - $order1->expects($this->once()) - ->method('cancel'); - $order1->expects($this->once()) - ->method('save'); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn($countOrders); - - $order2->expects($this->once()) - ->method('canCancel') - ->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with('1 order(s) cannot be canceled.'); - - $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') - ->with('We canceled 1 order(s).'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } - - /** - * Test for excluded orders - * Two orders could't be canceled - */ - public function testExcludedCannotCancelOrders() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - $countOrders = count($orders); - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn([$order1, $order2]); - - $order1->expects($this->once()) - ->method('canCancel') - ->willReturn(false); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn($countOrders); - - $order2->expects($this->once()) - ->method('canCancel') - ->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with('You cannot cancel the order(s).'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } - - /** - * Order throws exception while canceling - */ - public function testException() - { - $exception = new \Exception('Can not cancel'); - - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn([$order1]); - - $order1->expects($this->once()) - ->method('canCancel') - ->willReturn(true); - $order1->expects($this->once()) - ->method('cancel') - ->willThrowException($exception); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with('Can not cancel'); - - $this->massAction->execute(); - } -} diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php deleted file mode 100644 index 02ff208445596..0000000000000 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassHoldTest.php +++ /dev/null @@ -1,253 +0,0 @@ -orderManagementMock = $this->getMockBuilder(\Magento\Sales\Api\OrderManagementInterface::class) - ->getMockForAbstractClass(); - $this->contextMock = $this->createMock(\Magento\Backend\App\Action\Context::class); - $resultRedirectFactory = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); - $this->responseMock = $this->createMock(\Magento\Framework\App\ResponseInterface::class); - $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) - ->disableOriginalConstructor()->getMock(); - $this->objectManagerMock = $this->createPartialMock( - \Magento\Framework\ObjectManager\ObjectManager::class, - ['create'] - ); - $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\Manager::class); - $this->orderCollectionMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Collection::class) - ->disableOriginalConstructor() - ->getMock(); - $orderCollection = \Magento\Sales\Model\ResourceModel\Order\CollectionFactory::class; - $this->orderCollectionFactoryMock = $this->getMockBuilder($orderCollection) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $redirectMock = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $resultFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $resultFactoryMock->expects($this->any()) - ->method('create') - ->with(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) - ->willReturn($redirectMock); - - $this->sessionMock = $this->createPartialMock(\Magento\Backend\Model\Session::class, ['setIsUrlNotice']); - $this->actionFlagMock = $this->createPartialMock(\Magento\Framework\App\ActionFlag::class, ['get', 'set']); - $this->helperMock = $this->createPartialMock(\Magento\Backend\Helper\Data::class, ['getUrl']); - $this->resultRedirectMock = $this->createMock(\Magento\Backend\Model\View\Result\Redirect::class); - $resultRedirectFactory->expects($this->any())->method('create')->willReturn($this->resultRedirectMock); - - $this->contextMock->expects($this->once())->method('getMessageManager')->willReturn($this->messageManagerMock); - $this->contextMock->expects($this->once())->method('getRequest')->willReturn($this->requestMock); - $this->contextMock->expects($this->once())->method('getResponse')->willReturn($this->responseMock); - $this->contextMock->expects($this->once())->method('getObjectManager')->willReturn($this->objectManagerMock); - $this->contextMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); - $this->contextMock->expects($this->once())->method('getActionFlag')->willReturn($this->actionFlagMock); - $this->contextMock->expects($this->once())->method('getHelper')->willReturn($this->helperMock); - $this->contextMock - ->expects($this->once()) - ->method('getResultRedirectFactory') - ->willReturn($resultRedirectFactory); - $this->contextMock->expects($this->any()) - ->method('getResultFactory') - ->willReturn($resultFactoryMock); - - $this->filterMock = $this->createMock(\Magento\Ui\Component\MassAction\Filter::class); - $this->filterMock->expects($this->once()) - ->method('getCollection') - ->with($this->orderCollectionMock) - ->willReturn($this->orderCollectionMock); - $this->orderCollectionFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->orderCollectionMock); - - $this->massAction = $objectManagerHelper->getObject( - \Magento\Sales\Controller\Adminhtml\Order\MassHold::class, - [ - 'context' => $this->contextMock, - 'filter' => $this->filterMock, - 'collectionFactory' => $this->orderCollectionFactoryMock, - 'orderManagement' => $this->orderManagementMock - ] - ); - } - - public function testExecuteOneOrderPutOnHold() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - $countOrders = count($orders); - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('canHold') - ->willReturn(true); - $this->orderManagementMock->expects($this->once()) - ->method('hold'); - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn($countOrders); - - $order2->expects($this->once()) - ->method('canHold') - ->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with('1 order(s) were not put on hold.'); - - $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') - ->with('You have put 1 order(s) on hold.'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } - - public function testExecuteNoOrdersPutOnHold() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - $countOrders = count($orders); - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('canHold') - ->willReturn(false); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn($countOrders); - - $order2->expects($this->once()) - ->method('canHold') - ->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with('No order(s) were put on hold.'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } -} diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php deleted file mode 100644 index cddb503925987..0000000000000 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/MassUnholdTest.php +++ /dev/null @@ -1,252 +0,0 @@ -contextMock = $this->createMock(\Magento\Backend\App\Action\Context::class); - $resultRedirectFactory = $this->createMock(\Magento\Backend\Model\View\Result\RedirectFactory::class); - $this->responseMock = $this->createMock(\Magento\Framework\App\ResponseInterface::class); - $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) - ->disableOriginalConstructor()->getMock(); - $this->objectManagerMock = $this->createMock(\Magento\Framework\ObjectManager\ObjectManager::class); - $this->messageManagerMock = $this->createMock(\Magento\Framework\Message\Manager::class); - - $this->orderCollectionMock = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Collection::class) - ->disableOriginalConstructor() - ->getMock(); - $orderCollection = \Magento\Sales\Model\ResourceModel\Order\CollectionFactory::class; - $this->orderCollectionFactoryMock = $this->getMockBuilder($orderCollection) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - $this->sessionMock = $this->createPartialMock(\Magento\Backend\Model\Session::class, ['setIsUrlNotice']); - $this->actionFlagMock = $this->createPartialMock(\Magento\Framework\App\ActionFlag::class, ['get', 'set']); - $this->helperMock = $this->createPartialMock(\Magento\Backend\Helper\Data::class, ['getUrl']); - $this->resultRedirectMock = $this->createMock(\Magento\Backend\Model\View\Result\Redirect::class); - $resultRedirectFactory->expects($this->any())->method('create')->willReturn($this->resultRedirectMock); - - $redirectMock = $this->getMockBuilder(\Magento\Backend\Model\View\Result\Redirect::class) - ->disableOriginalConstructor() - ->getMock(); - - $resultFactoryMock = $this->getMockBuilder(\Magento\Framework\Controller\ResultFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $resultFactoryMock->expects($this->any()) - ->method('create') - ->with(\Magento\Framework\Controller\ResultFactory::TYPE_REDIRECT) - ->willReturn($redirectMock); - - $this->contextMock->expects($this->once())->method('getMessageManager')->willReturn($this->messageManagerMock); - $this->contextMock->expects($this->once())->method('getRequest')->willReturn($this->requestMock); - $this->contextMock->expects($this->once())->method('getResponse')->willReturn($this->responseMock); - $this->contextMock->expects($this->once())->method('getObjectManager')->willReturn($this->objectManagerMock); - $this->contextMock->expects($this->once())->method('getSession')->willReturn($this->sessionMock); - $this->contextMock->expects($this->once())->method('getActionFlag')->willReturn($this->actionFlagMock); - $this->contextMock->expects($this->once())->method('getHelper')->willReturn($this->helperMock); - $this->contextMock - ->expects($this->once()) - ->method('getResultRedirectFactory') - ->willReturn($resultRedirectFactory); - $this->contextMock->expects($this->any()) - ->method('getResultFactory') - ->willReturn($resultFactoryMock); - - $this->filterMock = $this->createMock(\Magento\Ui\Component\MassAction\Filter::class); - $this->filterMock->expects($this->once()) - ->method('getCollection') - ->with($this->orderCollectionMock) - ->willReturn($this->orderCollectionMock); - $this->orderCollectionFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->orderCollectionMock); - - $this->orderManagementMock = $this->createMock(\Magento\Sales\Api\OrderManagementInterface::class); - - $this->massAction = $objectManagerHelper->getObject( - \Magento\Sales\Controller\Adminhtml\Order\MassUnhold::class, - [ - 'context' => $this->contextMock, - 'filter' => $this->filterMock, - 'collectionFactory' => $this->orderCollectionFactoryMock, - 'orderManagement' => $this->orderManagementMock - ] - ); - } - - public function testExecuteOneOrdersReleasedFromHold() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('canUnhold') - ->willReturn(true); - $order1->expects($this->once()) - ->method('getEntityId'); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn(count($orders)); - - $order2->expects($this->once()) - ->method('canUnhold') - ->willReturn(false); - - $this->orderManagementMock->expects($this->atLeastOnce())->method('unHold')->willReturn(true); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with('1 order(s) were not released from on hold status.'); - - $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') - ->with('1 order(s) have been released from on hold status.'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } - - public function testExecuteNoReleasedOrderFromHold() - { - $order1 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - $order2 = $this->getMockBuilder(\Magento\Sales\Model\Order::class) - ->disableOriginalConstructor() - ->getMock(); - - $orders = [$order1, $order2]; - - $this->orderCollectionMock->expects($this->any()) - ->method('getItems') - ->willReturn($orders); - - $order1->expects($this->once()) - ->method('canUnhold') - ->willReturn(false); - - $this->orderCollectionMock->expects($this->once()) - ->method('count') - ->willReturn(count($orders)); - - $order2->expects($this->once()) - ->method('canUnhold') - ->willReturn(false); - - $this->messageManagerMock->expects($this->once()) - ->method('addError') - ->with('No order(s) were released from on hold status.'); - - $this->resultRedirectMock->expects($this->once()) - ->method('setPath') - ->with('sales/*/') - ->willReturnSelf(); - - $this->massAction->execute(); - } -} From fc1c1d2ab5d774d527ff97630f75a5072fa1bf18 Mon Sep 17 00:00:00 2001 From: Vinai Kopp Date: Sat, 16 Jun 2018 20:51:24 +0200 Subject: [PATCH 029/529] Rename parameter variable to make intent more easy to understand. --- .../Customer/view/frontend/web/js/customer-data.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js index 56ee437d9704f..27c8230f9b9af 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js +++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js @@ -74,17 +74,17 @@ define([ /** * @param {Object} sectionNames - * @param {Boolean} updateSectionId + * @param {Boolean} forceNewSectionTimestamp * @return {*} */ - getFromServer: function (sectionNames, updateSectionId) { + getFromServer: function (sectionNames, forceNewSectionTimestamp) { var parameters; sectionNames = sectionConfig.filterClientSideSections(sectionNames); parameters = _.isArray(sectionNames) ? { sections: sectionNames.join(',') } : []; - parameters['update_section_id'] = updateSectionId; + parameters['update_section_id'] = forceNewSectionTimestamp; return $.getJSON(options.sectionLoadUrl, parameters).fail(function (jqXHR) { throw new Error(jqXHR); @@ -324,11 +324,11 @@ define([ /** * @param {Array} sectionNames - * @param {Boolean} updateSectionId + * @param {Boolean} forceNewSectionTimestamp * @return {*} */ - reload: function (sectionNames, updateSectionId) { - return dataProvider.getFromServer(sectionNames, updateSectionId).done(function (sections) { + reload: function (sectionNames, forceNewSectionTimestamp) { + return dataProvider.getFromServer(sectionNames, forceNewSectionTimestamp).done(function (sections) { $(document).trigger('customer-data-reload', [sectionNames]); buffer.update(sections); }); From dbef5af8ae69a2f908aa7dc6602157c62000d8e5 Mon Sep 17 00:00:00 2001 From: Oleksandr Gorkun Date: Mon, 18 Jun 2018 16:57:18 +0300 Subject: [PATCH 030/529] MAGETWO-92722: [Backport for 2.2.x] E-mail admin users when a new administrator is created. --- .../User/Controller/Adminhtml/User/Save.php | 7 +- app/code/Magento/User/Model/User.php | 155 ++++++++++++++---- app/code/Magento/User/etc/config.xml | 1 + app/code/Magento/User/etc/email_templates.xml | 6 + .../email/new_user_notification.html | 18 ++ 5 files changed, 151 insertions(+), 36 deletions(-) create mode 100644 app/code/Magento/User/view/adminhtml/email/new_user_notification.html diff --git a/app/code/Magento/User/Controller/Adminhtml/User/Save.php b/app/code/Magento/User/Controller/Adminhtml/User/Save.php index 3b37ce10c0151..d7d1c8b0e22a6 100644 --- a/app/code/Magento/User/Controller/Adminhtml/User/Save.php +++ b/app/code/Magento/User/Controller/Adminhtml/User/Save.php @@ -6,6 +6,7 @@ namespace Magento\User\Controller\Adminhtml\User; use Magento\Framework\Exception\AuthenticationException; +use Magento\Framework\Exception\MailException; use Magento\Framework\Exception\State\UserLockedException; use Magento\Security\Model\SecurityCookie; @@ -84,17 +85,19 @@ public function execute() $currentUser->performIdentityCheck($data[$currentUserPasswordField]); $model->save(); - $model->sendNotificationEmailsIfRequired(); - $this->messageManager->addSuccess(__('You saved the user.')); $this->_getSession()->setUserData(false); $this->_redirect('adminhtml/*/'); + + $model->sendNotificationEmailsIfRequired(); } catch (UserLockedException $e) { $this->_auth->logout(); $this->getSecurityCookie()->setLogoutReasonCookie( \Magento\Security\Model\AdminSessionsManager::LOGOUT_REASON_USER_LOCKED ); $this->_redirect('adminhtml/*/'); + } catch (MailException $exception) { + $this->messageManager->addErrorMessage($exception->getMessage()); } catch (\Magento\Framework\Exception\AuthenticationException $e) { $this->messageManager->addError(__('You have entered an invalid password for current user.')); $this->redirectToEdit($model, $data); diff --git a/app/code/Magento/User/Model/User.php b/app/code/Magento/User/Model/User.php index 2a7d43008f2ad..5a44de24fd40d 100644 --- a/app/code/Magento/User/Model/User.php +++ b/app/code/Magento/User/Model/User.php @@ -7,7 +7,9 @@ use Magento\Backend\App\Area\FrontNameResolver; use Magento\Backend\Model\Auth\Credential\StorageInterface; +use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Exception\MailException; use Magento\Framework\Model\AbstractModel; use Magento\Framework\Exception\AuthenticationException; use Magento\Framework\Serialize\Serializer\Json; @@ -40,10 +42,14 @@ class User extends AbstractModel implements StorageInterface, UserInterface */ const XML_PATH_FORGOT_EMAIL_TEMPLATE = 'admin/emails/forgot_email_template'; + const XML_PATH_NEW_USER_EMAIL_TEMPLATE = 'admin/emails/new_user_notification_template'; + const XML_PATH_FORGOT_EMAIL_IDENTITY = 'admin/emails/forgot_email_identity'; const XML_PATH_USER_NOTIFICATION_TEMPLATE = 'admin/emails/user_notification_template'; + const DEPLOYMENT_CONFIG_ADMIN_EMAIL = 'user_admin_email'; + /** @deprecated */ const XML_PATH_RESET_PASSWORD_TEMPLATE = 'admin/emails/reset_password_template'; @@ -121,6 +127,11 @@ class User extends AbstractModel implements StorageInterface, UserInterface */ private $serializer; + /** + * @var DeploymentConfig + */ + private $deploymentConfig; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -136,6 +147,7 @@ class User extends AbstractModel implements StorageInterface, UserInterface * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data * @param Json $serializer + * @param DeploymentConfig|null $deploymentConfig * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -152,7 +164,8 @@ public function __construct( \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, array $data = [], - Json $serializer = null + Json $serializer = null, + DeploymentConfig $deploymentConfig = null ) { $this->_encryptor = $encryptor; parent::__construct($context, $registry, $resource, $resourceCollection, $data); @@ -164,6 +177,8 @@ public function __construct( $this->_storeManager = $storeManager; $this->validationRules = $validationRules; $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + $this->deploymentConfig = $deploymentConfig + ?? ObjectManager::getInstance()->get(DeploymentConfig::class); } /** @@ -395,6 +410,41 @@ public function roleUserExists() return is_array($result) && count($result) > 0 ? true : false; } + /** + * Send a notification to an admin. + * + * @param string $templateConfigId + * @param array $templateVars + * @param string|null $toEmail + * @param string|null $toName + * @throws MailException + * + * @return void + */ + private function sendNotification( + string $templateConfigId, + array $templateVars, + string $toEmail = null, + string $toName = null + ) { + $toEmail = $toEmail ?? $this->getEmail(); + $toName = $toName ?? $this->getName(); + $this->_transportBuilder + ->setTemplateIdentifier($this->_config->getValue($templateConfigId)) + ->setTemplateModel(\Magento\Email\Model\BackendTemplate::class) + ->setTemplateOptions([ + 'area' => FrontNameResolver::AREA_CODE, + 'store' => Store::DEFAULT_STORE_ID + ]) + ->setTemplateVars($templateVars) + ->setFrom( + $this->_config->getValue(self::XML_PATH_FORGOT_EMAIL_IDENTITY) + ) + ->addTo($toEmail, $toName) + ->getTransport() + ->sendMessage(); + } + /** * Send email with reset password confirmation link * @@ -402,16 +452,16 @@ public function roleUserExists() */ public function sendPasswordResetConfirmationEmail() { - $templateId = $this->_config->getValue(self::XML_PATH_FORGOT_EMAIL_TEMPLATE); - $transport = $this->_transportBuilder->setTemplateIdentifier($templateId) - ->setTemplateModel(\Magento\Email\Model\BackendTemplate::class) - ->setTemplateOptions(['area' => FrontNameResolver::AREA_CODE, 'store' => Store::DEFAULT_STORE_ID]) - ->setTemplateVars(['user' => $this, 'store' => $this->_storeManager->getStore(Store::DEFAULT_STORE_ID)]) - ->setFrom($this->_config->getValue(self::XML_PATH_FORGOT_EMAIL_IDENTITY)) - ->addTo($this->getEmail(), $this->getName()) - ->getTransport(); + $this->sendNotification( + self::XML_PATH_FORGOT_EMAIL_TEMPLATE, + [ + 'user' => $this, + 'store' => $this->_storeManager->getStore( + Store::DEFAULT_STORE_ID + ) + ] + ); - $transport->sendMessage(); return $this; } @@ -427,19 +477,63 @@ public function sendPasswordResetNotificationEmail() return $this; } + /** + * Send notification about a new user created. + * + * @throws MailException + * @return void + */ + private function sendNewUserNotificationEmail() + { + $toEmails = []; + $generalEmail = $this->_config->getValue( + 'trans_email/ident_general/email' + ); + if ($generalEmail) { + $toEmails[] = $generalEmail; + } + $adminEmail = $this->deploymentConfig->get( + static::DEPLOYMENT_CONFIG_ADMIN_EMAIL + ); + if ($adminEmail) { + $toEmails[] = $adminEmail; + } + + foreach ($toEmails as $toEmail) { + $this->sendNotification( + self::XML_PATH_NEW_USER_EMAIL_TEMPLATE, + [ + 'user' => $this, + 'store' => $this->_storeManager->getStore( + Store::DEFAULT_STORE_ID + ) + ], + $toEmail, + 'Administrator' + ); + } + } + /** * Check changes and send notification emails * + * @throws MailException * @return $this * @since 100.1.0 */ public function sendNotificationEmailsIfRequired() { - $changes = $this->createChangesDescriptionString(); - - if ($changes) { - if ($this->getEmail() != $this->getOrigData('email') && $this->getOrigData('email')) { - $this->sendUserNotificationEmail($changes, $this->getOrigData('email')); + if ($this->isObjectNew()) { + //Notification about a new user + $this->sendNewUserNotificationEmail(); + } elseif ($changes = $this->createChangesDescriptionString()) { + if ($this->getEmail() != $this->getOrigData('email') + && $this->getOrigData('email') + ) { + $this->sendUserNotificationEmail( + $changes, + $this->getOrigData('email') + ); } $this->sendUserNotificationEmail($changes); } @@ -479,31 +573,24 @@ protected function createChangesDescriptionString() * * @param string $changes * @param string $email + * @throws MailException * @return $this * @since 100.1.0 */ protected function sendUserNotificationEmail($changes, $email = null) { - if ($email === null) { - $email = $this->getEmail(); - } - - $transport = $this->_transportBuilder - ->setTemplateIdentifier($this->_config->getValue(self::XML_PATH_USER_NOTIFICATION_TEMPLATE)) - ->setTemplateModel(\Magento\Email\Model\BackendTemplate::class) - ->setTemplateOptions(['area' => FrontNameResolver::AREA_CODE, 'store' => Store::DEFAULT_STORE_ID]) - ->setTemplateVars( - [ - 'user' => $this, - 'store' => $this->_storeManager->getStore(Store::DEFAULT_STORE_ID), - 'changes' => $changes - ] - ) - ->setFrom($this->_config->getValue(self::XML_PATH_FORGOT_EMAIL_IDENTITY)) - ->addTo($email, $this->getName()) - ->getTransport(); + $this->sendNotification( + self::XML_PATH_USER_NOTIFICATION_TEMPLATE, + [ + 'user' => $this, + 'store' => $this->_storeManager->getStore( + Store::DEFAULT_STORE_ID + ), + 'changes' => $changes + ], + $email + ); - $transport->sendMessage(); return $this; } diff --git a/app/code/Magento/User/etc/config.xml b/app/code/Magento/User/etc/config.xml index f6a3924b5a27d..c1f51bcbecef4 100644 --- a/app/code/Magento/User/etc/config.xml +++ b/app/code/Magento/User/etc/config.xml @@ -10,6 +10,7 @@ admin_emails_forgot_email_template + admin_emails_new_user_notification_template general admin_emails_user_notification_template diff --git a/app/code/Magento/User/etc/email_templates.xml b/app/code/Magento/User/etc/email_templates.xml index b998f304c249b..637c2b799f37a 100644 --- a/app/code/Magento/User/etc/email_templates.xml +++ b/app/code/Magento/User/etc/email_templates.xml @@ -8,4 +8,10 @@