Skip to content

Commit efef37f

Browse files
authored
Merge branch '1.0-develop' into patch-1
2 parents 766064b + 63756a1 commit efef37f

File tree

20 files changed

+577
-42
lines changed

20 files changed

+577
-42
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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\ReCaptchaCustomer\Observer;
9+
10+
use Magento\Framework\App\Action\Action;
11+
use Magento\Framework\Event\Observer;
12+
use Magento\Framework\Event\ObserverInterface;
13+
use Magento\Framework\UrlInterface;
14+
use Magento\ReCaptchaUi\Model\IsCaptchaEnabledInterface;
15+
use Magento\ReCaptchaUi\Model\RequestHandlerInterface;
16+
17+
/**
18+
* NewsletterObserver
19+
*
20+
* Process the response during customer account editing
21+
*/
22+
class EditCustomerObserver implements ObserverInterface
23+
{
24+
/**
25+
* @var UrlInterface
26+
*/
27+
private $url;
28+
29+
/**
30+
* @var IsCaptchaEnabledInterface
31+
*/
32+
private $isCaptchaEnabled;
33+
34+
/**
35+
* @var RequestHandlerInterface
36+
*/
37+
private $requestHandler;
38+
39+
/**
40+
* @param UrlInterface $url
41+
* @param IsCaptchaEnabledInterface $isCaptchaEnabled
42+
* @param RequestHandlerInterface $requestHandler
43+
*/
44+
public function __construct(
45+
UrlInterface $url,
46+
IsCaptchaEnabledInterface $isCaptchaEnabled,
47+
RequestHandlerInterface $requestHandler
48+
) {
49+
$this->url = $url;
50+
$this->isCaptchaEnabled = $isCaptchaEnabled;
51+
$this->requestHandler = $requestHandler;
52+
}
53+
54+
/**
55+
* @inheritdoc
56+
*
57+
* @param Observer $observer
58+
* @return void
59+
* @throws \Magento\Framework\Exception\LocalizedException
60+
*/
61+
public function execute(Observer $observer): void
62+
{
63+
$key = 'customer_edit';
64+
if ($this->isCaptchaEnabled->isCaptchaEnabledFor($key)) {
65+
/** @var Action $controller */
66+
$controller = $observer->getControllerAction();
67+
$request = $controller->getRequest();
68+
$response = $controller->getResponse();
69+
$redirectOnFailureUrl = $this->url->getUrl('*/*/edit', ['_secure' => true]);
70+
71+
$this->requestHandler->execute($key, $request, $response, $redirectOnFailureUrl);
72+
}
73+
}
74+
}
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
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\ReCaptchaCustomer\Test\Integration;
9+
10+
use Magento\Customer\Api\CustomerRepositoryInterface;
11+
use Magento\Customer\Model\Session;
12+
use Magento\Framework\App\Request\Http;
13+
use Magento\Framework\Data\Form\FormKey;
14+
use Magento\Framework\Message\MessageInterface;
15+
use Magento\Framework\UrlInterface;
16+
use Magento\Framework\Validation\ValidationResult;
17+
use Magento\ReCaptchaUi\Model\CaptchaResponseResolverInterface;
18+
use Magento\ReCaptchaValidation\Model\Validator;
19+
use Magento\Store\Model\ScopeInterface;
20+
use Magento\TestFramework\App\MutableScopeConfig;
21+
use Magento\TestFramework\TestCase\AbstractController;
22+
use PHPUnit\Framework\MockObject\MockObject;
23+
24+
/**
25+
* @magentoDataFixture Magento/Customer/_files/customer.php
26+
* @magentoAppArea frontend
27+
* @magentoAppIsolation enabled
28+
*/
29+
class EditFromTest extends AbstractController
30+
{
31+
/**
32+
* @var MutableScopeConfig
33+
*/
34+
private $mutableScopeConfig;
35+
36+
/**
37+
* @var CustomerRepositoryInterface
38+
*/
39+
private $customerRepository;
40+
41+
/**
42+
* @var FormKey
43+
*/
44+
private $formKey;
45+
46+
/**
47+
* @var Session
48+
*/
49+
private $session;
50+
51+
/**
52+
* @var UrlInterface
53+
*/
54+
private $url;
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->mutableScopeConfig = $this->_objectManager->get(MutableScopeConfig::class);
68+
$this->formKey = $this->_objectManager->get(FormKey::class);
69+
$this->customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class);
70+
$this->session = $this->_objectManager->get(Session::class);
71+
$this->url = $this->_objectManager->get(UrlInterface::class);
72+
73+
$this->captchaValidationResultMock = $this->createMock(ValidationResult::class);
74+
$captchaValidationResultMock = $this->createMock(Validator::class);
75+
$captchaValidationResultMock->expects($this->any())
76+
->method('isValid')
77+
->willReturn($this->captchaValidationResultMock);
78+
$this->_objectManager->addSharedInstance($captchaValidationResultMock, Validator::class);
79+
}
80+
81+
/**
82+
* @magentoConfigFixture default_store customer/captcha/enable 0
83+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key
84+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key
85+
*/
86+
public function testGetRequestIfReCaptchaIsDisabled(): void
87+
{
88+
$this->setConfig(false, 'test_public_key', 'test_private_key');
89+
90+
$this->checkSuccessfulGetResponse();
91+
}
92+
93+
/**
94+
* @magentoConfigFixture default_store customer/captcha/enable 0
95+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible
96+
*
97+
* It's needed for proper work of "ifconfig" in layout during tests running
98+
* @magentoConfigFixture default_store recaptcha_frontend/type_for/customer_edit invisible
99+
*/
100+
public function testGetRequestIfReCaptchaKeysAreNotConfigured(): void
101+
{
102+
$this->setConfig(true, null, null);
103+
104+
$this->checkSuccessfulGetResponse();
105+
}
106+
107+
/**
108+
* @magentoConfigFixture default_store customer/captcha/enable 0
109+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key
110+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key
111+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible
112+
*
113+
* It's needed for proper work of "ifconfig" in layout during tests running
114+
* @magentoConfigFixture default_store recaptcha_frontend/type_for/customer_edit invisible
115+
*/
116+
public function testGetRequestIfReCaptchaIsEnabled(): void
117+
{
118+
$this->setConfig(true, 'test_public_key', 'test_private_key');
119+
120+
$this->checkSuccessfulGetResponse(true);
121+
}
122+
123+
/**
124+
* @magentoConfigFixture default_store customer/captcha/enable 0
125+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key
126+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key
127+
*/
128+
public function testPostRequestIfReCaptchaIsDisabled(): void
129+
{
130+
$this->setConfig(false, 'test_public_key', 'test_private_key');
131+
132+
$this->checkSuccessfulPostResponse();
133+
}
134+
135+
/**
136+
* @magentoConfigFixture default_store customer/captcha/enable 0
137+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible
138+
*/
139+
public function testPostRequestIfReCaptchaKeysAreNotConfigured(): void
140+
{
141+
$this->setConfig(true, null, null);
142+
143+
$this->checkSuccessfulPostResponse();
144+
}
145+
146+
/**
147+
* @magentoConfigFixture default_store customer/captcha/enable 0
148+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key
149+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key
150+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible
151+
*/
152+
public function testPostRequestWithSuccessfulReCaptchaValidation(): void
153+
{
154+
$this->setConfig(true, 'test_public_key', 'test_private_key');
155+
$this->captchaValidationResultMock->expects($this->once())->method('isValid')->willReturn(true);
156+
157+
$this->checkSuccessfulPostResponse(
158+
[CaptchaResponseResolverInterface::PARAM_RECAPTCHA => 'test']
159+
);
160+
}
161+
162+
/**
163+
* @magentoConfigFixture default_store customer/captcha/enable 0
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/customer_edit invisible
167+
*/
168+
public function testPostRequestIfReCaptchaParameterIsMissed(): void
169+
{
170+
$this->setConfig(true, 'test_public_key', 'test_private_key');
171+
172+
$this->checkFailedPostResponse();
173+
}
174+
175+
/**
176+
* @magentoConfigFixture default_store customer/captcha/enable 0
177+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key
178+
* @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key
179+
* @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible
180+
*/
181+
public function testPostRequestWithFailedReCaptchaValidation(): void
182+
{
183+
$this->setConfig(true, 'test_public_key', 'test_private_key');
184+
$this->captchaValidationResultMock->expects($this->once())->method('isValid')->willReturn(false);
185+
186+
$this->checkFailedPostResponse(
187+
[CaptchaResponseResolverInterface::PARAM_RECAPTCHA => 'test']
188+
);
189+
}
190+
191+
/**
192+
* @param bool $shouldContainReCaptcha
193+
* @return void
194+
*/
195+
private function checkSuccessfulGetResponse($shouldContainReCaptcha = false): void
196+
{
197+
$this->session->loginById(1);
198+
$this->dispatch('customer/account/edit');
199+
$content = $this->getResponse()->getBody();
200+
201+
self::assertNotEmpty($content);
202+
203+
$shouldContainReCaptcha
204+
? $this->assertStringContainsString('field-recaptcha', $content)
205+
: $this->assertStringNotContainsString('field-recaptcha', $content);
206+
207+
self::assertEmpty($this->getSessionMessages(MessageInterface::TYPE_ERROR));
208+
}
209+
210+
/**
211+
* @param array $postValues
212+
* @return void
213+
*/
214+
private function checkSuccessfulPostResponse(array $postValues = []): void
215+
{
216+
$this->session->loginById(1);
217+
$this->makePostRequest($postValues);
218+
219+
$this->assertRedirect(self::equalTo($this->url->getRouteUrl('customer/account')));
220+
self::assertEmpty($this->getSessionMessages(MessageInterface::TYPE_ERROR));
221+
222+
$customer = $this->customerRepository->getById(1);
223+
$this->assertEquals('Test First Name', $customer->getFirstname());
224+
$this->assertEquals('Test Last Name', $customer->getLastname());
225+
$this->assertEquals('[email protected]', $customer->getEmail());
226+
}
227+
228+
/**
229+
* @param array $postValues
230+
* @return void
231+
*/
232+
private function checkFailedPostResponse(array $postValues = []): void
233+
{
234+
$this->session->loginById(1);
235+
$this->makePostRequest($postValues);
236+
237+
$this->assertRedirect(self::stringStartsWith($this->url->getRouteUrl('customer/account/edit')));
238+
$this->assertSessionMessages(
239+
self::equalTo(['reCAPTCHA verification failed']),
240+
MessageInterface::TYPE_ERROR
241+
);
242+
243+
$customer = $this->customerRepository->getById(1);
244+
$this->assertEquals('John', $customer->getFirstname());
245+
$this->assertEquals('Smith', $customer->getLastname());
246+
$this->assertEquals('[email protected]', $customer->getEmail());
247+
}
248+
249+
/**
250+
* @param array $postValues
251+
* @return void
252+
*/
253+
private function makePostRequest(array $postValues = []): void
254+
{
255+
$this->getRequest()
256+
->setMethod(Http::METHOD_POST)
257+
->setPostValue(
258+
array_replace_recursive(
259+
[
260+
'form_key' => $this->formKey->getFormKey(),
261+
'firstname' => 'Test First Name',
262+
'lastname' => 'Test Last Name',
263+
],
264+
$postValues
265+
)
266+
);
267+
268+
$this->dispatch('customer/account/editpost');
269+
}
270+
271+
/**
272+
* @param bool $isEnabled
273+
* @param string|null $public
274+
* @param string|null $private
275+
* @return void
276+
*/
277+
private function setConfig(bool $isEnabled, ?string $public, ?string $private): void
278+
{
279+
$this->mutableScopeConfig->setValue(
280+
'recaptcha_frontend/type_for/customer_edit',
281+
$isEnabled ? 'invisible' : null,
282+
ScopeInterface::SCOPE_WEBSITE
283+
);
284+
$this->mutableScopeConfig->setValue(
285+
'recaptcha_frontend/type_invisible/public_key',
286+
$public,
287+
ScopeInterface::SCOPE_WEBSITE
288+
);
289+
$this->mutableScopeConfig->setValue(
290+
'recaptcha_frontend/type_invisible/private_key',
291+
$private,
292+
ScopeInterface::SCOPE_WEBSITE
293+
);
294+
}
295+
296+
protected function tearDown(): void
297+
{
298+
parent::tearDown();
299+
300+
$this->mutableScopeConfig->setValue(
301+
'recaptcha_frontend/type_for/customer_edit',
302+
null,
303+
ScopeInterface::SCOPE_WEBSITE
304+
);
305+
$this->mutableScopeConfig->setValue(
306+
'recaptcha_frontend/type_invisible/public_key',
307+
null,
308+
ScopeInterface::SCOPE_WEBSITE
309+
);
310+
$this->mutableScopeConfig->setValue(
311+
'recaptcha_frontend/type_invisible/private_key',
312+
null,
313+
ScopeInterface::SCOPE_WEBSITE
314+
);
315+
}
316+
}

0 commit comments

Comments
 (0)