[CalendarServer-changes] [12121] CalendarServer/branches/users/cdaboo/cross-pod-sharing

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


Revision: 12121
          http://trac.calendarserver.org//changeset/12121
Author:   cdaboo at apple.com
Date:     2013-12-17 11:25:31 -0800 (Tue, 17 Dec 2013)
Log Message:
-----------
Checkpoint: more tests done.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/directory/resource.py
    CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py
    CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py
    CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/carddav/datastore/sql.py
    CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py
    CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/test/test_conduit.py
    CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py

Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/directory/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/directory/resource.py	2013-12-17 19:23:03 UTC (rev 12120)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/directory/resource.py	2013-12-17 19:25:31 UTC (rev 12121)
@@ -22,6 +22,8 @@
 
 from twistedcaldav.client.reverseproxy import ReverseProxyResource
 
+from twisted.internet.defer import succeed
+
 __all__ = ["DirectoryReverseProxyResource"]
 
 class DirectoryReverseProxyResource(ReverseProxyResource):
@@ -35,3 +37,32 @@
 
     def url(self):
         return joinURL(self.parent.url(), self.record.uid)
+
+
+    def hasQuota(self, request):
+        return succeed(False)
+
+
+    def hasQuotaRoot(self, request):
+        return succeed(False)
+
+
+    def quotaRootResource(self, request):
+        """
+        Return the quota root for this resource.
+
+        @return: L{DAVResource} or C{None}
+        """
+
+        return succeed(None)
+
+
+    def checkPrivileges(
+        self, request, privileges, recurse=False,
+        principal=None, inherited_aces=None
+    ):
+        return succeed(None)
+
+
+    def hasProperty(self, property, request):
+        return succeed(False)

Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py	2013-12-17 19:23:03 UTC (rev 12120)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py	2013-12-17 19:25:31 UTC (rev 12121)
@@ -1123,7 +1123,7 @@
         isowner = (yield self.isOwner(request))
         accessPrincipal = (yield self.resourceOwnerPrincipal(request))
 
-        for name, _ignore_uid, _ignore_type in (yield maybeDeferred(self.index().bruteForceSearch)):
+        for name in (yield self._newStoreObject.listObjectResources()):
             try:
                 child = yield request.locateChildResource(self, name)
             except TypeError:

Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py	2013-12-17 19:23:03 UTC (rev 12120)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py	2013-12-17 19:25:31 UTC (rev 12121)
@@ -1294,6 +1294,37 @@
         yield self.setDefaultAlarm("empty", False, False)
 
 
+    def getInviteCopyProperties(self):
+        """
+        Get a dictionary of property name/values (as strings) for properties that are shadowable and
+        need to be copied to a sharee's collection when an external (cross-pod) share is created.
+        Sub-classes should override to expose the properties they care about.
+        """
+        props = {}
+        for elem in (element.DisplayName, caldavxml.CalendarDescription, caldavxml.CalendarTimeZone, customxml.CalendarColor,):
+            if PropertyName.fromElement(elem) in self.properties():
+                props[elem.sname()] = str(self.properties()[PropertyName.fromElement(elem)])
+        return props
+
+
+    def setInviteCopyProperties(self, props):
+        """
+        Copy a set of shadowable properties (as name/value strings) onto this shared resource when
+        a cross-pod invite is processed. Sub-classes should override to expose the properties they
+        care about.
+        """
+        # Initialize these for all shares
+        for elem in (caldavxml.CalendarDescription, caldavxml.CalendarTimeZone,):
+            if PropertyName.fromElement(elem) not in self.properties() and elem.sname() in props:
+                self.properties()[PropertyName.fromElement(elem)] = elem.fromString(props[elem.sname()])
+
+        # Only initialize these for direct shares
+        if self.direct():
+            for elem in (element.DisplayName, customxml.CalendarColor,):
+                if PropertyName.fromElement(elem) not in self.properties() and elem.sname() in props:
+                    self.properties()[PropertyName.fromElement(elem)] = elem.fromString(props[elem.sname()])
+
+
     # FIXME: this is DAV-ish.  Data store calendar objects don't have
     # mime types.  -wsv
     def contentType(self):

Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/carddav/datastore/sql.py	2013-12-17 19:23:03 UTC (rev 12120)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/carddav/datastore/sql.py	2013-12-17 19:25:31 UTC (rev 12121)
@@ -568,6 +568,37 @@
         )
 
 
+    def getInviteCopyProperties(self):
+        """
+        Get a dictionary of property name/values (as strings) for properties that are shadowable and
+        need to be copied to a sharee's collection when an external (cross-pod) share is created.
+        Sub-classes should override to expose the properties they care about.
+        """
+        props = {}
+        for elem in (element.DisplayName, carddavxml.AddressBookDescription,):
+            if PropertyName.fromElement(elem) in self.properties():
+                props[elem.sname()] = str(self.properties()[PropertyName.fromElement(elem)])
+        return props
+
+
+    def setInviteCopyProperties(self, props):
+        """
+        Copy a set of shadowable properties (as name/value strings) onto this shared resource when
+        a cross-pod invite is processed. Sub-classes should override to expose the properties they
+        care about.
+        """
+        # Initialize these for all shares
+        for elem in (carddavxml.AddressBookDescription,):
+            if PropertyName.fromElement(elem) not in self.properties() and elem.sname() in props:
+                self.properties()[PropertyName.fromElement(elem)] = elem.fromString(props[elem.sname()])
+
+        # Only initialize these for direct shares
+        if self.direct():
+            for elem in (element.DisplayName,):
+                if PropertyName.fromElement(elem) not in self.properties() and elem.sname() in props:
+                    self.properties()[PropertyName.fromElement(elem)] = elem.fromString(props[elem.sname()])
+
+
     def contentType(self):
         """
         The content type of addressbook objects is text/vcard.

Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py	2013-12-17 19:23:03 UTC (rev 12120)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py	2013-12-17 19:25:31 UTC (rev 12121)
@@ -163,7 +163,7 @@
     #
 
     @inlineCallbacks
-    def send_shareinvite(self, txn, homeType, ownerUID, ownerID, ownerName, shareeUID, shareUID, bindMode, summary, supported_components):
+    def send_shareinvite(self, txn, homeType, ownerUID, ownerID, ownerName, shareeUID, shareUID, bindMode, summary, copy_properties, supported_components):
         """
         Send a sharing invite cross-pod message.
 
@@ -183,6 +183,8 @@
         @type bindMode: C{str}
         @param summary: sharing message
         @type summary: C{str}
+        @param copy_properties: C{str} name/value for properties to be copied
+        @type copy_properties: C{dict}
         @param supported_components: supproted components, may be C{None}
         @type supported_components: C{str}
         """
@@ -199,6 +201,7 @@
             "share_id": shareUID,
             "mode": bindMode,
             "summary": summary,
+            "properties": copy_properties,
         }
         if supported_components is not None:
             action["supported-components"] = supported_components
@@ -232,6 +235,7 @@
                 message["share_id"],
                 message["mode"],
                 message["summary"],
+                message["properties"],
                 supported_components=message.get("supported-components")
             )
         except ExternalShareFailed as e:
@@ -507,7 +511,7 @@
     #
 
     @inlineCallbacks
-    def _simple_send(self, actionName, shareeView, objectResource=None, args=None, kwargs=None):
+    def _simple_send(self, actionName, shareeView, objectResource=None, transform=None, args=None, kwargs=None):
         """
         A simple send operation that returns a value.
 
@@ -532,7 +536,7 @@
             action["keywords"] = kwargs
         result = yield self.sendRequest(shareeView._txn, recipient, action)
         if result["result"] == "ok":
-            returnValue(result["value"])
+            returnValue(result["value"] if transform is None else transform(result["value"], shareeView, objectResource))
         elif result["result"] == "exception":
             raise namedClass(result["class"])(result["message"])
 
@@ -652,12 +656,17 @@
 
 
     @staticmethod
-    def _result_string(value, shareeView, objectResource):
+    def _to_tuple(value, shareeView, objectResource):
+        return tuple(value)
+
+
+    @staticmethod
+    def _to_string(value, shareeView, objectResource):
         return str(value)
 
 
     @staticmethod
-    def _result_externalize(value, shareeView, objectResource):
+    def _to_externalize(value, shareeView, objectResource):
         if isinstance(value, shareeView._objectResourceClass):
             value = value.externalize()
         elif value is not None:
@@ -666,34 +675,34 @@
 
 
     @classmethod
-    def _make_simple_homechild_action(cls, action, method):
+    def _make_simple_homechild_action(cls, action, method, transform_recv=None, transform_send=None):
         setattr(
             cls,
             "send_{}".format(action),
             lambda self, shareeView, *args, **kwargs:
-                self._simple_send(action, shareeView, args=args, kwargs=kwargs)
+                self._simple_send(action, shareeView, transform=transform_send, args=args, kwargs=kwargs)
         )
         setattr(
             cls,
             "recv_{}".format(action),
             lambda self, txn, message:
-                self._simple_recv(txn, action, message, method)
+                self._simple_recv(txn, action, message, method, transform=transform_recv)
         )
 
 
     @classmethod
-    def _make_simple_object_action(cls, action, method, transform_result=None):
+    def _make_simple_object_action(cls, action, method, transform_recv=None, transform_send=None):
         setattr(
             cls,
             "send_{}".format(action),
             lambda self, shareeView, objectResource, *args, **kwargs:
-                self._simple_send(action, shareeView, objectResource, args=args, kwargs=kwargs)
+                self._simple_send(action, shareeView, objectResource, transform=transform_send, args=args, kwargs=kwargs)
         )
         setattr(
             cls,
             "recv_{}".format(action),
             lambda self, txn, message:
-                self._simple_recv(txn, action, message, method, onHomeChild=False, transform=transform_result)
+                self._simple_recv(txn, action, message, method, onHomeChild=False, transform=transform_recv)
         )
 
 
@@ -701,15 +710,15 @@
 PoddingConduit._make_simple_homechild_action("countobjects", "countObjectResources")
 PoddingConduit._make_simple_homechild_action("listobjects", "listObjectResources")
 PoddingConduit._make_simple_homechild_action("synctoken", "syncToken")
-PoddingConduit._make_simple_homechild_action("resourcenamessincerevision", "resourceNamesSinceRevision")
+PoddingConduit._make_simple_homechild_action("resourcenamessincerevision", "resourceNamesSinceRevision", transform_send=PoddingConduit._to_tuple)
 PoddingConduit._make_simple_homechild_action("resourceuidforname", "resourceUIDForName")
 PoddingConduit._make_simple_homechild_action("resourcenameforuid", "resourceNameForUID")
 
 # Calls on L{CommonObjectResource} objects
-PoddingConduit._make_simple_object_action("loadallobjects", "loadAllObjects", transform_result=PoddingConduit._result_externalize)
-PoddingConduit._make_simple_object_action("loadallobjectswithnames", "loadAllObjectsWithNames", transform_result=PoddingConduit._result_externalize)
-PoddingConduit._make_simple_object_action("objectwith", "objectWith", transform_result=PoddingConduit._result_externalize)
-PoddingConduit._make_simple_object_action("create", "create", transform_result=PoddingConduit._result_externalize)
+PoddingConduit._make_simple_object_action("loadallobjects", "loadAllObjects", transform_recv=PoddingConduit._to_externalize)
+PoddingConduit._make_simple_object_action("loadallobjectswithnames", "loadAllObjectsWithNames", transform_recv=PoddingConduit._to_externalize)
+PoddingConduit._make_simple_object_action("objectwith", "objectWith", transform_recv=PoddingConduit._to_externalize)
+PoddingConduit._make_simple_object_action("create", "create", transform_recv=PoddingConduit._to_externalize)
 PoddingConduit._make_simple_object_action("setcomponent", "setComponent")
-PoddingConduit._make_simple_object_action("component", "component", transform_result=PoddingConduit._result_string)
+PoddingConduit._make_simple_object_action("component", "component", transform_recv=PoddingConduit._to_string)
 PoddingConduit._make_simple_object_action("remove", "remove")

Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/test/test_conduit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/test/test_conduit.py	2013-12-17 19:23:03 UTC (rev 12120)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/test/test_conduit.py	2013-12-17 19:25:31 UTC (rev 12121)
@@ -439,13 +439,13 @@
         calendar1 = yield self.calendarUnderTest(home="user01", name="calendar")
         token1_2 = yield calendar1.syncToken()
         names1 = yield calendar1.resourceNamesSinceToken(token1_1)
-        self.assertEqual(names1, (["1.ics"], [],))
+        self.assertEqual(names1, ([u"1.ics"], [],))
         yield self.commit()
 
         shared = yield self.calendarUnderTest(txn=self.newOtherTransaction(), home="puser01", name="shared-calendar")
         token2_2 = yield shared.syncToken()
         names2 = yield shared.resourceNamesSinceToken(token2_1)
-        self.assertEqual(names2, (["1.ics"], [],))
+        self.assertEqual(names2, ([u"1.ics"], [],))
         yield self.otherCommit()
 
         calendar1 = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -458,13 +458,13 @@
         calendar1 = yield self.calendarUnderTest(home="user01", name="calendar")
         token1_3 = yield calendar1.syncToken()
         names1 = yield calendar1.resourceNamesSinceToken(token1_2)
-        self.assertEqual(names1, ([], ["1.ics"],))
+        self.assertEqual(names1, ([], [u"1.ics"],))
         yield self.commit()
 
         shared = yield self.calendarUnderTest(txn=self.newOtherTransaction(), home="puser01", name="shared-calendar")
         token2_3 = yield shared.syncToken()
         names2 = yield shared.resourceNamesSinceToken(token2_2)
-        self.assertEqual(names2, ([], ["1.ics"],))
+        self.assertEqual(names2, ([], [u"1.ics"],))
         yield self.otherCommit()
 
         calendar1 = yield self.calendarUnderTest(home="user01", name="calendar")
@@ -518,17 +518,17 @@
         yield self.commit()
 
         calendar1 = yield self.calendarUnderTest(home="user01", name="calendar")
-        uid = yield calendar1.resourceNameForUID("uid1")
-        self.assertEqual(uid, "1.ics")
-        uid = yield calendar1.resourceNameForUID("uid2")
-        self.assertTrue(uid is None)
+        name = yield calendar1.resourceNameForUID("uid1")
+        self.assertEqual(name, "1.ics")
+        name = yield calendar1.resourceNameForUID("uid2")
+        self.assertTrue(name is None)
         yield self.commit()
 
         shared = yield self.calendarUnderTest(txn=self.newOtherTransaction(), home="puser01", name="shared-calendar")
-        uid = yield shared.resourceNameForUID("uid1")
-        self.assertEqual(uid, "1.ics")
-        uid = yield shared.resourceNameForUID("uid2")
-        self.assertTrue(uid is None)
+        name = yield shared.resourceNameForUID("uid1")
+        self.assertEqual(name, "1.ics")
+        name = yield shared.resourceNameForUID("uid2")
+        self.assertTrue(name is None)
         yield self.otherCommit()
 
 

Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py	2013-12-17 19:23:03 UTC (rev 12120)
+++ CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py	2013-12-17 19:25:31 UTC (rev 12121)
@@ -1479,7 +1479,7 @@
     # External (cross-pod) sharing - entry point is the sharee's home collection.
     #
     @inlineCallbacks
-    def processExternalInvite(self, ownerUID, ownerRID, ownerName, shareUID, bindMode, summary, supported_components=None):
+    def processExternalInvite(self, ownerUID, ownerRID, ownerName, shareUID, bindMode, summary, copy_invite_properties, supported_components=None):
         """
         External invite received.
         """
@@ -1513,11 +1513,13 @@
 
         # Now carry out the share operation
         if bindMode == _BIND_MODE_DIRECT:
-            yield ownerView.directShareWithUser(self.uid(), shareName=shareUID)
+            shareeView = yield ownerView.directShareWithUser(self.uid(), shareName=shareUID)
         else:
-            yield ownerView.inviteUserToShare(self.uid(), bindMode, summary, shareName=shareUID)
+            shareeView = yield ownerView.inviteUserToShare(self.uid(), bindMode, summary, shareName=shareUID)
 
+        shareeView.setInviteCopyProperties(copy_invite_properties)
 
+
     @inlineCallbacks
     def processExternalUninvite(self, ownerUID, ownerRID, shareUID):
         """
@@ -2630,7 +2632,7 @@
     def revisionFromToken(self, token):
         if token is None:
             return 0
-        elif isinstance(token, str):
+        elif isinstance(token, str) or isinstance(token, unicode):
             _ignore_uuid, revision = token.split("_", 1)
             return int(revision)
         else:
@@ -3342,6 +3344,7 @@
             shareeView.shareUID(),
             shareeView.shareMode(),
             shareeView.shareMessage(),
+            self.getInviteCopyProperties(),
             supported_components=self.getSupportedComponents() if hasattr(self, "getSupportedComponents") else None,
         )
 
@@ -3807,6 +3810,24 @@
         return self._bindMessage
 
 
+    def getInviteCopyProperties(self):
+        """
+        Get a dictionary of property name/values (as strings) for properties that are shadowable and
+        need to be copied to a sharee's collection when an external (cross-pod) share is created.
+        Sub-classes should override to expose the properties they care about.
+        """
+        return {}
+
+
+    def setInviteCopyProperties(self, props):
+        """
+        Copy a set of shadowable properties (as name/value strings) onto this shared resource when
+        a cross-pod invite is processed. Sub-classes should override to expose the properties they
+        care about.
+        """
+        pass
+
+
     @classmethod
     def metadataColumns(cls):
         """
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140312/ec1dad8b/attachment.html>


More information about the calendarserver-changes mailing list