From 533e3439c66250ee0fdbd443495c3e28bf0908dc Mon Sep 17 00:00:00 2001 From: TheCoreDev Date: Sat, 4 Mar 2023 21:47:58 +0100 Subject: [PATCH] [04/03/2023] Ajout du module ReCaptcha et config --- .../ReCaptcha/Action/ReCaptchaAction.php | 55 +++++++++++++ local/modules/ReCaptcha/Config/config.xml | 60 ++++++++++++++ local/modules/ReCaptcha/Config/module.xml | 26 ++++++ local/modules/ReCaptcha/Config/routing.xml | 10 +++ local/modules/ReCaptcha/Config/schema.xml | 30 +++++++ .../Controller/ConfigurationController.php | 49 +++++++++++ .../ReCaptcha/Event/ReCaptchaCheckEvent.php | 80 ++++++++++++++++++ .../ReCaptcha/Event/ReCaptchaEvents.php | 8 ++ .../EventListeners/ContactFormListener.php | 59 +++++++++++++ .../ReCaptcha/Form/ConfigurationForm.php | 74 +++++++++++++++++ .../ReCaptcha/Form/MyTheliaFormValidator.php | 34 ++++++++ local/modules/ReCaptcha/Hook/HookManager.php | 82 +++++++++++++++++++ .../I18n/backOffice/default/fr_FR.php | 7 ++ local/modules/ReCaptcha/I18n/en_US.php | 4 + local/modules/ReCaptcha/I18n/fr_FR.php | 11 +++ local/modules/ReCaptcha/LICENSE | 21 +++++ local/modules/ReCaptcha/ReCaptcha.php | 55 +++++++++++++ local/modules/ReCaptcha/Readme.md | 65 +++++++++++++++ local/modules/ReCaptcha/composer.json | 11 +++ .../default/recaptcha/configuration.html | 48 +++++++++++ .../default/recaptcha-js-invisible.html | 56 +++++++++++++ .../frontOffice/default/recaptcha-js.html | 23 ++++++ .../frontOffice/default2020/contact.html | 1 + .../frontOffice/default2020/register.html | 32 ++++---- 24 files changed, 886 insertions(+), 15 deletions(-) create mode 100644 local/modules/ReCaptcha/Action/ReCaptchaAction.php create mode 100644 local/modules/ReCaptcha/Config/config.xml create mode 100644 local/modules/ReCaptcha/Config/module.xml create mode 100644 local/modules/ReCaptcha/Config/routing.xml create mode 100644 local/modules/ReCaptcha/Config/schema.xml create mode 100644 local/modules/ReCaptcha/Controller/ConfigurationController.php create mode 100644 local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php create mode 100644 local/modules/ReCaptcha/Event/ReCaptchaEvents.php create mode 100644 local/modules/ReCaptcha/EventListeners/ContactFormListener.php create mode 100644 local/modules/ReCaptcha/Form/ConfigurationForm.php create mode 100644 local/modules/ReCaptcha/Form/MyTheliaFormValidator.php create mode 100644 local/modules/ReCaptcha/Hook/HookManager.php create mode 100644 local/modules/ReCaptcha/I18n/backOffice/default/fr_FR.php create mode 100644 local/modules/ReCaptcha/I18n/en_US.php create mode 100644 local/modules/ReCaptcha/I18n/fr_FR.php create mode 100644 local/modules/ReCaptcha/LICENSE create mode 100644 local/modules/ReCaptcha/ReCaptcha.php create mode 100644 local/modules/ReCaptcha/Readme.md create mode 100644 local/modules/ReCaptcha/composer.json create mode 100644 local/modules/ReCaptcha/templates/backOffice/default/recaptcha/configuration.html create mode 100644 local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js-invisible.html create mode 100644 local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js.html diff --git a/local/modules/ReCaptcha/Action/ReCaptchaAction.php b/local/modules/ReCaptcha/Action/ReCaptchaAction.php new file mode 100644 index 00000000..82d9f8f6 --- /dev/null +++ b/local/modules/ReCaptcha/Action/ReCaptchaAction.php @@ -0,0 +1,55 @@ +request = $request; + } + + public function checkCaptcha(ReCaptchaCheckEvent $event) + { + $requestUrl = "https://www.google.com/recaptcha/api/siteverify"; + + $secretKey = ReCaptcha::getConfigValue('secret_key'); + $requestUrl .= "?secret=$secretKey"; + + $captchaResponse = $event->getCaptchaResponse(); + if (null === $captchaResponse) { + $captchaResponse = $this->request->request->get('g-recaptcha-response'); + } + + $requestUrl .= "&response=$captchaResponse"; + + $remoteIp = $event->getRemoteIp(); + if (null === $remoteIp) { + $remoteIp = $this->request->server->get('REMOTE_ADDR'); + } + + $requestUrl .= "&remoteip=$remoteIp"; + + $result = json_decode(file_get_contents($requestUrl), true); + + if ((bool) $result['success'] === true) { + $event->setHuman(true); + } + } + + public static function getSubscribedEvents() + { + return [ + ReCaptchaEvents::CHECK_CAPTCHA_EVENT => ['checkCaptcha', 128], + ]; + } +} diff --git a/local/modules/ReCaptcha/Config/config.xml b/local/modules/ReCaptcha/Config/config.xml new file mode 100644 index 00000000..87f5bc6b --- /dev/null +++ b/local/modules/ReCaptcha/Config/config.xml @@ -0,0 +1,60 @@ + + + + + + + + + +
+ + + + + + + + + + + + + + %kernel.environment% + + + + + + + + + + + + + + + + + + + + + + diff --git a/local/modules/ReCaptcha/Config/module.xml b/local/modules/ReCaptcha/Config/module.xml new file mode 100644 index 00000000..0d42cf1f --- /dev/null +++ b/local/modules/ReCaptcha/Config/module.xml @@ -0,0 +1,26 @@ + + + ReCaptcha\ReCaptcha + + ReCaptcha + + + ReCaptcha + + + en_US + fr_FR + + 2.0.4 + + + Vincent Lopes-Vicente + vlopes@openstudio.fr + + + classic + 2.3.0 + other + diff --git a/local/modules/ReCaptcha/Config/routing.xml b/local/modules/ReCaptcha/Config/routing.xml new file mode 100644 index 00000000..7ff27f31 --- /dev/null +++ b/local/modules/ReCaptcha/Config/routing.xml @@ -0,0 +1,10 @@ + + + + + + ReCaptcha\Controller\ConfigurationController::saveAction + + diff --git a/local/modules/ReCaptcha/Config/schema.xml b/local/modules/ReCaptcha/Config/schema.xml new file mode 100644 index 00000000..e42d1ef7 --- /dev/null +++ b/local/modules/ReCaptcha/Config/schema.xml @@ -0,0 +1,30 @@ + + + + + diff --git a/local/modules/ReCaptcha/Controller/ConfigurationController.php b/local/modules/ReCaptcha/Controller/ConfigurationController.php new file mode 100644 index 00000000..b010f9da --- /dev/null +++ b/local/modules/ReCaptcha/Controller/ConfigurationController.php @@ -0,0 +1,49 @@ +checkAuth(array(AdminResources::MODULE), 'ReCaptcha', AccessManager::VIEW)) { + return $response; + } + + $saveMode = $this->getRequest()->request->get("save_mode"); + + $form = $this->createForm("recaptcha_configuration.form"); + + try { + $data = $this->validateForm($form)->getData(); + + ReCaptcha::setConfigValue('site_key', $data['site_key']); + ReCaptcha::setConfigValue('secret_key', $data['secret_key']); + ReCaptcha::setConfigValue('captcha_style', $data['captcha_style']); + ReCaptcha::setConfigValue('add_to_contact_form', $data['add_to_contact_form'] ? 1 : 0); + + if ($saveMode !== 'stay') { + return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/modules')); + } + } catch (\Exception $e) { + $this->setupFormErrorContext( + Translator::getInstance()->trans( + "Error", + [], + ReCaptcha::DOMAIN_NAME + ), + $e->getMessage(), + $form + ); + } + + return $this->generateRedirect(URL::getInstance()->absoluteUrl('/admin/module/ReCaptcha')); + } +} diff --git a/local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php b/local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php new file mode 100644 index 00000000..42b30ddb --- /dev/null +++ b/local/modules/ReCaptcha/Event/ReCaptchaCheckEvent.php @@ -0,0 +1,80 @@ +captchaResponse = $captchaResponse; + } + + if (null !== $remoteIp) { + $this->remoteIp = $remoteIp; + } + } + + /** + * @return null + */ + public function getCaptchaResponse() + { + return $this->captchaResponse; + } + + /** + * @param null $captchaResponse + * @return ReCaptchaCheckEvent + */ + public function setCaptchaResponse($captchaResponse) + { + $this->captchaResponse = $captchaResponse; + return $this; + } + + /** + * @return null + */ + public function getRemoteIp() + { + return $this->remoteIp; + } + + /** + * @param null $remoteIp + * @return ReCaptchaCheckEvent + */ + public function setRemoteIp($remoteIp) + { + $this->remoteIp = $remoteIp; + return $this; + } + + /** + * @return bool + */ + public function isHuman() + { + return $this->human; + } + + /** + * @param bool $human + * @return ReCaptchaCheckEvent + */ + public function setHuman($human) + { + $this->human = $human; + return $this; + } +} diff --git a/local/modules/ReCaptcha/Event/ReCaptchaEvents.php b/local/modules/ReCaptcha/Event/ReCaptchaEvents.php new file mode 100644 index 00000000..2e8b054f --- /dev/null +++ b/local/modules/ReCaptcha/Event/ReCaptchaEvents.php @@ -0,0 +1,8 @@ + [ 'validateCaptcha', 128 ] + ]; + } + + public function validateCaptcha(ContactEvent $event, $eventName, EventDispatcherInterface $dispatcher) + { + $checkCaptchaEvent = new ReCaptchaCheckEvent(); + + $dispatcher->dispatch(ReCaptchaEvents::CHECK_CAPTCHA_EVENT, $checkCaptchaEvent); + + if (! $checkCaptchaEvent->isHuman()) { + throw new FormValidationException( + Translator::getInstance()->trans("Captcha validation failed, please try again.", [], ReCaptcha::DOMAIN_NAME) + ); + } + } +} diff --git a/local/modules/ReCaptcha/Form/ConfigurationForm.php b/local/modules/ReCaptcha/Form/ConfigurationForm.php new file mode 100644 index 00000000..410584ff --- /dev/null +++ b/local/modules/ReCaptcha/Form/ConfigurationForm.php @@ -0,0 +1,74 @@ +formBuilder + ->add( + "site_key", + "text", + [ + "data" => ReCaptcha::getConfigValue("site_key"), + "label"=>Translator::getInstance()->trans("Site key", array(), ReCaptcha::DOMAIN_NAME), + "label_attr" => ["for" => "site_key"], + "required" => true + ] + ) + ->add( + "secret_key", + "text", + [ + "data" => ReCaptcha::getConfigValue("secret_key"), + "label"=>Translator::getInstance()->trans("Secret key", array(), ReCaptcha::DOMAIN_NAME), + "label_attr" => ["for" => "secret_key"], + "required" => true + ] + ) + ->add( + "captcha_style", + "choice", + [ + "data" => ReCaptcha::getConfigValue("captcha_style"), + "label"=>Translator::getInstance()->trans("ReCaptcha style", array(), ReCaptcha::DOMAIN_NAME), + "label_attr" => ["for" => "captcha_style"], + "required" => true, + 'choices' => [ + 'normal'=>'Normal', + 'compact'=>'Compact', + 'invisible'=>'Invisible' + ] + ] + ); + + if (defined('\Thelia\Core\Event\TheliaEvents::CONTACT_SUBMIT')) { + $this->formBuilder + ->add( + "add_to_contact_form", + "checkbox", + [ + "required" => false, + "data" => (bool) ReCaptcha::getConfigValue("add_to_contact_form"), + "value" => 1, + "label" => $this->translator->trans("Add captcha to standard contact form", [], ReCaptcha::DOMAIN_NAME), + "label_attr" => [ + "for" => "add_to_contact_form", + 'help' => $this->translator->trans("Check this box to add a captcha to the standard Thelia 2 contact form", [], ReCaptcha::DOMAIN_NAME) + ], + + ] + ); + } + } + + public function getName() + { + return "recaptcha_configuration_form"; + } +} diff --git a/local/modules/ReCaptcha/Form/MyTheliaFormValidator.php b/local/modules/ReCaptcha/Form/MyTheliaFormValidator.php new file mode 100644 index 00000000..f70accb4 --- /dev/null +++ b/local/modules/ReCaptcha/Form/MyTheliaFormValidator.php @@ -0,0 +1,34 @@ +dispatcher = $dispatcher; + parent::__construct($translator, $environment); + } + + public function validateForm(BaseForm $aBaseForm, $expectedMethod = null) + { + if ($aBaseForm->getRequest()->get('captcha')) { + $checkCaptchaEvent = new ReCaptchaCheckEvent(); + $this->dispatcher->dispatch(ReCaptchaEvents::CHECK_CAPTCHA_EVENT, $checkCaptchaEvent); + if ($checkCaptchaEvent->isHuman() == false) { + throw new FormValidationException('Veuillez confirmer que vous n\'êtes pas un robot.'); + } + } + + return parent::validateForm($aBaseForm, $expectedMethod); // TODO: Change the autogenerated stub + } + +} \ No newline at end of file diff --git a/local/modules/ReCaptcha/Hook/HookManager.php b/local/modules/ReCaptcha/Hook/HookManager.php new file mode 100644 index 00000000..4a874b7a --- /dev/null +++ b/local/modules/ReCaptcha/Hook/HookManager.php @@ -0,0 +1,82 @@ +add( + $this->render( + 'recaptcha/configuration.html', + [ + 'with_contact_form' => defined('\Thelia\Core\Event\TheliaEvents::CONTACT_SUBMIT') + ] + ) + ); + } + + public function addRecaptchaCheckContact(HookRenderEvent $event) + { + // Ensure comptatibility with pre-2.4 versions + if (defined('\Thelia\Core\Event\TheliaEvents::CONTACT_SUBMIT') + && + (bool) ReCaptcha::getConfigValue('add_to_contact_form') + ) { + $this->addRecaptchaCheck($event); + } + } + + public function addRecaptchaCheck(HookRenderEvent $event) + { + $siteKey = ReCaptcha::getConfigValue('site_key'); + $captchaStyle = ReCaptcha::getConfigValue('captcha_style'); + + $captchaId= "recaptcha"; + $captchaCallback = ""; + $type = ""; + + if ($captchaStyle === 'invisible') { + $captchaCallback = "data-callback='onCompleted'"; + $type = "g-invisible"; + $captchaId .= '-invisible'; + } + + if (null !== $event->getArgument('id')) { + $captchaId = $event->getArgument('id'); + } + + $event->add("
"); + } + + public function loadRecaptcha(HookRenderEvent $event) + { + $siteKey = ReCaptcha::getConfigValue('site_key'); + $captchaStyle = ReCaptcha::getConfigValue('captcha_style'); + + if ($captchaStyle !== 'invisible') { + $event->add($this->render( + 'recaptcha-js.html', + [ + "siteKey" => $siteKey, + "captchaStyle" => $captchaStyle, + ] + )); + + return; + } + + $event->add($this->render( + 'recaptcha-js-invisible.html', + [ + "siteKey" => $siteKey, + "captchaStyle" => $captchaStyle, + ] + )); + } +} diff --git a/local/modules/ReCaptcha/I18n/backOffice/default/fr_FR.php b/local/modules/ReCaptcha/I18n/backOffice/default/fr_FR.php new file mode 100644 index 00000000..85634178 --- /dev/null +++ b/local/modules/ReCaptcha/I18n/backOffice/default/fr_FR.php @@ -0,0 +1,7 @@ + 'Envoyer', + 'These infos are available here : ' => 'Ces infos sont disponibles ici : ', + 'reCAPTCHA Configuration' => 'Configuration reCAPTCHA', +); diff --git a/local/modules/ReCaptcha/I18n/en_US.php b/local/modules/ReCaptcha/I18n/en_US.php new file mode 100644 index 00000000..0b4fa142 --- /dev/null +++ b/local/modules/ReCaptcha/I18n/en_US.php @@ -0,0 +1,4 @@ + 'The displayed english string', +); diff --git a/local/modules/ReCaptcha/I18n/fr_FR.php b/local/modules/ReCaptcha/I18n/fr_FR.php new file mode 100644 index 00000000..00914ac1 --- /dev/null +++ b/local/modules/ReCaptcha/I18n/fr_FR.php @@ -0,0 +1,11 @@ + 'Ajouter un CAPTCHA au formulaire de contact', + 'Captcha validation failed, please try again.' => 'Nous n\'avons pas pu vérifier ', + 'Check this box to add a captcha to the standard Thelia 2 contact form' => 'Cochez cette case pour ajouter un CAPTCHA au formulaire de contact standard de Thelia', + 'Error' => 'Erreur', + 'ReCaptcha style' => 'Style du CAPTCHA', + 'Secret key' => 'Clé secrète', + 'Site key' => 'Clé du site', +); diff --git a/local/modules/ReCaptcha/LICENSE b/local/modules/ReCaptcha/LICENSE new file mode 100644 index 00000000..2152256c --- /dev/null +++ b/local/modules/ReCaptcha/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 OpenStudio + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/local/modules/ReCaptcha/ReCaptcha.php b/local/modules/ReCaptcha/ReCaptcha.php new file mode 100644 index 00000000..dafde8f5 --- /dev/null +++ b/local/modules/ReCaptcha/ReCaptcha.php @@ -0,0 +1,55 @@ + TemplateDefinition::FRONT_OFFICE, + "code" => "recaptcha.js", + "title" => [ + "en_US" => "reCaptcha js", + "fr_FR" => "Js pour recaptcha", + ], + "block" => false, + "active" => true, + ], + [ + "type" => TemplateDefinition::FRONT_OFFICE, + "code" => "recaptcha.check", + "title" => [ + "en_US" => "reCaptcha check hook", + "fr_FR" => "reCaptcha check hook", + ], + "block" => false, + "active" => true, + ], + ]; + } +} diff --git a/local/modules/ReCaptcha/Readme.md b/local/modules/ReCaptcha/Readme.md new file mode 100644 index 00000000..877cfe59 --- /dev/null +++ b/local/modules/ReCaptcha/Readme.md @@ -0,0 +1,65 @@ +# Re Captcha + +This module allow you to add easily a reCAPTCHA to your form +## Installation + +### Composer + +Add it in your main thelia composer.json file + +``` +composer require thelia/re-captcha-module:~2.0.3 +``` + +## Usage + +Before using this module you have to create google api key here http://www.google.com/recaptcha/admin +next configure your reCAPTCHA access here http://your_site.com`/admin/module/ReCaptcha` with keys you obtained in Google's page +and choose which style of captcha you want : + +- A standard captcha (or a compact version of this one) + + ![Checkbox captcha](https://developers.google.com/recaptcha/images/newCaptchaAnchor.gif) + +- An invisible captcha + + ![Invisible captcha](https://developers.google.com/recaptcha/images/invisible_badge.png) + +If you're using Thelia 2.4 or better, you can automatically add a CAPTCHA to the standard Thelia +contact form. To do so, just check the "Add captcha to standard contact form" box in the module +configuration. + +For thelia 2.3, you'll need help from a developer to add some hooks in template and dispatch the check events, see details below. + +### Hook + +First if you don't have `{hook name="main.head-top"}` hook in your template you have to put this hook `{hook name="recaptcha.js"}` in the top of your head +Then add this hook `{hook name="recaptcha.check"}` in every form where you want to check if the user is human, +be careful if you want to use the invisible captcha this hook must be placed directly in the form tag like this : +``` + + {hook name="recaptcha.check"} + // End of the form +
+``` + +### Event + +To check in server-side if the captcha is valid you have to dispatch the "CHECK_CAPTCHA_EVENT" like this : +``` +$checkCaptchaEvent = new ReCaptchaCheckEvent(); +$this->dispatch(ReCaptchaEvents::CHECK_CAPTCHA_EVENT, $checkCaptchaEvent); +``` + +Then the result of check is available in `$checkCaptchaEvent->isHuman()`as boolean so you can do a test like this : +``` +if ($checkCaptchaEvent->isHuman() == false) { + throw new \Exception('Invalid captcha'); +} +``` + +Don't forget to add this use at the top of your class : +``` +use ReCaptcha\Event\ReCaptchaCheckEvent; +use ReCaptcha\Event\ReCaptchaEvents; +``` diff --git a/local/modules/ReCaptcha/composer.json b/local/modules/ReCaptcha/composer.json new file mode 100644 index 00000000..84b27144 --- /dev/null +++ b/local/modules/ReCaptcha/composer.json @@ -0,0 +1,11 @@ +{ + "name": "thelia/re-captcha-module", + "license": "LGPL-3.0+", + "type": "thelia-module", + "require": { + "thelia/installer": "~1.1" + }, + "extra": { + "installer-name": "ReCaptcha" + } +} \ No newline at end of file diff --git a/local/modules/ReCaptcha/templates/backOffice/default/recaptcha/configuration.html b/local/modules/ReCaptcha/templates/backOffice/default/recaptcha/configuration.html new file mode 100644 index 00000000..0dc3b717 --- /dev/null +++ b/local/modules/ReCaptcha/templates/backOffice/default/recaptcha/configuration.html @@ -0,0 +1,48 @@ +
+
+
+
+ {intl d='payzen.bo.default' l="reCAPTCHA Configuration" d='recaptcha.bo.default'} +
+
+ +
+
+
+ {form name="recaptcha_configuration.form"} +
+ {form_hidden_fields form=$form} + + {if $form_error} +
{$form_error_message}
+ {/if} + + {include file = "includes/inner-form-toolbar.html" + hide_flags = true + page_url = "{url path='/admin/module/ReCaptcha'}" + close_url = "{url path='/admin/modules'}" + } + +
+
+ {render_form_field field="site_key" } + {render_form_field field="secret_key"} +

{intl l="These infos are available here : " d='recaptcha.bo.default'}http://www.google.com/recaptcha/admin

+
+ +
+ {render_form_field field="captcha_style"} + + {if $with_contact_form} + + {render_form_field field="add_to_contact_form"} + {/if} +
+
+
+ {/form} +
+
+
+
+
diff --git a/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js-invisible.html b/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js-invisible.html new file mode 100644 index 00000000..7164ae3d --- /dev/null +++ b/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js-invisible.html @@ -0,0 +1,56 @@ + + + + + +{literal} + +{/literal} \ No newline at end of file diff --git a/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js.html b/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js.html new file mode 100644 index 00000000..e64a79c3 --- /dev/null +++ b/local/modules/ReCaptcha/templates/frontOffice/default/recaptcha-js.html @@ -0,0 +1,23 @@ + + \ No newline at end of file diff --git a/templates/frontOffice/default2020/contact.html b/templates/frontOffice/default2020/contact.html index 8d3bd4a3..5a16c063 100644 --- a/templates/frontOffice/default2020/contact.html +++ b/templates/frontOffice/default2020/contact.html @@ -94,6 +94,7 @@ + {hook name="recaptcha.check"} {/form} diff --git a/templates/frontOffice/default2020/register.html b/templates/frontOffice/default2020/register.html index 05e39602..84eeb3bd 100644 --- a/templates/frontOffice/default2020/register.html +++ b/templates/frontOffice/default2020/register.html @@ -291,21 +291,24 @@ - {form_field field="newsletter"} -
-
-
- - {if $error } - {$message} - {/if} -
-
-
- {/form_field} + + + + + + + + + + + + + + +
+ {hook name="recaptcha.check"} +
{hook name="register.form-bottom"}
@@ -315,7 +318,6 @@
{/form} - {hook name="register.bottom"}