forms: add exception string to technical error message (#63776) #815
|
@ -175,7 +175,8 @@ def test_form_item_data_source_error(pub, monkeypatch, fail_after_count_page, fa
|
|||
NamedDataSource, 'get_structured_value', failing_get_structured_value(fail_after_count_page).method
|
||||
)
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert 'Technical error, please try again' in resp.text
|
||||
assert resp.pyquery('.global-errors summary').text() == 'Technical error, please try again.'
|
||||
assert resp.pyquery('.global-errors p').text() == 'datasource is unavailable (field id: 1)'
|
||||
|
||||
# fix transient failure
|
||||
monkeypatch.setattr(NamedDataSource, 'get_structured_value', normal_get_structured_value)
|
||||
|
@ -189,7 +190,8 @@ def test_form_item_data_source_error(pub, monkeypatch, fail_after_count_page, fa
|
|||
failing_get_structured_value(fail_after_count_validation).method,
|
||||
)
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert 'Technical error, please try again' in resp.text
|
||||
assert resp.pyquery('.global-errors summary').text() == 'Technical error, please try again.'
|
||||
assert resp.pyquery('.global-errors p').text() == 'datasource is unavailable (field id: 1)'
|
||||
|
||||
# fix transient failure
|
||||
monkeypatch.setattr(NamedDataSource, 'get_structured_value', normal_get_structured_value)
|
||||
|
@ -257,7 +259,8 @@ def test_form_item_data_source_error_no_confirmation(pub, monkeypatch, fail_afte
|
|||
NamedDataSource, 'get_structured_value', failing_get_structured_value(fail_after_count_page).method
|
||||
)
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert 'Technical error, please try again' in resp.text
|
||||
assert resp.pyquery('.global-errors summary').text() == 'Technical error, please try again.'
|
||||
assert resp.pyquery('.global-errors p').text() == 'datasource is unavailable (field id: 1)'
|
||||
|
||||
# fix transient failure
|
||||
monkeypatch.setattr(NamedDataSource, 'get_structured_value', normal_get_structured_value)
|
||||
|
|
|
@ -228,12 +228,12 @@ def test_set_backoffice_field_map(http_requests, pub):
|
|||
assert pub.loggederror_class.count() == 1
|
||||
logged_error = pub.loggederror_class.select()[0]
|
||||
assert (
|
||||
logged_error.summary
|
||||
== "Failed to set Map field (bo1), error: invalid coordinates 'invalid value' (missing ;)"
|
||||
logged_error.summary == "Failed to set Map field (bo1), error: invalid coordinates 'invalid value' "
|
||||
'(missing ;) (field id: bo1)'
|
||||
)
|
||||
assert logged_error.formdata_id == str(formdata.id)
|
||||
assert logged_error.exception_class == 'SetValueError'
|
||||
assert logged_error.exception_message == "invalid coordinates 'invalid value' (missing ;)"
|
||||
assert logged_error.exception_message == "invalid coordinates 'invalid value' (missing ;) (field id: bo1)"
|
||||
pub.loggederror_class.wipe()
|
||||
|
||||
item.fields = [{'field_id': 'bo1', 'value': 'XXX;YYY'}]
|
||||
|
@ -241,10 +241,13 @@ def test_set_backoffice_field_map(http_requests, pub):
|
|||
formdata = formdef.data_class().get(formdata.id)
|
||||
assert pub.loggederror_class.count() == 1
|
||||
logged_error = pub.loggederror_class.select()[0]
|
||||
assert logged_error.summary == "Failed to set Map field (bo1), error: invalid coordinates 'XXX;YYY'"
|
||||
assert (
|
||||
logged_error.summary
|
||||
== "Failed to set Map field (bo1), error: invalid coordinates 'XXX;YYY' (field id: bo1)"
|
||||
)
|
||||
assert logged_error.formdata_id == str(formdata.id)
|
||||
assert logged_error.exception_class == 'SetValueError'
|
||||
assert logged_error.exception_message == "invalid coordinates 'XXX;YYY'"
|
||||
assert logged_error.exception_message == "invalid coordinates 'XXX;YYY' (field id: bo1)"
|
||||
pub.loggederror_class.wipe()
|
||||
|
||||
|
||||
|
@ -1453,7 +1456,7 @@ def test_set_backoffice_field_invalid_block_value(pub):
|
|||
logged_error = pub.loggederror_class.select()[0]
|
||||
assert (
|
||||
logged_error.summary
|
||||
== 'Failed to set Field Block (foobar) field (bo1), error: invalid value for block'
|
||||
== 'Failed to set Field Block (foobar) field (bo1), error: invalid value for block (field id: bo1)'
|
||||
)
|
||||
|
||||
formdata = formdef.data_class().get(formdata.id)
|
||||
|
|
|
@ -592,7 +592,11 @@ def test_frontoffice_workflow_form_with_disappearing_option(pub, monkeypatch):
|
|||
resp.form['fblah_1'] = '1'
|
||||
|
||||
resp = resp.form.submit('submit')
|
||||
assert 'Technical error, please try again' in resp.text
|
||||
assert resp.pyquery('.global-errors summary').text() == 'Technical error, please try again.'
|
||||
assert (
|
||||
resp.pyquery('.global-errors p').text()
|
||||
== "no matching value in datasource (field id: blah_1, value: '1')"
|
||||
)
|
||||
formdata.refresh_from_storage()
|
||||
assert formdata.status == 'wf-%s' % st1.id
|
||||
assert not formdata.workflow_data
|
||||
|
|
|
@ -626,7 +626,7 @@ class Field:
|
|||
if self.store_display_value:
|
||||
display_value = self.store_display_value(data, self.id)
|
||||
if raise_on_error and display_value is None:
|
||||
raise SetValueError('a datasource is unavailable (field id: %s)' % self.id)
|
||||
raise SetValueError(_('datasource is unavailable (field id: %s)') % self.id)
|
||||
|
||||
data['%s_display' % self.id] = display_value or None
|
||||
if self.store_structured_value and value:
|
||||
structured_value = self.store_structured_value(data, self.id, raise_on_error=raise_on_error)
|
||||
|
|
|
@ -292,7 +292,7 @@ class BlockField(WidgetField):
|
|||
if isinstance(value, BlockRowValue):
|
||||
value = value.make_value(block=self.block, field=self, data=data)
|
||||
elif value and not (isinstance(value, dict) and 'data' in value and 'schema' in value):
|
||||
raise SetValueError('invalid value for block')
|
||||
raise SetValueError(_('invalid value for block (field id: %s)') % self.id)
|
||||
super().set_value(data, value, **kwargs)
|
||||
|
||||
def get_json_value(self, value, **kwargs):
|
||||
|
|
|
@ -458,7 +458,7 @@ class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin, ItemWithImageField
|
|||
# wf/backoffice_fields.py action.
|
||||
if not data_source.get_structured_value(value):
|
||||
raise SetValueError(
|
||||
'no matching value in datasource (field id: %s, value: %r)' % (self.id, value)
|
||||
_('no matching value in datasource (field id: %s, value: %r)') % (self.id, value)
|
||||
)
|
||||
super().set_value(data, value, raise_on_error=raise_on_error)
|
||||
|
||||
|
@ -498,7 +498,7 @@ class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin, ItemWithImageField
|
|||
with get_publisher().with_language('default'):
|
||||
value = data_source.get_structured_value(data.get(field_id))
|
||||
if value is None and raise_on_error:
|
||||
raise SetValueError('a datasource is unavailable (field id: %s)' % field_id)
|
||||
raise SetValueError(_('datasource is unavailable (field id: %s)') % field_id)
|
||||
|
||||
if value is None or set(value.keys()) == {'id', 'text'}:
|
||||
return
|
||||
|
|
|
@ -334,7 +334,7 @@ class ItemsField(WidgetField, ItemFieldMixin, ItemWithImageFieldMixin):
|
|||
break
|
||||
else:
|
||||
if raise_on_error:
|
||||
raise SetValueError('datasource is unavailable')
|
||||
raise SetValueError(_('datasource is unavailable (field id: %s)') % self.id)
|
||||
return ', '.join(choices)
|
||||
|
||||
def store_structured_value(self, data, field_id, raise_on_error=False):
|
||||
|
|
|
@ -246,13 +246,13 @@ class MapField(WidgetField, MapOptionsMixin):
|
|||
if value == '':
|
||||
value = None
|
||||
elif value and ';' not in value:
|
||||
raise SetValueError('invalid coordinates %r (missing ;)' % value)
|
||||
raise SetValueError(_('invalid coordinates %r (missing ;) (field id: %s)') % (value, self.id))
|
||||
elif value:
|
||||
try:
|
||||
dummy, dummy = (float(x) for x in value.split(';'))
|
||||
except ValueError:
|
||||
# will catch both "too many values to unpack" and invalid float values
|
||||
raise SetValueError('invalid coordinates %r' % value)
|
||||
raise SetValueError(_('invalid coordinates %r (field id: %s)') % (value, self.id))
|
||||
super().set_value(data, value)
|
||||
|
||||
|
||||
|
|
|
@ -329,8 +329,7 @@ class FormStatusPage(Directory, FormTemplateMixin):
|
|||
try:
|
||||
response = self.check_submitted_form(form)
|
||||
except RedisplayFormException:
|
||||
# don't display errors after "add block" button has been clicked.
|
||||
form.clear_errors()
|
||||
pass
|
||||
fpeters
commented
Cette partie se trouve intégrée dans l'exception, pour éviter la duplication. Cette partie se trouve intégrée dans l'exception, pour éviter la duplication.
|
||||
else:
|
||||
if response:
|
||||
return response
|
||||
|
@ -638,8 +637,7 @@ class FormStatusPage(Directory, FormTemplateMixin):
|
|||
try:
|
||||
response = self.check_submitted_form(form)
|
||||
except RedisplayFormException:
|
||||
# don't display errors after "add block" button has been clicked.
|
||||
form.clear_errors()
|
||||
pass
|
||||
else:
|
||||
if response:
|
||||
get_session().unmark_visited_object(self.filled)
|
||||
|
|
|
@ -1281,11 +1281,13 @@ class FormPage(Directory, TempfileDirectoryMixin, FormTemplateMixin):
|
|||
self.reset_locked_data(form)
|
||||
try:
|
||||
data = self.formdef.get_data(form, raise_on_error=True)
|
||||
except SetValueError:
|
||||
except SetValueError as e:
|
||||
return self.page(
|
||||
page,
|
||||
page_change=False,
|
||||
page_error_messages=[_('Technical error, please try again')],
|
||||
page_error_messages=[
|
||||
{'summary': _('Technical error, please try again.'), 'details': e}
|
||||
],
|
||||
transient_formdata=transient_formdata,
|
||||
)
|
||||
computed_data = self.handle_computed_fields(magictoken, submitted_fields)
|
||||
|
@ -1311,11 +1313,13 @@ class FormPage(Directory, TempfileDirectoryMixin, FormTemplateMixin):
|
|||
try:
|
||||
with get_publisher().substitutions.temporary_feed(transient_formdata, force_mode='lazy'):
|
||||
data = self.formdef.get_data(form, raise_on_error=True)
|
||||
except SetValueError:
|
||||
except SetValueError as e:
|
||||
return self.page(
|
||||
page,
|
||||
page_change=False,
|
||||
page_error_messages=[_('Technical error, please try again')],
|
||||
page_error_messages=[
|
||||
{'summary': _('Technical error, please try again.'), 'details': e}
|
||||
],
|
||||
transient_formdata=transient_formdata,
|
||||
)
|
||||
form_data.update(data)
|
||||
|
@ -1361,11 +1365,13 @@ class FormPage(Directory, TempfileDirectoryMixin, FormTemplateMixin):
|
|||
with get_publisher().substitutions.temporary_feed(transient_formdata, force_mode='lazy'):
|
||||
try:
|
||||
data = self.formdef.get_data(form, raise_on_error=True)
|
||||
except SetValueError:
|
||||
except SetValueError as e:
|
||||
return self.page(
|
||||
page,
|
||||
page_change=False,
|
||||
page_error_messages=[_('Technical error, please try again')],
|
||||
page_error_messages=[
|
||||
{'summary': _('Technical error, please try again.'), 'details': e}
|
||||
],
|
||||
transient_formdata=transient_formdata,
|
||||
)
|
||||
form_data.update(data)
|
||||
|
@ -1411,11 +1417,13 @@ class FormPage(Directory, TempfileDirectoryMixin, FormTemplateMixin):
|
|||
view_form = self.create_view_form(form_data, use_tokens=False)
|
||||
try:
|
||||
return self.submitted_existing(view_form)
|
||||
except SetValueError:
|
||||
except SetValueError as e:
|
||||
return self.page(
|
||||
page,
|
||||
page_change=False,
|
||||
page_error_messages=[_('Technical error, please try again')],
|
||||
page_error_messages=[
|
||||
{'summary': _('Technical error, please try again.'), 'details': e}
|
||||
],
|
||||
transient_formdata=transient_formdata,
|
||||
)
|
||||
if self.has_confirmation_page():
|
||||
|
@ -1480,18 +1488,23 @@ class FormPage(Directory, TempfileDirectoryMixin, FormTemplateMixin):
|
|||
|
||||
try:
|
||||
return self.submitted(form, existing_formdata)
|
||||
except SetValueError:
|
||||
except SetValueError as e:
|
||||
if get_request().form.get('step') == '2':
|
||||
# submit came from the validation page
|
||||
return self.validating(
|
||||
form_data, page_error_messages=[_('Technical error, please try again')]
|
||||
form_data,
|
||||
page_error_messages=[
|
||||
{'summary': _('Technical error, please try again.'), 'details': e}
|
||||
],
|
||||
)
|
||||
else:
|
||||
# last page
|
||||
return self.page(
|
||||
page,
|
||||
page_change=False,
|
||||
page_error_messages=[_('Technical error, please try again')],
|
||||
page_error_messages=[
|
||||
{'summary': _('Technical error, please try again.'), 'details': e}
|
||||
],
|
||||
transient_formdata=transient_formdata,
|
||||
)
|
||||
|
||||
|
|
|
@ -496,7 +496,14 @@ class Form(QuixoteForm):
|
|||
def _render_error_notice_content(self, errors):
|
||||
t = TemplateIO(html=True)
|
||||
for error in errors:
|
||||
if isinstance(error, htmltext):
|
||||
if isinstance(error, dict):
|
||||
t += (
|
||||
htmltext(
|
||||
'<details><summary>%(summary)s</summary><p><small>%(details)s</small></p></details>'
|
||||
)
|
||||
% error
|
||||
fpeters
commented
On peut passer en erreur un dictionnaire, {"summary": ..., "details": ...} et ça sera affiché dans une zone dépliable. On peut passer en erreur un dictionnaire, {"summary": ..., "details": ...} et ça sera affiché dans une zone dépliable.
|
||||
)
|
||||
elif isinstance(error, htmltext):
|
||||
t += error
|
||||
else:
|
||||
t += htmltext('<p>%s</p>') % error
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from quixote import get_publisher, get_session
|
||||
from quixote import get_publisher
|
||||
from quixote.html import TemplateIO, htmltext
|
||||
|
||||
from wcs.admin.fields import FieldDefPage, FieldsDirectory
|
||||
|
@ -326,9 +326,10 @@ class FormWorkflowStatusItem(WorkflowStatusItem):
|
|||
self.prefix_form_fields()
|
||||
try:
|
||||
formdef_data = self.formdef.get_data(form, raise_on_error=submit)
|
||||
except SetValueError:
|
||||
get_session().message = ('error', _('Technical error, please try again'))
|
||||
raise RedisplayFormException()
|
||||
except SetValueError as e:
|
||||
raise RedisplayFormException(
|
||||
form=form, error={'summary': _('Technical error, please try again.'), 'details': e}
|
||||
fpeters
commented
Plutôt qu'utiliser l'infrastructure générale d'affichage de message de session, ça va aller le mettre correctement en erreur sur le formulaire. Plutôt qu'utiliser l'infrastructure générale d'affichage de message de session, ça va aller le mettre correctement en erreur sur le formulaire.
|
||||
)
|
||||
for k, v in get_dict_with_varnames(self.formdef.fields, formdef_data, varnames_only=True).items():
|
||||
workflow_data['%s_%s' % (self.varname, k)] = v
|
||||
if not get_publisher().has_site_option('disable-workflow-form-to-workflow-data'):
|
||||
|
@ -347,7 +348,7 @@ class FormWorkflowStatusItem(WorkflowStatusItem):
|
|||
if isinstance(widget, WidgetList): # BlockWidget
|
||||
add_element_widget = widget.get_widget('add_element')
|
||||
if add_element_widget and add_element_widget.parse():
|
||||
raise RedisplayFormException()
|
||||
raise RedisplayFormException(form=form)
|
||||
elif not form.has_errors():
|
||||
button_name = form.get_submit()
|
||||
button = form.get_widget(button_name)
|
||||
|
|
|
@ -148,7 +148,12 @@ class AbortActionException(Exception):
|
|||
|
||||
|
||||
class RedisplayFormException(Exception):
|
||||
pass
|
||||
def __init__(self, form, error=None):
|
||||
# don't display errors after "add block" button has been clicked.
|
||||
form.clear_errors()
|
||||
if error:
|
||||
# add explicit error
|
||||
form.add_global_errors([error])
|
||||
|
||||
|
||||
def get_role_dependencies(roles):
|
||||
|
|
Loading…
Reference in New Issue
Je marque les chaines pour traduction vu qu'elles apparaitront dans l'interface.