[CalendarServer-changes] [11902] CalendarServer/branches/users/sagen/groupcacher

source_changes at macosforge.org source_changes at macosforge.org
Wed Mar 12 11:23:13 PDT 2014


Revision: 11902
          http://trac.calendarserver.org//changeset/11902
Author:   sagen at apple.com
Date:     2013-11-07 10:24:00 -0800 (Thu, 07 Nov 2013)
Log Message:
-----------
Clean up the API a bit, and more testing

Modified Paths:
--------------
    CalendarServer/branches/users/sagen/groupcacher/twext/who/delegates.py
    CalendarServer/branches/users/sagen/groupcacher/twext/who/groups.py
    CalendarServer/branches/users/sagen/groupcacher/twext/who/test/test_delegates.py
    CalendarServer/branches/users/sagen/groupcacher/twext/who/test/test_groups.py
    CalendarServer/branches/users/sagen/groupcacher/txdav/common/datastore/sql.py

Modified: CalendarServer/branches/users/sagen/groupcacher/twext/who/delegates.py
===================================================================
--- CalendarServer/branches/users/sagen/groupcacher/twext/who/delegates.py	2013-11-07 17:02:26 UTC (rev 11901)
+++ CalendarServer/branches/users/sagen/groupcacher/twext/who/delegates.py	2013-11-07 18:24:00 UTC (rev 11902)
@@ -34,19 +34,23 @@
     if delegate.recordType == RecordType.group:
         # find the groupID
         groupID, name, membershipHash = (yield txn.groupByGUID(delegate.guid))
-        yield txn.addDelegate(delegator.guid, groupID,
-            1 if readWrite else 0, True)
+        yield txn.addDelegateGroup(delegator.guid, groupID, readWrite)
     else:
-        yield txn.addDelegate(delegator.guid, delegate.guid,
-            1 if readWrite else 0, False)
+        yield txn.addDelegate(delegator.guid, delegate.guid, readWrite)
         
 
+ at inlineCallbacks
 def removeDelegate(txn, delegator, delegate, readWrite):
     """
     Args are records
     """
-    return txn.removeDelegate(delegator.guid, delegate.guid,
-        1 if readWrite else 0, delegate.recordType==RecordType.group)
+    if delegate.recordType == RecordType.group:
+        # find the groupID
+        groupID, name, membershipHash = (yield txn.groupByGUID(delegate.guid))
+        yield txn.removeDelegateGroup(delegator.guid, groupID, readWrite)
+    else:
+        yield txn.removeDelegate(delegator.guid, delegate.guid,
+            readWrite)
 
 
 @inlineCallbacks
@@ -56,32 +60,30 @@
     """
     records = []
     directory = delegator.service
-    results = (yield txn.delegates(delegator.guid, 1 if readWrite else 0))
-    for row in results:
-        if row[0] != delegator.guid:
-            record = (yield directory.recordWithGUID(row[0]))
+    delegateGUIDs = (yield txn.delegates(delegator.guid, readWrite))
+    for guid in delegateGUIDs:
+        if guid != delegator.guid:
+            record = (yield directory.recordWithGUID(guid))
             if record is not None:
                 records.append(record)
     returnValue(records)
 
 
 @inlineCallbacks
-def delegateFor(txn, delegate, readWrite):
+def delegatedTo(txn, delegate, readWrite):
     """
     Args are records
     """
     records = []
     directory = delegate.service
-    results = (yield txn.delegators(delegate.guid, 1 if readWrite else 0))
-    for row in results:
-        if row[0] != delegate.guid:
-            record = (yield directory.recordWithGUID(row[0]))
+    delegatorGUIDs = (yield txn.delegators(delegate.guid, readWrite))
+    for guid in delegatorGUIDs:
+        if guid != delegate.guid:
+            record = (yield directory.recordWithGUID(guid))
             if record is not None:
                 records.append(record)
     returnValue(records)
 
 
- at inlineCallbacks
 def allGroupDelegates(txn):
-    results = (yield txn.allGroupDelegates())
-    returnValue([r[0] for r in results])
+    return txn.allGroupDelegates()

Modified: CalendarServer/branches/users/sagen/groupcacher/twext/who/groups.py
===================================================================
--- CalendarServer/branches/users/sagen/groupcacher/twext/who/groups.py	2013-11-07 17:02:26 UTC (rev 11901)
+++ CalendarServer/branches/users/sagen/groupcacher/twext/who/groups.py	2013-11-07 18:24:00 UTC (rev 11902)
@@ -27,6 +27,7 @@
 from twisted.internet.defer import inlineCallbacks, returnValue, succeed
 from twext.enterprise.dal.syntax import Delete
 from twext.who.idirectory import RecordType
+from twext.who.delegates import allGroupDelegates
 
 from twext.python.log import Logger
 log = Logger()
@@ -156,7 +157,9 @@
 
     @inlineCallbacks
     def update(self, txn):
-        # Pull in external proxy assignments and stick in proxy db
+        # Pull in external delegate assignments and stick in delegate db
+        # TODO
+
         # Figure out which groups matter
         groupGUIDs = yield self.groupsToRefresh()
         # For each of those groups, create a per-group refresh work item
@@ -166,9 +169,7 @@
             yield txn.enqueue(GroupRefreshWork,
                 groupGUID=groupGUID, notBefore=notBefore)
 
-        pass
 
-
     @inlineCallbacks
     def refreshGroup(self, txn, groupGUID):
         # Does the work of a per-group refresh work item
@@ -253,21 +254,11 @@
 
 
     @inlineCallbacks
-    def groupsToRefresh(self):
-        delegatedGUIDs = set((yield self.proxyDB.getAllMembers()))
-        self.log.info("There are %d proxies" % (len(delegatedGUIDs),))
-        self.log.info("Retrieving group hierarchy from directory")
+    def groupsToRefresh(self, txn):
+        delegatedGUIDs = set((yield allGroupDelegates(txn)))
+        self.log.info("There are %d group delegates" % (len(delegatedGUIDs),))
 
-        # "groups" maps a group to its members; the keys and values consist
-        # of whatever directory attribute is used to refer to members.  The
-        # attribute value comes from record.cachedGroupsAlias().
-        # "aliases" maps the record.cachedGroupsAlias() value for a group
-        # back to the group's guid.
-        groups, aliases = (yield self.getGroups(guids=delegatedGUIDs))
-        groupGUIDs = set(aliases.keys())
-        self.log.info("%d groups retrieved from the directory" %
-            (len(groupGUIDs),))
+        # TODO: Retrieve the set of attendee group guids
+        attendeeGroupGUIDs = set()
 
-        delegatedGUIDs = delegatedGUIDs.intersection(groupGUIDs)
-        self.log.info("%d groups are proxies" % (len(delegatedGUIDs),))
-        returnValue(delegatedGUIDs)
+        returnValue(delegatedGUIDs.union(attendeeGroupGUIDs))

Modified: CalendarServer/branches/users/sagen/groupcacher/twext/who/test/test_delegates.py
===================================================================
--- CalendarServer/branches/users/sagen/groupcacher/twext/who/test/test_delegates.py	2013-11-07 17:02:26 UTC (rev 11901)
+++ CalendarServer/branches/users/sagen/groupcacher/twext/who/test/test_delegates.py	2013-11-07 18:24:00 UTC (rev 11902)
@@ -19,12 +19,13 @@
 """
 
 from twext.who.delegates import (
-    addDelegate, removeDelegate, delegatesOf, delegateFor, allGroupDelegates
+    addDelegate, removeDelegate, delegatesOf, delegatedTo, allGroupDelegates
 )
 from twext.who.groups import GroupCacher
 from twext.who.test.test_xml import xmlService
 from twisted.internet.defer import inlineCallbacks
 from twistedcaldav.test.util import StoreTestCase
+from twext.who.idirectory import RecordType
 
 class DelegationTest(StoreTestCase):
 
@@ -53,7 +54,7 @@
         yield addDelegate(txn, delegator, delegate1, True)
         delegates = (yield delegatesOf(txn, delegator, True))
         self.assertEquals(["sagen"], [d.shortNames[0] for d in delegates])
-        delegators = (yield delegateFor(txn, delegate1, True))
+        delegators = (yield delegatedTo(txn, delegate1, True))
         self.assertEquals(["wsanchez"], [d.shortNames[0] for d in delegators])
 
         # Add another delegate
@@ -61,21 +62,21 @@
         delegates = (yield delegatesOf(txn, delegator, True))
         self.assertEquals(set(["sagen", "cdaboo"]),
             set([d.shortNames[0] for d in delegates]))
-        delegators = (yield delegateFor(txn, delegate2, True))
+        delegators = (yield delegatedTo(txn, delegate2, True))
         self.assertEquals(["wsanchez"], [d.shortNames[0] for d in delegators])
 
         # Remove 1 delegate
         yield removeDelegate(txn, delegator, delegate1, True)
         delegates = (yield delegatesOf(txn, delegator, True))
         self.assertEquals(["cdaboo"], [d.shortNames[0] for d in delegates])
-        delegators = (yield delegateFor(txn, delegate1, True))
+        delegators = (yield delegatedTo(txn, delegate1, True))
         self.assertEquals(0, len(delegators))
 
         # Remove the other delegate
         yield removeDelegate(txn, delegator, delegate2, True)
         delegates = (yield delegatesOf(txn, delegator, True))
         self.assertEquals(0, len(delegates))
-        delegators = (yield delegateFor(txn, delegate2, True))
+        delegators = (yield delegatedTo(txn, delegate2, True))
         self.assertEquals(0, len(delegators))
 
 
@@ -85,8 +86,9 @@
         txn = store.newTransaction()
 
         delegator = yield self.xmlService.recordWithUID("__wsanchez__")
+        delegate1 = yield self.xmlService.recordWithUID("__sagen__")
         group1 = yield self.xmlService.recordWithUID("__top_group_1__")
-        delegate1 = yield self.xmlService.recordWithUID("__sagen__")
+        group2 = yield self.xmlService.recordWithUID("__sub_group_1__")
 
         # Add group delegate, but before the group membership has been
         # pulled in
@@ -96,16 +98,16 @@
 
         # Now refresh the group and there will be 3 delegates (contained
         # within 2 nested groups)
-        guid = "49b350c69611477b94d95516b13856ab"
-        yield self.groupCacher.refreshGroup(txn, guid)
+        # guid = "49b350c69611477b94d95516b13856ab"
+        yield self.groupCacher.refreshGroup(txn, group1.guid)
+        yield self.groupCacher.refreshGroup(txn, group2.guid)
         delegates = (yield delegatesOf(txn, delegator, True))
         self.assertEquals(set(["sagen", "cdaboo", "glyph"]),
             set([d.shortNames[0] for d in delegates]))
-        delegators = (yield delegateFor(txn, delegate1, True))
+        delegators = (yield delegatedTo(txn, delegate1, True))
         self.assertEquals(["wsanchez"], [d.shortNames[0] for d in delegators])
 
         # Verify we can ask for all delegated-to groups
-        group2 = yield self.xmlService.recordWithUID("__sub_group_1__")
         yield addDelegate(txn, delegator, group2, True)
         groups = (yield allGroupDelegates(txn))
         self.assertEquals(
@@ -114,8 +116,39 @@
                 "86144f73345a409782f1b782672087c7"
                 ]), set(groups))
 
+        # Delegate to a user who is already indirectly delegated-to 
+        yield addDelegate(txn, delegator, delegate1, True)
+        delegates = (yield delegatesOf(txn, delegator, True))
+        self.assertEquals(set(["sagen", "cdaboo", "glyph"]),
+            set([d.shortNames[0] for d in delegates]))
 
+        # Add a member to the group; they become a delegate
+        newSet = set()
+        for name in ("wsanchez", "cdaboo", "sagen", "glyph", "dre"):
+            record = (yield self.xmlService.recordWithShortName(RecordType.user,
+                name))
+            newSet.add(record.guid)
+        groupID, name, membershipHash = (yield txn.groupByGUID(group1.guid))
+        numAdded, numRemoved = (yield self.groupCacher.synchronizeMembers(txn,
+            groupID, newSet))
+        delegates = (yield delegatesOf(txn, delegator, True))
+        self.assertEquals(set(["sagen", "cdaboo", "glyph", "dre"]),
+            set([d.shortNames[0] for d in delegates]))
 
+        # Remove delegate access from the top group
+        yield removeDelegate(txn, delegator, group1, True)
+        delegates = (yield delegatesOf(txn, delegator, True))
+        self.assertEquals(set(["sagen", "cdaboo"]),
+            set([d.shortNames[0] for d in delegates]))
+
+        # Remove delegate access from the sub group
+        yield removeDelegate(txn, delegator, group2, True)
+        delegates = (yield delegatesOf(txn, delegator, True))
+        self.assertEquals(set(["sagen"]),
+            set([d.shortNames[0] for d in delegates]))
+
+
+
 testXMLConfig = """<?xml version="1.0" encoding="utf-8"?>
 
 <directory realm="xyzzy">

Modified: CalendarServer/branches/users/sagen/groupcacher/twext/who/test/test_groups.py
===================================================================
--- CalendarServer/branches/users/sagen/groupcacher/twext/who/test/test_groups.py	2013-11-07 17:02:26 UTC (rev 11901)
+++ CalendarServer/branches/users/sagen/groupcacher/twext/who/test/test_groups.py	2013-11-07 18:24:00 UTC (rev 11902)
@@ -75,15 +75,19 @@
         self.assertEquals(membershipHash, "e90052eb63d47f32d5b03df0073f7854")
 
         results = (yield txn.membersOfGroup(groupID))
-        for row in results:
-            print row[0]
+        self.assertEquals(
+            set(["9064df911dbc4e079c2b6839b0953876",
+                 "4ad155cbae9b475f986ce08a7537893e",
+                 "3bdcb95484d54f6d8035eac19a6d6e1f",
+                 "7d45cb10479e456bb54d528958c5734b"]),
+            set([r[0] for r in results])
+        )
 
         records = (yield self.groupCacher.cachedMembers(txn, groupID))
         self.assertEquals(
             set([r.shortNames[0] for r in records]),
             set(["wsanchez", "cdaboo", "glyph", "sagen"])
         )
-        print records
 
 
     @inlineCallbacks

Modified: CalendarServer/branches/users/sagen/groupcacher/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/sagen/groupcacher/txdav/common/datastore/sql.py	2013-11-07 17:02:26 UTC (rev 11901)
+++ CalendarServer/branches/users/sagen/groupcacher/txdav/common/datastore/sql.py	2013-11-07 18:24:00 UTC (rev 11902)
@@ -1016,6 +1016,7 @@
                        de.READ_WRITE: Parameter("readWrite"),
                        })
 
+
     @classproperty
     def _addDelegateGroupQuery(cls): #@NoSelf
         ds = schema.DELEGATE_GROUPS
@@ -1024,6 +1025,7 @@
                        ds.READ_WRITE: Parameter("readWrite"),
                        })
 
+
     @classproperty
     def _removeDelegateQuery(cls): #@NoSelf
         de = schema.DELEGATES
@@ -1033,6 +1035,7 @@
                    de.READ_WRITE == Parameter("readWrite"))
             )
 
+
     @classproperty
     def _removeDelegateGroupQuery(cls): #@NoSelf
         ds = schema.DELEGATE_GROUPS
@@ -1042,6 +1045,7 @@
                    ds.READ_WRITE == Parameter("readWrite"))
             )
 
+
     @classproperty
     def _selectDelegatesQuery(cls): #@NoSelf
         de = schema.DELEGATES
@@ -1050,6 +1054,7 @@
                     de.READ_WRITE == Parameter("readWrite"))
                 )
 
+
     @classproperty
     def _selectDelegateGroupsQuery(cls): #@NoSelf
         ds = schema.DELEGATE_GROUPS
@@ -1059,6 +1064,7 @@
                     ds.READ_WRITE == Parameter("readWrite"))
                 )
 
+
     @classproperty
     def _selectDirectDelegatorsQuery(cls): #@NoSelf
         de = schema.DELEGATES
@@ -1068,17 +1074,6 @@
                     de.READ_WRITE == Parameter("readWrite"))
                 )
 
-    """
-    @classproperty
-    def _selectDelegatorsGroupsQuery(cls): #@NoSelf
-        ds = schema.DELEGATE_GROUPS
-        return Select([ds.DELEGATOR], From=ds,
-                Where=(
-                    ds.GROUP_ID == Parameter("groupID").And(
-                    ds.READ_WRITE == Parameter("readWrite"))
-                )
-            )
-    """
 
     @classproperty
     def _selectIndirectDelegatorsQuery(cls): #@NoSelf
@@ -1101,6 +1096,7 @@
             )
         )
 
+
     @classproperty
     def _selectIndirectDelegatesQuery(cls): #@NoSelf
         dg = schema.DELEGATE_GROUPS
@@ -1121,70 +1117,166 @@
             )
         )
 
-    def addDelegate(self, delegator, delegate, readWrite, isGroup):
-        if isGroup:
-            return self._addDelegateGroupQuery.on(self, delegator=delegator,
-                groupID=delegate, readWrite=readWrite)
-        else:
-            return self._addDelegateQuery.on(self, delegator=delegator,
-                delegate=delegate, readWrite=readWrite)
 
-    def removeDelegate(self, delegator, delegate, readWrite, isGroup):
-        if isGroup:
-            return self._removeDelegateGroupQuery.on(self, delegator=delegator,
-                groupID=delegate, readWrite=readWrite)
-        else:
-            return self._removeDelegateQuery.on(self, delegator=delegator,
-                delegate=delegate, readWrite=readWrite)
+    def addDelegate(self, delegator, delegate, readWrite):
+        """
+        Adds a row to the DELEGATES table.  The delegate should not be a
+        group.  To delegate to a group, call addDelegateGroup() instead.
 
-    """
-    def directDelegates(self, delegator, readWrite):
-        return self._selectDelegatesQuery.on(self, delegator=delegator,
-            readWrite=readWrite)
+        @param delegator: the GUID of the delegator
+        @type delegator: C{str} in normalized form (lowercase, no dashes)
+        @param delegate: the GUID of the delegate
+        @type delegate: C{str} in normalized form (lowercase, no dashes)
+        @param readWrite: grant read and write access if True, otherwise
+            read-only access
+        @type readWrite: C{boolean}
+        """
+        return self._addDelegateQuery.on(self, delegator=delegator,
+            delegate=delegate, readWrite=1 if readWrite else 0)
 
-    def groupDelegates(self, delegator, readWrite):
-        return self._selectDelegateGroupssQuery.on(self, delegator=delegator,
-            readWrite=readWrite)
-    """
 
+    def addDelegateGroup(self, delegator, delegateGroupID, readWrite):
+        """
+        Adds a row to the DELEGATE_GROUPS table.  The delegate should be a
+        group.  To delegate to a person, call addDelegate() instead.
+
+        @param delegator: the GUID of the delegator
+        @type delegator: C{str} in normalized form (lowercase, no dashes)
+        @param delegateGroupID: the GROUP_ID of the delegate group
+        @type delegateGroupID: C{int}
+        @param readWrite: grant read and write access if True, otherwise
+            read-only access
+        @type readWrite: C{boolean}
+        """
+        return self._addDelegateGroupQuery.on(self, delegator=delegator,
+            groupID=delegateGroupID, readWrite=1 if readWrite else 0)
+
+
+    def removeDelegate(self, delegator, delegate, readWrite):
+        """
+        Removes a row from the DELEGATES table.  The delegate should not be a
+        group.  To remove a delegate group, call removeDelegateGroup() instead.
+
+        @param delegator: the GUID of the delegator
+        @type delegator: C{str} in normalized form (lowercase, no dashes)
+        @param delegate: the GUID of the delegate
+        @type delegate: C{str} in normalized form (lowercase, no dashes)
+        @param readWrite: remove read and write access if True, otherwise
+            read-only access
+        @type readWrite: C{boolean}
+        """
+        return self._removeDelegateQuery.on(self, delegator=delegator,
+            delegate=delegate, readWrite=1 if readWrite else 0)
+
+
+    def removeDelegateGroup(self, delegator, delegateGroupID, readWrite):
+        """
+        Removes a row from the DELEGATE_GROUPS table.  The delegate should be a
+        group.  To remove a delegate person, call removeDelegate() instead.
+
+        @param delegator: the GUID of the delegator
+        @type delegator: C{str} in normalized form (lowercase, no dashes)
+        @param delegateGroupID: the GROUP_ID of the delegate group
+        @type delegateGroupID: C{int}
+        @param readWrite: remove read and write access if True, otherwise
+            read-only access
+        @type readWrite: C{boolean}
+        """
+        return self._removeDelegateGroupQuery.on(self, delegator=delegator,
+            groupID=delegateGroupID, readWrite=1 if readWrite else 0)
+
+
     @inlineCallbacks
     def delegates(self, delegator, readWrite):
+        """
+        Returns the GUIDs of all delegates for the given delegator.  If
+        delegate access was granted to any groups, those groups' members
+        (flattened) will be included. No GUIDs of the groups themselves
+        will be returned.
 
+        @param delegator: the GUID of the delegator
+        @type delegator: C{str} in normalized form (lowercase, no dashes)
+        @param readWrite: the access-type to check for; read and write
+            access if True, otherwise read-only access
+        @type readWrite: C{boolean}
+        @returns: the GUIDs of the delegates (for the specified access
+            type)
+        @rtype: a Deferred resulting in a set
+        """
+        delegates = set()
+
         # First get the direct delegates
         results = (yield self._selectDelegatesQuery.on(self,
-            delegator=delegator, readWrite=readWrite))
+            delegator=delegator, readWrite=1 if readWrite else 0))
+        for row in results:
+            delegates.add(row[0])
 
         # Finally get those who are in groups which have been delegated to
-        results.extend((yield self._selectIndirectDelegatesQuery.on(self,
-            delegator=delegator, readWrite=readWrite)))
+        results = (yield self._selectIndirectDelegatesQuery.on(self,
+            delegator=delegator, readWrite=1 if readWrite else 0))
+        for row in results:
+            delegates.add(row[0])
 
-        returnValue(results)
+        returnValue(delegates)
 
 
     @inlineCallbacks
     def delegators(self, delegate, readWrite):
+        """
+        Returns the GUIDs of all delegators which have granted access to
+        the given delegate, either directly or indirectly via groups.
 
+        @param delegate: the GUID of the delegate
+        @type delegate: C{str} in normalized form (lowercase, no dashes)
+        @param readWrite: the access-type to check for; read and write
+            access if True, otherwise read-only access
+        @type readWrite: C{boolean}
+        @returns: the GUIDs of the delegators (for the specified access
+            type)
+        @rtype: a Deferred resulting in a set
+        """
+        delegators = set()
+
         # First get the direct delegators
         results = (yield self._selectDirectDelegatorsQuery.on(self,
-            delegate=delegate, readWrite=readWrite))
+            delegate=delegate, readWrite=1 if readWrite else 0))
+        for row in results:
+            delegators.add(row[0])
 
         # Finally get those who have delegated to groups the delegate
         # is a member of
-        results.extend((yield self._selectIndirectDelegatorsQuery.on(self,
-            delegate=delegate, readWrite=readWrite)))
-        returnValue(results)
+        results = (yield self._selectIndirectDelegatorsQuery.on(self,
+            delegate=delegate, readWrite=1 if readWrite else 0))
+        for row in results:
+            delegators.add(row[0])
 
+        returnValue(delegators)
 
+
+    @inlineCallbacks
     def allGroupDelegates(self):
+        """
+        Return the GUIDs of all groups which have been delegated to.  Useful
+        for obtaining the set of groups which need to be synchronized from
+        the directory.
+
+        @returns: the GUIDs of all delegated-to groups
+        @rtype: a Deferred resulting in a set
+        """
         gr = schema.GROUPS
         dg = schema.DELEGATE_GROUPS
 
-        return Select(
+        results = (yield Select(
             [gr.GROUP_GUID],
             From=gr,
             Where=(gr.GROUP_ID.In(Select([dg.GROUP_ID], From=dg, Where=None)))
-        ).on(self)
+        ).on(self))
+        delegates = set()
+        for row in results:
+            delegates.add(row[0])
 
+        returnValue(delegates)
+
     # End of Delegates
 
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140312/b9047bb9/attachment.html>


More information about the calendarserver-changes mailing list