Skip to content

Commit 4f056c0

Browse files
author
hwyu@adobe.com
committed
Merge remote-tracking branch 'upstream/2.3.7-develop' into MC-38715
2 parents 400670f + 70e10bc commit 4f056c0

File tree

8 files changed

+376
-94
lines changed

8 files changed

+376
-94
lines changed

app/code/Magento/Customer/Controller/Account/EditPost.php

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Magento\Customer\Controller\Account;
99

1010
use Magento\Customer\Api\Data\CustomerInterface;
11+
use Magento\Customer\Api\SessionCleanerInterface;
1112
use Magento\Customer\Model\AddressRegistry;
1213
use Magento\Framework\App\Action\HttpPostActionInterface as HttpPostActionInterface;
1314
use Magento\Customer\Model\AuthenticationInterface;
@@ -27,13 +28,15 @@
2728
use Magento\Framework\Escaper;
2829
use Magento\Framework\Exception\InputException;
2930
use Magento\Framework\Exception\InvalidEmailOrPasswordException;
31+
use Magento\Framework\Exception\LocalizedException;
3032
use Magento\Framework\Exception\NoSuchEntityException;
3133
use Magento\Framework\Exception\State\UserLockedException;
3234
use Magento\Customer\Controller\AbstractAccount;
3335
use Magento\Framework\Phrase;
3436

3537
/**
36-
* Class EditPost
38+
* Customer edit page.
39+
*
3740
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
3841
*/
3942
class EditPost extends AbstractAccount implements CsrfAwareActionInterface, HttpPostActionInterface
@@ -69,7 +72,7 @@ class EditPost extends AbstractAccount implements CsrfAwareActionInterface, Http
6972
protected $session;
7073

7174
/**
72-
* @var \Magento\Customer\Model\EmailNotificationInterface
75+
* @var EmailNotificationInterface
7376
*/
7477
private $emailNotification;
7578

@@ -93,6 +96,11 @@ class EditPost extends AbstractAccount implements CsrfAwareActionInterface, Http
9396
*/
9497
private $addressRegistry;
9598

99+
/**
100+
* @var SessionCleanerInterface|null
101+
*/
102+
private $sessionCleaner;
103+
96104
/**
97105
* @param Context $context
98106
* @param Session $customerSession
@@ -102,6 +110,7 @@ class EditPost extends AbstractAccount implements CsrfAwareActionInterface, Http
102110
* @param CustomerExtractor $customerExtractor
103111
* @param Escaper|null $escaper
104112
* @param AddressRegistry|null $addressRegistry
113+
* @param SessionCleanerInterface|null $sessionCleaner
105114
*/
106115
public function __construct(
107116
Context $context,
@@ -111,7 +120,8 @@ public function __construct(
111120
Validator $formKeyValidator,
112121
CustomerExtractor $customerExtractor,
113122
?Escaper $escaper = null,
114-
AddressRegistry $addressRegistry = null
123+
AddressRegistry $addressRegistry = null,
124+
?SessionCleanerInterface $sessionCleaner = null
115125
) {
116126
parent::__construct($context);
117127
$this->session = $customerSession;
@@ -121,6 +131,7 @@ public function __construct(
121131
$this->customerExtractor = $customerExtractor;
122132
$this->escaper = $escaper ?: ObjectManager::getInstance()->get(Escaper::class);
123133
$this->addressRegistry = $addressRegistry ?: ObjectManager::getInstance()->get(AddressRegistry::class);
134+
$this->sessionCleaner = $sessionCleaner ?: ObjectManager::getInstance()->get(SessionCleanerInterface::class);
124135
}
125136

126137
/**
@@ -132,9 +143,7 @@ private function getAuthentication()
132143
{
133144

134145
if (!($this->authentication instanceof AuthenticationInterface)) {
135-
return ObjectManager::getInstance()->get(
136-
\Magento\Customer\Model\AuthenticationInterface::class
137-
);
146+
return ObjectManager::getInstance()->get(AuthenticationInterface::class);
138147
} else {
139148
return $this->authentication;
140149
}
@@ -149,9 +158,7 @@ private function getAuthentication()
149158
private function getEmailNotification()
150159
{
151160
if (!($this->emailNotification instanceof EmailNotificationInterface)) {
152-
return ObjectManager::getInstance()->get(
153-
EmailNotificationInterface::class
154-
);
161+
return ObjectManager::getInstance()->get(EmailNotificationInterface::class);
155162
} else {
156163
return $this->emailNotification;
157164
}
@@ -160,9 +167,8 @@ private function getEmailNotification()
160167
/**
161168
* @inheritDoc
162169
*/
163-
public function createCsrfValidationException(
164-
RequestInterface $request
165-
): ?InvalidRequestException {
170+
public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
171+
{
166172
/** @var Redirect $resultRedirect */
167173
$resultRedirect = $this->resultRedirectFactory->create();
168174
$resultRedirect->setPath('*/*/edit');
@@ -184,11 +190,11 @@ public function validateForCsrf(RequestInterface $request): ?bool
184190
/**
185191
* Change customer email or password action
186192
*
187-
* @return \Magento\Framework\Controller\Result\Redirect
193+
* @return Redirect
188194
*/
189195
public function execute()
190196
{
191-
/** @var \Magento\Framework\Controller\Result\Redirect $resultRedirect */
197+
/** @var Redirect $resultRedirect */
192198
$resultRedirect = $this->resultRedirectFactory->create();
193199
$validFormKey = $this->formKeyValidator->validate($this->getRequest());
194200

@@ -217,6 +223,7 @@ public function execute()
217223
);
218224
$this->dispatchSuccessEvent($customerCandidateDataObject);
219225
$this->messageManager->addSuccessMessage(__('You saved the account information.'));
226+
220227
return $resultRedirect->setPath('customer/account');
221228
} catch (InvalidEmailOrPasswordException $e) {
222229
$this->messageManager->addErrorMessage($this->escaper->escapeHtml($e->getMessage()));
@@ -228,13 +235,14 @@ public function execute()
228235
$this->session->logout();
229236
$this->session->start();
230237
$this->messageManager->addErrorMessage($message);
238+
231239
return $resultRedirect->setPath('customer/account/login');
232240
} catch (InputException $e) {
233241
$this->messageManager->addErrorMessage($this->escaper->escapeHtml($e->getMessage()));
234242
foreach ($e->getErrors() as $error) {
235243
$this->messageManager->addErrorMessage($this->escaper->escapeHtml($error->getMessage()));
236244
}
237-
} catch (\Magento\Framework\Exception\LocalizedException $e) {
245+
} catch (LocalizedException $e) {
238246
$this->messageManager->addErrorMessage($e->getMessage());
239247
} catch (\Exception $e) {
240248
$this->messageManager->addException($e, __('We can\'t save the customer.'));
@@ -246,16 +254,17 @@ public function execute()
246254
/** @var Redirect $resultRedirect */
247255
$resultRedirect = $this->resultRedirectFactory->create();
248256
$resultRedirect->setPath('*/*/edit');
257+
249258
return $resultRedirect;
250259
}
251260

252261
/**
253262
* Account editing action completed successfully event
254263
*
255-
* @param \Magento\Customer\Api\Data\CustomerInterface $customerCandidateDataObject
264+
* @param CustomerInterface $customerCandidateDataObject
256265
* @return void
257266
*/
258-
private function dispatchSuccessEvent(\Magento\Customer\Api\Data\CustomerInterface $customerCandidateDataObject)
267+
private function dispatchSuccessEvent(CustomerInterface $customerCandidateDataObject)
259268
{
260269
$this->_eventManager->dispatch(
261270
'customer_account_edited',
@@ -268,7 +277,7 @@ private function dispatchSuccessEvent(\Magento\Customer\Api\Data\CustomerInterfa
268277
*
269278
* @param int $customerId
270279
*
271-
* @return \Magento\Customer\Api\Data\CustomerInterface
280+
* @return CustomerInterface
272281
*/
273282
private function getCustomerDataObject($customerId)
274283
{
@@ -278,13 +287,13 @@ private function getCustomerDataObject($customerId)
278287
/**
279288
* Create Data Transfer Object of customer candidate
280289
*
281-
* @param \Magento\Framework\App\RequestInterface $inputData
282-
* @param \Magento\Customer\Api\Data\CustomerInterface $currentCustomerData
283-
* @return \Magento\Customer\Api\Data\CustomerInterface
290+
* @param RequestInterface $inputData
291+
* @param CustomerInterface $currentCustomerData
292+
* @return CustomerInterface
284293
*/
285294
private function populateNewCustomerDataObject(
286-
\Magento\Framework\App\RequestInterface $inputData,
287-
\Magento\Customer\Api\Data\CustomerInterface $currentCustomerData
295+
RequestInterface $inputData,
296+
CustomerInterface $currentCustomerData
288297
) {
289298
$attributeValues = $this->getCustomerMapper()->toFlatArray($currentCustomerData);
290299
$customerDto = $this->customerExtractor->extract(
@@ -330,12 +339,12 @@ protected function changeCustomerPassword($email)
330339
/**
331340
* Process change email request
332341
*
333-
* @param \Magento\Customer\Api\Data\CustomerInterface $currentCustomerDataObject
342+
* @param CustomerInterface $currentCustomerDataObject
334343
* @return void
335344
* @throws InvalidEmailOrPasswordException
336345
* @throws UserLockedException
337346
*/
338-
private function processChangeEmailRequest(\Magento\Customer\Api\Data\CustomerInterface $currentCustomerDataObject)
347+
private function processChangeEmailRequest(CustomerInterface $currentCustomerDataObject)
339348
{
340349
if ($this->getRequest()->getParam('change_email')) {
341350
// authenticate user for changing email
@@ -344,6 +353,7 @@ private function processChangeEmailRequest(\Magento\Customer\Api\Data\CustomerIn
344353
$currentCustomerDataObject->getId(),
345354
$this->getRequest()->getPost('current_password')
346355
);
356+
$this->sessionCleaner->clearFor($currentCustomerDataObject->getId());
347357
} catch (InvalidEmailOrPasswordException $e) {
348358
throw new InvalidEmailOrPasswordException(
349359
__("The password doesn't match this account. Verify the password and try again.")
@@ -362,7 +372,7 @@ private function processChangeEmailRequest(\Magento\Customer\Api\Data\CustomerIn
362372
private function getCustomerMapper()
363373
{
364374
if ($this->customerMapper === null) {
365-
$this->customerMapper = ObjectManager::getInstance()->get(\Magento\Customer\Model\Customer\Mapper::class);
375+
$this->customerMapper = ObjectManager::getInstance()->get(Mapper::class);
366376
}
367377
return $this->customerMapper;
368378
}

app/code/Magento/Customer/Model/Metadata/Form/File.php

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Magento\Framework\Api\Data\ImageContentInterface;
1212
use Magento\Framework\App\Filesystem\DirectoryList;
1313
use Magento\Framework\App\ObjectManager;
14+
use Magento\Framework\Exception\LocalizedException;
1415
use Magento\Framework\File\UploaderFactory;
1516
use Magento\Framework\Filesystem;
1617

@@ -111,6 +112,7 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request)
111112
$extend = $this->_getRequestValue($request);
112113

113114
$attrCode = $this->getAttribute()->getAttributeCode();
115+
// phpcs:ignore Magento2.Security.Superglobal
114116
if ($this->_requestScope || !isset($_FILES[$attrCode])) {
115117
$value = [];
116118
if (strpos($this->_requestScope, '/') !== false) {
@@ -120,9 +122,10 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request)
120122
$mainScope = $this->_requestScope;
121123
$scopes = [];
122124
}
123-
125+
// phpcs:disable Magento2.Security.Superglobal
124126
if (!empty($_FILES[$mainScope])) {
125127
foreach ($_FILES[$mainScope] as $fileKey => $scopeData) {
128+
// phpcs:enable Magento2.Security.Superglobal
126129
foreach ($scopes as $scopeName) {
127130
if (isset($scopeData[$scopeName])) {
128131
$scopeData = $scopeData[$scopeName];
@@ -147,8 +150,10 @@ public function extractValue(\Magento\Framework\App\RequestInterface $request)
147150
$value = [];
148151
}
149152
} else {
153+
// phpcs:disable Magento2.Security.Superglobal
150154
if (isset($_FILES[$attrCode])) {
151155
$value = $_FILES[$attrCode];
156+
// phpcs:enable Magento2.Security.Superglobal
152157
} else {
153158
$value = [];
154159
}
@@ -171,7 +176,7 @@ protected function _validateByRules($value)
171176
{
172177
$label = $value['name'];
173178
$rules = $this->getAttribute()->getValidationRules();
174-
$extension = pathinfo($value['name'], PATHINFO_EXTENSION);
179+
$extension = $this->fileProcessor->getStat($value['name'])['extension'];
175180
$fileExtensions = ArrayObjectSearch::getArrayElementByName(
176181
$rules,
177182
'file_extensions'
@@ -219,12 +224,13 @@ protected function _validateByRules($value)
219224
*/
220225
protected function _isUploadedFile($filename)
221226
{
227+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
222228
if (is_uploaded_file($filename)) {
223229
return true;
224230
}
225231

226232
// This case is required for file uploader UI component
227-
$temporaryFile = FileProcessor::TMP_DIR . '/' . pathinfo($filename)['basename'];
233+
$temporaryFile = FileProcessor::TMP_DIR . '/' . $this->fileProcessor->getStat($filename)['basename'];
228234
if ($this->fileProcessor->isExist($temporaryFile)) {
229235
return true;
230236
}
@@ -343,16 +349,20 @@ protected function processInputFieldValue($value)
343349
}
344350

345351
if (!empty($value['tmp_name'])) {
352+
$uploader = $this->uploaderFactory->create(['fileId' => $value]);
353+
$fileExtension = $uploader->getFileExtension();
354+
if (!$this->_fileValidator->isValid($fileExtension)) {
355+
throw new LocalizedException($this->_fileValidator->getMessages()[$fileExtension]);
356+
}
357+
$uploader->setFilesDispersion(true);
358+
$uploader->setFilenamesCaseSensitivity(false);
359+
$uploader->setAllowRenameFiles(true);
346360
try {
347-
$uploader = $this->uploaderFactory->create(['fileId' => $value]);
348-
$uploader->setFilesDispersion(true);
349-
$uploader->setFilenamesCaseSensitivity(false);
350-
$uploader->setAllowRenameFiles(true);
351361
$uploader->save($mediaDir->getAbsolutePath($this->_entityTypeCode), $value['name']);
352-
$result = $uploader->getUploadedFileName();
353362
} catch (\Exception $e) {
354363
$this->_logger->critical($e);
355364
}
365+
$result = $uploader->getUploadedFileName();
356366
}
357367

358368
return $result;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
11+
<test name="StorefrontChangeCustomerEmailTest">
12+
<annotations>
13+
<features value="Customer"/>
14+
<stories value="Update Customer"/>
15+
<title value="Changing Customer Email Test"/>
16+
<description value="Changing Customer's email with correct and wrong passwords"/>
17+
<testCaseId value="MC-38725"/>
18+
<useCaseId value="MC-38676"/>
19+
<severity value="MAJOR"/>
20+
<group value="customer"/>
21+
</annotations>
22+
<before>
23+
<createData entity="Simple_US_Customer" stepKey="customer"/>
24+
</before>
25+
<after>
26+
<actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="customerLogout"/>
27+
<deleteData createDataKey="customer" stepKey="deleteCustomer"/>
28+
</after>
29+
30+
<actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount">
31+
<argument name="Customer" value="$customer$"/>
32+
</actionGroup>
33+
<!-- Navigate to "Account Information" tab First Time-->
34+
<actionGroup ref="StorefrontOpenCustomerAccountInfoEditPageActionGroup" stepKey="goToCustomerEditPageFirstTime"/>
35+
<!-- Entering new email, saving with correct password -->
36+
<actionGroup ref="StorefrontCustomerChangeEmailActionGroup" stepKey="changeEmailCorrectAttempt">
37+
<argument name="email" value="$customer.email$"/>
38+
<argument name="password" value="$customer.password$"/>
39+
</actionGroup>
40+
<!-- See Success Notify, check that customer was force logged out -->
41+
<actionGroup ref="AssertMessageCustomerChangeAccountInfoActionGroup" stepKey="seeSuccessMessage">
42+
<argument name="message" value="You saved the account information."/>
43+
</actionGroup>
44+
<see userInput="Default welcome msg!" selector="{{StorefrontPanelHeaderSection.WelcomeMessage}}" stepKey="assertWelcomeMessage"/>
45+
<actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccountAfterEmailChange">
46+
<argument name="Customer" value="$customer$"/>
47+
</actionGroup>
48+
<!-- Navigate to "Account Information" tab Second Time-->
49+
<actionGroup ref="StorefrontOpenCustomerAccountInfoEditPageActionGroup" stepKey="goToCustomerEditPageSecondTime" />
50+
<!-- Entering new email, saving with wrong password -->
51+
<actionGroup ref="StorefrontCustomerChangeEmailActionGroup" stepKey="changeEmailWrongAttempt">
52+
<argument name="email" value="$customer.email$"/>
53+
<argument name="password" value="WRONG_PASSWORD_123123q"/>
54+
</actionGroup>
55+
<!-- See Failure Message-->
56+
<actionGroup ref="AssertMessageCustomerChangeAccountInfoActionGroup" stepKey="seeFailureMessage">
57+
<argument name="message" value="The password doesn't match this account. Verify the password and try again."/>
58+
<argument name="messageType" value="error"/>
59+
</actionGroup>
60+
</test>
61+
</tests>

0 commit comments

Comments
 (0)