Skip to content

Commit 91a1449

Browse files
Merge branch '2.4.7-beta3-develop' into cia-2.4.7-beta3-develop-bugfix-10272023
2 parents f905c6d + debec19 commit 91a1449

File tree

11 files changed

+384
-93
lines changed

11 files changed

+384
-93
lines changed

app/code/Magento/Config/Block/System/Config/Form/Field/File.php

100644100755
+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
*
1010
* @author Magento Core Team <[email protected]>
1111
*/
12+
declare(strict_types=1);
13+
1214
namespace Magento\Config\Block\System\Config\Form\Field;
1315

1416
class File extends \Magento\Framework\Data\Form\Element\File
@@ -35,7 +37,7 @@ protected function _getDeleteCheckbox()
3537
$html = '';
3638
if ((string)$this->getValue()) {
3739
$label = __('Delete File');
38-
$html .= '<div>' . $this->getValue() . ' ';
40+
$html .= '<div>' . $this->_escaper->escapeHtml($this->getValue()) . ' ';
3941
$html .= '<input type="checkbox" name="' .
4042
parent::getName() .
4143
'[delete]" value="1" class="checkbox" id="' .

app/code/Magento/Config/Test/Unit/Block/System/Config/Form/Field/FileTest.php

+62-19
Original file line numberDiff line numberDiff line change
@@ -8,49 +8,85 @@
88
namespace Magento\Config\Test\Unit\Block\System\Config\Form\Field;
99

1010
use Magento\Config\Block\System\Config\Form\Field\File;
11+
use Magento\Framework\Data\Form\Element\Factory;
12+
use Magento\Framework\Data\Form\Element\CollectionFactory;
1113
use Magento\Framework\DataObject;
1214
use Magento\Framework\Escaper;
1315
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
16+
use PHPUnit\Framework\MockObject\MockObject;
1417
use PHPUnit\Framework\TestCase;
1518

1619
/**
1720
* Tests for \Magento\Framework\Data\Form\Field\File
1821
*/
1922
class FileTest extends TestCase
2023
{
24+
/**
25+
* XSS value
26+
*/
27+
private const XSS_FILE_NAME_TEST = '<img src=x onerror=alert(1)>.crt';
28+
29+
/**
30+
* Input name
31+
*/
32+
private const INPUT_NAME_TEST = 'test_name';
33+
2134
/**
2235
* @var File
2336
*/
2437
protected $file;
2538

39+
/**
40+
* @var Factory|MockObject
41+
*/
42+
private $factoryMock;
43+
44+
/**
45+
* @var CollectionFactory|MockObject
46+
*/
47+
private $factoryCollectionMock;
48+
49+
/**
50+
* @var Escaper|MockObject
51+
*/
52+
private $escaperMock;
53+
2654
/**
2755
* @var array
2856
*/
29-
protected $testData;
57+
protected array $testData = [
58+
'before_element_html' => 'test_before_element_html',
59+
'html_id' => 'test_id',
60+
'name' => 'test_name',
61+
'value' => 'test_value',
62+
'title' => 'test_title',
63+
'disabled' => true,
64+
'after_element_js' => 'test_after_element_js',
65+
'after_element_html' => 'test_after_element_html',
66+
'html_id_prefix' => 'test_id_prefix_',
67+
'html_id_suffix' => '_test_id_suffix',
68+
];
3069

3170
protected function setUp(): void
3271
{
3372
$objectManager = new ObjectManager($this);
3473

35-
$this->testData = [
36-
'before_element_html' => 'test_before_element_html',
37-
'html_id' => 'test_id',
38-
'name' => 'test_name',
39-
'value' => 'test_value',
40-
'title' => 'test_title',
41-
'disabled' => true,
42-
'after_element_js' => 'test_after_element_js',
43-
'after_element_html' => 'test_after_element_html',
44-
'html_id_prefix' => 'test_id_prefix_',
45-
'html_id_suffix' => '_test_id_suffix',
46-
];
47-
74+
$this->factoryMock = $this->getMockBuilder(Factory::class)
75+
->disableOriginalConstructor()
76+
->getMock();
77+
$this->factoryCollectionMock = $this->getMockBuilder(CollectionFactory::class)
78+
->disableOriginalConstructor()
79+
->getMock();
80+
$this->escaperMock = $this->getMockBuilder(Escaper::class)
81+
->disableOriginalConstructor()
82+
->getMock();
4883
$this->file = $objectManager->getObject(
4984
File::class,
5085
[
51-
'_escaper' => $objectManager->getObject(Escaper::class),
86+
'factoryElement' => $this->factoryMock,
87+
'factoryCollection' => $this->factoryCollectionMock,
88+
'_escaper' => $this->escaperMock,
5289
'data' => $this->testData,
53-
5490
]
5591
);
5692

@@ -60,13 +96,20 @@ protected function setUp(): void
6096
$this->file->setForm($formMock);
6197
}
6298

63-
public function testGetElementHtml()
99+
public function testGetElementHtml(): void
64100
{
65-
$html = $this->file->getElementHtml();
66-
67101
$expectedHtmlId = $this->testData['html_id_prefix']
68102
. $this->testData['html_id']
69103
. $this->testData['html_id_suffix'];
104+
$this->escaperMock->expects($this->any())->method('escapeHtml')->willReturnMap(
105+
[
106+
[$expectedHtmlId, null, $expectedHtmlId],
107+
[self::XSS_FILE_NAME_TEST, null, self::XSS_FILE_NAME_TEST],
108+
[self::INPUT_NAME_TEST, null, self::INPUT_NAME_TEST],
109+
]
110+
);
111+
112+
$html = $this->file->getElementHtml();
70113

71114
$this->assertStringContainsString('<label class="addbefore" for="' . $expectedHtmlId . '"', $html);
72115
$this->assertStringContainsString($this->testData['before_element_html'], $html);

app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Generate.php

100644100755
+74-32
Original file line numberDiff line numberDiff line change
@@ -3,76 +3,105 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\SalesRule\Controller\Adminhtml\Promo\Quote;
79

10+
use Magento\Backend\App\Action\Context;
811
use Magento\Framework\App\Action\HttpPostActionInterface;
12+
use Magento\Framework\App\Config\ScopeConfigInterface;
13+
use Magento\Framework\App\ObjectManager;
14+
use Magento\Framework\App\Response\Http\FileFactory;
15+
use Magento\Framework\Exception\InputException;
16+
use Magento\Framework\Exception\LocalizedException;
917
use Magento\Framework\Filter\FilterInput;
18+
use Magento\Framework\Json\Helper\Data;
1019
use Magento\Framework\MessageQueue\PublisherInterface;
20+
use Magento\Framework\Registry;
21+
use Magento\Framework\Stdlib\DateTime\Filter\Date;
1122
use Magento\SalesRule\Api\Data\CouponGenerationSpecInterfaceFactory;
23+
use Magento\SalesRule\Controller\Adminhtml\Promo\Quote;
1224
use Magento\SalesRule\Model\CouponGenerator;
1325
use Magento\SalesRule\Model\Quote\GetCouponCodeLengthInterface;
26+
use Magento\SalesRule\Model\RegistryConstants;
27+
use Magento\SalesRule\Model\Rule;
28+
use Magento\Store\Model\ScopeInterface;
29+
use Psr\Log\LoggerInterface;
1430

1531
/**
1632
* Generate promo quote
1733
*
1834
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1935
*/
20-
class Generate extends \Magento\SalesRule\Controller\Adminhtml\Promo\Quote implements HttpPostActionInterface
36+
class Generate extends Quote implements HttpPostActionInterface
2137
{
38+
/**
39+
* Coupon quantity limit config path
40+
*/
41+
private const XML_CONFIG_COUPON_QUANTITY_LIMIT = 'promo/auto_generated_coupon_codes/quantity_limit';
42+
2243
/**
2344
* @var CouponGenerator
2445
*/
25-
private $couponGenerator;
46+
private CouponGenerator $couponGenerator;
2647

2748
/**
2849
* @var PublisherInterface
2950
*/
30-
private $messagePublisher;
51+
private PublisherInterface $messagePublisher;
3152

3253
/**
3354
* @var CouponGenerationSpecInterfaceFactory
3455
*/
35-
private $generationSpecFactory;
56+
private CouponGenerationSpecInterfaceFactory $generationSpecFactory;
3657

3758
/**
3859
* @var GetCouponCodeLengthInterface
3960
*/
40-
private $getCouponCodeLength;
61+
private GetCouponCodeLengthInterface $getCouponCodeLength;
62+
63+
/**
64+
* @var ScopeConfigInterface
65+
*/
66+
private ScopeConfigInterface $scopeConfig;
4167

4268
/**
4369
* Generate constructor.
44-
* @param \Magento\Backend\App\Action\Context $context
45-
* @param \Magento\Framework\Registry $coreRegistry
46-
* @param \Magento\Framework\App\Response\Http\FileFactory $fileFactory
47-
* @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter
70+
* @param Context $context
71+
* @param Registry $coreRegistry
72+
* @param FileFactory $fileFactory
73+
* @param Date $dateFilter
4874
* @param CouponGenerator|null $couponGenerator
4975
* @param PublisherInterface|null $publisher
5076
* @param CouponGenerationSpecInterfaceFactory|null $generationSpecFactory
5177
* @param GetCouponCodeLengthInterface|null $getCouponCodeLength
78+
* @param ScopeConfigInterface|null $scopeConfig
5279
*/
5380
public function __construct(
54-
\Magento\Backend\App\Action\Context $context,
55-
\Magento\Framework\Registry $coreRegistry,
56-
\Magento\Framework\App\Response\Http\FileFactory $fileFactory,
57-
\Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter,
81+
Context $context,
82+
Registry $coreRegistry,
83+
FileFactory $fileFactory,
84+
Date $dateFilter,
5885
CouponGenerator $couponGenerator = null,
5986
PublisherInterface $publisher = null,
6087
CouponGenerationSpecInterfaceFactory $generationSpecFactory = null,
61-
GetCouponCodeLengthInterface $getCouponCodeLength = null
88+
GetCouponCodeLengthInterface $getCouponCodeLength = null,
89+
ScopeConfigInterface $scopeConfig = null
6290
) {
6391
parent::__construct($context, $coreRegistry, $fileFactory, $dateFilter);
6492
$this->couponGenerator = $couponGenerator ?:
6593
$this->_objectManager->get(CouponGenerator::class);
66-
$this->messagePublisher = $publisher ?: \Magento\Framework\App\ObjectManager::getInstance()
94+
$this->messagePublisher = $publisher ?: ObjectManager::getInstance()
6795
->get(PublisherInterface::class);
6896
$this->generationSpecFactory = $generationSpecFactory ?:
69-
\Magento\Framework\App\ObjectManager::getInstance()->get(
97+
ObjectManager::getInstance()->get(
7098
CouponGenerationSpecInterfaceFactory::class
7199
);
72100
$this->getCouponCodeLength = $getCouponCodeLength ?:
73-
\Magento\Framework\App\ObjectManager::getInstance()->get(
101+
ObjectManager::getInstance()->get(
74102
GetCouponCodeLengthInterface::class
75103
);
104+
$this->scopeConfig = $scopeConfig;
76105
}
77106

78107
/**
@@ -81,7 +110,7 @@ public function __construct(
81110
* @return void
82111
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
83112
*/
84-
public function execute()
113+
public function execute(): void
85114
{
86115
if (!$this->getRequest()->isAjax()) {
87116
$this->_forward('noroute');
@@ -90,13 +119,13 @@ public function execute()
90119
$result = [];
91120
$this->_initRule();
92121

93-
$rule = $this->_coreRegistry->registry(\Magento\SalesRule\Model\RegistryConstants::CURRENT_SALES_RULE);
122+
$rule = $this->_coreRegistry->registry(RegistryConstants::CURRENT_SALES_RULE);
94123

95124
$data = $this->getRequest()->getParams();
96125

97126
if (!$rule->getId()) {
98127
$result['error'] = __('Rule is not defined');
99-
} elseif ((int) $rule->getCouponType() !== \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO
128+
} elseif ((int) $rule->getCouponType() !== Rule::COUPON_TYPE_AUTO
100129
&& !$rule->getUseAutoGeneration()) {
101130
$result['error'] =
102131
__('The rule coupon settings changed. Please save the rule before using auto-generation.');
@@ -123,7 +152,7 @@ public function execute()
123152
$result['error'] = __(
124153
'Something went wrong while validating coupon code length. Please review the log and try again.'
125154
);
126-
$this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
155+
$this->_objectManager->get(LoggerInterface::class)->critical($e);
127156
}
128157
} else {
129158
try {
@@ -132,29 +161,42 @@ public function execute()
132161
$data = $inputFilter->getUnescaped();
133162
}
134163

135-
$data['quantity'] = isset($data['qty']) ? $data['qty'] : null;
136-
137-
$couponSpec = $this->generationSpecFactory->create(['data' => $data]);
138-
139-
$this->messagePublisher->publish('sales_rule.codegenerator', $couponSpec);
140-
$this->messageManager->addSuccessMessage(
141-
__('Message is added to queue, wait to get your coupons soon')
164+
$data['quantity'] = $data['qty'] ?? 0;
165+
$couponQuantityLimit = (int)$this->scopeConfig->getValue(
166+
self::XML_CONFIG_COUPON_QUANTITY_LIMIT,
167+
ScopeInterface::SCOPE_STORE
142168
);
169+
// @codingStandardsIgnoreStart
170+
if ($data['quantity'] > 0 && ($data['quantity'] <= $couponQuantityLimit || $couponQuantityLimit === 0)) {
171+
$couponSpec = $this->generationSpecFactory->create(['data' => $data]);
172+
173+
$this->messagePublisher->publish('sales_rule.codegenerator', $couponSpec);
174+
$this->messageManager->addSuccessMessage(
175+
__('Message is added to queue, wait to get your coupons soon.')
176+
);
177+
} else {
178+
$this->messageManager->addErrorMessage(
179+
__(
180+
'Coupon quantity should be less than or equal to the coupon quantity in the store configuration.'
181+
)
182+
);
183+
}
184+
// @codingStandardsIgnoreEnd
143185
$this->_view->getLayout()->initMessages();
144186
$result['messages'] = $this->_view->getLayout()->getMessagesBlock()->getGroupedHtml();
145-
} catch (\Magento\Framework\Exception\InputException $inputException) {
187+
} catch (InputException $inputException) {
146188
$result['error'] = __('Invalid data provided');
147-
} catch (\Magento\Framework\Exception\LocalizedException $e) {
189+
} catch (LocalizedException $e) {
148190
$result['error'] = $e->getMessage();
149191
} catch (\Exception $e) {
150192
$result['error'] = __(
151193
'Something went wrong while generating coupons. Please review the log and try again.'
152194
);
153-
$this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
195+
$this->_objectManager->get(LoggerInterface::class)->critical($e);
154196
}
155197
}
156198
$this->getResponse()->representJson(
157-
$this->_objectManager->get(\Magento\Framework\Json\Helper\Data::class)->jsonEncode($result)
199+
$this->_objectManager->get(Data::class)->jsonEncode($result)
158200
);
159201
}
160202
}

0 commit comments

Comments
 (0)