diff --git a/tests/test_datasource_users.py b/tests/test_datasource_users.py
index 9e0ad56e6..3bce97a3a 100644
--- a/tests/test_datasource_users.py
+++ b/tests/test_datasource_users.py
@@ -1,3 +1,5 @@
+import xml.etree.ElementTree as ET
+
import pytest
from wcs import data_sources
@@ -525,3 +527,62 @@ def test_datasource_users_user_formdef(pub):
},
)
]
+
+
+def test_legacy_format_import(pub):
+ data_source_xml = """
+ Agents de la ville
+ agents_de_la_ville
+
+ wcs:users
+
+
+ - 8201764fc2c24b92bd691fd231a4cf76
+
+"""
+ ds = NamedDataSource.import_from_xml_tree(ET.fromstring(data_source_xml))
+ assert ds.users_included_roles == ['8201764fc2c24b92bd691fd231a4cf76']
+
+
+def test_new_format_import(pub):
+ data_source_xml = """
+ Agents de la ville
+ agents_de_la_ville
+
+ wcs:users
+
+
+ Agents
+
+"""
+ ds = NamedDataSource.import_from_xml_tree(ET.fromstring(data_source_xml))
+ assert ds.users_included_roles == [] # role doesn't exist
+
+ # import with id match
+ pub.role_class.wipe()
+ role1 = pub.role_class(name='role')
+ role1.id = '8201764fc2c24b92bd691fd231a4cf76'
+ role1.store()
+
+ ds = NamedDataSource.import_from_xml_tree(ET.fromstring(data_source_xml), include_id=True)
+ assert ds.users_included_roles == [role1.id]
+
+ # import with slug match
+ pub.role_class.wipe()
+ role1 = pub.role_class(name='Agents')
+ role1.slug = 'agent'
+ role1.store()
+
+ ds = NamedDataSource.import_from_xml_tree(ET.fromstring(data_source_xml), include_id=False)
+ assert ds.users_included_roles == [role1.id]
+
+ # import with name match
+ pub.role_class.wipe()
+ role1 = pub.role_class(name='Agents')
+ role1.slug = 'agent'
+ role1.store()
+
+ ds = NamedDataSource.import_from_xml_tree(
+ ET.fromstring(data_source_xml.replace('role-slug="agent"', '')), include_id=False
+ )
+ assert ds.users_included_roles == [role1.id]
diff --git a/wcs/data_sources.py b/wcs/data_sources.py
index 31c33c558..1c845dd87 100644
--- a/wcs/data_sources.py
+++ b/wcs/data_sources.py
@@ -717,8 +717,8 @@ class NamedDataSource(XmlStorableObject):
('data_source', 'data_source'),
('notify_on_errors', 'bool'),
('record_on_errors', 'bool'),
- ('users_included_roles', 'str_list'),
- ('users_excluded_roles', 'str_list'),
+ ('users_included_roles', 'ds_roles'),
+ ('users_excluded_roles', 'ds_roles'),
('include_disabled_users', 'bool'),
]
diff --git a/wcs/qommon/xml_storage.py b/wcs/qommon/xml_storage.py
index 427c74562..f8d86adb4 100644
--- a/wcs/qommon/xml_storage.py
+++ b/wcs/qommon/xml_storage.py
@@ -20,7 +20,7 @@ import xml.etree.ElementTree as ET
from quixote import get_publisher
from .misc import indent_xml, xml_node_text
-from .storage import Equal, Or, StorableObject
+from .storage import Contains, Equal, Or, StorableObject
class XmlStorableObject(StorableObject):
@@ -141,6 +141,8 @@ class XmlStorableObject(StorableObject):
def import_roles_from_xml(self, element, include_id=False, **kwargs):
criterias = []
for sub in element:
+ if sub.tag != 'role':
+ continue
if include_id and 'role-id' in sub.attrib:
criterias.append(Equal('id', sub.attrib['role-id']))
elif 'role-slug' in sub.attrib:
@@ -156,3 +158,22 @@ class XmlStorableObject(StorableObject):
return get_publisher().role_class.select([Or(criterias)], order_by='name')
return lazy_roles
+
+ def import_ds_roles_from_xml(self, element, include_id=False, **kwargs):
+ imported_roles = self.import_roles_from_xml(element, include_id=include_id, **kwargs)
+ if callable(imported_roles):
+ imported_roles = imported_roles()
+ role_ids = [x.id for x in imported_roles]
+ for sub in element:
+ if sub.tag == 'item': # legacy support for - {id}
+ role_ids.append(xml_node_text(sub))
+ return role_ids
+
+ def export_ds_roles_to_xml(self, element, attribute_name, include_id=False, **kwargs):
+ for role in get_publisher().role_class.select(
+ [Contains('id', getattr(self, attribute_name, None) or [])]
+ ):
+ sub = ET.SubElement(element, 'role')
+ sub.attrib['role-id'] = role.id # always include id
+ sub.attrib['role-slug'] = role.slug
+ sub.text = role.name