add possibility to create a formdef object from a json value (#5348)

This commit is contained in:
Frédéric Péters 2014-08-29 14:12:27 +02:00
parent 4b21a5cad0
commit afad1c2c59
3 changed files with 154 additions and 46 deletions

View File

@ -22,23 +22,42 @@ def setup_module(module):
def teardown_module(module):
shutil.rmtree(pub.APP_DIR)
def assert_import_export_works(formdef, include_id=False):
def export_to_indented_xml(formdef, include_id=False):
formdef_xml = formdef.export_to_xml(include_id=include_id)
indent(formdef_xml)
return formdef_xml
def assert_compare_formdef(formdef1, formdef2, include_id=False):
assert ET.tostring(export_to_indented_xml(formdef1, include_id=include_id)) == \
ET.tostring(export_to_indented_xml(formdef2, include_id=include_id))
assert formdef1.export_to_json(include_id=include_id, indent=2) == \
formdef2.export_to_json(include_id=include_id, indent=2)
def assert_xml_import_export_works(formdef, include_id=False):
formdef2 = FormDef.import_from_xml_tree(
formdef.export_to_xml(include_id=include_id), include_id=include_id)
assert ET.tostring(indent(formdef.export_to_xml(include_id=include_id))
) == ET.tostring(indent(formdef2.export_to_xml(include_id=include_id)))
assert_compare_formdef(formdef, formdef2, include_id=include_id)
return formdef2
def assert_json_import_export_works(formdef, include_id=False):
formdef2 = FormDef.import_from_json(
StringIO.StringIO(formdef.export_to_json(include_id=include_id)), include_id=include_id)
assert_compare_formdef(formdef, formdef2, include_id=include_id)
return formdef2
def test_empty():
formdef = FormDef()
formdef.name = 'empty'
assert_import_export_works(formdef)
assert_xml_import_export_works(formdef)
assert_json_import_export_works(formdef)
def test_text_attributes():
formdef = FormDef()
formdef.name = 'Foo'
formdef.url_name = 'foo'
f2 = assert_import_export_works(formdef)
f2 = assert_xml_import_export_works(formdef)
assert f2.url_name == formdef.url_name
f2 = assert_json_import_export_works(formdef)
assert f2.url_name == formdef.url_name
def test_boolean_attributes():
@ -47,7 +66,10 @@ def test_boolean_attributes():
formdef.url_name = 'foo'
formdef.confirmation = True
formdef.allow_drafts = True
f2 = assert_import_export_works(formdef)
f2 = assert_xml_import_export_works(formdef)
assert f2.allow_drafts == formdef.allow_drafts
assert f2.confirmation == formdef.confirmation
f2 = assert_json_import_export_works(formdef)
assert f2.allow_drafts == formdef.allow_drafts
assert f2.confirmation == formdef.confirmation
@ -55,9 +77,11 @@ def test_a_field():
formdef = FormDef()
formdef.name = 'Foo'
formdef.fields = [
fields.StringField(type='string', id=1, label='Bar', size=40)
fields.StringField(type='string', id=1, label='Bar', size='40')
]
f2 = assert_import_export_works(formdef)
f2 = assert_xml_import_export_works(formdef)
assert len(f2.fields) == len(formdef.fields)
f2 = assert_json_import_export_works(formdef)
assert len(f2.fields) == len(formdef.fields)
def test_more_fields():
@ -70,7 +94,13 @@ def test_more_fields():
fields.DateField(type='date', label='Bar', minimum_date='2014-01-01'),
fields.ItemField(type='item', label='Bar', items=['foo', 'bar', 'baz']),
]
f2 = assert_import_export_works(formdef)
f2 = assert_xml_import_export_works(formdef)
assert len(f2.fields) == len(formdef.fields)
assert f2.fields[2].type == formdef.fields[2].type
assert f2.fields[3].minimum_date == formdef.fields[3].minimum_date
assert f2.fields[4].items == formdef.fields[4].items
f2 = assert_json_import_export_works(formdef)
assert len(f2.fields) == len(formdef.fields)
assert f2.fields[2].type == formdef.fields[2].type
assert f2.fields[3].minimum_date == formdef.fields[3].minimum_date
@ -89,8 +119,12 @@ def test_include_id():
for field in formdef.fields:
field.id = formdef.get_new_field_id()
formdef.fields[4].id = '10'
f2 = assert_import_export_works(formdef, include_id=True)
f2 = assert_xml_import_export_works(formdef, include_id=True)
assert len(f2.fields) == len(formdef.fields)
assert f2.fields[0].id == formdef.fields[0].id
assert f2.fields[4].id == formdef.fields[4].id
f2 = assert_json_import_export_works(formdef, include_id=True)
assert len(f2.fields) == len(formdef.fields)
assert f2.fields[0].id == formdef.fields[0].id
assert f2.fields[4].id == formdef.fields[4].id

View File

@ -125,7 +125,7 @@ class Field:
def get_admin_attributes(self):
return ['label', 'type']
def export_to_json(self, charset, include_id=False):
def export_to_json(self, include_id=False):
field = {}
if include_id:
extra_fields = ['id']
@ -136,25 +136,16 @@ class Field:
continue
if hasattr(self, attribute) and getattr(self, attribute) is not None:
val = getattr(self, attribute)
if type(val) is dict:
if not val: continue
field[attribute] = {}
for k, v in val.items():
field[attribute][k] = unicode(v, charset, 'replace')
elif type(val) is list:
if not val: continue
field[attribute] = []
for v in val:
field[attribute].append(unicode(v, charset, 'replace'))
elif type(val) in (str, unicode):
if type(val) is unicode:
field[attribute] = val
else:
field[attribute] = unicode(val, charset, 'replace')
else:
field[attribute] = str(val)
field[attribute] = val
return field
def init_with_json(self, elem, include_id=False):
if include_id:
self.id = elem.get('id')
for attribute in self.get_admin_attributes():
if attribute in elem:
setattr(self, attribute, elem.get(attribute))
def export_to_xml(self, charset, include_id=False):
field = ET.Element('field')
if include_id:

View File

@ -80,13 +80,13 @@ class FormDef(StorableObject):
max_field_id = None
# declarations for serialization
TEXT_ATTRIBUTES = ('name', 'url_name',
'publication_date', 'expiration_date')
BOOLEAN_ATTRIBUTES = ('discussion', 'detailed_emails', 'disabled',
'only_allow_one', 'allow_drafts', 'disabled_redirection',
'always_advertise', 'private_status_and_history')
TEXT_ATTRIBUTES = ['name', 'url_name',
'publication_date', 'expiration_date',
'disabled_redirection',]
BOOLEAN_ATTRIBUTES = ['discussion', 'detailed_emails', 'disabled',
'only_allow_one', 'allow_drafts',
'always_advertise', 'private_status_and_history']
def migrate(self):
changed = False
@ -386,24 +386,104 @@ class FormDef(StorableObject):
return d
def export_to_json(self, include_id=False):
def export_to_json(self, include_id=False, indent=None):
charset = get_publisher().site_charset
root = {}
root['name'] = unicode(self.name, charset)
if include_id and self.id:
root['id'] = str(self.id)
if self.category:
root['category'] = unicode(self.category.name, charset)
for boolean_attribute in self.BOOLEAN_ATTRIBUTES:
value = getattr(self, boolean_attribute)
if value:
value = 'true'
else:
value = 'false'
root[boolean_attribute] = value
root['fields'] = []
for field in self.fields:
root['fields'].append(field.export_to_json(charset=charset, include_id=include_id))
root['category_id'] = str(self.category.id)
if self.workflow:
root['workflow'] = unicode(self.workflow.name, charset)
root['workflow_id'] = str(self.workflow.id)
return json.dumps(root)
if self.max_field_id is None and self.fields:
self.max_field_id = max([lax_int(x.id) for x in self.fields])
more_attributes = []
if self.max_field_id:
more_attributes.append('max_field_id')
if self.last_modification_time:
more_attributes.append('last_modification_time')
if include_id:
more_attributes.append('last_modification_user_id')
for attribute in self.TEXT_ATTRIBUTES + self.BOOLEAN_ATTRIBUTES + more_attributes:
if not hasattr(self, attribute):
continue
root[attribute] = getattr(self, attribute)
root['fields'] = []
if self.fields:
for field in self.fields:
root['fields'].append(field.export_to_json(include_id=include_id))
return json.dumps(root, indent=indent)
def import_from_json(cls, fd, charset=None, include_id=False):
if charset is None:
charset = get_publisher().site_charset
formdef = cls()
def unicode2str(v):
if isinstance(v, dict):
return dict([(unicode2str(k), unicode2str(v)) for k, v in v.items()])
elif isinstance(v, list):
return [unicode2str(x) for x in v]
elif isinstance(v, unicode):
return v.encode(charset)
else:
return v
# we have to make sure all strings are str object, not unicode.
value = unicode2str(json.load(fd))
if include_id and 'id' in value:
formdef.id = value.get('id')
if include_id and 'category_id' in value:
formdef.category_id = value.get('category_id')
elif 'category' in value:
category = value.get('category')
for c in Category.select():
if c.name == category:
formdef.category_id = c.id
break
if include_id and 'workflow_id' in value:
formdef.workflow_id = value.get('workflow_id')
elif 'workflow' in value:
workflow = value.get('workflow')
for w in Workflow.select():
if w.name == workflow:
formdef.workflow_id = w.id
break
more_attributes = ['max_field_id', 'last_modification_time',
'last_modification_user_id']
for attribute in cls.TEXT_ATTRIBUTES + cls.BOOLEAN_ATTRIBUTES + more_attributes:
if attribute in value:
setattr(formdef, attribute, value.get(attribute))
formdef.fields = []
for i, field in enumerate(value.get('fields', [])):
try:
field_o = fields.get_field_class_by_type(field.get('type'))()
except KeyError:
raise ValueError()
field_o.init_with_json(field, include_id=include_id)
if not field_o.id:
# this assumes all fields will have id, or none of them
field_o.id = str(i)
formdef.fields.append(field_o)
if formdef.fields and not formdef.max_field_id:
formdef.max_field_id = max([lax_int(x.id) for x in formdef.fields])+1
return formdef
import_from_json = classmethod(import_from_json)
def export_to_xml(self, include_id=False):
charset = get_publisher().site_charset
@ -437,6 +517,9 @@ class FormDef(StorableObject):
if include_id:
elem.attrib['workflow_id'] = str(self.workflow.id)
if self.max_field_id is None and self.fields:
self.max_field_id = max([lax_int(x.id) for x in self.fields])
if self.max_field_id:
ET.SubElement(root, 'max_field_id').text = str(self.max_field_id)