Skip to content

Commit

Permalink
support hCaptcha options
Browse files Browse the repository at this point in the history
  • Loading branch information
Erwane committed Aug 17, 2022
1 parent dd52728 commit 171b3c6
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 9 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
},
"require": {
"php": "^7.2 | ^8.0",
"ext-intl": "*",
"cakephp/cakephp": "^4.0"
},
"require-dev": {
"cakephp/cakephp-codesniffer": "^4.0",
"php-parallel-lint/php-parallel-lint": "^1.0",
"phpro/grumphp": "^v1.0",
"phpro/grumphp": "^v0.19 | ^v1.0",
"phpunit/phpunit": "^8.0 | ^9.0"
},
"scripts": {
Expand Down
55 changes: 49 additions & 6 deletions src/View/Widget/HCaptchaWidget.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use Cake\View\StringTemplate;
use Cake\View\View;
use Cake\View\Widget\WidgetInterface;
use Laminas\Diactoros\Uri;
use Locale;

/**
* Class HCaptchaWidget
Expand All @@ -27,11 +29,21 @@ class HCaptchaWidget implements WidgetInterface
*/
private $_view;

/**
* @var string
*/
protected $_apiUrl = 'https://hcaptcha.com/1/api.js';

/**
* @var string[]
*/
protected $_renderAllowedValues = ['explicit', 'onload'];

/**
* HCaptchaWidget constructor.
*
* @param \Cake\View\StringTemplate $templates String templates
* @param \Cake\View\View $view Cake view
* @param \Cake\View\StringTemplate $templates String templates
* @param \Cake\View\View $view Cake view
*/
public function __construct(StringTemplate $templates, View $view)
{
Expand All @@ -43,23 +55,54 @@ public function __construct(StringTemplate $templates, View $view)
/**
* Render HCaptcha div and append javascript call to script block
*
* @param array $data The data to render.
* @param \Cake\View\Form\ContextInterface $context The current form context.
* @param array $data The data to render.
* @param \Cake\View\Form\ContextInterface $context The current form context.
* @return string Generated HTML for the widget element.
*/
public function render(array $data, ContextInterface $context): string
{
$data += [
'fieldName' => '',
'withoutJs' => false,
'onload' => null,
'render' => null,
'lang' => null,
'recaptchacompat' => null,
];

$this->_view->Form->unlockField($data['fieldName']);
$this->_view->Form->unlockField('g-recaptcha-response');

// Append js
if (!$data['withoutJs']) {
$this->_view->Html->script('https://hcaptcha.com/1/api.js', ['block' => 'script']);
$uri = new Uri($this->_apiUrl);
$queryArgs = [];

if ($data['onload']) {
$queryArgs['onload'] = h($data['onload']);
}
if ($data['render'] && in_array($data['render'], $this->_renderAllowedValues)) {
$queryArgs['render'] = h($data['render']);
}

if ($data['lang']) {
$locale = Locale::parseLocale((string)$data['lang']);
if (!empty($locale['language'])) {
$queryArgs['hl'] = $locale['language'];
}
}

if ($data['recaptchacompat'] !== null) {
$queryArgs['recaptchacompat'] = in_array(
$data['recaptchacompat'],
[1, '1', 'y', 'Y', 'yes', 'on']
) ? 'on' : 'off';
}

$url = $uri->withQuery(http_build_query($queryArgs))
->__toString();

$this->_view->Html->script($url, ['block' => 'script', 'async', 'defer']);
}

$key = Configure::read('HCaptcha.key');
Expand All @@ -73,7 +116,7 @@ public function render(array $data, ContextInterface $context): string
/**
* No field should be secured
*
* @param array $data The data to render.
* @param array $data The data to render.
* @return string[] Array of fields to secure.
*/
public function secureFields(array $data): array
Expand Down
30 changes: 28 additions & 2 deletions tests/TestCase/View/Widget/HCaptchaWidgetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,45 @@ public function testRenderNoKey(): void
* @test
* @covers ::render
*/
public function testRender(): void
public function testRenderSimple(): void
{
Configure::write('HCaptcha.key', 'testing-site-key');
$context = new ArrayContext([]);

$this->html->expects($this->once())
->method('script')
->with('https://hcaptcha.com/1/api.js', ['block' => 'script']);
->with('https://hcaptcha.com/1/api.js', ['block' => 'script', 'async', 'defer']);

$result = $this->widget->render(['fieldName' => 'field'], $context);
$this->assertSame('<div class="h-captcha" data-sitekey="testing-site-key"></div>', $result);
}

/**
* @test
* @covers ::render
*/
public function testRenderWithOptions(): void
{
Configure::write('HCaptcha.key', 'testing-site-key');
$context = new ArrayContext([]);

$this->html->expects($this->once())
->method('script')
->with(
'https://hcaptcha.com/1/api.js?onload=myFunction&render=explicit&hl=fr&recaptchacompat=off',
['block' => 'script', 'async', 'defer']
);

$result = $this->widget->render([
'fieldName' => 'field',
'lang' => 'fr_FR',
'onload' => 'myFunction',
'render' => 'explicit',
'recaptchacompat' => false,
], $context);
$this->assertSame('<div class="h-captcha" data-sitekey="testing-site-key"></div>', $result);
}

/**
* @test
* @covers ::secureFields
Expand Down

0 comments on commit 171b3c6

Please sign in to comment.