formdef: add support for import/export of complex workflow options (#14043) #982
|
@ -282,6 +282,28 @@ def test_workflow_options_with_boolean(pub):
|
|||
assert formdef.workflow_options['foo'] == fd2.workflow_options['foo']
|
||||
|
||||
|
||||
def test_workflow_options_with_int(pub):
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo'
|
||||
formdef.workflow_options = {'foo': 123}
|
||||
fd2 = assert_xml_import_export_works(formdef)
|
||||
assert formdef.workflow_options['foo'] == fd2.workflow_options['foo']
|
||||
|
||||
|
||||
def test_workflow_options_with_list(pub):
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo'
|
||||
formdef.workflow_options = {
|
||||
'foo': ['a', 'b', 'c'],
|
||||
'foo2': [True, False],
|
||||
'foo3': [{'id': 1, 'text': 'blah'}],
|
||||
}
|
||||
fd2 = assert_xml_import_export_works(formdef)
|
||||
assert formdef.workflow_options['foo'] == fd2.workflow_options['foo']
|
||||
assert formdef.workflow_options['foo2'] == fd2.workflow_options['foo2']
|
||||
assert formdef.workflow_options['foo3'] == fd2.workflow_options['foo3']
|
||||
|
||||
|
||||
def test_workflow_reference(pub):
|
||||
Workflow.wipe()
|
||||
FormDef.wipe()
|
||||
|
|
|
@ -1312,30 +1312,42 @@ class FormDef(StorableObject):
|
|||
if sub is not None:
|
||||
sub.attrib['role_key'] = role_key
|
||||
|
||||
def make_xml_value(element, value):
|
||||
if isinstance(value, str):
|
||||
element.text = value
|
||||
elif hasattr(value, 'base_filename'):
|
||||
element.attrib['type'] = 'file'
|
||||
ET.SubElement(element, 'filename').text = value.base_filename
|
||||
ET.SubElement(element, 'content_type').text = value.content_type or 'application/octet-stream'
|
||||
ET.SubElement(element, 'content').text = force_str(base64.b64encode(value.get_content()))
|
||||
elif isinstance(value, time.struct_time):
|
||||
element.text = time.strftime('%Y-%m-%d', value)
|
||||
element.attrib['type'] = 'date'
|
||||
elif isinstance(value, bool):
|
||||
element.text = 'true' if value else 'false'
|
||||
element.attrib['type'] = 'bool'
|
||||
elif isinstance(value, int):
|
||||
element.attrib['type'] = 'int'
|
||||
element.text = str(value)
|
||||
elif isinstance(value, (set, tuple, list)):
|
||||
element.attrib['type'] = 'list'
|
||||
for child_value in value:
|
||||
sub_element = ET.SubElement(element, 'item')
|
||||
make_xml_value(sub_element, child_value)
|
||||
elif isinstance(value, dict):
|
||||
element.attrib['type'] = 'dict'
|
||||
for child_key, child_value in value.items():
|
||||
sub_element = ET.SubElement(element, child_key)
|
||||
make_xml_value(sub_element, child_value)
|
||||
else:
|
||||
assert value is None, 'option variable of unknown type (%s)' % type(value)
|
||||
|
||||
options = ET.SubElement(root, 'options')
|
||||
for option in sorted(self.workflow_options or []):
|
||||
element = ET.SubElement(options, 'option')
|
||||
element.attrib['varname'] = option
|
||||
option_value = self.workflow_options.get(option)
|
||||
if isinstance(option_value, str):
|
||||
element.text = force_str(self.workflow_options.get(option, ''), charset)
|
||||
elif hasattr(option_value, 'base_filename'):
|
||||
element.attrib['type'] = 'file'
|
||||
ET.SubElement(element, 'filename').text = option_value.base_filename
|
||||
ET.SubElement(element, 'content_type').text = (
|
||||
option_value.content_type or 'application/octet-stream'
|
||||
)
|
||||
ET.SubElement(element, 'content').text = force_str(
|
||||
base64.b64encode(option_value.get_content())
|
||||
)
|
||||
elif isinstance(option_value, time.struct_time):
|
||||
element.text = time.strftime('%Y-%m-%d', option_value)
|
||||
element.attrib['type'] = 'date'
|
||||
elif isinstance(option_value, bool):
|
||||
element.text = 'true' if option_value else 'false'
|
||||
element.attrib['type'] = 'bool'
|
||||
else:
|
||||
pass # TODO: extend support to other types
|
||||
make_xml_value(element, option_value)
|
||||
|
||||
custom_views_element = ET.SubElement(root, 'custom_views')
|
||||
if hasattr(self, '_custom_views'):
|
||||
|
@ -1471,21 +1483,30 @@ class FormDef(StorableObject):
|
|||
]
|
||||
|
||||
formdef.workflow_options = {}
|
||||
for option in tree.findall('options/option'):
|
||||
option_value = None
|
||||
if option.attrib.get('type') == 'date':
|
||||
option_value = time.strptime(option.text, '%Y-%m-%d')
|
||||
elif option.attrib.get('type') == 'bool':
|
||||
option_value = bool(option.text == 'true')
|
||||
elif option.attrib.get('type') == 'file' or option.findall('filename'):
|
||||
option_value = PicklableUpload(
|
||||
orig_filename=xml_node_text(option.find('filename')),
|
||||
content_type=xml_node_text(option.find('content_type')),
|
||||
|
||||
def get_value_from_xml(element):
|
||||
if element.attrib.get('type') == 'int':
|
||||
return int(xml_node_text(element))
|
||||
if element.attrib.get('type') == 'date':
|
||||
return time.strptime(element.text, '%Y-%m-%d')
|
||||
elif element.attrib.get('type') == 'bool':
|
||||
return bool(element.text == 'true')
|
||||
elif element.attrib.get('type') == 'file' or element.findall('filename'):
|
||||
value = PicklableUpload(
|
||||
orig_filename=xml_node_text(element.find('filename')),
|
||||
content_type=xml_node_text(element.find('content_type')),
|
||||
)
|
||||
option_value.receive([base64.decodebytes(force_bytes(xml_node_text(option.find('content'))))])
|
||||
elif option.text:
|
||||
option_value = xml_node_text(option)
|
||||
formdef.workflow_options[option.attrib.get('varname')] = option_value
|
||||
value.receive([base64.decodebytes(force_bytes(xml_node_text(element.find('content'))))])
|
||||
return value
|
||||
elif element.attrib.get('type') == 'list':
|
||||
return [get_value_from_xml(x) for x in element.findall('item')]
|
||||
elif element.attrib.get('type') == 'dict':
|
||||
return {x.tag: get_value_from_xml(x) for x in element.findall('*')}
|
||||
elif element.text:
|
||||
return xml_node_text(element)
|
||||
|
||||
for option in tree.findall('options/option'):
|
||||
formdef.workflow_options[option.attrib.get('varname')] = get_value_from_xml(option)
|
||||
|
||||
formdef._custom_views = []
|
||||
for view in tree.findall('custom_views/%s' % get_publisher().custom_view_class.xml_root_node):
|
||||
|
|
Loading…
Reference in New Issue