[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