changeset 4796:7dd5d15de911

Groups2009: BaseGroup and BaseBackend initial import. wiki_group.Group and wiki_group.Backend inherit from those classes. TestWikiGroupNameMapping is added to check group name mapping routines.
author Dmitrijs Milajevs <dimazest@gmail.com>
date Tue, 09 Jun 2009 23:35:01 +0200
parents 64ff4ea0b597
children 4539a7956eac
files MoinMoin/groups/backends/__init__.py MoinMoin/groups/backends/_tests/test_wiki_group.py MoinMoin/groups/backends/wiki_group.py
diffstat 3 files changed, 238 insertions(+), 108 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/groups/backends/__init__.py	Tue Jun 09 23:34:54 2009 +0200
+++ b/MoinMoin/groups/backends/__init__.py	Tue Jun 09 23:35:01 2009 +0200
@@ -0,0 +1,164 @@
+# -*- coding: iso-8859-1 -*-
+"""
+MoinMoin - base classes for group backends.
+
+@copyright: 2009 MoinMoin:DmitrijsMilajevs
+@license: GPL, see COPYING for details
+"""
+
+class BaseGroup(object):
+
+    def __init__(self, request, name, backend):
+        """
+        Initialize a group.
+
+        @param request
+        @param name: moin group name
+        @backend: backend object which created this object
+
+        """
+        self.request = request
+        self.name = name
+        self.backend = backend
+
+        self.to_backend_name = backend.to_backend_name
+        self.to_group_name = backend.to_group_name
+
+        self._load_group()
+
+    def _load_group(self):
+        """
+        Fill in self.members, self.member_groups with data retrieved from the backend.
+        member_groups are moin group names.
+        """
+        raise NotImplementedError()
+
+    def _contains(self, member, processed_groups):
+        """
+        First check if <member> is part of this group and then check
+        for every subgroup in this group.
+
+        <processed_groups> is needed to avoid infinite recursion, if
+        groups are defined recursively.
+
+        @param member: member name [unicode]
+        @param processed_groups: groups which were checked for containment before [set]
+        """
+        processed_groups.add(self.name)
+
+        if member in self.members:
+            return True
+        else:
+            groups = self.request.groups
+            for group_name in self.member_groups:
+                if group_name not in processed_groups and groups[group_name]._contains(member, processed_groups):
+                    return True
+
+        return False
+
+    def __contains__(self, member):
+        """
+        Check if <member> is defined in this group. Checks also for subgroups.
+        """
+        return self._contains(member, set())
+
+    def _iter(self, yielded_members, processed_groups):
+        """
+        Iterate first over members of this group, then over subgroups of this group.
+
+        <yielded_members> and <processed_groups> are needed to avoid infinite recursion.
+        This can happen if there are two groups like these:
+           OneGroup: Something, OtherGroup
+           OtherGroup: OneGroup, SomethingOther
+
+        @param yielded_members: members which have been already yielded before [set]
+        @param processed_groups: group names which have been iterated before [set]
+        """
+        processed_groups.add(self.name)
+
+        for member in self.members:
+            if member not in yielded_members:
+                yield member
+                yielded_members.add(member)
+
+        groups = self.request.groups
+        for group_name in self.member_groups:
+            if group_name not in processed_groups:
+                for member in groups[group_name]._iter(yielded_members, processed_groups):
+                    if member not in yielded_members:
+                        yield member
+                        yielded_members.add(member)
+
+
+    def __iter__(self):
+        """
+        Iterate over members of this group. Iterates also over subgroups if any.
+        """
+        return self._iter(set(), set())
+
+    def __repr__(self):
+        return "<%s name=%s members=%s member_groups=%s>" % (self.__class__,
+                                                                   self.name,
+                                                                   self.members,
+                                                                   self.member_groups)
+
+
+class BaseBackend(object):
+
+    def __init__(self, request):
+        self.request = request
+
+    def __contains__(self, group_name):
+        """
+        Check if a group called <group_name> is available in this backend.
+        """
+        return self._exists_group(group_name)
+
+    def __iter__(self):
+        """
+        Iterate over group names of the groups defined in this backend.
+
+        @return: moin group names
+        """
+        backend_group_names = self._get_group_names()
+        return (self.to_group_name(backend_group_name) for backend_group_name in backend_group_names)
+
+    def __getitem__(self, group_name):
+        """
+        Get a group by its moin group name.
+        """
+        return self._get_group(group_name)
+
+    # These methods should be overridden in children classes.
+    def to_backend_name(self, group_name):
+        """
+        A function mapping the moin group name to the backend group name.
+        """
+        return group_name
+
+    def to_group_name(self, backend_group_name):
+        """
+        A function mapping the backend group name to the moin group name.
+        """
+        return backend_group_name
+
+    def _exists_group(self, group_name):
+        """
+        Check if the group <group_name> is defined in the backend.
+        """
+        raise NotImplementedError()
+
+    def _get_group(self, group_name):
+        """
+        Retrieve a <group_name> group members from the backend.
+
+        @return: a group with retrieved members. [Group]
+        """
+        raise NotImplementedError()
+
+    def _get_group_names(self):
+        """
+        Retrieve moin group names stored in the backend.
+        """
+        raise NotImplementedError()
+
--- a/MoinMoin/groups/backends/_tests/test_wiki_group.py	Tue Jun 09 23:34:54 2009 +0200
+++ b/MoinMoin/groups/backends/_tests/test_wiki_group.py	Tue Jun 09 23:35:01 2009 +0200
@@ -350,5 +350,63 @@
         assert not acl.may(request, u"Someone", "admin")
 
 
+class TestWikiGroupNameMapping(object):
+    """
+    Test group name mapping:
+        moin -> backend (e.g. "AdminGroup" -> "VeryImportantAdminGroup")
+        backend -> moin (e.g. "VeryImportantAdminGroup" -> "AdminGroup")
+
+    Moin expects group names to match the page_group_regex (e.g. "AdminGroup"),
+    but a backend might want to use different group names (e.g. just "Admin").
+    """
+
+    class Config(wikiconfig.Config):
+
+        def group_manager_init(self, request):
+            backend = wiki_group.Backend(request)
+            backend.to_backend_name = lambda group_name: 'VeryImportant%s' % group_name
+            # Get rid of the prefix VeryImportant
+            # Note: In real set up it is more complicated.
+            backend.to_group_name = lambda backend_name: backend_name[13:]
+
+            return GroupManager(backends=[backend])
+
+    def setup_class(self):
+        become_trusted(self.request)
+
+        test_groups = {u'VeryImportantEditorGroup': [u'VeryImportantAdminGroup', u'John', u'JoeDoe', u'Editor'],
+                       u'VeryImportantAdminGroup': [u'Admin', u'Admin2', u'John']}
+
+        self.expanded_groups = {u'EditorGroup': [u'Admin', u'Admin2', u'John',
+                                                 u'JoeDoe', u'Editor'],
+                                u'AdminGroup': [u'Admin', u'Admin2', u'John']}
+
+        for (group, members) in test_groups.iteritems():
+            page_text = ' * %s' % '\n * '.join(members)
+            create_page(self.request, group, page_text)
+
+    def test_contains(self):
+        """
+        Test group_wiki Backend and Group containment methods.
+        """
+        groups = self.request.groups
+
+        for (group, members) in self.expanded_groups.iteritems():
+            print group
+            assert group in groups
+            for member in members:
+                assert member in groups[group]
+
+        raises(KeyError, lambda: groups[u'NotExistingGroup'])
+
+    def test_iter(self):
+        groups = self.request.groups
+
+        for (group, members) in self.expanded_groups.iteritems():
+            returned_members = [x for x in groups[group]]
+            assert len(returned_members) == len(members)
+            for member in members:
+                assert member in returned_members
+
 coverage_modules = ['MoinMoin.groups.backends.wiki_group']
 
--- a/MoinMoin/groups/backends/wiki_group.py	Tue Jun 09 23:34:54 2009 +0200
+++ b/MoinMoin/groups/backends/wiki_group.py	Tue Jun 09 23:35:01 2009 +0200
@@ -17,36 +17,24 @@
 
 from MoinMoin import caching, wikiutil
 from MoinMoin.Page import Page
+from MoinMoin.groups.backends import BaseGroup, BaseBackend
 
 
-class Group(object):
+class Group(BaseGroup):
 
     # * Member - ignore all but first level list items, strip
     # whitespace, strip free links markup. This is used for parsing
     # pages in order to find group page members
     group_page_parse_re = re.compile(ur'^ \* +(?:\[\[)?(?P<member>.+?)(?:\]\])? *$', re.MULTILINE | re.UNICODE)
 
-    def __init__(self, request, name, backend):
-        """
-        Initialize a wiki group.
-
-        @parm request: request object
-        @parm name: group name (== group page name)
-        """
-        self.request = request
-        self.name = name
-        self.backend = backend
-
-        self._load_group()
-
     def _load_group(self):
         request = self.request
-        group_name = self.name
+        backend_group_name = self.to_backend_name(self.name)
 
-        page = Page(request, group_name)
+        page = Page(request, backend_group_name)
         if page.exists():
             arena = 'pagegroups'
-            key = wikiutil.quoteWikinameFS(group_name)
+            key = wikiutil.quoteWikinameFS(backend_group_name)
             cache = caching.CacheEntry(request, arena, key, scope='wiki', use_pickle=True)
             try:
                 cache_mtime = cache.mtime()
@@ -63,7 +51,7 @@
                 self.members, self.member_groups = self._parse_page(text)
                 cache.update((self.members, self. member_groups))
         else:
-            raise KeyError("There is no such group page %s" % group_name)
+            raise KeyError("There is no such group page %s" % backend_group_name)
 
     def _parse_page(self, text):
         """
@@ -77,107 +65,27 @@
 
         for member in text_members:
             if self.request.cfg.cache.page_group_regexact.match(member):
-                member_groups.add(member)
+                member_groups.add(self.to_group_name(member))
             else:
                 members_final.add(member)
 
         return members_final, member_groups
 
-    def _contains(self, member, processed_groups):
-        """
-        First check if <member> is part of this group and then check
-        for every subgroup in this group.
-
-        <processed_groups> is needed to avoid infinite recursion, if
-        groups are defined recursively.
-
-        @param member: member name [unicode]
-        @param processed_groups: groups which were checked for containment before [set]
-        """
-        processed_groups.add(self.name)
-
-        if member in self.members:
-            return True
-        else:
-            groups = self.request.groups
-            for group_name in self.member_groups:
-                if group_name not in processed_groups and groups[group_name]._contains(member, processed_groups):
-                    return True
-
-        return False
-
-    def __contains__(self, member):
-        """
-        Check if <member> is defined in this group. Checks also for subgroups.
-        """
-        return self._contains(member, set())
-
-    def _iter(self, yielded_members, processed_groups):
-        """
-        Iterate first over members of this group, then over subgroups of this group.
 
-        <yielded_members> and <processed_groups> are needed to avoid infinite recursion.
-        This can happen if there are two groups like these:
-           OneGroup: Something, OtherGroup
-           OtherGroup: OneGroup, SomethingOther
-
-        @param yielded_members: members which have been already yielded before [set]
-        @param processed_groups: group names which have been iterated before [set]
-        """
-        processed_groups.add(self.name)
-
-        for member in self.members:
-            if member not in yielded_members:
-                yield member
-                yielded_members.add(member)
-
-        groups = self.request.groups
-        for group_name in self.member_groups:
-            if group_name not in processed_groups:
-                for member in groups[group_name]._iter(yielded_members, processed_groups):
-                    if member not in yielded_members:
-                        yield member
-                        yielded_members.add(member)
-
-
-    def __iter__(self):
-        """
-        Iterate over members of this group. Iterates also over subgroups if any.
-        """
-        return self._iter(set(), set())
-
-    def __repr__(self):
-        return "<%s group_name=%s members=%s member_groups=%s>" % (self.__class__,
-                                                                   self.name,
-                                                                   self.members,
-                                                                   self.member_groups)
-
-
-class Backend(object):
+class Backend(BaseBackend):
 
     def __init__(self, request):
-        """
-        Create a group manager backend object.
-        """
-        self.request = request
+        super(Backend, self).__init__(request)
+
         self.page_group_regex = request.cfg.cache.page_group_regexact
 
-    def __contains__(self, group_name):
-        """
-        Check if there is group page <group_name>. <group_name> must satisfy page_group_regex.
-        """
-        return self.page_group_regex.match(group_name) and Page(self.request, group_name).exists()
+    def _exists_group(self, group_name):
+        backend_group_name = self.to_backend_name(group_name)
+        return self.page_group_regex.match(group_name) and Page(self.request, backend_group_name).exists()
 
-    def __iter__(self):
-        """
-        Iterate over group names of groups available in the wiki.
-        """
-        grouppages = self.request.rootpage.getPageList(user='', filter=self.page_group_regex.search)
-        return iter(grouppages)
+    def _get_group_names(self):
+        return self.request.rootpage.getPageList(user='', filter=self.page_group_regex.search)
 
-    def __getitem__(self, group_name):
-        """
-        Return wiki group backend object.
-        """
+    def _get_group(self, group_name):
         return Group(request=self.request, name=group_name, backend=self)