[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