Skip to content

Commit b847675

Browse files
committed
Merge remote-tracking branch 'origin/2.2-develop' into MAGETWO-90056
2 parents 6365cad + ace297a commit b847675

File tree

58 files changed

+1288
-118
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1288
-118
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ atlassian*
3333
/.php_cs
3434
/.php_cs.cache
3535
/grunt-config.json
36-
/dev/tools/grunt/configs/local-themes.js
3736

3837
/pub/media/*.*
3938
!/pub/media/.htaccess

app/code/Magento/Bundle/Model/Product/Type.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -821,11 +821,11 @@ private function recursiveIntval(array $array)
821821
private function multiToFlatArray(array $array)
822822
{
823823
$flatArray = [];
824-
foreach ($array as $key => $value) {
824+
foreach ($array as $value) {
825825
if (is_array($value)) {
826826
$flatArray = array_merge($flatArray, $this->multiToFlatArray($value));
827827
} else {
828-
$flatArray[$key] = $value;
828+
$flatArray[] = $value;
829829
}
830830
}
831831

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Captcha\Test\Unit\Observer;
9+
10+
use Magento\Captcha\Helper\Data;
11+
use Magento\Captcha\Model\DefaultModel;
12+
use Magento\Captcha\Observer\CaptchaStringResolver;
13+
use Magento\Captcha\Observer\CheckUserLoginBackendObserver;
14+
use Magento\Framework\App\RequestInterface;
15+
use Magento\Framework\Event;
16+
use Magento\Framework\Event\Observer;
17+
use Magento\Framework\Message\ManagerInterface;
18+
use PHPUnit\Framework\TestCase;
19+
use PHPUnit_Framework_MockObject_MockObject as MockObject;
20+
21+
/**
22+
* Class CheckUserLoginBackendObserverTest
23+
*/
24+
class CheckUserLoginBackendObserverTest extends TestCase
25+
{
26+
/**
27+
* @var CheckUserLoginBackendObserver
28+
*/
29+
private $observer;
30+
31+
/**
32+
* @var ManagerInterface|MockObject
33+
*/
34+
private $messageManagerMock;
35+
36+
/**
37+
* @var CaptchaStringResolver|MockObject
38+
*/
39+
private $captchaStringResolverMock;
40+
41+
/**
42+
* @var RequestInterface|MockObject
43+
*/
44+
private $requestMock;
45+
46+
/**
47+
* @var Data|MockObject
48+
*/
49+
private $helperMock;
50+
51+
/**
52+
* Set Up
53+
*
54+
* @return void
55+
*/
56+
protected function setUp()
57+
{
58+
$this->helperMock = $this->createMock(Data::class);
59+
$this->messageManagerMock = $this->createMock(ManagerInterface::class);
60+
$this->captchaStringResolverMock = $this->createMock(CaptchaStringResolver::class);
61+
$this->requestMock = $this->createMock(RequestInterface::class);
62+
63+
$this->observer = new CheckUserLoginBackendObserver(
64+
$this->helperMock,
65+
$this->captchaStringResolverMock,
66+
$this->requestMock
67+
);
68+
}
69+
70+
/**
71+
* Test check user login in backend with correct captcha
72+
*
73+
* @dataProvider requiredCaptchaDataProvider
74+
* @param bool $isRequired
75+
* @return void
76+
*/
77+
public function testCheckOnBackendLoginWithCorrectCaptcha(bool $isRequired)
78+
{
79+
$formId = 'backend_login';
80+
$login = 'admin';
81+
$captchaValue = 'captcha-value';
82+
83+
/** @var Observer|MockObject $observerMock */
84+
$observerMock = $this->createPartialMock(Observer::class, ['getEvent']);
85+
$eventMock = $this->createPartialMock(Event::class, ['getUsername']);
86+
$captcha = $this->createMock(DefaultModel::class);
87+
88+
$eventMock->method('getUsername')->willReturn('admin');
89+
$observerMock->method('getEvent')->willReturn($eventMock);
90+
$captcha->method('isRequired')->with($login)->willReturn($isRequired);
91+
$captcha->method('isCorrect')->with($captchaValue)->willReturn(true);
92+
$this->helperMock->method('getCaptcha')->with($formId)->willReturn($captcha);
93+
$this->captchaStringResolverMock->method('resolve')->with($this->requestMock, $formId)
94+
->willReturn($captchaValue);
95+
96+
$this->observer->execute($observerMock);
97+
}
98+
99+
/**
100+
* @return array
101+
*/
102+
public function requiredCaptchaDataProvider(): array
103+
{
104+
return [
105+
[true],
106+
[false]
107+
];
108+
}
109+
110+
/**
111+
* Test check user login in backend with wrong captcha
112+
*
113+
* @return void
114+
* @expectedException \Magento\Framework\Exception\Plugin\AuthenticationException
115+
*/
116+
public function testCheckOnBackendLoginWithWrongCaptcha()
117+
{
118+
$formId = 'backend_login';
119+
$login = 'admin';
120+
$captchaValue = 'captcha-value';
121+
122+
/** @var Observer|MockObject $observerMock */
123+
$observerMock = $this->createPartialMock(Observer::class, ['getEvent']);
124+
$eventMock = $this->createPartialMock(Event::class, ['getUsername']);
125+
$captcha = $this->createMock(DefaultModel::class);
126+
127+
$eventMock->method('getUsername')->willReturn($login);
128+
$observerMock->method('getEvent')->willReturn($eventMock);
129+
$captcha->method('isRequired')->with($login)->willReturn(true);
130+
$captcha->method('isCorrect')->with($captchaValue)->willReturn(false);
131+
$this->helperMock->method('getCaptcha')->with($formId)->willReturn($captcha);
132+
$this->captchaStringResolverMock->method('resolve')->with($this->requestMock, $formId)
133+
->willReturn($captchaValue);
134+
135+
$this->observer->execute($observerMock);
136+
}
137+
}

app/code/Magento/Catalog/Block/Product/ProductList/Crosssell.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Crosssell extends \Magento\Catalog\Block\Product\AbstractProduct
2525
*/
2626
protected function _prepareData()
2727
{
28-
$product = $this->_coreRegistry->registry('product');
28+
$product = $this->getProduct();
2929
/* @var $product \Magento\Catalog\Model\Product */
3030

3131
$this->_itemCollection = $product->getCrossSellProductCollection()->addAttributeToSelect(

app/code/Magento/Catalog/Block/Product/ProductList/Related.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public function __construct(
8282
*/
8383
protected function _prepareData()
8484
{
85-
$product = $this->_coreRegistry->registry('product');
85+
$product = $this->getProduct();
8686
/* @var $product \Magento\Catalog\Model\Product */
8787

8888
$this->_itemCollection = $product->getRelatedProductCollection()->addAttributeToSelect(

app/code/Magento/Catalog/Block/Product/ProductList/Upsell.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public function __construct(
9797
*/
9898
protected function _prepareData()
9999
{
100-
$product = $this->_coreRegistry->registry('product');
100+
$product = $this->getProduct();
101101
/* @var $product \Magento\Catalog\Model\Product */
102102
$this->_itemCollection = $product->getUpSellProductCollection()->setPositionOrder()->addStoreFilter();
103103
if ($this->moduleManager->isEnabled('Magento_Checkout')) {

app/code/Magento/Catalog/Controller/Product/Compare.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,12 @@ public function setCustomerId($customerId)
139139
$this->_customerId = $customerId;
140140
return $this;
141141
}
142+
143+
/**
144+
* @inheritdoc
145+
*/
146+
public function execute()
147+
{
148+
return $this->resultRedirectFactory->create()->setPath('catalog/product_compare');
149+
}
142150
}

app/code/Magento/Catalog/Model/Product/Gallery/Processor.php

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
*/
66
namespace Magento\Catalog\Model\Product\Gallery;
77

8+
use Magento\Framework\Api\Data\ImageContentInterface;
89
use Magento\Framework\App\Filesystem\DirectoryList;
910
use Magento\Framework\Exception\LocalizedException;
10-
use Magento\Framework\Filesystem\DriverInterface;
11+
use Magento\Framework\App\ObjectManager;
1112

1213
/**
1314
* Catalog product Media Gallery attribute processor.
@@ -55,28 +56,39 @@ class Processor
5556
*/
5657
protected $resourceModel;
5758

59+
/**
60+
* @var \Magento\Framework\File\Mime
61+
*/
62+
private $mime;
63+
5864
/**
5965
* @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
6066
* @param \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageDb
6167
* @param \Magento\Catalog\Model\Product\Media\Config $mediaConfig
6268
* @param \Magento\Framework\Filesystem $filesystem
6369
* @param \Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel
70+
* @param \Magento\Framework\File\Mime|null $mime
71+
* @throws \Magento\Framework\Exception\FileSystemException
6472
*/
6573
public function __construct(
6674
\Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository,
6775
\Magento\MediaStorage\Helper\File\Storage\Database $fileStorageDb,
6876
\Magento\Catalog\Model\Product\Media\Config $mediaConfig,
6977
\Magento\Framework\Filesystem $filesystem,
70-
\Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel
78+
\Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel,
79+
\Magento\Framework\File\Mime $mime = null
7180
) {
7281
$this->attributeRepository = $attributeRepository;
7382
$this->fileStorageDb = $fileStorageDb;
7483
$this->mediaConfig = $mediaConfig;
7584
$this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
7685
$this->resourceModel = $resourceModel;
86+
$this->mime = $mime ?: ObjectManager::getInstance()->get(\Magento\Framework\File\Mime::class);
7787
}
7888

7989
/**
90+
* Return media_gallery attribute
91+
*
8092
* @return \Magento\Catalog\Api\Data\ProductAttributeInterface
8193
* @since 101.0.0
8294
*/
@@ -178,6 +190,13 @@ public function addImage(
178190
$attrCode = $this->getAttribute()->getAttributeCode();
179191
$mediaGalleryData = $product->getData($attrCode);
180192
$position = 0;
193+
194+
$absoluteFilePath = $this->mediaDirectory->getAbsolutePath($file);
195+
$imageMimeType = $this->mime->getMimeType($absoluteFilePath);
196+
$imageContent = $this->mediaDirectory->readFile($absoluteFilePath);
197+
$imageBase64 = base64_encode($imageContent);
198+
$imageName = $pathinfo['filename'];
199+
181200
if (!is_array($mediaGalleryData)) {
182201
$mediaGalleryData = ['images' => []];
183202
}
@@ -192,9 +211,17 @@ public function addImage(
192211
$mediaGalleryData['images'][] = [
193212
'file' => $fileName,
194213
'position' => $position,
195-
'media_type' => 'image',
196214
'label' => '',
197215
'disabled' => (int)$exclude,
216+
'media_type' => 'image',
217+
'types' => $mediaAttribute,
218+
'content' => [
219+
'data' => [
220+
ImageContentInterface::NAME => $imageName,
221+
ImageContentInterface::BASE64_ENCODED_DATA => $imageBase64,
222+
ImageContentInterface::TYPE => $imageMimeType,
223+
]
224+
]
198225
];
199226

200227
$product->setData($attrCode, $mediaGalleryData);
@@ -353,7 +380,8 @@ public function setMediaAttribute(\Magento\Catalog\Model\Product $product, $medi
353380
}
354381

355382
/**
356-
* get media attribute codes
383+
* Get media attribute codes
384+
*
357385
* @return array
358386
* @since 101.0.0
359387
*/
@@ -363,6 +391,8 @@ public function getMediaAttributeCodes()
363391
}
364392

365393
/**
394+
* Trim .tmp ending from filename
395+
*
366396
* @param string $file
367397
* @return string
368398
* @since 101.0.0
@@ -484,7 +514,6 @@ public function getAffectedFields($object)
484514
/**
485515
* Attribute value is not to be saved in a conventional way, separate table is used to store the complex value
486516
*
487-
* {@inheritdoc}
488517
* @since 101.0.0
489518
*/
490519
public function isScalar()

app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeSetSection.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
</section>
1919
<section name="AdminModifyAttributesSection">
2020
<!-- Parameter is the attribute name -->
21-
<element name="dropDownAttributeByName" type="select" selector="//*[text()='{{attributeName}}']/../..//select" parameterized="true"/>
21+
<element name="dropDownAttributeByName" type="select" selector="//*[text()='{{attributeName}}']/../../..//select" parameterized="true"/>
2222
</section>
2323
</sections>

app/code/Magento/Catalog/Test/Mftf/Section/AdminProductCustomizableOptionsSection.xml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
<element name="useDefaultOptionTitle" type="text" selector="[data-index='options'] tr.data-row [data-index='title'] [name^='options_use_default']"/>
1515
<element name="useDefaultOptionValueTitleByIndex" type="text" selector="[data-index='options'] [data-index='values'] tr[data-repeat-index='{{var1}}'] [name^='options_use_default']" parameterized="true"/>
1616
<element name="addOptionBtn" type="button" selector="button[data-index='button_add']"/>
17-
<element name="fillOptionTitle" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//label[text()='Option Title']/parent::span/parent::div//input[@class='admin__control-text']" parameterized="true"/>
18-
<element name="checkSelect" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//label[text()='Option Type']/parent::span/parent::div//div[@data-role='selected-option']" parameterized="true"/>
19-
<element name="checkDropDown" type="select" selector="//span[text()='{{var1}}']/ancestor::div[@class='fieldset-wrapper-title']/following-sibling::div[@data-role='collapsible-content']//div[@data-index='type']//div[contains(@class, 'action-menu')]//li[@class='admin__action-multiselect-menu-inner-item']//label[text()='Drop-down']" parameterized="true"/>
17+
<element name="fillOptionTitle" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//span[text()='Option Title']/parent::label/parent::div/parent::div//input[@class='admin__control-text']" parameterized="true"/>
18+
<element name="checkSelect" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//span[text()='Option Type']/parent::label/parent::div/parent::div//div[@data-role='selected-option']" parameterized="true"/>
19+
<element name="checkDropDown" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//parent::label/parent::div/parent::div//li[@class='admin__action-multiselect-menu-inner-item']//label[text()='Drop-down']" parameterized="true"/>
2020
<element name="clickAddValue" type="button" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tfoot//button" parameterized="true"/>
21-
<element name="fillOptionValueTitle" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody/tr[@data-repeat-index='{{var2}}']//label[text()='Title']/parent::span/parent::div//div[@class='admin__field-control']/input" parameterized="true"/>
21+
<element name="fillOptionValueTitle" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody/tr[@data-repeat-index='{{var2}}']//span[text()='Title']/parent::label/parent::div/parent::div//div[@class='admin__field-control']/input" parameterized="true"/>
2222
<element name="fillOptionValuePrice" type="input" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody/tr[@data-repeat-index='{{var2}}']//span[text()='Price']/parent::label/parent::div//div[@class='admin__control-addon']/input" parameterized="true"/>
23-
<element name="clickSelectPriceType" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody//tr[@data-repeat-index='{{var2}}']//label[text()='Price Type']/parent::span/parent::div//select" parameterized="true"/>
23+
<element name="clickSelectPriceType" type="select" selector="//span[text()='{{var1}}']/parent::div/parent::div/parent::div//tbody//tr[@data-repeat-index='{{var2}}']//span[text()='Price Type']/parent::label/parent::div/parent::div//select" parameterized="true"/>
2424
<!-- Elements that make it easier to select the most recently added element -->
2525
<element name="lastOptionTitle" type="input" selector="//*[@data-index='custom_options']//*[@data-index='options']/tbody/tr[last()]//*[contains(@class, '_required')]//input" />
2626
<element name="lastOptionTypeParent" type="block" selector="//*[@data-index='custom_options']//*[@data-index='options']/tbody/tr[last()]//*[contains(@class, 'admin__action-multiselect-text')]" />

0 commit comments

Comments
 (0)