From f9baeaef8a50b224aa851d61dfbaa94fd0bbec21 Mon Sep 17 00:00:00 2001 From: Paul Marillonnet Date: Thu, 8 Jul 2021 11:46:00 +0200 Subject: [PATCH] misc: replace get_logger().error() with newer record_error() (#55437) --- tests/form_pages/test_formdata.py | 7 +- tests/test_fc_auth.py | 6 +- wcs/backoffice/management.py | 329 ++++++++++++++++++++++++++++++ wcs/portfolio.py | 10 +- wcs/qommon/emails.py | 23 ++- wcs/qommon/ident/franceconnect.py | 23 +-- wcs/qommon/ident/idp.py | 3 +- wcs/qommon/ident/password.py | 6 +- wcs/qommon/saml2.py | 7 +- wcs/root.py | 19 +- wcs/wf/export_to_model.py | 7 +- wcs/wf/notification.py | 10 +- wcs/wf/profile.py | 4 +- wcs/wf/register_comment.py | 7 +- wcs/wf/roles.py | 12 +- wcs/workflows.py | 17 +- 16 files changed, 416 insertions(+), 74 deletions(-) diff --git a/tests/form_pages/test_formdata.py b/tests/form_pages/test_formdata.py index 58c8b0e6..8b432e30 100644 --- a/tests/form_pages/test_formdata.py +++ b/tests/form_pages/test_formdata.py @@ -761,9 +761,10 @@ def test_formdata_generated_document_odt_to_pdf_download_push_to_portfolio( http_post_request.return_value = None, 400, 'null', None # fail resp = resp.form.submit('button_export_to') assert http_post_request.call_count == 1 - assert caplog.records[-1].message.startswith( - "file 'template.pdf' failed to be pushed to portfolio of 'Foo" - ) + if pub.is_using_postgresql(): + assert pub.loggederror_class.select()[0].summary.startswith( + "file 'template.pdf' failed to be pushed to portfolio of 'Foo" + ) # failed to push to portfolio, but document is here resp = resp.follow() # $form/$id/create_doc diff --git a/tests/test_fc_auth.py b/tests/test_fc_auth.py index fd8990f6..83ff1f44 100644 --- a/tests/test_fc_auth.py +++ b/tests/test_fc_auth.py @@ -194,7 +194,8 @@ def test_fc_login_page(caplog): } ) ) - assert 'user did not authorize login' in caplog.records[-1].message + if pub.is_using_postgresql(): + assert 'user did not authorize login' in pub.loggederror_class.select()[-1].summary resp = app.get( '/ident/fc/callback?%s' % urllib.parse.urlencode( @@ -204,7 +205,8 @@ def test_fc_login_page(caplog): } ) ) - assert 'whatever' in caplog.records[-1].message + if pub.is_using_postgresql(): + assert 'whatever' in pub.loggederror_class.select()[-1].summary # Login existing user def logme(login_url): diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py index ad265b1f..742fef54 100644 --- a/wcs/backoffice/management.py +++ b/wcs/backoffice/management.py @@ -139,6 +139,335 @@ def geojson_formdatas(formdatas, geoloc_key='base', fields=None): return geojson +class SendCodeFormdefDirectory(Directory): + formdef = None + + def __init__(self, formdef): + self.formdef = formdef + + def _q_lookup(self, component): + html_top('management', _('Management')) + formdata = self.formdef.data_class().get(component) + + submitter_email = formdata.formdef.get_submitter_email(formdata) + mail_subject = EmailsDirectory.get_subject('tracking-code-reminder') + mail_body = EmailsDirectory.get_body('tracking-code-reminder') + + form = Form() + form.add(TextWidget, 'text', title=_('Message'), required=True, cols=60, rows=5, value=mail_body) + form.add(EmailWidget, 'email', title=_('Email'), required=False, value=submitter_email) + sms_class = None + if get_publisher().use_sms_feature: + sms_class = sms.SMS.get_sms_class() + if sms_class: + form.add(StringWidget, 'sms', title=_('SMS Number'), required=False) + form.add( + RadiobuttonsWidget, + 'method', + options=[('email', _('Email')), ('sms', _('SMS'))], + value='email', + required=True, + extra_css_class='widget-inline-radio', + ) + form.add_submit('submit', _('Send')) + form.add_submit('cancel', _('Cancel')) + + if not form.is_submitted() or form.has_errors(): + r = TemplateIO(html=True) + r += htmltext('

%s

') % _('Send tracking code') + r += form.render() + return r.getvalue() + + if not formdata.tracking_code: + tracking_code = get_publisher().tracking_code_class() + tracking_code.formdata = formdata # this stores both objects + + message = form.get_widget('text').parse() + data = { + 'form_tracking_code': formdata.tracking_code, + 'tracking_code': formdata.tracking_code, + 'email': form.get_widget('email').parse(), + } + data.update(self.formdef.get_substitution_variables(minimal=True)) + + if sms_class and form.get_widget('method').parse() == 'sms': + # send sms + sitename = get_cfg('misc', {}).get('sitename') or 'w.c.s.' + sms_cfg = get_cfg('sms', {}) + sender = sms_cfg.get('sender', sitename)[:11] + message = Template(message).render(data) + try: + sms_class.send(sender, [form.get_widget('sms').parse()], message) + except errors.SMSError as e: + get_publisher().record_error(_('Could not send SMS'), formdata=formdata, exception=e) + get_session().message = ('info', _('SMS with tracking code sent to the user')) + else: + # send mail + emails.template_email( + mail_subject, message, mail_body_data=data, email_rcpt=form.get_widget('email').parse() + ) + get_session().message = ('info', _('Email with tracking code sent to the user')) + + return redirect('../..') + + +class SendCodeDirectory(Directory): + def _q_lookup(self, component): + try: + formdef = FormDef.get_by_urlname(component) + if not formdef.enable_tracking_codes: + raise errors.TraversalError() + return SendCodeFormdefDirectory(formdef) + except KeyError: + raise errors.TraversalError() + + +class UserViewDirectory(Directory): + _q_exports = ['', 'sendcode'] + + sendcode = SendCodeDirectory() + user = None + + def __init__(self, user): + self.user = user + + def _q_index(self): + get_response().breadcrumb.append(('%s/' % self.user.id, self.user.display_name)) + html_top('management', _('Management')) + # display list of open formdata for the user + formdefs = [x for x in FormDef.select(lightweight=True) if not x.skip_from_360_view] + user_roles = set([logged_users_role().id] + get_request().user.get_roles()) + criterias = [ + Equal('is_at_endpoint', False), + Equal('user_id', str(self.user.id)), + Contains('formdef_id', [x.id for x in formdefs]), + ] + from wcs import sql + + formdatas = sql.AnyFormData.select(criterias, order_by='receipt_time') + + criterias = [ + Equal('is_at_endpoint', False), + Equal('user_id', str(self.user.id)), + Intersects('concerned_roles_array', user_roles), + ] + viewable_formdatas = sql.AnyFormData.select(criterias) + viewable_formdatas_ids = {} + for viewable_formdata in viewable_formdatas: + viewable_formdatas_ids[(viewable_formdata.formdef.id, viewable_formdata.id)] = True + + r = TemplateIO(html=True) + r += get_session().display_message() + + r += htmltext('
') + r += htmltext('

%s

') % self.user.display_name + formdef = UserFieldsFormDef() + r += htmltext('
') + for field in formdef.get_all_fields(): + if not hasattr(field, 'get_view_value'): + continue + value = self.user.form_data.get(field.id) + if not value: + continue + r += htmltext('
') + r += field.label + r += htmltext('
') + r += htmltext('
') + r += field.get_view_value(value) + r += htmltext('
') + r += htmltext('
') + r += htmltext('
') + + if formdatas: + categories = {} + formdata_by_category = {} + for formdata in formdatas: + if formdata.formdef.category_id not in categories: + categories[formdata.formdef.category_id] = formdata.formdef.category + formdata_by_category[formdata.formdef.category_id] = [] + formdata_by_category[formdata.formdef.category_id].append(formdata) + cats = list(categories.values()) + Category.sort_by_position(cats) + for cat in cats: + r += htmltext('
') + if len(cats) > 1: + if cat is None: + r += htmltext('

%s

') % _('Misc') + cat_formdatas = formdata_by_category[None] + else: + r += htmltext('

%s

') % cat.name + cat_formdatas = formdata_by_category[cat.id] + else: + cat_formdatas = formdatas + r += htmltext('') + r += htmltext('
') + r += htmltext('') + + return r.getvalue() + + +class UsersViewDirectory(Directory): + _q_exports = [''] + + def _q_traverse(self, path): + if not get_publisher().is_using_postgresql(): + raise errors.TraversalError() + get_response().breadcrumb.append(('users', _('Per User View'))) + return super()._q_traverse(path) + + def get_search_sidebar(self, offset=None, limit=None, order_by=None): + get_response().add_javascript(['wcs.listing.js']) + + r = TemplateIO(html=True) + r += htmltext('
') + if offset or limit: + if not offset: + offset = 0 + r += htmltext('') % offset + if limit: + r += htmltext('') % limit + + if order_by is None: + order_by = '' + r += htmltext('') % order_by + + r += htmltext('

%s

') % _('Search') + if get_request().form.get('q'): + q = force_text(get_request().form.get('q')) + r += htmltext('') % force_str(q) + else: + r += htmltext('') + r += htmltext('') % _('Search') + + return r.getvalue() + + def _q_index(self): + html_top('management', _('Management')) + r = TemplateIO(html=True) + + limit = misc.get_int_or_400( + get_request().form.get('limit', get_publisher().get_site_option('default-page-size')) or 20 + ) + offset = misc.get_int_or_400(get_request().form.get('offset', 0)) + order_by = misc.get_order_by_or_400(get_request().form.get('order_by', None)) or 'name' + query = get_request().form.get('q') + + get_response().filter['sidebar'] = self.get_search_sidebar( + limit=limit, offset=offset, order_by=order_by + ) + + if not query: + r += htmltext('
') + r += htmltext('
') + r += htmltext('

%s

') % _('Use the search field on the right ' 'to look for an user.') + r += htmltext('
') + r += htmltext('
') + if get_request().form.get('ajax') == 'true': + get_response().filter = {'raw': True} + return r.getvalue() + + formdef = UserFieldsFormDef() + criteria_fields = [ + ILike('name', query), + ILike('ascii_name', misc.simplify(query, ' ')), + ILike('email', query), + ] + for field in formdef.get_all_fields(): + if field.type in ('string', 'text', 'email'): + criteria_fields.append(ILike('f%s' % field.id, query)) + if get_publisher().is_using_postgresql(): + criteria_fields.append(FtsMatch(query)) + criterias = [Or(criteria_fields)] + users = get_publisher().user_class.select( + order_by=order_by, clause=criterias, limit=limit, offset=offset + ) + total_count = get_publisher().user_class.count(criterias) + + users_cfg = get_cfg('users', {}) + include_name_column = not (users_cfg.get('field_name')) + include_email_column = not (users_cfg.get('field_email')) + r += htmltext('
') + r += htmltext('') + r += htmltext('') + r += htmltext('') + if include_name_column: + r += htmltext('') % _('Name') + if include_email_column: + r += htmltext('') % _('Email') + for field in formdef.get_all_fields(): + if field.include_in_listing: + r += htmltext('') % (field.id, field.label) + r += htmltext('') + r += htmltext('') + r += htmltext('') + + for user in users: + r += htmltext('') % user.id + if include_name_column: + r += htmltext('') % (user.name or '') + if include_email_column: + r += htmltext('') % (user.email or '') + for field in formdef.get_all_fields(): + if field.include_in_listing: + r += htmltext('') % (user.form_data.get(field.id) or '') + r += htmltext('') + + r += htmltext('') + r += htmltext('
%s%s%s
%s%s%s
') + + if get_publisher().is_using_postgresql(): + r += pagination_links(offset, limit, total_count) + + r += htmltext('
') + + if get_request().form.get('ajax') == 'true': + get_response().filter = {'raw': True} + return r.getvalue() + + return r.getvalue() + + def _q_lookup(self, component): + try: + user = get_publisher().user_class.get(component) + return UserViewDirectory(user) + except KeyError: + pass + raise errors.TraversalError() + + class ManagementDirectory(Directory): _q_exports = ['', 'forms', 'listing', 'statistics', 'lookup', 'count', 'geojson', 'map'] diff --git a/wcs/portfolio.py b/wcs/portfolio.py index f76899a2..a7281d24 100644 --- a/wcs/portfolio.py +++ b/wcs/portfolio.py @@ -62,13 +62,14 @@ class fargo_post_json_async: def push_document(user, filename, stream): if not user: return - charset = get_publisher().site_charset + publisher = get_publisher() + charset = publisher.site_charset payload = {} if user.name_identifiers: payload['user_nameid'] = force_text(user.name_identifiers[0], 'ascii') elif user.email: payload['user_email'] = force_text(user.email, 'ascii') - payload['origin'] = urllib.parse.urlparse(get_publisher().get_frontoffice_url()).netloc + payload['origin'] = urllib.parse.urlparse(publisher.get_frontoffice_url()).netloc payload['file_name'] = force_text(filename, charset) stream.seek(0) payload['file_b64_content'] = force_text(base64.b64encode(stream.read())) @@ -80,7 +81,10 @@ def push_document(user, filename, stream): if status == 200: get_logger().info('file %r pushed to portfolio of %r', filename, user.display_name) else: - get_logger().error('file %r failed to be pushed to portfolio of %r', filename, user.display_name) + publisher.record_error( + _('file %(filename)r failed to be pushed to portfolio of %(display_name)r') + % {'filename': filename, 'display_name': user.display_name} + ) if get_response(): get_response().add_after_job( diff --git a/wcs/qommon/emails.py b/wcs/qommon/emails.py index cbd07079..caaa1301 100644 --- a/wcs/qommon/emails.py +++ b/wcs/qommon/emails.py @@ -43,7 +43,7 @@ from django.template.loader import render_to_string from django.utils.safestring import mark_safe from quixote import get_publisher, get_request, get_response -from . import errors, force_str +from . import _, errors, force_str from .admin.emails import EmailsDirectory from .publisher import get_cfg, get_logger from .template import Template @@ -350,35 +350,36 @@ def email( def create_smtp_server(emails_cfg, smtp_timeout=None): + publisher = get_publisher() try: s = smtplib.SMTP(emails_cfg.get('smtp_server', None) or 'localhost', timeout=smtp_timeout) - except socket.timeout: - get_logger().error('Failed to connect to SMTP server (timeout)') + except socket.timeout as e: + publisher.record_error(_('Failed to connect to SMTP server (timeout)'), exception=e) raise errors.EmailError('Failed to connect to SMTP server (timeout)') except OSError: # XXX: write message in a queue somewhere? - get_logger().error('Failed to connect to SMTP server') + publisher.record_error(_('Failed to connect to SMTP server'), exception=e) raise errors.EmailError('Failed to connect to SMTP server') if not s.sock: - get_logger().error('Failed to connect to SMTP server') + publisher.record_error(_('Failed to connect to SMTP server')) raise errors.EmailError('Failed to connect to SMTP server') rc_code, ehlo_answer = s.ehlo() if rc_code != 250: - get_logger().error('Failed to EHLO to SMTP server (%s)', rc_code) + publisher.record_error(_('Failed to EHLO to SMTP server (%s)') % rc_code) raise errors.EmailError('Failed to EHLO to SMTP server (%s)' % rc_code) if b'STARTTLS' in ehlo_answer: rc_code = s.starttls()[0] if rc_code != 220: - get_logger().error('Failed to STARTTLS to SMTP server (%s)', rc_code) + publisher.record_error(_('Failed to STARTTLS to SMTP server (%s)') % rc_code) raise errors.EmailError('Failed to STARTTLS to SMTP server (%s)' % rc_code) if emails_cfg.get('smtp_login'): try: s.login(emails_cfg.get('smtp_login') or '', emails_cfg.get('smtp_password') or '') - except smtplib.SMTPAuthenticationError: - get_logger().error('Failed to authenticate to SMTP server') + except smtplib.SMTPAuthenticationError as e: + publisher.record_error(_('Failed to authenticate to SMTP server'), exception=e) raise errors.EmailError('Failed to authenticate to SMTP server') - except smtplib.SMTPException: - get_logger().error('Failed to authenticate to SMTP server, unknown error.') + except smtplib.SMTPException as e: + publisher.record_error(_('Failed to authenticate to SMTP server, unknown error.'), exception=e) raise errors.EmailError('Failed to authenticate to SMTP server, unknown error.') return s diff --git a/wcs/qommon/ident/franceconnect.py b/wcs/qommon/ident/franceconnect.py index e11a8519..685b7185 100644 --- a/wcs/qommon/ident/franceconnect.py +++ b/wcs/qommon/ident/franceconnect.py @@ -28,7 +28,7 @@ from quixote.html import TemplateIO, htmltext from wcs.formdata import flatten_dict from wcs.workflows import WorkflowStatusItem -from .. import _, get_cfg, get_logger, template +from .. import _, get_cfg, template from ..backoffice.menu import html_top from ..form import ( CompositeWidget, @@ -324,7 +324,7 @@ class FCAuthMethod(AuthMethod): return False def get_access_token(self, code): - logger = get_logger() + publisher = get_publisher() session = get_session() fc_cfg = get_cfg('fc', {}) client_id = fc_cfg.get('client_id') @@ -345,11 +345,11 @@ class FCAuthMethod(AuthMethod): }, ) if status != 200: - logger.error('status from FranceConnect token_url is not 200') + publisher.record_error(_('Status from FranceConnect token_url is not 200')) return None result = json_loads(data) if 'error' in result: - logger.error('FranceConnect code resolution failed: %s', result['error']) + publisher.record_error(_('FranceConnect code resolution failed: %s') % result['error']) return None # check id_token nonce id_token = result['id_token'] @@ -358,12 +358,12 @@ class FCAuthMethod(AuthMethod): payload = json_loads(base64url_decode(force_bytes(payload))) nonce = hashlib.sha256(force_bytes(session.id)).hexdigest() if payload['nonce'] != nonce: - logger.error('FranceConnect returned nonce did not match') + publisher.record_error(_('FranceConnect returned nonce did not match')) return None return access_token, id_token def get_user_info(self, access_token): - logger = get_logger() + publisher = get_publisher() dummy, status, data, dummy = http_get_page( self.get_user_info_url(), headers={ @@ -371,9 +371,9 @@ class FCAuthMethod(AuthMethod): }, ) if status != 200: - logger.error( - 'status from FranceConnect user_info_url is not 200 but %s and data is' ' %s', - status.data[:100], + publisher.record_error( + _('Status from FranceConnect user_info_url is not 200 but %(status)s and data is %(data)s') + % {'status': status, 'data': data[:100]} ) return None return json_loads(data) @@ -452,7 +452,6 @@ class FCAuthMethod(AuthMethod): pub = get_publisher() request = get_request() session = get_session() - logger = get_logger() state = request.form.get('state', '') next_url = (session.extra_user_variables or {}).pop( 'fc_next_url_' + state, '' @@ -464,7 +463,7 @@ class FCAuthMethod(AuthMethod): if error: # we log only errors whose user is not responsible msg = self.AUTHORIZATION_REQUEST_ERRORS.get(error) - logger.error(_('FranceConnect authentication failed: %s'), msg if msg else error) + pub.record_error(_('FranceConnect authentication failed: %s') % msg if msg else error) return redirect(next_url) access_token, id_token = self.get_access_token(request.form['code']) if not access_token: @@ -493,7 +492,7 @@ class FCAuthMethod(AuthMethod): if not (user.name and user.email): # we didn't get useful attributes, forget it. - logger.error('failed to get name and/or email attribute from FranceConnect') + pub.record_error(_('Failed to get name and/or email attribute from FranceConnect')) return redirect(next_url) user.store() diff --git a/wcs/qommon/ident/idp.py b/wcs/qommon/ident/idp.py index 6736847b..73921aa1 100644 --- a/wcs/qommon/ident/idp.py +++ b/wcs/qommon/ident/idp.py @@ -29,7 +29,7 @@ from quixote import get_publisher, get_request, get_response, get_session, redir from quixote.directory import Directory from quixote.html import TemplateIO, htmltext -from .. import _, errors, get_cfg, get_logger, misc, saml2utils, template, x509utils +from .. import _, errors, get_cfg, misc, saml2utils, template, x509utils from ..admin.menu import command_icon from ..backoffice.menu import html_top from ..form import ( @@ -84,7 +84,6 @@ class MethodDirectory(Directory): idps = get_cfg('idp', {}) if not lasso: - get_logger().error('/login unavailable - lasso is not installed') raise Exception("lasso is missing, idp method cannot be used") if len(idps) == 0: diff --git a/wcs/qommon/ident/password.py b/wcs/qommon/ident/password.py index 2ec743c7..a640e0aa 100644 --- a/wcs/qommon/ident/password.py +++ b/wcs/qommon/ident/password.py @@ -23,7 +23,7 @@ from quixote.html import TemplateIO, htmltext from wcs.qommon.admin.texts import TextsDirectory -from .. import _, emails, errors, get_cfg, get_logger, misc, ngettext +from .. import _, emails, errors, get_cfg, misc, ngettext from .. import storage as st from .. import template, tokens from ..admin.emails import EmailsDirectory @@ -606,7 +606,7 @@ class MethodDirectory(Directory): if identities_cfg.get('email-confirmation', False): if not user.email: - get_logger().error( + get_publisher().record_error( _( 'Accounts are configured to require confirmation but accounts can be created without emails' ) @@ -624,7 +624,7 @@ class MethodDirectory(Directory): if passwords_cfg.get('generate', True): if not user.email: - get_logger().error( + get_publisher().record_error( _( 'Accounts are configured to have a generated password ' 'but accounts can be created without emails' diff --git a/wcs/qommon/saml2.py b/wcs/qommon/saml2.py index 6c3f5348..523a2dff 100644 --- a/wcs/qommon/saml2.py +++ b/wcs/qommon/saml2.py @@ -79,7 +79,9 @@ def soap_endpoint(method): try: return method(*args, **kwargs) except Exception as e: - get_logger().error('Exception in method %r: %s; returning a SOAP error' % (method, e)) + get_publisher().record_error( + _('Exception in method %r: returning a SOAP error') % method, exception=e + ) fault = lasso.SoapFault.newFull('Internal Server Error', str(e)) body = lasso.SoapBody() body.any = [fault] @@ -125,9 +127,6 @@ class Saml2Directory(Directory): def _q_traverse(self, path): # if lasso is not installed, hide the saml endpoints if lasso is None: - if does_idp_authentication(): - rel_path = os.path.join('/saml', *path) - get_logger().error('%s unavailable - lasso is not installed' % rel_path) raise errors.TraversalError() return Directory._q_traverse(self, path) diff --git a/wcs/root.py b/wcs/root.py index e1ada479..d065c318 100644 --- a/wcs/root.py +++ b/wcs/root.py @@ -82,9 +82,9 @@ class LoginDirectory(Directory): method = ident_methods[0] try: return ident.login(method) - except KeyError: - msg = 'failed to login with method %s' % method - get_logger().error(msg) + except KeyError as e: + msg = _('Failed to login with method %s') % method + get_publisher().record_error(msg, exception=e) return errors.TraversalError(msg) else: form = Form(enctype='multipart/form-data') @@ -108,9 +108,10 @@ class LoginDirectory(Directory): else: try: return ident.login(method) - except KeyError: - msg = 'failed to login with method %s' % method - get_logger().error(msg) + except KeyError as e: + get_publisher().record_error( + _('Failed to login with method %s') % method, exception=e + ) return errors.TraversalError() else: template.html_top(_('Login')) @@ -148,8 +149,8 @@ class RegisterDirectory(Directory): method = ident_methods[0] try: return ident.register(method) - except KeyError: - get_logger().error('failed to register with method %s' % method) + except KeyError as e: + get_publisher().record_error(_('Failed to register with method %s') % method, exception=e) return errors.TraversalError() else: form = Form(enctype='multipart/form-data') @@ -332,7 +333,7 @@ class RootDirectory(Directory): } ) except UploadStorageError as e: - get_logger().error('upload storage error: %s' % e) + get_publisher().record_error(_('Upload storage error'), exception=e) results.append({'error': _('failed to store file (system error)')}) get_response().set_content_type('application/json') diff --git a/wcs/wf/export_to_model.py b/wcs/wf/export_to_model.py index edde2903..f5992de8 100644 --- a/wcs/wf/export_to_model.py +++ b/wcs/wf/export_to_model.py @@ -45,7 +45,7 @@ from wcs.workflows import ( template_on_formdata, ) -from ..qommon import _, ezt, force_str, get_logger, misc +from ..qommon import _, ezt, force_str, misc from ..qommon.form import ( CheckboxWidget, ComputedExpressionWidget, @@ -547,8 +547,9 @@ class ExportToModel(WorkflowStatusItem): ) ) except TemplateError as e: - url = formdata.get_url() - get_logger().error('error in template for export to model [%s]: %s' % (url, str(e))) + get_publisher().record_error( + _('Error in template for export to model'), formdata=formdata, exception=e + ) raise TemplatingError(_('Error in template: %s') % str(e)) def apply_od_template_to_formdata(self, formdata): diff --git a/wcs/wf/notification.py b/wcs/wf/notification.py index c15c5340..cba1d4f9 100644 --- a/wcs/wf/notification.py +++ b/wcs/wf/notification.py @@ -20,7 +20,7 @@ from quixote import get_publisher from wcs.workflows import WorkflowStatusItem, register_item_class, template_on_formdata -from ..qommon import _, get_logger +from ..qommon import _ from ..qommon.form import ComputedExpressionWidget, SingleSelectWidget, StringWidget, TextWidget, WidgetList from ..qommon.template import TemplateError from .wscall import WebserviceCallStatusItem @@ -124,16 +124,16 @@ class SendNotificationWorkflowStatusItem(WebserviceCallStatusItem): try: title = template_on_formdata(formdata, self.compute(self.title, render=False), autoescape=False) except TemplateError as e: - get_logger().error( - 'error in template for notification title, ' 'mail could not be generated: %s' % str(e) + get_publisher().record_error( + _('error in template for notification title, mail could not be generated'), exception=e ) return try: body = template_on_formdata(formdata, self.compute(self.body, render=False), autoescape=False) except TemplateError as e: - get_logger().error( - 'error in template for notification body, ' 'mail could not be generated: %s' % str(e) + get_publisher().record_error( + _('error in template for notification body, mail could not be generated'), exception=e ) return diff --git a/wcs/wf/profile.py b/wcs/wf/profile.py index 10bf2227..6e46737c 100644 --- a/wcs/wf/profile.py +++ b/wcs/wf/profile.py @@ -29,7 +29,7 @@ from ..qommon import _ from ..qommon.form import CompositeWidget, ComputedExpressionWidget, SingleSelectWidget, WidgetListAsTable from ..qommon.ident.idp import is_idp_managing_user_attributes from ..qommon.misc import JSONEncoder, http_patch_request -from ..qommon.publisher import get_cfg, get_logger +from ..qommon.publisher import get_cfg def user_ws_url(user_uuid): @@ -207,7 +207,7 @@ class UpdateUserProfileStatusItem(WorkflowStatusItem): url, payload, headers={'Content-type': 'application/json'} ) if status != 200: - get_logger().error('failed to update profile for user %r', user) + get_publisher().record_error(_('Failed to update profile for user %r') % user) if get_request(): get_response().add_after_job(_('Updating user profile'), after_job) diff --git a/wcs/wf/register_comment.py b/wcs/wf/register_comment.py index 72a8df56..11a0d8d2 100644 --- a/wcs/wf/register_comment.py +++ b/wcs/wf/register_comment.py @@ -25,7 +25,7 @@ from wcs.workflows import ( template_on_formdata, ) -from ..qommon import _, ezt, get_logger +from ..qommon import _, ezt from ..qommon.form import TextWidget, WidgetListOfRoles from ..qommon.template import TemplateError @@ -136,9 +136,8 @@ class RegisterCommenterWorkflowStatusItem(WorkflowStatusItem): formdata.evolution[-1].add_part(JournalEvolutionPart(formdata, self.comment, self.to)) formdata.store() except TemplateError as e: - url = formdata.get_url() - get_logger().error( - 'error in template for comment [%s], ' 'comment could not be generated: %s' % (url, str(e)) + get_publisher().record_error( + _('Error in template, comment could not be generated'), formdata=formdata, exception=e ) diff --git a/wcs/wf/roles.py b/wcs/wf/roles.py index 12109c20..a4c5eca8 100644 --- a/wcs/wf/roles.py +++ b/wcs/wf/roles.py @@ -26,7 +26,7 @@ from ..qommon import _ from ..qommon.form import SingleSelectWidgetWithOther from ..qommon.ident.idp import is_idp_managing_user_attributes from ..qommon.misc import http_delete_request, http_post_request -from ..qommon.publisher import get_cfg, get_logger +from ..qommon.publisher import get_cfg def roles_ws_url(role_uuid, user_uuid): @@ -125,7 +125,10 @@ class AddRoleWorkflowStatusItem(RoleMixin, WorkflowStatusItem): signed_url = sign_ws_url(url) dummy, status, dummy, dummy = http_post_request(signed_url) if status != 201: - get_logger().error('failed to add role %r to user %r', role, user) + get_publisher().record_error( + _('Failed to add role %(role)r to user %(user)r') % {'role': role, 'user': user}, + formdata=formdata, + ) if get_request(): get_response().add_after_job(_('Adding role'), after_job) @@ -196,7 +199,10 @@ class RemoveRoleWorkflowStatusItem(RoleMixin, WorkflowStatusItem): # pylint: disable=unused-variable response, status, data, auth_header = http_delete_request(signed_url) if status != 200: - get_logger().error('failed to remove role %r from user %r', role, user) + get_publisher().record_error( + _('Failed to remove role %(role)r from user %(user)r') % {'role': role, 'user': user}, + formdata=formdata, + ) if get_request(): get_response().add_after_job(_('Removing role'), after_job) diff --git a/wcs/workflows.py b/wcs/workflows.py index 059dcfa4..fd79a770 100644 --- a/wcs/workflows.py +++ b/wcs/workflows.py @@ -36,7 +36,7 @@ from .fields import FileField from .formdata import Evolution from .formdef import FormDef, FormdefImportError from .mail_templates import MailTemplate -from .qommon import _, emails, errors, ezt, force_str, get_cfg, get_logger, misc +from .qommon import _, emails, errors, ezt, force_str, get_cfg, misc from .qommon.form import ( CheckboxWidget, ComputedExpressionWidget, @@ -3040,7 +3040,6 @@ class SendmailWorkflowStatusItem(WorkflowStatusItem): if not (self.subject and self.body) and not self.mail_template: return - url = formdata.get_url() body = self.body subject = self.subject extra_attachments = None @@ -3063,8 +3062,8 @@ class SendmailWorkflowStatusItem(WorkflowStatusItem): formdata, self.compute(body, render=False), autoescape=body.startswith('<') ) except TemplateError as e: - get_logger().error( - 'error in template for email body [%s], ' 'mail could not be generated: %s' % (url, str(e)) + get_publisher().record_error( + _('Error in body template, mail could not be generated'), formdata=formdata, exception=e ) return @@ -3073,8 +3072,8 @@ class SendmailWorkflowStatusItem(WorkflowStatusItem): formdata, self.compute(subject, render=False), autoescape=False ) except TemplateError as e: - get_logger().error( - 'error in template for email subject [%s], ' 'mail could not be generated: %s' % (url, str(e)) + get_publisher().record_error( + _('Error in subject template, mail could not be generated'), formdata=formdata, exception=e ) return @@ -3247,7 +3246,9 @@ class SendSMSWorkflowStatusItem(WorkflowStatusItem): try: sms_body = template_on_formdata(formdata, self.compute(self.body, render=False)) except TemplateError as e: - get_logger().error('error in template for sms [%s], sms could not be generated' % str(e)) + get_publisher().record_error( + _('Error in template, sms could not be generated'), formdata=formdata, exception=e + ) return from .qommon import sms @@ -3257,7 +3258,7 @@ class SendSMSWorkflowStatusItem(WorkflowStatusItem): try: sms.SMS.get_sms_class().send(sender, destinations, sms_body) except errors.SMSError as e: - get_logger().error(e) + get_publisher().record_error(_('Could not send SMS'), formdata=formdata, exception=e) register_item_class(SendSMSWorkflowStatusItem) -- 2.32.0.rc0