Skip to content

Commit 9a794cc

Browse files
committed
Merge remote-tracking branch 'origin/2.4-develop' into ACP2E-1338
2 parents e0e44d7 + 3218b12 commit 9a794cc

File tree

209 files changed

+8757
-764
lines changed

Some content is hidden

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

209 files changed

+8757
-764
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Authorization\Model;
10+
11+
use Magento\Framework\App\Backpressure\ContextInterface;
12+
use Magento\Framework\App\Backpressure\IdentityProviderInterface;
13+
use Magento\Framework\Exception\RuntimeException;
14+
use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress;
15+
16+
/**
17+
* Utilizes UserContext for backpressure identity
18+
*/
19+
class IdentityProvider implements IdentityProviderInterface
20+
{
21+
/**
22+
* User context identity type map
23+
*/
24+
private const USER_CONTEXT_IDENTITY_TYPE_MAP = [
25+
UserContextInterface::USER_TYPE_CUSTOMER => ContextInterface::IDENTITY_TYPE_CUSTOMER,
26+
UserContextInterface::USER_TYPE_ADMIN => ContextInterface::IDENTITY_TYPE_ADMIN
27+
];
28+
29+
/**
30+
* @var UserContextInterface
31+
*/
32+
private UserContextInterface $userContext;
33+
34+
/**
35+
* @var RemoteAddress
36+
*/
37+
private RemoteAddress $remoteAddress;
38+
39+
/**
40+
* @param UserContextInterface $userContext
41+
* @param RemoteAddress $remoteAddress
42+
*/
43+
public function __construct(UserContextInterface $userContext, RemoteAddress $remoteAddress)
44+
{
45+
$this->userContext = $userContext;
46+
$this->remoteAddress = $remoteAddress;
47+
}
48+
49+
/**
50+
* @inheritDoc
51+
*
52+
* @throws RuntimeException
53+
*/
54+
public function fetchIdentityType(): int
55+
{
56+
if (!$this->userContext->getUserId()) {
57+
return ContextInterface::IDENTITY_TYPE_IP;
58+
}
59+
60+
$userType = $this->userContext->getUserType();
61+
if (isset(self::USER_CONTEXT_IDENTITY_TYPE_MAP[$userType])) {
62+
return self::USER_CONTEXT_IDENTITY_TYPE_MAP[$userType];
63+
}
64+
65+
throw new RuntimeException(__('User type not defined'));
66+
}
67+
68+
/**
69+
* @inheritDoc
70+
*
71+
* @throws RuntimeException
72+
*/
73+
public function fetchIdentity(): string
74+
{
75+
$userId = $this->userContext->getUserId();
76+
if ($userId) {
77+
return (string)$userId;
78+
}
79+
80+
$address = $this->remoteAddress->getRemoteAddress();
81+
if (!$address) {
82+
throw new RuntimeException(__('Failed to extract remote address'));
83+
}
84+
85+
return $address;
86+
}
87+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Authorization\Test\Unit\Model;
10+
11+
use Magento\Authorization\Model\IdentityProvider;
12+
use Magento\Authorization\Model\UserContextInterface;
13+
use Magento\Framework\App\Backpressure\ContextInterface;
14+
use Magento\Framework\Exception\RuntimeException;
15+
use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress;
16+
use PHPUnit\Framework\MockObject\MockObject;
17+
use PHPUnit\Framework\TestCase;
18+
19+
/**
20+
* Tests the IdentityProvider class
21+
*/
22+
class IdentityProviderTest extends TestCase
23+
{
24+
/**
25+
* @var UserContextInterface|MockObject
26+
*/
27+
private $userContext;
28+
29+
/**
30+
* @var RemoteAddress|MockObject
31+
*/
32+
private $remoteAddress;
33+
34+
/**
35+
* @var IdentityProvider
36+
*/
37+
private $model;
38+
39+
/**
40+
* @inheritDoc
41+
*/
42+
protected function setUp(): void
43+
{
44+
parent::setUp();
45+
46+
$this->userContext = $this->createMock(UserContextInterface::class);
47+
$this->remoteAddress = $this->createMock(RemoteAddress::class);
48+
$this->model = new IdentityProvider($this->userContext, $this->remoteAddress);
49+
}
50+
51+
/**
52+
* Cases for identity provider.
53+
*
54+
* @return array
55+
*/
56+
public function getIdentityCases(): array
57+
{
58+
return [
59+
'empty-user-context' => [null, null, '127.0.0.1', ContextInterface::IDENTITY_TYPE_IP, '127.0.0.1'],
60+
'guest-user-context' => [
61+
UserContextInterface::USER_TYPE_GUEST,
62+
null,
63+
'127.0.0.1',
64+
ContextInterface::IDENTITY_TYPE_IP,
65+
'127.0.0.1'
66+
],
67+
'admin-user-context' => [
68+
UserContextInterface::USER_TYPE_ADMIN,
69+
42,
70+
'127.0.0.1',
71+
ContextInterface::IDENTITY_TYPE_ADMIN,
72+
'42'
73+
],
74+
'customer-user-context' => [
75+
UserContextInterface::USER_TYPE_CUSTOMER,
76+
42,
77+
'127.0.0.1',
78+
ContextInterface::IDENTITY_TYPE_CUSTOMER,
79+
'42'
80+
],
81+
];
82+
}
83+
84+
/**
85+
* Verify identity provider.
86+
*
87+
* @param int|null $userType
88+
* @param int|null $userId
89+
* @param string $remoteAddr
90+
* @param int $expectedType
91+
* @param string $expectedIdentity
92+
* @return void
93+
* @dataProvider getIdentityCases
94+
*/
95+
public function testFetchIdentity(
96+
?int $userType,
97+
?int $userId,
98+
string $remoteAddr,
99+
int $expectedType,
100+
string $expectedIdentity
101+
): void {
102+
$this->userContext->method('getUserType')->willReturn($userType);
103+
$this->userContext->method('getUserId')->willReturn($userId);
104+
$this->remoteAddress->method('getRemoteAddress')->willReturn($remoteAddr);
105+
106+
$this->assertEquals($expectedType, $this->model->fetchIdentityType());
107+
$this->assertEquals($expectedIdentity, $this->model->fetchIdentity());
108+
}
109+
110+
/**
111+
* Tests fetching an identity type when user type can't be defined
112+
*/
113+
public function testFetchIdentityTypeUserTypeNotDefined()
114+
{
115+
$this->userContext->method('getUserId')->willReturn(2);
116+
$this->userContext->method('getUserType')->willReturn(null);
117+
$this->expectException(RuntimeException::class);
118+
$this->expectExceptionMessage(__('User type not defined')->getText());
119+
$this->model->fetchIdentityType();
120+
}
121+
122+
/**
123+
* Tests fetching an identity when user address can't be extracted
124+
*/
125+
public function testFetchIdentityFailedToExtractRemoteAddress()
126+
{
127+
$this->userContext->method('getUserId')->willReturn(null);
128+
$this->remoteAddress->method('getRemoteAddress')->willReturn(false);
129+
$this->expectException(RuntimeException::class);
130+
$this->expectExceptionMessage(__('Failed to extract remote address')->getText());
131+
$this->model->fetchIdentity();
132+
}
133+
}

app/code/Magento/Authorization/etc/di.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@
2424
</arguments>
2525
</type>
2626
<preference for="Magento\Authorization\Model\UserContextInterface" type="Magento\Authorization\Model\CompositeUserContext"/>
27+
<preference for="Magento\Framework\App\Backpressure\IdentityProviderInterface"
28+
type="Magento\Authorization\Model\IdentityProvider"/>
2729
</config>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
"We can't find the role for the user you wanted.","We can't find the role for the user you wanted."
22
"Something went wrong while compiling a list of allowed resources. You can find out more in the exceptions log.","Something went wrong while compiling a list of allowed resources. You can find out more in the exceptions log."
3+
"User type not defined","User type not defined"
4+
"Failed to extract remote address","Failed to extract remote address"

app/code/Magento/Bundle/Pricing/Adjustment/DefaultSelectionPriceListProvider.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ public function getPriceList(Product $bundleProduct, $searchMin, $useRegularPric
8484
[(int)$option->getOptionId()],
8585
$bundleProduct
8686
);
87+
$selectionsCollection->setFlag('has_stock_status_filter', true);
8788
$selectionsCollection->removeAttributeToSelect();
88-
$selectionsCollection->addQuantityFilter();
8989

9090
if (!$useRegularPrice) {
9191
$selectionsCollection->addAttributeToSelect('special_price');
@@ -140,6 +140,9 @@ private function isShouldFindMinOption(Product $bundleProduct, $searchMin)
140140
private function addMiniMaxPriceList(Product $bundleProduct, $selectionsCollection, $searchMin, $useRegularPrice)
141141
{
142142
$selectionsCollection->addPriceFilter($bundleProduct, $searchMin, $useRegularPrice);
143+
if ($bundleProduct->isSalable()) {
144+
$selectionsCollection->addQuantityFilter();
145+
}
143146
$selectionsCollection->setPage(0, 1);
144147

145148
$selection = $selectionsCollection->getFirstItem();

app/code/Magento/Bundle/Test/Unit/Pricing/Adjustment/DefaultSelectionPriceListProviderTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,47 @@ public function testGetPriceList(): void
177177
$this->selectionCollection->expects($this->once())
178178
->method('getIterator')
179179
->willReturn(new \ArrayIterator([]));
180+
$this->selectionCollection->expects($this->once())
181+
->method('setFlag')
182+
->with('has_stock_status_filter', true);
180183

181184
$this->model->getPriceList($this->product, false, false);
182185
}
186+
187+
public function testGetPriceListWithSearchMin(): void
188+
{
189+
$option = $this->createMock(Option::class);
190+
$option->expects($this->once())->method('getRequired')
191+
->willReturn(true);
192+
$this->optionsCollection->expects($this->any())
193+
->method('getIterator')
194+
->willReturn(new \ArrayIterator([$option]));
195+
$this->typeInstance->expects($this->any())
196+
->method('getOptionsCollection')
197+
->with($this->product)
198+
->willReturn($this->optionsCollection);
199+
$this->product->expects($this->any())
200+
->method('getTypeInstance')
201+
->willReturn($this->typeInstance);
202+
$this->selectionCollection->expects($this->once())
203+
->method('getFirstItem')
204+
->willReturn($this->createMock(Product::class));
205+
$this->typeInstance->expects($this->once())
206+
->method('getSelectionsCollection')
207+
->willReturn($this->selectionCollection);
208+
$this->selectionCollection->expects($this->once())
209+
->method('setFlag')
210+
->with('has_stock_status_filter', true);
211+
$this->selectionCollection->expects($this->once())
212+
->method('addQuantityFilter');
213+
$this->product->expects($this->once())->method('isSalable')->willReturn(true);
214+
$this->optionsCollection->expects($this->once())
215+
->method('getSize')
216+
->willReturn(1);
217+
$this->optionsCollection->expects($this->once())
218+
->method('addFilter')
219+
->willReturn($this->optionsCollection);
220+
221+
$this->model->getPriceList($this->product, true, false);
222+
}
183223
}

0 commit comments

Comments
 (0)