From 7dff0b4d2d6bced373f6271323e0f74a89136749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Fri, 29 Aug 2014 14:12:27 +0200 Subject: [PATCH] add possibility to create a formdef object from a json value (#5348) --- tests/test_formdef_import.py | 39 ++++++++++++++--- wcs/fields.py | 27 ++++-------- wcs/formdef.py | 102 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 130 insertions(+), 38 deletions(-) diff --git a/tests/test_formdef_import.py b/tests/test_formdef_import.py index e476901..0a6b362 100644 --- a/tests/test_formdef_import.py +++ b/tests/test_formdef_import.py @@ -22,23 +22,33 @@ def setup_module(module): def teardown_module(module): shutil.rmtree(pub.APP_DIR) -def assert_import_export_works(formdef, include_id=False): +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))) 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 ET.tostring(indent(formdef.export_to_xml(include_id=include_id)) + ) == ET.tostring(indent(formdef2.export_to_xml(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 +57,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 @@ -57,7 +70,9 @@ def test_a_field(): formdef.fields = [ 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 +85,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 +110,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 diff --git a/wcs/fields.py b/wcs/fields.py index c3bd0a4..f9e48e9 100644 --- a/wcs/fields.py +++ b/wcs/fields.py @@ -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: diff --git a/wcs/formdef.py b/wcs/formdef.py index b3741a9..814c1a2 100644 --- a/wcs/formdef.py +++ b/wcs/formdef.py @@ -82,11 +82,11 @@ class FormDef(StorableObject): # declarations for serialization - TEXT_ATTRIBUTES = ('name', 'url_name', - 'publication_date', 'expiration_date') - BOOLEAN_ATTRIBUTES = ('discussion', 'detailed_emails', 'disabled', + 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') + 'always_advertise', 'private_status_and_history'] def migrate(self): changed = False @@ -390,21 +390,97 @@ class FormDef(StorableObject): 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['category_id'] = str(self.category.id) + if self.workflow: + root['workflow'] = unicode(self.workflow.name, charset) + root['workflow_id'] = str(self.workflow.id) + + 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'] = [] - for field in self.fields: - root['fields'].append(field.export_to_json(charset=charset, include_id=include_id)) + if self.fields: + for field in self.fields: + root['fields'].append(field.export_to_json(include_id=include_id)) return json.dumps(root) + 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: + 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 root = ET.Element('formdef') -- 2.1.0