Mailing List Archive

SVN: PluggableAuthService/trunk/plugins/ Add adapter for DynamicGroupsPlugin.
Log message for revision 40167:
Add adapter for DynamicGroupsPlugin.

Changed:
U PluggableAuthService/trunk/plugins/exportimport.py
U PluggableAuthService/trunk/plugins/tests/test_exportimport.py
A PluggableAuthService/trunk/plugins/xml/dynamicgroups.xml

-=-
Modified: PluggableAuthService/trunk/plugins/exportimport.py
===================================================================
--- PluggableAuthService/trunk/plugins/exportimport.py 2005-11-16 18:01:36 UTC (rev 40166)
+++ PluggableAuthService/trunk/plugins/exportimport.py 2005-11-16 18:50:53 UTC (rev 40167)
@@ -42,13 +42,13 @@

- [X] SessionAuthHelper (TitleOnlyExportImport)

- - [/] ScriptablePlugin (stock GenericSetup folderish support?)
+ - [?] ScriptablePlugin (stock GenericSetup folderish support?)

- [X] DelegatingMultiPlugin (DelegatePathExportImport)

- [X] SearchPrincipalsPlugin (DelegatePathExportImport)

- - [_] DynamicGroupsPlugin (use folderish support, w/ handler for
+ - [X] DynamicGroupsPlugin (use folderish support, w/ handler for
DynamicGroupDefinition? or use a single XML file?)

o Review BasePlugin to ensure we haven't left anything out.
@@ -86,6 +86,7 @@
'_updateFromDOM' -- a method taking the root node of the DOM.
"""
implements(IFilesystemExporter, IFilesystemImporter)
+ encoding = None

def __init__(self, context):
self.context = context
@@ -110,6 +111,8 @@
def import_(self, import_context, subdir, root=False):
""" See IFilesystemImporter
"""
+ self.encoding = import_context.getEncoding()
+
if import_context.shouldPurge():
self._purgeContext()

@@ -122,15 +125,18 @@
root = dom.firstChild
assert root.tagName == self._ROOT_TAGNAME

- title = root.attributes.get('title')
+ self.context.title = self._getNodeAttr(root, 'title', None)
+ self._updateFromDOM(root)

- if title is not None:
- title = title.value
+ def _getNodeAttr(self, node, attrname, default=None):
+ attr = node.attributes.get(attrname)
+ if attr is None:
+ return default
+ value = attr.value
+ if isinstance(value, unicode) and self.encoding is not None:
+ value = value.encode(self.encoding)
+ return value

- self.context.title = title
-
- self._updateFromDOM(root)
-
class ZODBUserManagerExportImport(SimpleXMLExportImport):
""" Adapter for dumping / loading ZODBUSerManager to an XML file.
"""
@@ -144,10 +150,13 @@

def _updateFromDOM(self, root):
for user in root.getElementsByTagName('user'):
- user_id = user.attributes['user_id'].value
- login_name = user.attributes['login_name'].value
- password_hash = user.attributes['password_hash'].value
+ user_id = self._getNodeAttr(user, 'user_id', None)
+ login_name = self._getNodeAttr(user, 'login_name', None)
+ password_hash = self._getNodeAttr(user, 'password_hash', None)

+ if user_id is None or login_name is None or password_hash is None:
+ raise ValueError, 'Invalid user record'
+
self.context.addUser(user_id, login_name, 'x')
self.context._user_passwords[user_id] = password_hash

@@ -181,14 +190,14 @@
def _updateFromDOM(self, root):

for group in root.getElementsByTagName('group'):
- group_id = group.attributes['group_id'].value
- title = group.attributes['title'].value
- description = group.attributes['description'].value
+ group_id = self._getNodeAttr(group, 'group_id', None)
+ title = self._getNodeAttr(group, 'title', None)
+ description = self._getNodeAttr(group, 'description', None)

self.context.addGroup(group_id, title, description)

for principal in group.getElementsByTagName('principal'):
- principal_id = principal.attributes['principal_id'].value
+ principal_id = self._getNodeAttr(principal, 'principal_id', None)
self.context.addPrincipalToGroup(principal_id, group_id)

def _getExportInfo(self):
@@ -227,14 +236,14 @@

def _updateFromDOM(self, root):
for role in root.getElementsByTagName('role'):
- role_id = role.attributes['role_id'].value
- title = role.attributes['title'].value
- description = role.attributes['description'].value
+ role_id = self._getNodeAttr(role, 'role_id', None)
+ title = self._getNodeAttr(role, 'title', None)
+ description = self._getNodeAttr(role, 'description', None)

self.context.addRole(role_id, title, description)

for principal in role.getElementsByTagName('principal'):
- principal_id = principal.attributes['principal_id'].value
+ principal_id = self._getNodeAttr(principal, 'principal_id', None)
self.context.assignRoleToPrincipal(role_id, principal_id)

def _getExportInfo(self):
@@ -272,18 +281,18 @@
pass

def _updateFromDOM(self, root):
- cookie_name = root.attributes.get('cookie_name')
+ cookie_name = self._getNodeAttr(root, 'cookie_name', None)
if cookie_name is not None:
- self.context.cookie_name = cookie_name.value
+ self.context.cookie_name = cookie_name
else:
try:
del self.context.cookie_name
except AttributeError:
pass

- login_path = root.attributes.get('login_path')
+ login_path = self._getNodeAttr(root, 'login_path', None)
if login_path is not None:
- self.context.login_path = login_path.value
+ self.context.login_path = login_path
else:
try:
del self.context.login_path
@@ -307,13 +316,13 @@

def _updateFromDOM(self, root):
for user in root.getElementsByTagName('user'):
- user_id = user.attributes['user_id'].value
+ user_id = self._getNodeAttr(user, 'user_id', None)

for match in user.getElementsByTagName('match'):
- username = match.attributes['username'].value
- match_type = match.attributes['match_type'].value
- match_string = match.attributes['match_string'].value
- role_tokens = match.attributes['roles'].value
+ username = self._getNodeAttr(match, 'username', None)
+ match_type = self._getNodeAttr(match, 'match_type', None)
+ match_string = self._getNodeAttr(match, 'match_string', None)
+ role_tokens = self._getNodeAttr(match, 'roles', None)
roles = role_tokens.split(',')

self.context.manage_addMapping(user_id=user_id,
@@ -362,9 +371,9 @@
pass

def _updateFromDOM(self, root):
- delegate_path = root.attributes.get('delegate_path')
+ delegate_path = self._getNodeAttr(root, 'delegate_path', None)
if delegate_path is not None:
- self.context.delegate_path = delegate_path.value
+ self.context.delegate_path = delegate_path
else:
try:
del self.context.delegate_path
@@ -375,3 +384,44 @@
return {'title': self.context.title,
'delegate_path': self.context.delegate_path,
}
+
+class DynamicGroupsPluginExportImport(SimpleXMLExportImport):
+ """ Adapter for dumping / loading DynamicGroupsPlugin to an XML file.
+ """
+ _FILENAME = 'dynamicgroups.xml'
+ _ROOT_TAGNAME = 'dynamic-groups'
+
+ def _purgeContext(self):
+ for group_id in self.context.listGroupIds():
+ self.context.removeGroup(group_id)
+
+ def _updateFromDOM(self, root):
+ for group in root.getElementsByTagName('group'):
+ group_id = self._getNodeAttr(group, 'group_id', None)
+ predicate = self._getNodeAttr(group, 'predicate', None)
+ title = self._getNodeAttr(group, 'title', None)
+ description = self._getNodeAttr(group, 'description', None)
+ active = self._getNodeAttr(group, 'active', None)
+
+ self.context.addGroup(group_id,
+ predicate,
+ title,
+ description,
+ active == 'True',
+ )
+ def _getExportInfo(self):
+ group_info = []
+
+ for ginfo in self.context.listGroupInfo():
+ group_id = ginfo['id']
+ info = {'group_id': group_id,
+ 'predicate': ginfo['predicate'],
+ 'title': ginfo['title'],
+ 'description': ginfo['description'],
+ 'active': ginfo['active'],
+ }
+ group_info.append(info)
+
+ return {'title': self.context.title,
+ 'groups': group_info,
+ }

Modified: PluggableAuthService/trunk/plugins/tests/test_exportimport.py
===================================================================
--- PluggableAuthService/trunk/plugins/tests/test_exportimport.py 2005-11-16 18:01:36 UTC (rev 40166)
+++ PluggableAuthService/trunk/plugins/tests/test_exportimport.py 2005-11-16 18:50:53 UTC (rev 40167)
@@ -998,6 +998,163 @@
self.assertEqual( plugin.title, None )
self.assertEqual( plugin.delegate_path, DELEGATE_PATH )

+ class DynamicGroupsPluginExportImportTests(_TestBase):
+
+ def _getTargetClass(self):
+ from Products.PluggableAuthService.plugins.exportimport \
+ import DynamicGroupsPluginExportImport
+ return DynamicGroupsPluginExportImport
+
+ def _makePlugin(self, id, *args, **kw):
+ from Products.PluggableAuthService.plugins.DynamicGroupsPlugin \
+ import DynamicGroupsPlugin
+
+ return DynamicGroupsPlugin(id, *args, **kw)
+
+ def test_listExportableItems(self):
+ plugin = self._makePlugin('lEI').__of__(self.root)
+ adapter = self._makeOne(plugin)
+
+ self.assertEqual(len(adapter.listExportableItems()), 0)
+ plugin.addGroup('group_id', 'python:1', 'Group Title' )
+ self.assertEqual(len(adapter.listExportableItems()), 0)
+
+ def test__getExportInfo_empty(self):
+ plugin = self._makePlugin('empty', None).__of__(self.root)
+ adapter = self._makeOne(plugin)
+
+ info = adapter._getExportInfo()
+ self.assertEqual(info['title'], None)
+ self.assertEqual(len(info['groups']), 0)
+
+ def test_export_empty(self):
+ plugin = self._makePlugin('empty', None).__of__(self.root)
+ adapter = self._makeOne(plugin)
+
+ context = DummyExportContext(plugin)
+ adapter.export(context, 'plugins', False)
+
+ self.assertEqual( len( context._wrote ), 1 )
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual( filename, 'plugins/empty.xml' )
+ self._compareDOM( text, _EMPTY_DYNAMIC_GROUPS )
+ self.assertEqual( content_type, 'text/xml' )
+
+ def test__getExportInfo_with_groups(self):
+
+ plugin = self._makePlugin('with_groups').__of__(self.root)
+ plugin.title = 'Plugin Title'
+
+ for g in _DYNAMIC_GROUP_INFO:
+ plugin.addGroup(g['group_id'],
+ g['predicate'],
+ g['title'],
+ g['description'],
+ g['active'],
+ )
+
+ adapter = self._makeOne(plugin)
+
+ info = adapter._getExportInfo()
+ self.assertEqual(info['title'], 'Plugin Title')
+ self.assertEqual(len(info['groups']), len(_DYNAMIC_GROUP_INFO))
+
+ for x, y in zip(info['groups'], _DYNAMIC_GROUP_INFO):
+ self.assertEqual(x, y)
+
+ def test_export_with_groups(self):
+
+ plugin = self._makePlugin('with_groups').__of__(self.root)
+ plugin.title = 'Plugin Title'
+
+ for g in _DYNAMIC_GROUP_INFO:
+ plugin.addGroup(g['group_id'],
+ g['predicate'],
+ g['title'],
+ g['description'],
+ g['active'],
+ )
+
+ adapter = self._makeOne(plugin)
+ context = DummyExportContext(plugin)
+ adapter.export(context, 'plugins', False)
+
+ self.assertEqual( len(context._wrote), 1)
+ filename, text, content_type = context._wrote[ 0 ]
+ self.assertEqual(filename, 'plugins/with_groups.xml')
+ self._compareDOM(text, _FILLED_DYNAMIC_GROUPS)
+ self.assertEqual(content_type, 'text/xml')
+
+ def test_import_empty(self):
+ plugin = self._makePlugin('empty', None).__of__(self.root)
+ adapter = self._makeOne(plugin)
+
+ context = DummyImportContext(plugin, encoding='ascii')
+ context._files['plugins/empty.xml'] = _FILLED_DYNAMIC_GROUPS
+ self.assertEqual(plugin.title, None)
+
+ adapter.import_(context, 'plugins', False)
+
+ found = plugin.listGroupInfo()
+ self.assertEqual(len(found), len(_DYNAMIC_GROUP_INFO))
+ self.assertEqual(plugin.title, 'Plugin Title')
+
+ for finfo, ginfo in zip(found, _DYNAMIC_GROUP_INFO):
+ self.assertEqual(finfo['id'], ginfo['group_id'])
+ self.assertEqual(finfo['predicate'], ginfo['predicate'])
+ self.assertEqual(finfo['title'], ginfo['title'])
+ self.assertEqual(finfo['description'], ginfo['description'])
+ self.assertEqual(finfo['active'], ginfo['active'])
+
+ def test_import_without_purge_leaves_existing_users(self):
+
+ plugin = self._makePlugin('with_groups').__of__(self.root)
+ plugin.title = 'Plugin Title'
+
+ for g in _DYNAMIC_GROUP_INFO:
+ plugin.addGroup(g['group_id'],
+ g['predicate'],
+ g['title'],
+ g['description'],
+ g['active'],
+ )
+
+ adapter = self._makeOne(plugin)
+
+ context = DummyImportContext(plugin, purge=False)
+ context._files['plugins/with_groups.xml'] = _EMPTY_DYNAMIC_GROUPS
+
+ self.assertEqual(len(plugin.listGroupIds()),
+ len(_DYNAMIC_GROUP_INFO))
+ adapter.import_(context, 'plugins', False)
+ self.assertEqual(len(plugin.listGroupIds()),
+ len(_DYNAMIC_GROUP_INFO))
+ self.assertEqual(plugin.title, None)
+
+ def test_import_with_purge_wipes_existing_users(self):
+
+ plugin = self._makePlugin('with_groups').__of__(self.root)
+ plugin.title = 'Plugin Title'
+
+ for g in _DYNAMIC_GROUP_INFO:
+ plugin.addGroup(g['group_id'],
+ g['predicate'],
+ g['title'],
+ g['description'],
+ g['active'],
+ )
+
+ adapter = self._makeOne(plugin)
+
+ context = DummyImportContext(plugin, purge=True)
+ context._files['plugins/with_groups.xml'] = _EMPTY_DYNAMIC_GROUPS
+
+ self.assertEqual(len(plugin.listGroupIds()),
+ len(_DYNAMIC_GROUP_INFO))
+ adapter.import_(context, 'plugins', False)
+ self.assertEqual(len(plugin.listGroupIds()), 0)
+ self.assertEqual(plugin.title, None)
+
def test_suite():
suite = unittest.TestSuite((
unittest.makeSuite(ZODBUserManagerExportImportTests),
@@ -1007,6 +1164,7 @@
unittest.makeSuite(DomainAuthHelperExportImportTests),
unittest.makeSuite(TitleOnlyExportImportTests),
unittest.makeSuite(DelegatePathExportImportTests),
+ unittest.makeSuite(DynamicGroupsPluginExportImportTests),
))
return suite

@@ -1147,5 +1305,45 @@
<delegating-plugin title="%s" delegate_path="%s" />
"""

+_DYNAMIC_GROUP_INFO = ({'group_id': 'group_1',
+ 'title': 'Group 1',
+ 'predicate': 'python:1',
+ 'description': 'First Group',
+ 'active': True,
+ },
+ {'group_id': 'group_2',
+ 'title': 'Group 2',
+ 'predicate': 'python:0',
+ 'description': 'Second Group',
+ 'active': False,
+ },
+ )
+
+_EMPTY_DYNAMIC_GROUPS = """\
+<?xml version="1.0" ?>
+<dynamic-groups>
+</dynamic-groups>
+"""
+
+_FILLED_DYNAMIC_GROUPS = """\
+<?xml version="1.0" ?>
+<dynamic-groups title="Plugin Title">
+<group
+ group_id="group_1"
+ predicate="python:1"
+ title="Group 1"
+ description="First Group"
+ active="True"
+ />
+<group
+ group_id="group_2"
+ predicate="python:0"
+ title="Group 2"
+ description="Second Group"
+ active="False"
+ />
+</dynamic-groups>
+"""
+
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')

Added: PluggableAuthService/trunk/plugins/xml/dynamicgroups.xml
===================================================================
--- PluggableAuthService/trunk/plugins/xml/dynamicgroups.xml 2005-11-16 18:01:36 UTC (rev 40166)
+++ PluggableAuthService/trunk/plugins/xml/dynamicgroups.xml 2005-11-16 18:50:53 UTC (rev 40167)
@@ -0,0 +1,21 @@
+<?xml version="1.0" ?>
+<dynamic-groups xmlns:tal="http://xml.zope.org/namespaces/tal"
+ title="PLUGIN TITLE"
+ tal:define="info options/info;
+ "
+ tal:attributes="title info/title;
+ "
+>
+ <group group_id="GROUP_ID"
+ predicate="PREDICATE"
+ title="TITLE"
+ description="DESCRIPTION"
+ active="ACTIVE"
+ tal:repeat="group info/groups"
+ tal:attributes="group_id group/group_id;
+ predicate group/predicate;
+ title group/title;
+ description group/description;
+ active group/active;
+ " />
+</dynamic-groups>


Property changes on: PluggableAuthService/trunk/plugins/xml/dynamicgroups.xml
___________________________________________________________________
Name: svn:eol-style
+ native

_______________________________________________
Zope-CVS maillist - Zope-CVS@zope.org
http://mail.zope.org/mailman/listinfo/zope-cvs

Zope CVS instructions: http://dev.zope.org/CVS