[CalendarServer-changes] [3146] CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Mon Oct 13 12:59:14 PDT 2008
Revision: 3146
http://trac.macosforge.org/projects/calendarserver/changeset/3146
Author: cdaboo at apple.com
Date: 2008-10-13 12:59:14 -0700 (Mon, 13 Oct 2008)
Log Message:
-----------
Index the directory-based proxy relationships and add two new properties to principal resources
that contain the list of fully expanded proxy-for principals.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/customxml.py
CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/appleopendirectory.py
CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/principal.py
CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/test/test_proxyprincipalmembers.py
CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/extensions.py
CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/resource.py
Modified: CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/customxml.py 2008-10-13 19:01:58 UTC (rev 3145)
+++ CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/customxml.py 2008-10-13 19:59:14 UTC (rev 3146)
@@ -23,6 +23,7 @@
change.
"""
+from twisted.web2.dav.davxml import dav_namespace
from twisted.web2.dav.davxml import twisted_dav_namespace
from twisted.web2.dav import davxml
@@ -96,6 +97,30 @@
namespace = calendarserver_namespace
name = "calendar-proxy-write"
+class CalendarProxyReadFor (davxml.WebDAVElement):
+ """
+ List of principals granting read-only proxy status.
+ (Apple Extension to CalDAV)
+ """
+ namespace = calendarserver_namespace
+ name = "calendar-proxy-read-for"
+ hidden = True
+ protected = True
+
+ allowed_children = { (dav_namespace, "href"): (0, None) }
+
+class CalendarProxyWriteFor (davxml.WebDAVElement):
+ """
+ List of principals granting read-write proxy status.
+ (Apple Extension to CalDAV)
+ """
+ namespace = calendarserver_namespace
+ name = "calendar-proxy-write-for"
+ hidden = True
+ protected = True
+
+ allowed_children = { (dav_namespace, "href"): (0, None) }
+
class TwistedCalendarPrincipalURI(davxml.WebDAVTextElement):
"""
Contains the calendarPrincipalURI value for a directory record corresponding to a principal.
Modified: CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/appleopendirectory.py 2008-10-13 19:01:58 UTC (rev 3145)
+++ CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/appleopendirectory.py 2008-10-13 19:59:14 UTC (rev 3146)
@@ -23,7 +23,6 @@
"OpenDirectoryInitError",
]
-import itertools
import sys
from random import random
from uuid import UUID
@@ -308,8 +307,24 @@
except KeyError:
return ()
- def _indexGroup(self, group, index):
- for guid in group._memberGUIDs:
+ def proxiesForGUID(self, recordType, guid):
+
+ # Lookup in index
+ try:
+ return self._storage(recordType)["proxiesForGUID"][guid]
+ except KeyError:
+ return ()
+
+ def readOnlyProxiesForGUID(self, recordType, guid):
+
+ # Lookup in index
+ try:
+ return self._storage(recordType)["readOnlyProxiesForGUID"][guid]
+ except KeyError:
+ return ()
+
+ def _indexGroup(self, group, guids, index):
+ for guid in guids:
index.setdefault(guid, set()).add(group)
_ODFields = {
@@ -397,6 +412,9 @@
if recordType == DirectoryService.recordType_groups:
groupsForGUID = {}
+ elif recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ proxiesForGUID = {}
+ readOnlyProxiesForGUID = {}
else:
storage = self._records[recordType]
@@ -408,6 +426,9 @@
if recordType == DirectoryService.recordType_groups:
groupsForGUID = storage["groupsForGUID"]
+ elif recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ proxiesForGUID = storage["proxiesForGUID"]
+ readOnlyProxiesForGUID = storage["readOnlyProxiesForGUID"]
enabled_count = 0
for (recordShortName, value) in results:
@@ -551,8 +572,13 @@
# Do group indexing if needed
if recordType == DirectoryService.recordType_groups:
- self._indexGroup(record, groupsForGUID)
+ self._indexGroup(record, record._memberGUIDs, groupsForGUID)
+ # Do proxy indexing if needed
+ elif recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ self._indexGroup(record, record._proxyGUIDs, proxiesForGUID)
+ self._indexGroup(record, record._readOnlyProxyGUIDs, readOnlyProxiesForGUID)
+
if shortName is None and guid is None:
#
# Replace the entire cache
@@ -569,6 +595,11 @@
if recordType == DirectoryService.recordType_groups:
storage["groupsForGUID"] = groupsForGUID
+ # Add proxy indexing if needed
+ elif recordType in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
+ storage["proxiesForGUID"] = proxiesForGUID
+ storage["readOnlyProxiesForGUID"] = readOnlyProxiesForGUID
+
def rot():
storage["status"] = "stale"
removals = set()
@@ -772,12 +803,10 @@
yield proxyRecord
def proxyFor(self):
- for proxyRecord in itertools.chain(
- self.service.recordsForType(DirectoryService.recordType_resources).itervalues(),
- self.service.recordsForType(DirectoryService.recordType_locations).itervalues(),
- ):
- if self.guid in proxyRecord._proxyGUIDs:
- yield proxyRecord
+ result = set()
+ result.update(self.service.proxiesForGUID(DirectoryService.recordType_resources, self.guid))
+ result.update(self.service.proxiesForGUID(DirectoryService.recordType_locations, self.guid))
+ return result
def readOnlyProxies(self):
if self.recordType not in (DirectoryService.recordType_resources, DirectoryService.recordType_locations):
@@ -791,12 +820,10 @@
yield proxyRecord
def readOnlyProxyFor(self):
- for proxyRecord in itertools.chain(
- self.service.recordsForType(DirectoryService.recordType_resources).itervalues(),
- self.service.recordsForType(DirectoryService.recordType_locations).itervalues(),
- ):
- if self.guid in proxyRecord._readOnlyProxyGUIDs:
- yield proxyRecord
+ result = set()
+ result.update(self.service.readOnlyProxiesForGUID(DirectoryService.recordType_resources, self.guid))
+ result.update(self.service.readOnlyProxiesForGUID(DirectoryService.recordType_locations, self.guid))
+ return result
def verifyCredentials(self, credentials):
if isinstance(credentials, UsernamePassword):
Modified: CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/calendaruserproxy.py 2008-10-13 19:01:58 UTC (rev 3145)
+++ CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/calendaruserproxy.py 2008-10-13 19:59:14 UTC (rev 3146)
@@ -133,6 +133,15 @@
else:
return super(CalendarUserProxyPrincipalResource, self).resourceType()
+ def isProxyType(self, read_write):
+ if (
+ read_write and self.proxyType == "calendar-proxy-write" or
+ not read_write and self.proxyType == "calendar-proxy-read"
+ ):
+ return True
+ else:
+ return False
+
def isCollection(self):
return True
Modified: CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/principal.py 2008-10-13 19:01:58 UTC (rev 3145)
+++ CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/principal.py 2008-10-13 19:59:14 UTC (rev 3146)
@@ -444,6 +444,10 @@
members = (yield self.groupMembers())
memberships = (yield self.groupMemberships())
+
+ proxyFor = (yield self.proxyFor(True))
+
+ readOnlyProxyFor = (yield self.proxyFor(False))
returnValue("".join((
"""<div class="directory-listing">"""
@@ -468,6 +472,8 @@
"""\nAlternate URIs:\n""" , format_list(format_link(u) for u in self.alternateURIs()),
"""\nGroup members:\n""" , format_principals(members),
"""\nGroup memberships:\n""" , format_principals(memberships),
+ """\nRead-write Proxy For:\n""" , format_principals(proxyFor),
+ """\nRead-only Proxy For:\n""" , format_principals(readOnlyProxyFor),
"""</pre></blockquote></div>""",
output
)))
@@ -565,6 +571,36 @@
returnValue(groups)
+ @inlineCallbacks
+ def proxyFor(self, read_write, resolve_memberships=True):
+ proxyFors = set()
+
+ if resolve_memberships:
+ memberships = self._getRelatives("groups")
+ for membership in memberships:
+ results = (yield membership.proxyFor(read_write, False))
+ proxyFors.update(results)
+
+ if config.EnableProxyPrincipals:
+ # Get any directory specified proxies
+ if read_write:
+ directoryProxies = self._getRelatives("proxyFor", proxy='read-write')
+ else:
+ directoryProxies = self._getRelatives("readOnlyProxyFor", proxy='read-only')
+ proxyFors.update([subprincipal.parent for subprincipal in directoryProxies])
+
+ # Get proxy group UIDs and map to principal resources
+ proxies = []
+ memberships = (yield self._calendar_user_proxy_index().getMemberships(self.principalUID()))
+ for uid in memberships:
+ subprincipal = self.parent.principalForUID(uid)
+ if subprincipal and subprincipal.isProxyType(read_write):
+ proxies.append(subprincipal.parent)
+
+ proxyFors.update(proxies)
+
+ returnValue(proxyFors)
+
def principalCollections(self):
return self.parent.principalCollections()
@@ -608,6 +644,10 @@
memberships = (yield self.groupMemberships())
+ proxyFor = (yield self.proxyFor(True))
+
+ readOnlyProxyFor = (yield self.proxyFor(False))
+
returnValue("".join((
"""<div class="directory-listing">"""
"""<h1>Principal Details</h1>"""
@@ -631,6 +671,8 @@
"""\nAlternate URIs:\n""" , format_list(format_link(u) for u in self.alternateURIs()),
"""\nGroup members:\n""" , format_principals(members),
"""\nGroup memberships:\n""" , format_principals(memberships),
+ """\nRead-write Proxy For:\n""" , format_principals(proxyFor),
+ """\nRead-only Proxy For:\n""" , format_principals(readOnlyProxyFor),
"""\nCalendar homes:\n""" , format_list(format_link(u) for u in self.calendarHomeURLs()),
"""\nCalendar user addresses:\n""" , format_list(format_link(a) for a in self.calendarUserAddresses()),
"""</pre></blockquote></div>""",
Modified: CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/test/test_proxyprincipalmembers.py
===================================================================
--- CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/test/test_proxyprincipalmembers.py 2008-10-13 19:01:58 UTC (rev 3145)
+++ CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/directory/test/test_proxyprincipalmembers.py 2008-10-13 19:59:14 UTC (rev 3146)
@@ -14,7 +14,7 @@
# limitations under the License.
##
-from twisted.internet.defer import DeferredList
+from twisted.internet.defer import DeferredList, inlineCallbacks
from twisted.web2.dav import davxml
from twistedcaldav.directory.directory import DirectoryService
@@ -74,6 +74,13 @@
d = principal.groupMemberships()
d.addCallback(gotMemberships)
return d
+
+ @inlineCallbacks
+ def _proxyForTest(self, recordType, recordName, expectedProxies, read_write):
+ principal = self._getPrincipalByShortName(recordType, recordName)
+ proxies = (yield principal.proxyFor(read_write))
+ proxies = set([principal.displayName() for principal in proxies])
+ self.assertEquals(proxies, set(expectedProxies))
def test_groupMembersRegular(self):
"""
@@ -254,3 +261,20 @@
self.assertEquals(notifier.changedCount, 1)
finally:
DirectoryPrincipalResource.cacheNotifierFactory = oldCacheNotifier
+
+ def test_proxyFor(self):
+
+ return self._proxyForTest(
+ DirectoryService.recordType_users, "wsanchez",
+ ("Mecury Seven", "Gemini Twelve", "Apollo Eleven", "Orion", ),
+ True
+ )
+
+ def test_readOnlyProxyFor(self):
+
+ return self._proxyForTest(
+ DirectoryService.recordType_users, "wsanchez",
+ ("Non-calendar proxy", ),
+ False
+ )
+
Modified: CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/extensions.py 2008-10-13 19:01:58 UTC (rev 3145)
+++ CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/extensions.py 2008-10-13 19:59:14 UTC (rev 3146)
@@ -617,7 +617,7 @@
return f
- for qname in qnames:
+ for qname in sorted(qnames):
d = self.readProperty(qname, request)
d.addCallback(gotProperty)
d.addErrback(gotError, qname)
Modified: CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/resource.py 2008-10-13 19:01:58 UTC (rev 3145)
+++ CalendarServer/branches/users/cdaboo/better-proxy-3132/twistedcaldav/resource.py 2008-10-13 19:59:14 UTC (rev 3146)
@@ -696,6 +696,8 @@
(calendarserver_namespace, "first-name" ),
(calendarserver_namespace, "last-name" ),
(calendarserver_namespace, "email-address-set"),
+ (calendarserver_namespace, "calendar-proxy-read-for" ),
+ (calendarserver_namespace, "calendar-proxy-write-for" ),
)
@classmethod
@@ -709,71 +711,82 @@
def isCollection(self):
return True
+ @inlineCallbacks
def readProperty(self, property, request):
- def defer():
- if type(property) is tuple:
- qname = property
- else:
- qname = property.qname()
+ if type(property) is tuple:
+ qname = property
+ else:
+ qname = property.qname()
- namespace, name = qname
+ namespace, name = qname
- if namespace == caldav_namespace:
- if name == "calendar-home-set":
- return caldavxml.CalendarHomeSet(
- *[davxml.HRef(url) for url in self.calendarHomeURLs()]
- )
+ if namespace == caldav_namespace:
+ if name == "calendar-home-set":
+ returnValue(caldavxml.CalendarHomeSet(
+ *[davxml.HRef(url) for url in self.calendarHomeURLs()]
+ ))
- if name == "calendar-user-address-set":
- return succeed(caldavxml.CalendarUserAddressSet(
- *[davxml.HRef(uri) for uri in self.calendarUserAddresses()]
- ))
+ elif name == "calendar-user-address-set":
+ returnValue(caldavxml.CalendarUserAddressSet(
+ *[davxml.HRef(uri) for uri in self.calendarUserAddresses()]
+ ))
- if name == "schedule-inbox-URL":
- url = self.scheduleInboxURL()
- if url is None:
- return None
- else:
- return caldavxml.ScheduleInboxURL(davxml.HRef(url))
+ elif name == "schedule-inbox-URL":
+ url = self.scheduleInboxURL()
+ if url is None:
+ returnValue(None)
+ else:
+ returnValue(caldavxml.ScheduleInboxURL(davxml.HRef(url)))
- if name == "schedule-outbox-URL":
- url = self.scheduleOutboxURL()
- if url is None:
- return None
- else:
- return caldavxml.ScheduleOutboxURL(davxml.HRef(url))
+ elif name == "schedule-outbox-URL":
+ url = self.scheduleOutboxURL()
+ if url is None:
+ returnValue(None)
+ else:
+ returnValue(caldavxml.ScheduleOutboxURL(davxml.HRef(url)))
- elif namespace == calendarserver_namespace:
- if name == "dropbox-home-URL" and config.EnableDropBox:
- url = self.dropboxURL()
- if url is None:
- return None
- else:
- return customxml.DropBoxHomeURL(davxml.HRef(url))
+ elif namespace == calendarserver_namespace:
+ if name == "dropbox-home-URL" and config.EnableDropBox:
+ url = self.dropboxURL()
+ if url is None:
+ returnValue(None)
+ else:
+ returnValue(customxml.DropBoxHomeURL(davxml.HRef(url)))
- if name == "first-name":
- firstName = self.record.firstName
- if firstName:
- return customxml.FirstNameProperty(firstName)
- else:
- return None
+ elif name == "first-name":
+ firstName = self.record.firstName
+ if firstName:
+ returnValue(customxml.FirstNameProperty(firstName))
+ else:
+ returnValue(None)
- if name == "last-name":
- lastName = self.record.lastName
- if lastName:
- return customxml.LastNameProperty(lastName)
- else:
- return None
+ elif name == "last-name":
+ lastName = self.record.lastName
+ if lastName:
+ returnValue(customxml.LastNameProperty(lastName))
+ else:
+ returnValue(None)
- if name == "email-address-set":
- return succeed(customxml.EmailAddressSet(
- *[customxml.EmailAddressProperty(addr) for addr in self.record.emailAddresses]
- ))
+ elif name == "email-address-set":
+ returnValue(customxml.EmailAddressSet(
+ *[customxml.EmailAddressProperty(addr) for addr in self.record.emailAddresses]
+ ))
- return super(CalendarPrincipalResource, self).readProperty(property, request)
+ elif name == "calendar-proxy-read-for":
+ results = (yield self.proxyFor(False))
+ returnValue(customxml.CalendarProxyReadFor(
+ *[davxml.HRef(principal.principalURL()) for principal in results]
+ ))
- return maybeDeferred(defer)
+ elif name == "calendar-proxy-write-for":
+ results = (yield self.proxyFor(True))
+ returnValue(customxml.CalendarProxyWriteFor(
+ *[davxml.HRef(principal.principalURL()) for principal in results]
+ ))
+ result = (yield super(CalendarPrincipalResource, self).readProperty(property, request))
+ returnValue(result)
+
def groupMembers(self):
return succeed(())
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20081013/9c2fab42/attachment-0001.html
More information about the calendarserver-changes
mailing list