0001-misc-replace-get_logger-.error-with-newer-record_err.patch
tests/form_pages/test_formdata.py | ||
---|---|---|
761 | 761 |
http_post_request.return_value = None, 400, 'null', None # fail |
762 | 762 |
resp = resp.form.submit('button_export_to') |
763 | 763 |
assert http_post_request.call_count == 1 |
764 |
assert caplog.records[-1].message.startswith( |
|
765 |
"file 'template.pdf' failed to be pushed to portfolio of 'Foo" |
|
766 |
) |
|
764 |
if pub.is_using_postgresql(): |
|
765 |
assert pub.loggederror_class.select()[0].summary.startswith( |
|
766 |
"file 'template.pdf' failed to be pushed to portfolio of 'Foo" |
|
767 |
) |
|
767 | 768 | |
768 | 769 |
# failed to push to portfolio, but document is here |
769 | 770 |
resp = resp.follow() # $form/$id/create_doc |
tests/test_fc_auth.py | ||
---|---|---|
194 | 194 |
} |
195 | 195 |
) |
196 | 196 |
) |
197 |
assert 'user did not authorize login' in caplog.records[-1].message |
|
197 |
if pub.is_using_postgresql(): |
|
198 |
assert 'user did not authorize login' in pub.loggederror_class.select()[-1].summary |
|
198 | 199 |
resp = app.get( |
199 | 200 |
'/ident/fc/callback?%s' |
200 | 201 |
% urllib.parse.urlencode( |
... | ... | |
204 | 205 |
} |
205 | 206 |
) |
206 | 207 |
) |
207 |
assert 'whatever' in caplog.records[-1].message |
|
208 |
if pub.is_using_postgresql(): |
|
209 |
assert 'whatever' in pub.loggederror_class.select()[-1].summary |
|
208 | 210 | |
209 | 211 |
# Login existing user |
210 | 212 |
def logme(login_url): |
wcs/backoffice/management.py | ||
---|---|---|
139 | 139 |
return geojson |
140 | 140 | |
141 | 141 | |
142 |
class SendCodeFormdefDirectory(Directory): |
|
143 |
formdef = None |
|
144 | ||
145 |
def __init__(self, formdef): |
|
146 |
self.formdef = formdef |
|
147 | ||
148 |
def _q_lookup(self, component): |
|
149 |
html_top('management', _('Management')) |
|
150 |
formdata = self.formdef.data_class().get(component) |
|
151 | ||
152 |
submitter_email = formdata.formdef.get_submitter_email(formdata) |
|
153 |
mail_subject = EmailsDirectory.get_subject('tracking-code-reminder') |
|
154 |
mail_body = EmailsDirectory.get_body('tracking-code-reminder') |
|
155 | ||
156 |
form = Form() |
|
157 |
form.add(TextWidget, 'text', title=_('Message'), required=True, cols=60, rows=5, value=mail_body) |
|
158 |
form.add(EmailWidget, 'email', title=_('Email'), required=False, value=submitter_email) |
|
159 |
sms_class = None |
|
160 |
if get_publisher().use_sms_feature: |
|
161 |
sms_class = sms.SMS.get_sms_class() |
|
162 |
if sms_class: |
|
163 |
form.add(StringWidget, 'sms', title=_('SMS Number'), required=False) |
|
164 |
form.add( |
|
165 |
RadiobuttonsWidget, |
|
166 |
'method', |
|
167 |
options=[('email', _('Email')), ('sms', _('SMS'))], |
|
168 |
value='email', |
|
169 |
required=True, |
|
170 |
extra_css_class='widget-inline-radio', |
|
171 |
) |
|
172 |
form.add_submit('submit', _('Send')) |
|
173 |
form.add_submit('cancel', _('Cancel')) |
|
174 | ||
175 |
if not form.is_submitted() or form.has_errors(): |
|
176 |
r = TemplateIO(html=True) |
|
177 |
r += htmltext('<h2>%s</h2>') % _('Send tracking code') |
|
178 |
r += form.render() |
|
179 |
return r.getvalue() |
|
180 | ||
181 |
if not formdata.tracking_code: |
|
182 |
tracking_code = get_publisher().tracking_code_class() |
|
183 |
tracking_code.formdata = formdata # this stores both objects |
|
184 | ||
185 |
message = form.get_widget('text').parse() |
|
186 |
data = { |
|
187 |
'form_tracking_code': formdata.tracking_code, |
|
188 |
'tracking_code': formdata.tracking_code, |
|
189 |
'email': form.get_widget('email').parse(), |
|
190 |
} |
|
191 |
data.update(self.formdef.get_substitution_variables(minimal=True)) |
|
192 | ||
193 |
if sms_class and form.get_widget('method').parse() == 'sms': |
|
194 |
# send sms |
|
195 |
sitename = get_cfg('misc', {}).get('sitename') or 'w.c.s.' |
|
196 |
sms_cfg = get_cfg('sms', {}) |
|
197 |
sender = sms_cfg.get('sender', sitename)[:11] |
|
198 |
message = Template(message).render(data) |
|
199 |
try: |
|
200 |
sms_class.send(sender, [form.get_widget('sms').parse()], message) |
|
201 |
except errors.SMSError as e: |
|
202 |
get_publisher().record_error(_('Could not send SMS'), formdata=formdata, exception=e) |
|
203 |
get_session().message = ('info', _('SMS with tracking code sent to the user')) |
|
204 |
else: |
|
205 |
# send mail |
|
206 |
emails.template_email( |
|
207 |
mail_subject, message, mail_body_data=data, email_rcpt=form.get_widget('email').parse() |
|
208 |
) |
|
209 |
get_session().message = ('info', _('Email with tracking code sent to the user')) |
|
210 | ||
211 |
return redirect('../..') |
|
212 | ||
213 | ||
214 |
class SendCodeDirectory(Directory): |
|
215 |
def _q_lookup(self, component): |
|
216 |
try: |
|
217 |
formdef = FormDef.get_by_urlname(component) |
|
218 |
if not formdef.enable_tracking_codes: |
|
219 |
raise errors.TraversalError() |
|
220 |
return SendCodeFormdefDirectory(formdef) |
|
221 |
except KeyError: |
|
222 |
raise errors.TraversalError() |
|
223 | ||
224 | ||
225 |
class UserViewDirectory(Directory): |
|
226 |
_q_exports = ['', 'sendcode'] |
|
227 | ||
228 |
sendcode = SendCodeDirectory() |
|
229 |
user = None |
|
230 | ||
231 |
def __init__(self, user): |
|
232 |
self.user = user |
|
233 | ||
234 |
def _q_index(self): |
|
235 |
get_response().breadcrumb.append(('%s/' % self.user.id, self.user.display_name)) |
|
236 |
html_top('management', _('Management')) |
|
237 |
# display list of open formdata for the user |
|
238 |
formdefs = [x for x in FormDef.select(lightweight=True) if not x.skip_from_360_view] |
|
239 |
user_roles = set([logged_users_role().id] + get_request().user.get_roles()) |
|
240 |
criterias = [ |
|
241 |
Equal('is_at_endpoint', False), |
|
242 |
Equal('user_id', str(self.user.id)), |
|
243 |
Contains('formdef_id', [x.id for x in formdefs]), |
|
244 |
] |
|
245 |
from wcs import sql |
|
246 | ||
247 |
formdatas = sql.AnyFormData.select(criterias, order_by='receipt_time') |
|
248 | ||
249 |
criterias = [ |
|
250 |
Equal('is_at_endpoint', False), |
|
251 |
Equal('user_id', str(self.user.id)), |
|
252 |
Intersects('concerned_roles_array', user_roles), |
|
253 |
] |
|
254 |
viewable_formdatas = sql.AnyFormData.select(criterias) |
|
255 |
viewable_formdatas_ids = {} |
|
256 |
for viewable_formdata in viewable_formdatas: |
|
257 |
viewable_formdatas_ids[(viewable_formdata.formdef.id, viewable_formdata.id)] = True |
|
258 | ||
259 |
r = TemplateIO(html=True) |
|
260 |
r += get_session().display_message() |
|
261 | ||
262 |
r += htmltext('<div class="bo-block">') |
|
263 |
r += htmltext('<h2>%s</h2>') % self.user.display_name |
|
264 |
formdef = UserFieldsFormDef() |
|
265 |
r += htmltext('<div class="form">') |
|
266 |
for field in formdef.get_all_fields(): |
|
267 |
if not hasattr(field, 'get_view_value'): |
|
268 |
continue |
|
269 |
value = self.user.form_data.get(field.id) |
|
270 |
if not value: |
|
271 |
continue |
|
272 |
r += htmltext('<div class="title">') |
|
273 |
r += field.label |
|
274 |
r += htmltext('</div>') |
|
275 |
r += htmltext('<div class="StringWidget content">') |
|
276 |
r += field.get_view_value(value) |
|
277 |
r += htmltext('</div>') |
|
278 |
r += htmltext('</div>') |
|
279 |
r += htmltext('</div>') |
|
280 | ||
281 |
if formdatas: |
|
282 |
categories = {} |
|
283 |
formdata_by_category = {} |
|
284 |
for formdata in formdatas: |
|
285 |
if formdata.formdef.category_id not in categories: |
|
286 |
categories[formdata.formdef.category_id] = formdata.formdef.category |
|
287 |
formdata_by_category[formdata.formdef.category_id] = [] |
|
288 |
formdata_by_category[formdata.formdef.category_id].append(formdata) |
|
289 |
cats = list(categories.values()) |
|
290 |
Category.sort_by_position(cats) |
|
291 |
for cat in cats: |
|
292 |
r += htmltext('<div class="bo-block">') |
|
293 |
if len(cats) > 1: |
|
294 |
if cat is None: |
|
295 |
r += htmltext('<h2>%s</h2>') % _('Misc') |
|
296 |
cat_formdatas = formdata_by_category[None] |
|
297 |
else: |
|
298 |
r += htmltext('<h2>%s</h2>') % cat.name |
|
299 |
cat_formdatas = formdata_by_category[cat.id] |
|
300 |
else: |
|
301 |
cat_formdatas = formdatas |
|
302 |
r += htmltext('<ul class="biglist c-360-user-view">') |
|
303 |
for formdata in cat_formdatas: |
|
304 |
status_label = formdata.get_status_label() |
|
305 |
submit_date = misc.strftime(misc.date_format(), formdata.receipt_time) |
|
306 |
formdata_key_id = (formdata.formdef.id, formdata.id) |
|
307 |
if formdata_key_id in viewable_formdatas_ids: |
|
308 |
r += htmltext( |
|
309 |
'<li><a href="%s">%s, ' |
|
310 |
'<span class="datetime">%s</span> ' |
|
311 |
'<span class="status">(%s)</span></a>' |
|
312 |
% ( |
|
313 |
formdata.get_url(backoffice=True), |
|
314 |
formdata.formdef.name, |
|
315 |
submit_date, |
|
316 |
status_label, |
|
317 |
) |
|
318 |
) |
|
319 |
else: |
|
320 |
r += htmltext( |
|
321 |
'<li><span>%s, ' |
|
322 |
'<span class="datetime">%s</span> ' |
|
323 |
'<span class="status">(%s)</span></span>' |
|
324 |
% (formdata.formdef.name, submit_date, status_label) |
|
325 |
) |
|
326 |
if formdata.formdef.enable_tracking_codes: |
|
327 |
r += htmltext('<p class="commands">') |
|
328 |
r += command_icon( |
|
329 |
'sendcode/%s/%s' % (formdata.formdef.url_name, formdata.id), |
|
330 |
'export', |
|
331 |
label=_('Send tracking code'), |
|
332 |
popup=True, |
|
333 |
) |
|
334 |
r += htmltext('</p>') |
|
335 |
r += htmltext('</ul>') |
|
336 |
r += htmltext('</div>') |
|
337 |
r += htmltext('</div>') |
|
338 | ||
339 |
return r.getvalue() |
|
340 | ||
341 | ||
342 |
class UsersViewDirectory(Directory): |
|
343 |
_q_exports = [''] |
|
344 | ||
345 |
def _q_traverse(self, path): |
|
346 |
if not get_publisher().is_using_postgresql(): |
|
347 |
raise errors.TraversalError() |
|
348 |
get_response().breadcrumb.append(('users', _('Per User View'))) |
|
349 |
return super()._q_traverse(path) |
|
350 | ||
351 |
def get_search_sidebar(self, offset=None, limit=None, order_by=None): |
|
352 |
get_response().add_javascript(['wcs.listing.js']) |
|
353 | ||
354 |
r = TemplateIO(html=True) |
|
355 |
r += htmltext('<form id="listing-settings" action=".">') |
|
356 |
if offset or limit: |
|
357 |
if not offset: |
|
358 |
offset = 0 |
|
359 |
r += htmltext('<input type="hidden" name="offset" value="%s"/>') % offset |
|
360 |
if limit: |
|
361 |
r += htmltext('<input type="hidden" name="limit" value="%s"/>') % limit |
|
362 | ||
363 |
if order_by is None: |
|
364 |
order_by = '' |
|
365 |
r += htmltext('<input type="hidden" name="order_by" value="%s"/>') % order_by |
|
366 | ||
367 |
r += htmltext('<h3>%s</h3>') % _('Search') |
|
368 |
if get_request().form.get('q'): |
|
369 |
q = force_text(get_request().form.get('q')) |
|
370 |
r += htmltext('<input name="q" value="%s">') % force_str(q) |
|
371 |
else: |
|
372 |
r += htmltext('<input name="q">') |
|
373 |
r += htmltext('<input type="submit" value="%s"/>') % _('Search') |
|
374 | ||
375 |
return r.getvalue() |
|
376 | ||
377 |
def _q_index(self): |
|
378 |
html_top('management', _('Management')) |
|
379 |
r = TemplateIO(html=True) |
|
380 | ||
381 |
limit = misc.get_int_or_400( |
|
382 |
get_request().form.get('limit', get_publisher().get_site_option('default-page-size')) or 20 |
|
383 |
) |
|
384 |
offset = misc.get_int_or_400(get_request().form.get('offset', 0)) |
|
385 |
order_by = misc.get_order_by_or_400(get_request().form.get('order_by', None)) or 'name' |
|
386 |
query = get_request().form.get('q') |
|
387 | ||
388 |
get_response().filter['sidebar'] = self.get_search_sidebar( |
|
389 |
limit=limit, offset=offset, order_by=order_by |
|
390 |
) |
|
391 | ||
392 |
if not query: |
|
393 |
r += htmltext('<div id="listing">') |
|
394 |
r += htmltext('<div class="big-msg-info">') |
|
395 |
r += htmltext('<p>%s</p>') % _('Use the search field on the right ' 'to look for an user.') |
|
396 |
r += htmltext('</div>') |
|
397 |
r += htmltext('</div>') |
|
398 |
if get_request().form.get('ajax') == 'true': |
|
399 |
get_response().filter = {'raw': True} |
|
400 |
return r.getvalue() |
|
401 | ||
402 |
formdef = UserFieldsFormDef() |
|
403 |
criteria_fields = [ |
|
404 |
ILike('name', query), |
|
405 |
ILike('ascii_name', misc.simplify(query, ' ')), |
|
406 |
ILike('email', query), |
|
407 |
] |
|
408 |
for field in formdef.get_all_fields(): |
|
409 |
if field.type in ('string', 'text', 'email'): |
|
410 |
criteria_fields.append(ILike('f%s' % field.id, query)) |
|
411 |
if get_publisher().is_using_postgresql(): |
|
412 |
criteria_fields.append(FtsMatch(query)) |
|
413 |
criterias = [Or(criteria_fields)] |
|
414 |
users = get_publisher().user_class.select( |
|
415 |
order_by=order_by, clause=criterias, limit=limit, offset=offset |
|
416 |
) |
|
417 |
total_count = get_publisher().user_class.count(criterias) |
|
418 | ||
419 |
users_cfg = get_cfg('users', {}) |
|
420 |
include_name_column = not (users_cfg.get('field_name')) |
|
421 |
include_email_column = not (users_cfg.get('field_email')) |
|
422 |
r += htmltext('<div id="listing">') |
|
423 |
r += htmltext('<table class="main">') |
|
424 |
r += htmltext('<thead>') |
|
425 |
r += htmltext('<tr>') |
|
426 |
if include_name_column: |
|
427 |
r += htmltext('<th data-field-sort-key="name"><span>%s</span></th>') % _('Name') |
|
428 |
if include_email_column: |
|
429 |
r += htmltext('<th data-field-sort-key="email"><span>%s</span></th>') % _('Email') |
|
430 |
for field in formdef.get_all_fields(): |
|
431 |
if field.include_in_listing: |
|
432 |
r += htmltext('<th data-field-sort-key="f%s"><span>%s</span></th>') % (field.id, field.label) |
|
433 |
r += htmltext('</tr>') |
|
434 |
r += htmltext('</thead>') |
|
435 |
r += htmltext('<tbody>') |
|
436 | ||
437 |
for user in users: |
|
438 |
r += htmltext('<tr data-link="%s/">') % user.id |
|
439 |
if include_name_column: |
|
440 |
r += htmltext('<td>%s</td>') % (user.name or '') |
|
441 |
if include_email_column: |
|
442 |
r += htmltext('<td>%s</td>') % (user.email or '') |
|
443 |
for field in formdef.get_all_fields(): |
|
444 |
if field.include_in_listing: |
|
445 |
r += htmltext('<td>%s</td>') % (user.form_data.get(field.id) or '') |
|
446 |
r += htmltext('</tr>') |
|
447 | ||
448 |
r += htmltext('</tbody>') |
|
449 |
r += htmltext('</table>') |
|
450 | ||
451 |
if get_publisher().is_using_postgresql(): |
|
452 |
r += pagination_links(offset, limit, total_count) |
|
453 | ||
454 |
r += htmltext('</div>') |
|
455 | ||
456 |
if get_request().form.get('ajax') == 'true': |
|
457 |
get_response().filter = {'raw': True} |
|
458 |
return r.getvalue() |
|
459 | ||
460 |
return r.getvalue() |
|
461 | ||
462 |
def _q_lookup(self, component): |
|
463 |
try: |
|
464 |
user = get_publisher().user_class.get(component) |
|
465 |
return UserViewDirectory(user) |
|
466 |
except KeyError: |
|
467 |
pass |
|
468 |
raise errors.TraversalError() |
|
469 | ||
470 | ||
142 | 471 |
class ManagementDirectory(Directory): |
143 | 472 |
_q_exports = ['', 'forms', 'listing', 'statistics', 'lookup', 'count', 'geojson', 'map'] |
144 | 473 |
wcs/portfolio.py | ||
---|---|---|
62 | 62 |
def push_document(user, filename, stream): |
63 | 63 |
if not user: |
64 | 64 |
return |
65 |
charset = get_publisher().site_charset |
|
65 |
publisher = get_publisher() |
|
66 |
charset = publisher.site_charset |
|
66 | 67 |
payload = {} |
67 | 68 |
if user.name_identifiers: |
68 | 69 |
payload['user_nameid'] = force_text(user.name_identifiers[0], 'ascii') |
69 | 70 |
elif user.email: |
70 | 71 |
payload['user_email'] = force_text(user.email, 'ascii') |
71 |
payload['origin'] = urllib.parse.urlparse(get_publisher().get_frontoffice_url()).netloc
|
|
72 |
payload['origin'] = urllib.parse.urlparse(publisher.get_frontoffice_url()).netloc
|
|
72 | 73 |
payload['file_name'] = force_text(filename, charset) |
73 | 74 |
stream.seek(0) |
74 | 75 |
payload['file_b64_content'] = force_text(base64.b64encode(stream.read())) |
... | ... | |
80 | 81 |
if status == 200: |
81 | 82 |
get_logger().info('file %r pushed to portfolio of %r', filename, user.display_name) |
82 | 83 |
else: |
83 |
get_logger().error('file %r failed to be pushed to portfolio of %r', filename, user.display_name) |
|
84 |
publisher.record_error( |
|
85 |
_('file %(filename)r failed to be pushed to portfolio of %(display_name)r') |
|
86 |
% {'filename': filename, 'display_name': user.display_name} |
|
87 |
) |
|
84 | 88 | |
85 | 89 |
if get_response(): |
86 | 90 |
get_response().add_after_job( |
wcs/qommon/emails.py | ||
---|---|---|
43 | 43 |
from django.utils.safestring import mark_safe |
44 | 44 |
from quixote import get_publisher, get_request, get_response |
45 | 45 | |
46 |
from . import errors, force_str |
|
46 |
from . import _, errors, force_str
|
|
47 | 47 |
from .admin.emails import EmailsDirectory |
48 | 48 |
from .publisher import get_cfg, get_logger |
49 | 49 |
from .template import Template |
... | ... | |
350 | 350 | |
351 | 351 | |
352 | 352 |
def create_smtp_server(emails_cfg, smtp_timeout=None): |
353 |
publisher = get_publisher() |
|
353 | 354 |
try: |
354 | 355 |
s = smtplib.SMTP(emails_cfg.get('smtp_server', None) or 'localhost', timeout=smtp_timeout) |
355 |
except socket.timeout: |
|
356 |
get_logger().error('Failed to connect to SMTP server (timeout)')
|
|
356 |
except socket.timeout as e:
|
|
357 |
publisher.record_error(_('Failed to connect to SMTP server (timeout)'), exception=e)
|
|
357 | 358 |
raise errors.EmailError('Failed to connect to SMTP server (timeout)') |
358 | 359 |
except OSError: |
359 | 360 |
# XXX: write message in a queue somewhere? |
360 |
get_logger().error('Failed to connect to SMTP server')
|
|
361 |
publisher.record_error(_('Failed to connect to SMTP server'), exception=e)
|
|
361 | 362 |
raise errors.EmailError('Failed to connect to SMTP server') |
362 | 363 |
if not s.sock: |
363 |
get_logger().error('Failed to connect to SMTP server')
|
|
364 |
publisher.record_error(_('Failed to connect to SMTP server'))
|
|
364 | 365 |
raise errors.EmailError('Failed to connect to SMTP server') |
365 | 366 |
rc_code, ehlo_answer = s.ehlo() |
366 | 367 |
if rc_code != 250: |
367 |
get_logger().error('Failed to EHLO to SMTP server (%s)', rc_code)
|
|
368 |
publisher.record_error(_('Failed to EHLO to SMTP server (%s)') % rc_code)
|
|
368 | 369 |
raise errors.EmailError('Failed to EHLO to SMTP server (%s)' % rc_code) |
369 | 370 |
if b'STARTTLS' in ehlo_answer: |
370 | 371 |
rc_code = s.starttls()[0] |
371 | 372 |
if rc_code != 220: |
372 |
get_logger().error('Failed to STARTTLS to SMTP server (%s)', rc_code)
|
|
373 |
publisher.record_error(_('Failed to STARTTLS to SMTP server (%s)') % rc_code)
|
|
373 | 374 |
raise errors.EmailError('Failed to STARTTLS to SMTP server (%s)' % rc_code) |
374 | 375 |
if emails_cfg.get('smtp_login'): |
375 | 376 |
try: |
376 | 377 |
s.login(emails_cfg.get('smtp_login') or '', emails_cfg.get('smtp_password') or '') |
377 |
except smtplib.SMTPAuthenticationError: |
|
378 |
get_logger().error('Failed to authenticate to SMTP server')
|
|
378 |
except smtplib.SMTPAuthenticationError as e:
|
|
379 |
publisher.record_error(_('Failed to authenticate to SMTP server'), exception=e)
|
|
379 | 380 |
raise errors.EmailError('Failed to authenticate to SMTP server') |
380 |
except smtplib.SMTPException: |
|
381 |
get_logger().error('Failed to authenticate to SMTP server, unknown error.')
|
|
381 |
except smtplib.SMTPException as e:
|
|
382 |
publisher.record_error(_('Failed to authenticate to SMTP server, unknown error.'), exception=e)
|
|
382 | 383 |
raise errors.EmailError('Failed to authenticate to SMTP server, unknown error.') |
383 | 384 |
return s |
384 | 385 |
wcs/qommon/ident/franceconnect.py | ||
---|---|---|
28 | 28 |
from wcs.formdata import flatten_dict |
29 | 29 |
from wcs.workflows import WorkflowStatusItem |
30 | 30 | |
31 |
from .. import _, get_cfg, get_logger, template
|
|
31 |
from .. import _, get_cfg, template |
|
32 | 32 |
from ..backoffice.menu import html_top |
33 | 33 |
from ..form import ( |
34 | 34 |
CompositeWidget, |
... | ... | |
324 | 324 |
return False |
325 | 325 | |
326 | 326 |
def get_access_token(self, code): |
327 |
logger = get_logger()
|
|
327 |
publisher = get_publisher()
|
|
328 | 328 |
session = get_session() |
329 | 329 |
fc_cfg = get_cfg('fc', {}) |
330 | 330 |
client_id = fc_cfg.get('client_id') |
... | ... | |
345 | 345 |
}, |
346 | 346 |
) |
347 | 347 |
if status != 200: |
348 |
logger.error('status from FranceConnect token_url is not 200')
|
|
348 |
publisher.record_error(_('Status from FranceConnect token_url is not 200'))
|
|
349 | 349 |
return None |
350 | 350 |
result = json_loads(data) |
351 | 351 |
if 'error' in result: |
352 |
logger.error('FranceConnect code resolution failed: %s', result['error'])
|
|
352 |
publisher.record_error(_('FranceConnect code resolution failed: %s') % result['error'])
|
|
353 | 353 |
return None |
354 | 354 |
# check id_token nonce |
355 | 355 |
id_token = result['id_token'] |
... | ... | |
358 | 358 |
payload = json_loads(base64url_decode(force_bytes(payload))) |
359 | 359 |
nonce = hashlib.sha256(force_bytes(session.id)).hexdigest() |
360 | 360 |
if payload['nonce'] != nonce: |
361 |
logger.error('FranceConnect returned nonce did not match')
|
|
361 |
publisher.record_error(_('FranceConnect returned nonce did not match'))
|
|
362 | 362 |
return None |
363 | 363 |
return access_token, id_token |
364 | 364 | |
365 | 365 |
def get_user_info(self, access_token): |
366 |
logger = get_logger()
|
|
366 |
publisher = get_publisher()
|
|
367 | 367 |
dummy, status, data, dummy = http_get_page( |
368 | 368 |
self.get_user_info_url(), |
369 | 369 |
headers={ |
... | ... | |
371 | 371 |
}, |
372 | 372 |
) |
373 | 373 |
if status != 200: |
374 |
logger.error(
|
|
375 |
'status from FranceConnect user_info_url is not 200 but %s and data is' ' %s',
|
|
376 |
status.data[:100],
|
|
374 |
publisher.record_error(
|
|
375 |
_('Status from FranceConnect user_info_url is not 200 but %(status)s and data is %(data)s')
|
|
376 |
% {'status': status, 'data': data[:100]}
|
|
377 | 377 |
) |
378 | 378 |
return None |
379 | 379 |
return json_loads(data) |
... | ... | |
452 | 452 |
pub = get_publisher() |
453 | 453 |
request = get_request() |
454 | 454 |
session = get_session() |
455 |
logger = get_logger() |
|
456 | 455 |
state = request.form.get('state', '') |
457 | 456 |
next_url = (session.extra_user_variables or {}).pop( |
458 | 457 |
'fc_next_url_' + state, '' |
... | ... | |
464 | 463 |
if error: |
465 | 464 |
# we log only errors whose user is not responsible |
466 | 465 |
msg = self.AUTHORIZATION_REQUEST_ERRORS.get(error) |
467 |
logger.error(_('FranceConnect authentication failed: %s'), msg if msg else error)
|
|
466 |
pub.record_error(_('FranceConnect authentication failed: %s') % msg if msg else error)
|
|
468 | 467 |
return redirect(next_url) |
469 | 468 |
access_token, id_token = self.get_access_token(request.form['code']) |
470 | 469 |
if not access_token: |
... | ... | |
493 | 492 | |
494 | 493 |
if not (user.name and user.email): |
495 | 494 |
# we didn't get useful attributes, forget it. |
496 |
logger.error('failed to get name and/or email attribute from FranceConnect')
|
|
495 |
pub.record_error(_('Failed to get name and/or email attribute from FranceConnect'))
|
|
497 | 496 |
return redirect(next_url) |
498 | 497 | |
499 | 498 |
user.store() |
wcs/qommon/ident/idp.py | ||
---|---|---|
29 | 29 |
from quixote.directory import Directory |
30 | 30 |
from quixote.html import TemplateIO, htmltext |
31 | 31 | |
32 |
from .. import _, errors, get_cfg, get_logger, misc, saml2utils, template, x509utils
|
|
32 |
from .. import _, errors, get_cfg, misc, saml2utils, template, x509utils |
|
33 | 33 |
from ..admin.menu import command_icon |
34 | 34 |
from ..backoffice.menu import html_top |
35 | 35 |
from ..form import ( |
... | ... | |
84 | 84 |
idps = get_cfg('idp', {}) |
85 | 85 | |
86 | 86 |
if not lasso: |
87 |
get_logger().error('/login unavailable - lasso is not installed') |
|
88 | 87 |
raise Exception("lasso is missing, idp method cannot be used") |
89 | 88 | |
90 | 89 |
if len(idps) == 0: |
wcs/qommon/ident/password.py | ||
---|---|---|
23 | 23 | |
24 | 24 |
from wcs.qommon.admin.texts import TextsDirectory |
25 | 25 | |
26 |
from .. import _, emails, errors, get_cfg, get_logger, misc, ngettext
|
|
26 |
from .. import _, emails, errors, get_cfg, misc, ngettext |
|
27 | 27 |
from .. import storage as st |
28 | 28 |
from .. import template, tokens |
29 | 29 |
from ..admin.emails import EmailsDirectory |
... | ... | |
606 | 606 | |
607 | 607 |
if identities_cfg.get('email-confirmation', False): |
608 | 608 |
if not user.email: |
609 |
get_logger().error(
|
|
609 |
get_publisher().record_error(
|
|
610 | 610 |
_( |
611 | 611 |
'Accounts are configured to require confirmation but accounts can be created without emails' |
612 | 612 |
) |
... | ... | |
624 | 624 | |
625 | 625 |
if passwords_cfg.get('generate', True): |
626 | 626 |
if not user.email: |
627 |
get_logger().error(
|
|
627 |
get_publisher().record_error(
|
|
628 | 628 |
_( |
629 | 629 |
'Accounts are configured to have a generated password ' |
630 | 630 |
'but accounts can be created without emails' |
wcs/qommon/saml2.py | ||
---|---|---|
79 | 79 |
try: |
80 | 80 |
return method(*args, **kwargs) |
81 | 81 |
except Exception as e: |
82 |
get_logger().error('Exception in method %r: %s; returning a SOAP error' % (method, e)) |
|
82 |
get_publisher().record_error( |
|
83 |
_('Exception in method %r: returning a SOAP error') % method, exception=e |
|
84 |
) |
|
83 | 85 |
fault = lasso.SoapFault.newFull('Internal Server Error', str(e)) |
84 | 86 |
body = lasso.SoapBody() |
85 | 87 |
body.any = [fault] |
... | ... | |
125 | 127 |
def _q_traverse(self, path): |
126 | 128 |
# if lasso is not installed, hide the saml endpoints |
127 | 129 |
if lasso is None: |
128 |
if does_idp_authentication(): |
|
129 |
rel_path = os.path.join('/saml', *path) |
|
130 |
get_logger().error('%s unavailable - lasso is not installed' % rel_path) |
|
131 | 130 |
raise errors.TraversalError() |
132 | 131 |
return Directory._q_traverse(self, path) |
133 | 132 |
wcs/root.py | ||
---|---|---|
82 | 82 |
method = ident_methods[0] |
83 | 83 |
try: |
84 | 84 |
return ident.login(method) |
85 |
except KeyError: |
|
86 |
msg = 'failed to login with method %s' % method
|
|
87 |
get_logger().error(msg)
|
|
85 |
except KeyError as e:
|
|
86 |
msg = _('Failed to login with method %s') % method
|
|
87 |
get_publisher().record_error(msg, exception=e)
|
|
88 | 88 |
return errors.TraversalError(msg) |
89 | 89 |
else: |
90 | 90 |
form = Form(enctype='multipart/form-data') |
... | ... | |
108 | 108 |
else: |
109 | 109 |
try: |
110 | 110 |
return ident.login(method) |
111 |
except KeyError: |
|
112 |
msg = 'failed to login with method %s' % method |
|
113 |
get_logger().error(msg) |
|
111 |
except KeyError as e: |
|
112 |
get_publisher().record_error( |
|
113 |
_('Failed to login with method %s') % method, exception=e |
|
114 |
) |
|
114 | 115 |
return errors.TraversalError() |
115 | 116 |
else: |
116 | 117 |
template.html_top(_('Login')) |
... | ... | |
148 | 149 |
method = ident_methods[0] |
149 | 150 |
try: |
150 | 151 |
return ident.register(method) |
151 |
except KeyError: |
|
152 |
get_logger().error('failed to register with method %s' % method)
|
|
152 |
except KeyError as e:
|
|
153 |
get_publisher().record_error(_('Failed to register with method %s') % method, exception=e)
|
|
153 | 154 |
return errors.TraversalError() |
154 | 155 |
else: |
155 | 156 |
form = Form(enctype='multipart/form-data') |
... | ... | |
332 | 333 |
} |
333 | 334 |
) |
334 | 335 |
except UploadStorageError as e: |
335 |
get_logger().error('upload storage error: %s' % e)
|
|
336 |
get_publisher().record_error(_('Upload storage error'), exception=e)
|
|
336 | 337 |
results.append({'error': _('failed to store file (system error)')}) |
337 | 338 | |
338 | 339 |
get_response().set_content_type('application/json') |
wcs/wf/export_to_model.py | ||
---|---|---|
45 | 45 |
template_on_formdata, |
46 | 46 |
) |
47 | 47 | |
48 |
from ..qommon import _, ezt, force_str, get_logger, misc
|
|
48 |
from ..qommon import _, ezt, force_str, misc |
|
49 | 49 |
from ..qommon.form import ( |
50 | 50 |
CheckboxWidget, |
51 | 51 |
ComputedExpressionWidget, |
... | ... | |
547 | 547 |
) |
548 | 548 |
) |
549 | 549 |
except TemplateError as e: |
550 |
url = formdata.get_url() |
|
551 |
get_logger().error('error in template for export to model [%s]: %s' % (url, str(e))) |
|
550 |
get_publisher().record_error( |
|
551 |
_('Error in template for export to model'), formdata=formdata, exception=e |
|
552 |
) |
|
552 | 553 |
raise TemplatingError(_('Error in template: %s') % str(e)) |
553 | 554 | |
554 | 555 |
def apply_od_template_to_formdata(self, formdata): |
wcs/wf/notification.py | ||
---|---|---|
20 | 20 | |
21 | 21 |
from wcs.workflows import WorkflowStatusItem, register_item_class, template_on_formdata |
22 | 22 | |
23 |
from ..qommon import _, get_logger
|
|
23 |
from ..qommon import _ |
|
24 | 24 |
from ..qommon.form import ComputedExpressionWidget, SingleSelectWidget, StringWidget, TextWidget, WidgetList |
25 | 25 |
from ..qommon.template import TemplateError |
26 | 26 |
from .wscall import WebserviceCallStatusItem |
... | ... | |
124 | 124 |
try: |
125 | 125 |
title = template_on_formdata(formdata, self.compute(self.title, render=False), autoescape=False) |
126 | 126 |
except TemplateError as e: |
127 |
get_logger().error(
|
|
128 |
'error in template for notification title, ' 'mail could not be generated: %s' % str(e)
|
|
127 |
get_publisher().record_error(
|
|
128 |
_('error in template for notification title, mail could not be generated'), exception=e
|
|
129 | 129 |
) |
130 | 130 |
return |
131 | 131 | |
132 | 132 |
try: |
133 | 133 |
body = template_on_formdata(formdata, self.compute(self.body, render=False), autoescape=False) |
134 | 134 |
except TemplateError as e: |
135 |
get_logger().error(
|
|
136 |
'error in template for notification body, ' 'mail could not be generated: %s' % str(e)
|
|
135 |
get_publisher().record_error(
|
|
136 |
_('error in template for notification body, mail could not be generated'), exception=e
|
|
137 | 137 |
) |
138 | 138 |
return |
139 | 139 |
wcs/wf/profile.py | ||
---|---|---|
29 | 29 |
from ..qommon.form import CompositeWidget, ComputedExpressionWidget, SingleSelectWidget, WidgetListAsTable |
30 | 30 |
from ..qommon.ident.idp import is_idp_managing_user_attributes |
31 | 31 |
from ..qommon.misc import JSONEncoder, http_patch_request |
32 |
from ..qommon.publisher import get_cfg, get_logger
|
|
32 |
from ..qommon.publisher import get_cfg |
|
33 | 33 | |
34 | 34 | |
35 | 35 |
def user_ws_url(user_uuid): |
... | ... | |
207 | 207 |
url, payload, headers={'Content-type': 'application/json'} |
208 | 208 |
) |
209 | 209 |
if status != 200: |
210 |
get_logger().error('failed to update profile for user %r', user)
|
|
210 |
get_publisher().record_error(_('Failed to update profile for user %r') % user)
|
|
211 | 211 | |
212 | 212 |
if get_request(): |
213 | 213 |
get_response().add_after_job(_('Updating user profile'), after_job) |
wcs/wf/register_comment.py | ||
---|---|---|
25 | 25 |
template_on_formdata, |
26 | 26 |
) |
27 | 27 | |
28 |
from ..qommon import _, ezt, get_logger
|
|
28 |
from ..qommon import _, ezt |
|
29 | 29 |
from ..qommon.form import TextWidget, WidgetListOfRoles |
30 | 30 |
from ..qommon.template import TemplateError |
31 | 31 | |
... | ... | |
136 | 136 |
formdata.evolution[-1].add_part(JournalEvolutionPart(formdata, self.comment, self.to)) |
137 | 137 |
formdata.store() |
138 | 138 |
except TemplateError as e: |
139 |
url = formdata.get_url() |
|
140 |
get_logger().error( |
|
141 |
'error in template for comment [%s], ' 'comment could not be generated: %s' % (url, str(e)) |
|
139 |
get_publisher().record_error( |
|
140 |
_('Error in template, comment could not be generated'), formdata=formdata, exception=e |
|
142 | 141 |
) |
143 | 142 | |
144 | 143 |
wcs/wf/roles.py | ||
---|---|---|
26 | 26 |
from ..qommon.form import SingleSelectWidgetWithOther |
27 | 27 |
from ..qommon.ident.idp import is_idp_managing_user_attributes |
28 | 28 |
from ..qommon.misc import http_delete_request, http_post_request |
29 |
from ..qommon.publisher import get_cfg, get_logger
|
|
29 |
from ..qommon.publisher import get_cfg |
|
30 | 30 | |
31 | 31 | |
32 | 32 |
def roles_ws_url(role_uuid, user_uuid): |
... | ... | |
125 | 125 |
signed_url = sign_ws_url(url) |
126 | 126 |
dummy, status, dummy, dummy = http_post_request(signed_url) |
127 | 127 |
if status != 201: |
128 |
get_logger().error('failed to add role %r to user %r', role, user) |
|
128 |
get_publisher().record_error( |
|
129 |
_('Failed to add role %(role)r to user %(user)r') % {'role': role, 'user': user}, |
|
130 |
formdata=formdata, |
|
131 |
) |
|
129 | 132 | |
130 | 133 |
if get_request(): |
131 | 134 |
get_response().add_after_job(_('Adding role'), after_job) |
... | ... | |
196 | 199 |
# pylint: disable=unused-variable |
197 | 200 |
response, status, data, auth_header = http_delete_request(signed_url) |
198 | 201 |
if status != 200: |
199 |
get_logger().error('failed to remove role %r from user %r', role, user) |
|
202 |
get_publisher().record_error( |
|
203 |
_('Failed to remove role %(role)r from user %(user)r') % {'role': role, 'user': user}, |
|
204 |
formdata=formdata, |
|
205 |
) |
|
200 | 206 | |
201 | 207 |
if get_request(): |
202 | 208 |
get_response().add_after_job(_('Removing role'), after_job) |
wcs/workflows.py | ||
---|---|---|
36 | 36 |
from .formdata import Evolution |
37 | 37 |
from .formdef import FormDef, FormdefImportError |
38 | 38 |
from .mail_templates import MailTemplate |
39 |
from .qommon import _, emails, errors, ezt, force_str, get_cfg, get_logger, misc
|
|
39 |
from .qommon import _, emails, errors, ezt, force_str, get_cfg, misc |
|
40 | 40 |
from .qommon.form import ( |
41 | 41 |
CheckboxWidget, |
42 | 42 |
ComputedExpressionWidget, |
... | ... | |
3040 | 3040 |
if not (self.subject and self.body) and not self.mail_template: |
3041 | 3041 |
return |
3042 | 3042 | |
3043 |
url = formdata.get_url() |
|
3044 | 3043 |
body = self.body |
3045 | 3044 |
subject = self.subject |
3046 | 3045 |
extra_attachments = None |
... | ... | |
3063 | 3062 |
formdata, self.compute(body, render=False), autoescape=body.startswith('<') |
3064 | 3063 |
) |
3065 | 3064 |
except TemplateError as e: |
3066 |
get_logger().error(
|
|
3067 |
'error in template for email body [%s], ' 'mail could not be generated: %s' % (url, str(e))
|
|
3065 |
get_publisher().record_error(
|
|
3066 |
_('Error in body template, mail could not be generated'), formdata=formdata, exception=e
|
|
3068 | 3067 |
) |
3069 | 3068 |
return |
3070 | 3069 | |
... | ... | |
3073 | 3072 |
formdata, self.compute(subject, render=False), autoescape=False |
3074 | 3073 |
) |
3075 | 3074 |
except TemplateError as e: |
3076 |
get_logger().error(
|
|
3077 |
'error in template for email subject [%s], ' 'mail could not be generated: %s' % (url, str(e))
|
|
3075 |
get_publisher().record_error(
|
|
3076 |
_('Error in subject template, mail could not be generated'), formdata=formdata, exception=e
|
|
3078 | 3077 |
) |
3079 | 3078 |
return |
3080 | 3079 | |
... | ... | |
3247 | 3246 |
try: |
3248 | 3247 |
sms_body = template_on_formdata(formdata, self.compute(self.body, render=False)) |
3249 | 3248 |
except TemplateError as e: |
3250 |
get_logger().error('error in template for sms [%s], sms could not be generated' % str(e)) |
|
3249 |
get_publisher().record_error( |
|
3250 |
_('Error in template, sms could not be generated'), formdata=formdata, exception=e |
|
3251 |
) |
|
3251 | 3252 |
return |
3252 | 3253 | |
3253 | 3254 |
from .qommon import sms |
... | ... | |
3257 | 3258 |
try: |
3258 | 3259 |
sms.SMS.get_sms_class().send(sender, destinations, sms_body) |
3259 | 3260 |
except errors.SMSError as e: |
3260 |
get_logger().error(e)
|
|
3261 |
get_publisher().record_error(_('Could not send SMS'), formdata=formdata, exception=e)
|
|
3261 | 3262 | |
3262 | 3263 | |
3263 | 3264 |
register_item_class(SendSMSWorkflowStatusItem) |
3264 |
- |