workflows: report all missing things in one time (#57753)
gitea-wip/wcs/pipeline/head Build started... Details

This commit is contained in:
Lauréline Guérin 2021-11-04 14:50:26 +01:00
parent 3c1ca2d57b
commit 252955bf2f
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
6 changed files with 166 additions and 21 deletions

View File

@ -302,7 +302,7 @@ def test_settings_export_import(pub):
resp = app.get('/backoffice/settings/import')
resp.form['file'] = Upload('export.wcs', zip_content.getvalue())
resp = resp.form.submit('submit')
assert 'Unknown referenced role (qux)' in resp
assert 'Unknown referenced objects [Unknown roles: qux]' in resp
def test_settings_themes(pub):

View File

@ -644,7 +644,7 @@ def test_workflows_export_import_create_role(pub):
resp = resp.click('Import')
resp.form['file'] = Upload('xxx.wcs', wf_export)
resp = resp.form.submit('submit')
assert 'Invalid File (Unknown referenced role (PLOP))' in resp.text
assert 'Invalid File (Unknown referenced objects [Unknown roles: PLOP])' in resp.text
def test_workflows_duplicate(pub):

View File

@ -282,7 +282,7 @@ def test_form_snapshot_restore_with_import_error(pub):
snapshot = pub.snapshot_class.select_object_history(formdef)[0]
resp = app.get('/backoffice/forms/%s/history/%s/restore' % (formdef.id, snapshot.id))
resp = resp.form.submit('submit')
assert 'Can not restore snapshot (Unknown datasources [unknown])' in resp
assert 'Can not restore snapshot (Unknown referenced objects [Unknown datasources: unknown])' in resp
def test_block_snapshot_browse(pub):
@ -461,7 +461,7 @@ def test_form_snapshot_browse_with_import_error(pub):
resp = app.get('/backoffice/forms/%s/history/%s/view/' % (formdef.id, snapshot.id), status=302)
assert resp.location == 'http://example.net/backoffice/forms/%s/history/' % formdef.id
resp = resp.follow()
assert 'Can not display snapshot (Unknown field type [foobar])' in resp
assert 'Can not display snapshot (Unknown referenced objects [Unknown field types: foobar])' in resp
def test_workflow_snapshot_browse(pub):
@ -563,7 +563,7 @@ def test_workflow_snapshot_restore_with_import_error(pub):
snapshot = pub.snapshot_class.select_object_history(wf)[0]
resp = app.get('/backoffice/workflows/%s/history/%s/restore' % (wf.id, snapshot.id))
resp = resp.form.submit('submit')
assert 'Can not restore snapshot (Unknown datasources [unknown])' in resp
assert 'Can not restore snapshot (Unknown referenced objects [Unknown datasources: unknown])' in resp
def test_workflow_snapshot_restore_with_missing_role(pub):

View File

@ -136,8 +136,10 @@ def test_action_dispatch(pub):
pub.cfg['sp'] = {'idp-manage-roles': True}
# now roles are managed: cannot create them
dispatch.role_id = 'unknown'
with pytest.raises(WorkflowImportError, match=r'.*Unknown referenced role.*'):
with pytest.raises(WorkflowImportError) as excinfo:
wf2 = assert_import_export_works(wf)
assert excinfo.value.msg == 'Unknown referenced objects'
assert excinfo.value.details == 'Unknown roles: unknown'
# but allow computed roles
dispatch.role_id = '=form_var_bar'
wf2 = assert_import_export_works(wf)
@ -895,8 +897,10 @@ def test_worklow_with_mail_template(pub):
# import with non existing mail template
MailTemplate.wipe()
export = ET.tostring(wf.export_to_xml(include_id=True))
with pytest.raises(WorkflowImportError, match='Unknown referenced mail template'):
with pytest.raises(WorkflowImportError) as excinfo:
Workflow.import_from_xml_tree(ET.fromstring(export), include_id=True)
assert excinfo.value.msg == 'Unknown referenced objects'
assert excinfo.value.details == 'Unknown mail templates: test-mail-template'
def test_workflow_with_unknown_data_source(pub):
@ -1039,3 +1043,73 @@ def test_workflow_with_category(pub):
export = ET.tostring(wf.export_to_xml(include_id=True))
wf3 = Workflow.import_from_xml_tree(ET.fromstring(export), include_id=True)
assert wf3.category_id is None
def test_import_workflow_multiple_errors(pub):
BlockDef.wipe()
pub.cfg['sp'] = {'idp-manage-roles': True}
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
display_form = FormWorkflowStatusItem()
display_form.id = '_x'
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields = [
BlockField(id='1', type='block:foobar1'),
BlockField(id='2', type='block:foobaz1'),
StringField(id='3', type='string', data_source={'type': 'foobar1'}),
StringField(id='4', type='string', data_source={'type': 'carddef:unknown1'}),
]
st1.items.append(display_form)
display_form.parent = st1
dispatch1 = DispatchWorkflowStatusItem()
dispatch1.id = '_x1'
dispatch1.role_id = 'unknown-role1'
dispatch1.role_key = 'plop'
st1.items.append(dispatch1)
dispatch1.parent = st1
dispatch2 = DispatchWorkflowStatusItem()
dispatch2.id = '_x2'
dispatch2.role_id = 'unknown-role2'
dispatch2.role_key = 'plop'
st1.items.append(dispatch2)
dispatch2.parent = st1
item1 = SendmailWorkflowStatusItem()
item1.to = ['_receiver']
item1.mail_template = 'unknown-mt-1'
st1.items.append(item1)
item1.parent = st1
item2 = SendmailWorkflowStatusItem()
item2.to = ['_receiver']
item2.mail_template = 'unknown-mt-2'
st1.items.append(item2)
item2.parent = st1
wf.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=wf)
wf.variables_formdef.fields = [
BlockField(id='1', type='block:foobar2'),
BlockField(id='2', type='block:foobaz2'),
StringField(id='3', type='string', data_source={'type': 'foobar2'}),
StringField(id='4', type='string', data_source={'type': 'carddef:unknown2'}),
]
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf)
wf.backoffice_fields_formdef.fields = [
BlockField(id='1', type='block:foobar3'),
BlockField(id='2', type='block:foobaz3'),
StringField(id='3', type='string', data_source={'type': 'foobar3'}),
StringField(id='4', type='string', data_source={'type': 'carddef:unknown3'}),
]
export = ET.tostring(export_to_indented_xml(wf))
with pytest.raises(WorkflowImportError) as excinfo:
Workflow.import_from_xml(io.BytesIO(export))
assert excinfo.value.msg == 'Unknown referenced objects'
assert excinfo.value.details == (
'Unknown datasources: carddef:unknown1, carddef:unknown2, carddef:unknown3, foobar1, foobar2, foobar3; '
'Unknown field types: block:foobar1, block:foobar2, block:foobar3, block:foobaz1, block:foobaz2, block:foobaz3; '
'Unknown mail templates: unknown-mt-1, unknown-mt-2; '
'Unknown roles: unknown-role1, unknown-role2'
)

View File

@ -15,6 +15,7 @@
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import base64
import collections
import contextlib
import copy
import datetime
@ -60,6 +61,22 @@ class FormdefImportError(Exception):
self.details = details
class FormdefImportUnknownReferencedError(FormdefImportError):
def __init__(self, msg, msg_args=None, details=None):
self.msg = msg
self.msg_args = msg_args or ()
self._details = details
@property
def details(self):
if not self._details:
return None
details = []
for kind in self._details:
details.append('%s: %s' % (kind, ', '.join(sorted(self._details[kind]))))
return '; '.join(details)
class FormdefImportRecoverableError(FormdefImportError):
pass
@ -1357,12 +1374,12 @@ class FormDef(StorableObject):
unknown_datasources.add(data_source_id)
if unknown_field_types or unknown_datasources:
details = []
details = collections.defaultdict(set)
if unknown_field_types:
details.append('%s: %s' % (_('Unknown field types'), ', '.join(sorted(unknown_field_types))))
details[_('Unknown field types')].update(unknown_field_types)
if unknown_datasources:
details.append('%s: %s' % (_('Unknown datasources'), ', '.join(sorted(unknown_datasources))))
raise FormdefImportError(_('Unknown referenced objects'), details='; '.join(details))
details[_('Unknown datasources')].update(unknown_datasources)
raise FormdefImportUnknownReferencedError(_('Unknown referenced objects'), details=details)
return formdef

View File

@ -34,7 +34,7 @@ from .categories import WorkflowCategory
from .conditions import Condition
from .fields import FileField
from .formdata import Evolution
from .formdef import FormDef, FormdefImportError
from .formdef import FormDef, FormdefImportError, FormdefImportUnknownReferencedError
from .mail_templates import MailTemplate
from .qommon import _, emails, errors, ezt, force_str, get_cfg, misc
from .qommon.form import (
@ -121,6 +121,22 @@ class WorkflowImportError(Exception):
self.details = details
class WorkflowImportUnknownReferencedError(WorkflowImportError):
def __init__(self, msg, msg_args=None, details=None):
self.msg = msg
self.msg_args = msg_args or ()
self._details = details
@property
def details(self):
if not self._details:
return None
details = []
for kind in sorted(self._details.keys()):
details.append('%s: %s' % (kind, ', '.join(sorted(self._details[kind]))))
return '; '.join(details)
class AbortActionException(Exception):
def __init__(self, url=None):
self.url = url
@ -802,6 +818,7 @@ class Workflow(StorableObject):
for role_node in tree.findall('roles/role'):
workflow.roles[role_node.attrib['id']] = xml_node_text(role_node)
unknown_referenced_objects_details = collections.defaultdict(set)
workflow.possible_status = []
for status in tree.find('possible_status'):
status_o = WorkflowStatus()
@ -814,9 +831,13 @@ class Workflow(StorableObject):
snapshot=snapshot,
check_datasources=check_datasources,
)
except WorkflowImportUnknownReferencedError as e:
for k, v in e._details.items():
unknown_referenced_objects_details[k].update(v)
except FormdefImportError as e:
raise WorkflowImportError(e.msg, details=e.details)
workflow.possible_status.append(status_o)
else:
workflow.possible_status.append(status_o)
workflow.global_actions = []
global_actions = tree.find('global_actions')
@ -842,10 +863,14 @@ class Workflow(StorableObject):
imported_formdef = FormDef.import_from_xml_tree(
formdef, include_id=True, snapshot=snapshot, check_datasources=check_datasources
)
except FormdefImportUnknownReferencedError as e:
for k, v in e._details.items():
unknown_referenced_objects_details[k].update(v)
except FormdefImportError as e:
raise WorkflowImportError(e.msg, details=e.details)
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
workflow.variables_formdef.fields = imported_formdef.fields
else:
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
workflow.variables_formdef.fields = imported_formdef.fields
variables = tree.find('backoffice-fields')
if variables is not None:
@ -854,10 +879,19 @@ class Workflow(StorableObject):
imported_formdef = FormDef.import_from_xml_tree(
formdef, include_id=True, snapshot=snapshot, check_datasources=check_datasources
)
except FormdefImportUnknownReferencedError as e:
for k, v in e._details.items():
unknown_referenced_objects_details[k].update(v)
except FormdefImportError as e:
raise WorkflowImportError(e.msg, details=e.details)
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow=workflow)
workflow.backoffice_fields_formdef.fields = imported_formdef.fields
else:
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow=workflow)
workflow.backoffice_fields_formdef.fields = imported_formdef.fields
if unknown_referenced_objects_details:
raise WorkflowImportUnknownReferencedError(
_('Unknown referenced objects'), details=unknown_referenced_objects_details
)
return workflow
@ -1197,7 +1231,9 @@ class XmlSerialisable:
if get_publisher() and get_cfg('sp', {}).get('idp-manage-roles') is True:
if snapshot:
return value
raise WorkflowImportError(_('Unknown referenced role (%s)'), (value,))
raise WorkflowImportUnknownReferencedError(
_('Unknown referenced role (%s)'), details={_('Unknown roles'): {value}}
)
# and if there's no match, create a new role
role = get_publisher().role_class()
@ -2003,13 +2039,29 @@ class WorkflowStatus:
self.visibility.append(visibility_role.text)
self.items = []
unknown_referenced_objects_details = collections.defaultdict(set)
for item in elem.find('items'):
item_type = item.attrib['type']
self.append_item(item_type)
item_o = self.items[-1]
item_o.parent = self
item_o.init_with_xml(
item, charset, include_id=include_id, snapshot=snapshot, check_datasources=check_datasources
try:
item_o.init_with_xml(
item,
charset,
include_id=include_id,
snapshot=snapshot,
check_datasources=check_datasources,
)
except (WorkflowImportUnknownReferencedError, FormdefImportUnknownReferencedError) as e:
for k, v in e._details.items():
unknown_referenced_objects_details[k].update(v)
except FormdefImportError as e:
raise WorkflowImportError(e.msg, details=e.details)
if unknown_referenced_objects_details:
raise WorkflowImportUnknownReferencedError(
_('Unknown referenced objects'), details=unknown_referenced_objects_details
)
def __repr__(self):
@ -2442,7 +2494,9 @@ class WorkflowStatusItem(XmlSerialisable):
value = xml_node_text(elem)
mail_template = MailTemplate.get_by_slug(value)
if not mail_template:
raise WorkflowImportError(_('Unknown referenced mail template (%s)'), (value,))
raise WorkflowImportUnknownReferencedError(
_('Unknown referenced mail template (%s)'), details={_('Unknown mail templates'): {value}}
)
self.mail_template = value
return