[Zope-CVS] SVN: PluggableAuthService/trunk/plugins/ Add adapter for DynamicGroupsPlugin.

Tres Seaver tseaver at palladion.com
Wed Nov 16 13:50:54 EST 2005


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



More information about the Zope-CVS mailing list