[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