Skip to content
This repository was archived by the owner on Apr 29, 2019. It is now read-only.

Commit 81d8ea6

Browse files
author
Magento CICD
authored
merge magento/2.3-develop into magento-borg/MAGETWO-91497-product-website
2 parents b91cdef + dcca458 commit 81d8ea6

File tree

55 files changed

+1251
-244
lines changed

Some content is hidden

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

55 files changed

+1251
-244
lines changed
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
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\Catalog\Test\Unit\Ui\Component\Product;
9+
10+
use Magento\Catalog\Ui\Component\Product\MassAction;
11+
use Magento\Framework\AuthorizationInterface;
12+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
13+
use Magento\Framework\View\Element\UiComponent\ContextInterface;
14+
15+
class MassActionTest extends \PHPUnit\Framework\TestCase
16+
{
17+
/**
18+
* @var ContextInterface|\PHPUnit_Framework_MockObject_MockObject
19+
*/
20+
private $contextMock;
21+
22+
/**
23+
* @var ObjectManager
24+
*/
25+
private $objectManager;
26+
27+
/**
28+
* @var AuthorizationInterface|\PHPUnit_Framework_MockObject_MockObject
29+
*/
30+
private $authorizationMock;
31+
32+
/**
33+
* @var MassAction
34+
*/
35+
private $massAction;
36+
37+
protected function setUp()
38+
{
39+
$this->objectManager = new ObjectManager($this);
40+
41+
$this->contextMock = $this->getMockBuilder(ContextInterface::class)
42+
->getMockForAbstractClass();
43+
$this->authorizationMock = $this->getMockBuilder(AuthorizationInterface::class)
44+
->getMockForAbstractClass();
45+
46+
$this->massAction = $this->objectManager->getObject(
47+
MassAction::class,
48+
[
49+
'authorization' => $this->authorizationMock,
50+
'context' => $this->contextMock,
51+
'data' => []
52+
]
53+
);
54+
}
55+
56+
public function testGetComponentName()
57+
{
58+
$this->assertTrue($this->massAction->getComponentName() === MassAction::NAME);
59+
}
60+
61+
/**
62+
* @param string $componentName
63+
* @param array $componentData
64+
* @param bool $isAllowed
65+
* @param bool $expectActionConfig
66+
* @return void
67+
* @dataProvider getPrepareDataProvider
68+
*/
69+
public function testPrepare($componentName, $componentData, $isAllowed = true, $expectActionConfig = true)
70+
{
71+
$processor = $this->getMockBuilder(\Magento\Framework\View\Element\UiComponent\Processor::class)
72+
->disableOriginalConstructor()
73+
->getMock();
74+
$this->contextMock->expects($this->atLeastOnce())->method('getProcessor')->willReturn($processor);
75+
/** @var \Magento\Ui\Component\MassAction $action */
76+
$action = $this->objectManager->getObject(
77+
\Magento\Ui\Component\MassAction::class,
78+
[
79+
'context' => $this->contextMock,
80+
'data' => [
81+
'name' => $componentName,
82+
'config' => $componentData,
83+
]
84+
]
85+
);
86+
$this->authorizationMock->method('isAllowed')
87+
->willReturn($isAllowed);
88+
$this->massAction->addComponent('action', $action);
89+
$this->massAction->prepare();
90+
$expected = $expectActionConfig ? ['actions' => [$action->getConfiguration()]] : [];
91+
$this->assertEquals($expected, $this->massAction->getConfiguration());
92+
}
93+
94+
/**
95+
* @return array
96+
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
97+
*/
98+
public function getPrepareDataProvider() : array
99+
{
100+
return [
101+
[
102+
'test_component1',
103+
[
104+
'type' => 'first_action',
105+
'label' => 'First Action',
106+
'url' => '/module/controller/firstAction'
107+
],
108+
],
109+
[
110+
'test_component2',
111+
[
112+
'type' => 'second_action',
113+
'label' => 'Second Action',
114+
'actions' => [
115+
[
116+
'type' => 'second_sub_action1',
117+
'label' => 'Second Sub Action 1',
118+
'url' => '/module/controller/secondSubAction1'
119+
],
120+
[
121+
'type' => 'second_sub_action2',
122+
'label' => 'Second Sub Action 2',
123+
'url' => '/module/controller/secondSubAction2'
124+
],
125+
]
126+
],
127+
],
128+
[
129+
'status_component',
130+
[
131+
'type' => 'status',
132+
'label' => 'Status',
133+
'actions' => [
134+
[
135+
'type' => 'enable',
136+
'label' => 'Second Sub Action 1',
137+
'url' => '/module/controller/enable'
138+
],
139+
[
140+
'type' => 'disable',
141+
'label' => 'Second Sub Action 2',
142+
'url' => '/module/controller/disable'
143+
],
144+
]
145+
],
146+
],
147+
[
148+
'status_component_not_allowed',
149+
[
150+
'type' => 'status',
151+
'label' => 'Status',
152+
'actions' => [
153+
[
154+
'type' => 'enable',
155+
'label' => 'Second Sub Action 1',
156+
'url' => '/module/controller/enable'
157+
],
158+
[
159+
'type' => 'disable',
160+
'label' => 'Second Sub Action 2',
161+
'url' => '/module/controller/disable'
162+
],
163+
]
164+
],
165+
false,
166+
false
167+
],
168+
[
169+
'delete_component',
170+
[
171+
'type' => 'delete',
172+
'label' => 'First Action',
173+
'url' => '/module/controller/delete'
174+
],
175+
],
176+
[
177+
'delete_component_not_allowed',
178+
[
179+
'type' => 'delete',
180+
'label' => 'First Action',
181+
'url' => '/module/controller/delete'
182+
],
183+
false,
184+
false
185+
],
186+
[
187+
'attributes_component',
188+
[
189+
'type' => 'delete',
190+
'label' => 'First Action',
191+
'url' => '/module/controller/attributes'
192+
],
193+
],
194+
[
195+
'attributes_component_not_allowed',
196+
[
197+
'type' => 'delete',
198+
'label' => 'First Action',
199+
'url' => '/module/controller/attributes'
200+
],
201+
false,
202+
false
203+
],
204+
];
205+
}
206+
207+
/**
208+
* @param bool $expected
209+
* @param string $actionType
210+
* @param int $callNum
211+
* @param string $resource
212+
* @param bool $isAllowed
213+
* @dataProvider isActionAllowedDataProvider
214+
*/
215+
public function testIsActionAllowed($expected, $actionType, $callNum, $resource = '', $isAllowed = true)
216+
{
217+
$this->authorizationMock->expects($this->exactly($callNum))
218+
->method('isAllowed')
219+
->with($resource)
220+
->willReturn($isAllowed);
221+
222+
$this->assertEquals($expected, $this->massAction->isActionAllowed($actionType));
223+
}
224+
225+
public function isActionAllowedDataProvider()
226+
{
227+
return [
228+
'other' => [true, 'other', 0,],
229+
'delete-allowed' => [true, 'delete', 1, 'Magento_Catalog::products'],
230+
'delete-not-allowed' => [false, 'delete', 1, 'Magento_Catalog::products', false],
231+
'status-allowed' => [true, 'status', 1, 'Magento_Catalog::products'],
232+
'status-not-allowed' => [false, 'status', 1, 'Magento_Catalog::products', false],
233+
'attributes-allowed' => [true, 'attributes', 1, 'Magento_Catalog::update_attributes'],
234+
'attributes-not-allowed' => [false, 'attributes', 1, 'Magento_Catalog::update_attributes', false],
235+
236+
];
237+
}
238+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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\Catalog\Ui\Component\Product;
9+
10+
use Magento\Framework\AuthorizationInterface;
11+
use Magento\Framework\View\Element\UiComponentInterface;
12+
use Magento\Framework\View\Element\UiComponent\ContextInterface;
13+
use Magento\Ui\Component\AbstractComponent;
14+
15+
class MassAction extends AbstractComponent
16+
{
17+
const NAME = 'massaction';
18+
19+
/**
20+
* @var AuthorizationInterface
21+
*/
22+
private $authorization;
23+
24+
/**
25+
* Constructor
26+
*
27+
* @param AuthorizationInterface $authorization
28+
* @param ContextInterface $context
29+
* @param UiComponentInterface[] $components
30+
* @param array $data
31+
*/
32+
public function __construct(
33+
AuthorizationInterface $authorization,
34+
ContextInterface $context,
35+
array $components = [],
36+
array $data = []
37+
) {
38+
$this->authorization = $authorization;
39+
parent::__construct($context, $components, $data);
40+
}
41+
42+
/**
43+
* {@inheritdoc}
44+
*/
45+
public function prepare() : void
46+
{
47+
$config = $this->getConfiguration();
48+
49+
foreach ($this->getChildComponents() as $actionComponent) {
50+
$actionType = $actionComponent->getConfiguration()['type'];
51+
if ($this->isActionAllowed($actionType)) {
52+
$config['actions'][] = $actionComponent->getConfiguration();
53+
}
54+
}
55+
$origConfig = $this->getConfiguration();
56+
if ($origConfig !== $config) {
57+
$config = array_replace_recursive($config, $origConfig);
58+
}
59+
60+
$this->setData('config', $config);
61+
$this->components = [];
62+
63+
parent::prepare();
64+
}
65+
66+
/**
67+
* {@inheritdoc}
68+
*/
69+
public function getComponentName() : string
70+
{
71+
return static::NAME;
72+
}
73+
74+
/**
75+
* Check if the given type of action is allowed
76+
*
77+
* @param string $actionType
78+
* @return bool
79+
*/
80+
public function isActionAllowed($actionType) : bool
81+
{
82+
$isAllowed = true;
83+
switch ($actionType) {
84+
case 'delete':
85+
$isAllowed = $this->authorization->isAllowed('Magento_Catalog::products');
86+
break;
87+
case 'status':
88+
$isAllowed = $this->authorization->isAllowed('Magento_Catalog::products');
89+
break;
90+
case 'attributes':
91+
$isAllowed = $this->authorization->isAllowed('Magento_Catalog::update_attributes');
92+
break;
93+
default:
94+
break;
95+
}
96+
return $isAllowed;
97+
}
98+
}

app/code/Magento/Catalog/view/adminhtml/ui_component/product_listing.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@
4848
</settings>
4949
</filterSelect>
5050
</filters>
51-
<massaction name="listing_massaction" component="Magento_Ui/js/grid/tree-massactions">
51+
<massaction name="listing_massaction"
52+
component="Magento_Ui/js/grid/tree-massactions"
53+
class="\Magento\Catalog\Ui\Component\Product\MassAction">
5254
<action name="delete">
5355
<settings>
5456
<confirm>

app/code/Magento/CatalogGraphQl/Model/Resolver/Category.php renamed to app/code/Magento/CatalogGraphQl/Model/Resolver/Categories.php

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,10 @@
2020
use Magento\Framework\Reflection\DataObjectProcessor;
2121

2222
/**
23-
* Category field resolver, used for GraphQL request processing.
23+
* Resolver for category objects the product is assigned to.
2424
*/
25-
class Category implements ResolverInterface
25+
class Categories implements ResolverInterface
2626
{
27-
/**
28-
* Product category ids
29-
*/
30-
const PRODUCT_CATEGORY_IDS_KEY = 'category_ids';
31-
3227
/**
3328
* @var Collection
3429
*/
@@ -89,10 +84,13 @@ public function __construct(
8984
*/
9085
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value
9186
{
92-
$this->categoryIds = array_merge($this->categoryIds, $value[self::PRODUCT_CATEGORY_IDS_KEY]);
87+
/** @var \Magento\Catalog\Model\Product $product */
88+
$product = $value['model'];
89+
$categoryIds = $product->getCategoryIds();
90+
$this->categoryIds = array_merge($this->categoryIds, $categoryIds);
9391
$that = $this;
9492

95-
return $this->valueFactory->create(function () use ($that, $value, $info) {
93+
return $this->valueFactory->create(function () use ($that, $categoryIds, $info) {
9694
$categories = [];
9795
if (empty($that->categoryIds)) {
9896
return [];
@@ -104,7 +102,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
104102
}
105103
/** @var CategoryInterface | \Magento\Catalog\Model\Category $item */
106104
foreach ($this->collection as $item) {
107-
if (in_array($item->getId(), $value[$that::PRODUCT_CATEGORY_IDS_KEY])) {
105+
if (in_array($item->getId(), $categoryIds)) {
108106
$categories[$item->getId()] = $this->dataObjectProcessor->buildOutputDataArray(
109107
$item,
110108
CategoryInterface::class

0 commit comments

Comments
 (0)