src/pyams_default_theme/shared/form/__init__.py
changeset 460 77cec5c9ef84
parent 459 07781aca5cd7
child 469 b8d287df9d34
--- a/src/pyams_default_theme/shared/form/__init__.py	Wed Sep 04 16:10:10 2019 +0200
+++ b/src/pyams_default_theme/shared/form/__init__.py	Tue Sep 17 12:00:26 2019 +0200
@@ -13,11 +13,13 @@
 import requests
 from pyramid.csrf import get_csrf_token
 from z3c.form import button, field
+from z3c.form.browser.checkbox import SingleCheckBoxFieldWidget
 from z3c.form.interfaces import HIDDEN_MODE
-from zope.interface import Interface, Invalid
-from zope.schema import TextLine
+from zope.interface import Interface, Invalid, alsoProvides
+from zope.schema import Bool, TextLine
 
 from pyams_content.shared.form import IFormFieldContainer, IFormFieldContainerTarget, IWfForm
+from pyams_content.shared.form.interfaces import IFormFieldDataConverter
 from pyams_default_theme.component.paragraph.interfaces import IParagraphContainerPortletRenderer
 from pyams_default_theme.interfaces import IContentTitle
 from pyams_default_theme.layer import IPyAMSDefaultLayer
@@ -31,6 +33,8 @@
 from pyams_template.template import template_config
 from pyams_utils.adapter import adapter_config
 from pyams_utils.interfaces import PUBLIC_PERMISSION, VIEW_PERMISSION
+from pyams_utils.interfaces.data import IObjectData
+from pyams_utils.text import text_to_html
 from pyams_utils.url import relative_url
 from pyams_viewlet.viewlet import ViewContentProvider, Viewlet, viewlet_config
 
@@ -42,6 +46,7 @@
 
 CSRF_FIELD_NAME = 'csrf_token'
 RECAPTCHA_FIELD_NAME = 'g-recaptcha-response'
+RGPD_CONSENT_FIELD_NAME = 'rgpd_consent'
 
 MISSING_TOKEN_ERROR = _("Missing recaptcha token!")
 INVALID_TOKEN_ERROR = _("Can't verify recaptcha token! Are you a robot?")
@@ -84,8 +89,18 @@
                 captcha.__name__ = RECAPTCHA_FIELD_NAME
                 yield captcha
             yield from IFormFieldContainer(self.context).get_fields()
+            if self.context.rgpd_consent:
+                consent = Bool(title=II18n(self.context).query_attribute('rgpd_warning',
+                                                                         request=self.request),
+                               required=True,
+                               default=False)
+                consent.__name__ = RGPD_CONSENT_FIELD_NAME
+                yield consent
 
-        return field.Fields(*tuple(get_fields()))
+        fields = field.Fields(*tuple(get_fields()))
+        if self.context.rgpd_consent:
+            fields[RGPD_CONSENT_FIELD_NAME].widgetFactory = SingleCheckBoxFieldWidget
+        return fields
 
     def updateActions(self):
         super(FormFieldContainerInputForm, self).updateActions()
@@ -103,6 +118,20 @@
             elif widget.field.__name__ == RECAPTCHA_FIELD_NAME:
                 widget.name = RECAPTCHA_FIELD_NAME
                 widget.mode = HIDDEN_MODE
+            elif widget.field.__name__ == RGPD_CONSENT_FIELD_NAME:
+                widget.name = RGPD_CONSENT_FIELD_NAME
+                widget.required = False
+                user_rights = II18n(self.context).query_attribute('rgpd_user_rights',
+                                                                  request=self.request)
+                widget.after_widget_notice = '<div><br />{0}</div>'.format(
+                    text_to_html(user_rights, 'oid_to_href'))
+                widget.object_data = {
+                    'ams-validate-messages': {
+                        'required': self.request.localizer.translate(
+                            _("You can't submit this form without accepting data usage rules."))
+                    }
+                }
+                alsoProvides(widget, IObjectData)
             else:
                 field = IFormFieldContainer(self.context).get(widget.field.__name__)
                 if field is not None:
@@ -110,33 +139,44 @@
 
     @button.buttonAndHandler('title', name='submit')
     def update_content(self, action):
+        request = self.request
         form = IWfForm(self.context)
         handler = form.query_handler()
         if handler is not None:
             data, errors = self.extractData()
             if errors:
-                self.status = self.formErrorsMessage
+                self.status = request.localizer.translate(self.formErrorsMessage)
             else:
                 # remove custom data fields from handler data
                 if CSRF_FIELD_NAME in data:
                     del data[CSRF_FIELD_NAME]
-                if self.context.use_captcha:
+                if form.use_captcha:
                     if RECAPTCHA_FIELD_NAME not in data:
                         self.add_error(Invalid(MISSING_TOKEN_ERROR), RECAPTCHA_FIELD_NAME)
                         return
-                    proxies = {'https': self.context.captcha_proxy} if self.context.captcha_proxy else {}
-                    recaptcha_verify_api = self.request.registry.settings.get('pyams.recaptcha.verify')
+                    proxies = {'https': form.captcha_proxy} if form.captcha_proxy else {}
+                    recaptcha_verify_api = \
+                        request.registry.settings.get('pyams.recaptcha.verify')
                     if not recaptcha_verify_api:
                         recaptcha_verify_api = 'https://www.google.com/recaptcha/api/siteverify'
                     verify = requests.post(recaptcha_verify_api, {
-                        'secret': self.context.server_captcha_key,
+                        'secret': form.server_captcha_key,
                         'response': data[RECAPTCHA_FIELD_NAME]
                     }, proxies=proxies).json()
                     if not verify['success']:
                         self.add_error(INVALID_TOKEN_ERROR, RECAPTCHA_FIELD_NAME)
                         return
                     del data[RECAPTCHA_FIELD_NAME]
-                handler.handle(form, data)
+                # convert form data
+                user_data = data.copy()
+                for field in IFormFieldContainer(form).get_fields():
+                    converter = request.registry.queryMultiAdapter((field, request),
+                                                                   IFormFieldDataConverter)
+                    if converter is not None:
+                        user_data[field.__name__] = converter.convert(data.get(field.__name__))
+                output = handler.handle(form, data, user_data)
+                if output:
+                    request.annotations['form.output'] = output
 
 
 @adapter_config(context=(IFormFieldContainerTarget, IPyAMSLayer, FormFieldContainerInputForm),