11 # |
11 # |
12 |
12 |
13 import requests |
13 import requests |
14 from pyramid.csrf import get_csrf_token |
14 from pyramid.csrf import get_csrf_token |
15 from z3c.form import button, field |
15 from z3c.form import button, field |
|
16 from z3c.form.browser.checkbox import SingleCheckBoxFieldWidget |
16 from z3c.form.interfaces import HIDDEN_MODE |
17 from z3c.form.interfaces import HIDDEN_MODE |
17 from zope.interface import Interface, Invalid |
18 from zope.interface import Interface, Invalid, alsoProvides |
18 from zope.schema import TextLine |
19 from zope.schema import Bool, TextLine |
19 |
20 |
20 from pyams_content.shared.form import IFormFieldContainer, IFormFieldContainerTarget, IWfForm |
21 from pyams_content.shared.form import IFormFieldContainer, IFormFieldContainerTarget, IWfForm |
|
22 from pyams_content.shared.form.interfaces import IFormFieldDataConverter |
21 from pyams_default_theme.component.paragraph.interfaces import IParagraphContainerPortletRenderer |
23 from pyams_default_theme.component.paragraph.interfaces import IParagraphContainerPortletRenderer |
22 from pyams_default_theme.interfaces import IContentTitle |
24 from pyams_default_theme.interfaces import IContentTitle |
23 from pyams_default_theme.layer import IPyAMSDefaultLayer |
25 from pyams_default_theme.layer import IPyAMSDefaultLayer |
24 from pyams_form.form import AddForm |
26 from pyams_form.form import AddForm |
25 from pyams_form.help import FormHelp |
27 from pyams_form.help import FormHelp |
29 from pyams_portal.views import PortalContextIndexPage |
31 from pyams_portal.views import PortalContextIndexPage |
30 from pyams_skin.layer import IPyAMSLayer |
32 from pyams_skin.layer import IPyAMSLayer |
31 from pyams_template.template import template_config |
33 from pyams_template.template import template_config |
32 from pyams_utils.adapter import adapter_config |
34 from pyams_utils.adapter import adapter_config |
33 from pyams_utils.interfaces import PUBLIC_PERMISSION, VIEW_PERMISSION |
35 from pyams_utils.interfaces import PUBLIC_PERMISSION, VIEW_PERMISSION |
|
36 from pyams_utils.interfaces.data import IObjectData |
|
37 from pyams_utils.text import text_to_html |
34 from pyams_utils.url import relative_url |
38 from pyams_utils.url import relative_url |
35 from pyams_viewlet.viewlet import ViewContentProvider, Viewlet, viewlet_config |
39 from pyams_viewlet.viewlet import ViewContentProvider, Viewlet, viewlet_config |
36 |
40 |
37 |
41 |
38 __docformat__ = 'restructuredtext' |
42 __docformat__ = 'restructuredtext' |
82 if self.context.use_captcha: |
87 if self.context.use_captcha: |
83 captcha = TextLine(title=_("Captcha"), required=True) |
88 captcha = TextLine(title=_("Captcha"), required=True) |
84 captcha.__name__ = RECAPTCHA_FIELD_NAME |
89 captcha.__name__ = RECAPTCHA_FIELD_NAME |
85 yield captcha |
90 yield captcha |
86 yield from IFormFieldContainer(self.context).get_fields() |
91 yield from IFormFieldContainer(self.context).get_fields() |
87 |
92 if self.context.rgpd_consent: |
88 return field.Fields(*tuple(get_fields())) |
93 consent = Bool(title=II18n(self.context).query_attribute('rgpd_warning', |
|
94 request=self.request), |
|
95 required=True, |
|
96 default=False) |
|
97 consent.__name__ = RGPD_CONSENT_FIELD_NAME |
|
98 yield consent |
|
99 |
|
100 fields = field.Fields(*tuple(get_fields())) |
|
101 if self.context.rgpd_consent: |
|
102 fields[RGPD_CONSENT_FIELD_NAME].widgetFactory = SingleCheckBoxFieldWidget |
|
103 return fields |
89 |
104 |
90 def updateActions(self): |
105 def updateActions(self): |
91 super(FormFieldContainerInputForm, self).updateActions() |
106 super(FormFieldContainerInputForm, self).updateActions() |
92 if 'submit' in self.actions: |
107 if 'submit' in self.actions: |
93 self.actions['submit'].title = II18n(self.context).query_attribute('submit_label', |
108 self.actions['submit'].title = II18n(self.context).query_attribute('submit_label', |
101 widget.mode = HIDDEN_MODE |
116 widget.mode = HIDDEN_MODE |
102 widget.value = get_csrf_token(self.request) |
117 widget.value = get_csrf_token(self.request) |
103 elif widget.field.__name__ == RECAPTCHA_FIELD_NAME: |
118 elif widget.field.__name__ == RECAPTCHA_FIELD_NAME: |
104 widget.name = RECAPTCHA_FIELD_NAME |
119 widget.name = RECAPTCHA_FIELD_NAME |
105 widget.mode = HIDDEN_MODE |
120 widget.mode = HIDDEN_MODE |
|
121 elif widget.field.__name__ == RGPD_CONSENT_FIELD_NAME: |
|
122 widget.name = RGPD_CONSENT_FIELD_NAME |
|
123 widget.required = False |
|
124 user_rights = II18n(self.context).query_attribute('rgpd_user_rights', |
|
125 request=self.request) |
|
126 widget.after_widget_notice = '<div><br />{0}</div>'.format( |
|
127 text_to_html(user_rights, 'oid_to_href')) |
|
128 widget.object_data = { |
|
129 'ams-validate-messages': { |
|
130 'required': self.request.localizer.translate( |
|
131 _("You can't submit this form without accepting data usage rules.")) |
|
132 } |
|
133 } |
|
134 alsoProvides(widget, IObjectData) |
106 else: |
135 else: |
107 field = IFormFieldContainer(self.context).get(widget.field.__name__) |
136 field = IFormFieldContainer(self.context).get(widget.field.__name__) |
108 if field is not None: |
137 if field is not None: |
109 widget.placeholder = field.placeholder |
138 widget.placeholder = field.placeholder |
110 |
139 |
111 @button.buttonAndHandler('title', name='submit') |
140 @button.buttonAndHandler('title', name='submit') |
112 def update_content(self, action): |
141 def update_content(self, action): |
|
142 request = self.request |
113 form = IWfForm(self.context) |
143 form = IWfForm(self.context) |
114 handler = form.query_handler() |
144 handler = form.query_handler() |
115 if handler is not None: |
145 if handler is not None: |
116 data, errors = self.extractData() |
146 data, errors = self.extractData() |
117 if errors: |
147 if errors: |
118 self.status = self.formErrorsMessage |
148 self.status = request.localizer.translate(self.formErrorsMessage) |
119 else: |
149 else: |
120 # remove custom data fields from handler data |
150 # remove custom data fields from handler data |
121 if CSRF_FIELD_NAME in data: |
151 if CSRF_FIELD_NAME in data: |
122 del data[CSRF_FIELD_NAME] |
152 del data[CSRF_FIELD_NAME] |
123 if self.context.use_captcha: |
153 if form.use_captcha: |
124 if RECAPTCHA_FIELD_NAME not in data: |
154 if RECAPTCHA_FIELD_NAME not in data: |
125 self.add_error(Invalid(MISSING_TOKEN_ERROR), RECAPTCHA_FIELD_NAME) |
155 self.add_error(Invalid(MISSING_TOKEN_ERROR), RECAPTCHA_FIELD_NAME) |
126 return |
156 return |
127 proxies = {'https': self.context.captcha_proxy} if self.context.captcha_proxy else {} |
157 proxies = {'https': form.captcha_proxy} if form.captcha_proxy else {} |
128 recaptcha_verify_api = self.request.registry.settings.get('pyams.recaptcha.verify') |
158 recaptcha_verify_api = \ |
|
159 request.registry.settings.get('pyams.recaptcha.verify') |
129 if not recaptcha_verify_api: |
160 if not recaptcha_verify_api: |
130 recaptcha_verify_api = 'https://www.google.com/recaptcha/api/siteverify' |
161 recaptcha_verify_api = 'https://www.google.com/recaptcha/api/siteverify' |
131 verify = requests.post(recaptcha_verify_api, { |
162 verify = requests.post(recaptcha_verify_api, { |
132 'secret': self.context.server_captcha_key, |
163 'secret': form.server_captcha_key, |
133 'response': data[RECAPTCHA_FIELD_NAME] |
164 'response': data[RECAPTCHA_FIELD_NAME] |
134 }, proxies=proxies).json() |
165 }, proxies=proxies).json() |
135 if not verify['success']: |
166 if not verify['success']: |
136 self.add_error(INVALID_TOKEN_ERROR, RECAPTCHA_FIELD_NAME) |
167 self.add_error(INVALID_TOKEN_ERROR, RECAPTCHA_FIELD_NAME) |
137 return |
168 return |
138 del data[RECAPTCHA_FIELD_NAME] |
169 del data[RECAPTCHA_FIELD_NAME] |
139 handler.handle(form, data) |
170 # convert form data |
|
171 user_data = data.copy() |
|
172 for field in IFormFieldContainer(form).get_fields(): |
|
173 converter = request.registry.queryMultiAdapter((field, request), |
|
174 IFormFieldDataConverter) |
|
175 if converter is not None: |
|
176 user_data[field.__name__] = converter.convert(data.get(field.__name__)) |
|
177 output = handler.handle(form, data, user_data) |
|
178 if output: |
|
179 request.annotations['form.output'] = output |
140 |
180 |
141 |
181 |
142 @adapter_config(context=(IFormFieldContainerTarget, IPyAMSLayer, FormFieldContainerInputForm), |
182 @adapter_config(context=(IFormFieldContainerTarget, IPyAMSLayer, FormFieldContainerInputForm), |
143 provides=IFormHelp) |
183 provides=IFormHelp) |
144 class FormFieldContainerDisplayFormHelp(FormHelp): |
184 class FormFieldContainerDisplayFormHelp(FormHelp): |