Skip to content

Commit 442bb83

Browse files
Merge pull request #175 from magento-cia/cia-2.4.8-beta2-develop-bugfix-101272024
AC-10142: Wishlist sharing email issue fixed
2 parents 6b9e6ca + dd21bad commit 442bb83

File tree

12 files changed

+479
-0
lines changed

12 files changed

+479
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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\ReCaptchaWishlist\Observer;
9+
10+
use Magento\Framework\App\Action\Action;
11+
use Magento\Framework\App\Response\RedirectInterface;
12+
use Magento\Framework\Event\Observer;
13+
use Magento\Framework\Event\ObserverInterface;
14+
use Magento\Framework\Exception\InputException;
15+
use Magento\ReCaptchaUi\Model\IsCaptchaEnabledInterface;
16+
use Magento\ReCaptchaUi\Model\RequestHandlerInterface;
17+
18+
/**
19+
* Adds Captcha support for share wishlist
20+
*/
21+
class ShareWishlistObserver implements ObserverInterface
22+
{
23+
/**
24+
* @var string Captcha key
25+
*/
26+
private const CAPTCHA_KEY = 'wishlist';
27+
28+
/**
29+
* @var RedirectInterface
30+
*/
31+
private $redirect;
32+
33+
/**
34+
* @var IsCaptchaEnabledInterface
35+
*/
36+
private $isCaptchaEnabled;
37+
38+
/**
39+
* @var RequestHandlerInterface
40+
*/
41+
private $requestHandler;
42+
43+
/**
44+
* @param RedirectInterface $redirect
45+
* @param IsCaptchaEnabledInterface $isCaptchaEnabled
46+
* @param RequestHandlerInterface $requestHandler
47+
*/
48+
public function __construct(
49+
RedirectInterface $redirect,
50+
IsCaptchaEnabledInterface $isCaptchaEnabled,
51+
RequestHandlerInterface $requestHandler
52+
) {
53+
$this->redirect = $redirect;
54+
$this->isCaptchaEnabled = $isCaptchaEnabled;
55+
$this->requestHandler = $requestHandler;
56+
}
57+
58+
/**
59+
* @inheritdoc
60+
* @param Observer $observer
61+
* @return void
62+
* @throws InputException
63+
*/
64+
public function execute(Observer $observer): void
65+
{
66+
if ($this->isCaptchaEnabled->isCaptchaEnabledFor(self::CAPTCHA_KEY)) {
67+
/** @var Action $controller */
68+
$controller = $observer->getControllerAction();
69+
$request = $controller->getRequest();
70+
$response = $controller->getResponse();
71+
$redirectOnFailureUrl = $this->redirect->getRefererUrl();
72+
73+
$this->requestHandler->execute(self::CAPTCHA_KEY, $request, $response, $redirectOnFailureUrl);
74+
}
75+
}
76+
}

ReCaptchaWishlist/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Please refer to: https://github.com/magento/security-package
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
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\ReCaptchaWishlist\Test\Integration;
9+
10+
use Magento\Customer\Model\Session;
11+
use Magento\Framework\App\Request\Http;
12+
use Magento\Framework\Data\Form\FormKey;
13+
use Magento\Framework\Message\MessageInterface;
14+
use Magento\Framework\Validation\ValidationResult;
15+
use Magento\ReCaptchaValidation\Model\Validator;
16+
use Magento\TestFramework\TestCase\AbstractController;
17+
use Magento\TestFramework\Wishlist\Model\GetWishlistByCustomerId;
18+
use Magento\ReCaptchaUi\Model\CaptchaResponseResolverInterface;
19+
use Magento\Framework\UrlInterface;
20+
use PHPUnit\Framework\MockObject\MockObject;
21+
22+
/**
23+
* Tests for create wish list
24+
*
25+
* @magentoDataFixture Magento/Customer/_files/customer.php
26+
* @magentoDbIsolation enabled
27+
* @magentoAppArea frontend
28+
*/
29+
class ShareWishlistFormTest extends AbstractController
30+
{
31+
/**
32+
* @var string Customer ID
33+
*/
34+
private const CUSTOMER_ID = 1;
35+
36+
/**
37+
* @var Session
38+
*/
39+
private $customerSession;
40+
41+
/**
42+
* @var string
43+
*/
44+
private $formKey;
45+
46+
/**
47+
* @var UrlInterface
48+
*/
49+
private $url;
50+
51+
/**
52+
* @var int
53+
*/
54+
private $wishlistId;
55+
56+
/**
57+
* @var ValidationResult|MockObject
58+
*/
59+
private $captchaValidationResultMock;
60+
61+
/**
62+
* @inheritdoc
63+
*/
64+
protected function setUp(): void
65+
{
66+
parent::setUp();
67+
$this->formKey = $this->_objectManager->get(FormKey::class)->getFormKey();
68+
$this->customerSession = $this->_objectManager->get(Session::class);
69+
$this->customerSession->setCustomerId(self::CUSTOMER_ID);
70+
$this->wishlistId = $this->_objectManager->get(GetWishlistByCustomerId::class)
71+
->execute(self::CUSTOMER_ID)
72+
->getId();
73+
$this->url = $this->_objectManager->get(UrlInterface::class);
74+
$this->captchaValidationResultMock = $this->createMock(ValidationResult::class);
75+
$captchaValidatorMock = $this->createMock(Validator::class);
76+
$captchaValidatorMock->expects($this->any())
77+
->method('isValid')
78+
->willReturn($this->captchaValidationResultMock);
79+
$this->_objectManager->addSharedInstance($captchaValidatorMock, Validator::class);
80+
}
81+
82+
/**
83+
* Checks the content of the 'Wish List Sharing' page when ReCaptcha is disabled
84+
*/
85+
public function testGetRequestIfReCaptchaIsDisabled(): void
86+
{
87+
$this->checkSuccessfulGetResponse();
88+
}
89+
90+
/**
91+
* Checks the content of the 'Wish List Sharing' page when ReCaptcha is enabled
92+
* but keys are not configured
93+
*
94+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/wishlist invisible
95+
*
96+
* It's needed for proper work of "ifconfig" in layout during tests running
97+
* @magentoConfigFixture default_store recaptcha_frontend/type_for/wishlist invisible
98+
*/
99+
public function testGetRequestIfReCaptchaKeysAreNotConfigured(): void
100+
{
101+
$this->checkSuccessfulGetResponse();
102+
}
103+
104+
/**
105+
* Checks the content of the 'Wish List Sharing' page when ReCaptcha is enabled
106+
* and keys are configured
107+
*
108+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key
109+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key
110+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/wishlist invisible
111+
*
112+
* It's needed for proper work of "ifconfig" in layout during tests running
113+
* @magentoConfigFixture default_store recaptcha_frontend/type_for/wishlist invisible
114+
*/
115+
public function testGetRequestIfReCaptchaIsEnabled(): void
116+
{
117+
$this->checkSuccessfulGetResponse(true);
118+
}
119+
120+
/**
121+
* Checks GET response
122+
*
123+
* @param bool $shouldContainReCaptcha
124+
* @return void
125+
*/
126+
private function checkSuccessfulGetResponse(bool $shouldContainReCaptcha = false): void
127+
{
128+
$this->dispatch('wishlist/index/share/wishlist_id/' . $this->wishlistId);
129+
$content = $this->getResponse()->getBody();
130+
131+
$this->assertNotEmpty($content);
132+
133+
$shouldContainReCaptcha
134+
? $this->assertStringContainsString('field-recaptcha', $content)
135+
: $this->assertStringNotContainsString('field-recaptcha', $content);
136+
137+
$this->assertEmpty($this->getSessionMessages(MessageInterface::TYPE_ERROR));
138+
}
139+
140+
/**
141+
* Checks the sharing process without ReCaptcha validation
142+
*/
143+
public function testPostRequestWithoutReCaptchaValidation(): void
144+
{
145+
$this->checkSuccessfulPostRequest();
146+
}
147+
148+
/**
149+
* Checks the sharing process if ReCaptcha is enabled but keys are not configured
150+
*
151+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/wishlist invisible
152+
*
153+
* It's needed for proper work of "ifconfig" in layout during tests running
154+
* @magentoConfigFixture default_store recaptcha_frontend/type_for/wishlist invisible
155+
*/
156+
public function testPostRequestIfReCaptchaKeysAreNotConfigured(): void
157+
{
158+
$this->checkSuccessfulPostRequest();
159+
}
160+
161+
/**
162+
* Checks the successful sharing process with ReCaptcha validation
163+
*
164+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key
165+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key
166+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/wishlist invisible
167+
*
168+
* It's needed for proper work of "ifconfig" in layout during tests running
169+
* @magentoConfigFixture default_store recaptcha_frontend/type_for/wishlist invisible
170+
*/
171+
public function testPostRequestWithSuccessfulReCaptchaValidation(): void
172+
{
173+
$this->captchaValidationResultMock->expects($this->once())
174+
->method('isValid')
175+
->willReturn(true);
176+
$this->checkSuccessfulPostRequest(true);
177+
}
178+
179+
/**
180+
* Checks successful sharing process
181+
*
182+
* @param bool $withParamReCaptcha
183+
*/
184+
private function checkSuccessfulPostRequest(bool $withParamReCaptcha = false):void
185+
{
186+
$this->makePostRequest($withParamReCaptcha);
187+
$url = $this->url->getRouteUrl('wishlist/index/index/wishlist_id/' . $this->wishlistId . '/');
188+
$this->assertRedirect(self::equalTo($url));
189+
$this->assertEmpty($this->getSessionMessages(MessageInterface::TYPE_ERROR));
190+
}
191+
192+
/**
193+
* Checks the sharing process with ReCaptcha validation when `g-recaptcha-response` missed
194+
*
195+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key
196+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key
197+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/wishlist invisible
198+
*
199+
* It's needed for proper work of "ifconfig" in layout during tests running
200+
* @magentoConfigFixture default_store recaptcha_frontend/type_for/wishlist invisible
201+
*/
202+
public function testPostRequestIfReCaptchaParameterIsMissed(): void
203+
{
204+
$this->checkFailedPostRequest();
205+
}
206+
207+
/**
208+
* Checks the failed sharing process with ReCaptcha validation
209+
*
210+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key
211+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key
212+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/wishlist invisible
213+
*
214+
* It's needed for proper work of "ifconfig" in layout during tests running
215+
* @magentoConfigFixture default_store recaptcha_frontend/type_for/wishlist invisible
216+
*/
217+
public function testPostRequestWithFailedReCaptchaValidation(): void
218+
{
219+
$this->captchaValidationResultMock->expects($this->once())
220+
->method('isValid')
221+
->willReturn(false);
222+
$this->checkFailedPostRequest(true);
223+
}
224+
225+
/**
226+
* Checks failed sharing process
227+
*
228+
* @param bool $withParamReCaptcha
229+
*/
230+
private function checkFailedPostRequest(bool $withParamReCaptcha = false): void
231+
{
232+
$this->makePostRequest($withParamReCaptcha);
233+
$this->assertSessionMessages(
234+
$this->equalTo(['Something went wrong with reCAPTCHA. Please contact the store owner.']),
235+
MessageInterface::TYPE_ERROR
236+
);
237+
}
238+
239+
/**
240+
* Makes post request
241+
*
242+
* @param bool $withParamReCaptcha
243+
* @return void
244+
*/
245+
private function makePostRequest(bool $withParamReCaptcha = false): void
246+
{
247+
$postValue = [
248+
'form_key' => $this->formKey,
249+
250+
];
251+
252+
if ($withParamReCaptcha) {
253+
$postValue[CaptchaResponseResolverInterface::PARAM_RECAPTCHA] = 'test';
254+
}
255+
256+
$this->getRequest()
257+
->setMethod(Http::METHOD_POST)
258+
->setPostValue($postValue);
259+
260+
$this->dispatch('wishlist/index/send/wishlist_id/' . $this->wishlistId);
261+
}
262+
263+
/**
264+
* @inheritDoc
265+
*/
266+
public function tearDown(): void
267+
{
268+
$this->customerSession->setCustomerId(null);
269+
parent::tearDown();
270+
}
271+
}

ReCaptchaWishlist/composer.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "magento/module-re-captcha-wishlist",
3+
"description": "Google reCAPTCHA integration for Magento2",
4+
"type": "magento2-module",
5+
"license": "OSL-3.0",
6+
"require": {
7+
"php": "~8.1.0||~8.2.0||~8.3.0",
8+
"magento/framework": "*",
9+
"magento/module-re-captcha-ui": "*"
10+
},
11+
"autoload": {
12+
"files": [
13+
"registration.php"
14+
],
15+
"psr-4": {
16+
"Magento\\ReCaptchaWishlist\\": ""
17+
}
18+
}
19+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
10+
<system>
11+
<section id="recaptcha_frontend">
12+
<group id="type_for">
13+
<field id="wishlist" translate="label" type="select" sortOrder="180" showInDefault="1"
14+
showInWebsite="1" showInStore="0" canRestore="1">
15+
<label>Enable for Wishlist Sharing</label>
16+
<source_model>Magento\ReCaptchaAdminUi\Model\OptionSource\Type</source_model>
17+
</field>
18+
</group>
19+
</section>
20+
</system>
21+
</config>

0 commit comments

Comments
 (0)