<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[12121] CalendarServer/branches/users/cdaboo/cross-pod-sharing</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/12121">12121</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2013-12-17 11:25:31 -0800 (Tue, 17 Dec 2013)</dd>
</dl>

<h3>Log Message</h3>
<pre>Checkpoint: more tests done.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServerbranchesuserscdaboocrosspodsharingtwistedcaldavdirectoryresourcepy">CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/directory/resource.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboocrosspodsharingtwistedcaldavstorebridgepy">CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboocrosspodsharingtxdavcaldavdatastoresqlpy">CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboocrosspodsharingtxdavcarddavdatastoresqlpy">CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/carddav/datastore/sql.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboocrosspodsharingtxdavcommondatastorepoddingconduitpy">CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboocrosspodsharingtxdavcommondatastorepoddingtesttest_conduitpy">CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/test/test_conduit.py</a></li>
<li><a href="#CalendarServerbranchesuserscdaboocrosspodsharingtxdavcommondatastoresqlpy">CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServerbranchesuserscdaboocrosspodsharingtwistedcaldavdirectoryresourcepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/directory/resource.py (12120 => 12121)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -22,6 +22,8 @@
</span><span class="cx"> 
</span><span class="cx"> from twistedcaldav.client.reverseproxy import ReverseProxyResource
</span><span class="cx"> 
</span><ins>+from twisted.internet.defer import succeed
+
</ins><span class="cx"> __all__ = [&quot;DirectoryReverseProxyResource&quot;]
</span><span class="cx"> 
</span><span class="cx"> class DirectoryReverseProxyResource(ReverseProxyResource):
</span><span class="lines">@@ -35,3 +37,32 @@
</span><span class="cx"> 
</span><span class="cx">     def url(self):
</span><span class="cx">         return joinURL(self.parent.url(), self.record.uid)
</span><ins>+
+
+    def hasQuota(self, request):
+        return succeed(False)
+
+
+    def hasQuotaRoot(self, request):
+        return succeed(False)
+
+
+    def quotaRootResource(self, request):
+        &quot;&quot;&quot;
+        Return the quota root for this resource.
+
+        @return: L{DAVResource} or C{None}
+        &quot;&quot;&quot;
+
+        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)
</ins></span></pre></div>
<a id="CalendarServerbranchesuserscdaboocrosspodsharingtwistedcaldavstorebridgepy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/twistedcaldav/storebridge.py (12120 => 12121)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1123,7 +1123,7 @@
</span><span class="cx">         isowner = (yield self.isOwner(request))
</span><span class="cx">         accessPrincipal = (yield self.resourceOwnerPrincipal(request))
</span><span class="cx"> 
</span><del>-        for name, _ignore_uid, _ignore_type in (yield maybeDeferred(self.index().bruteForceSearch)):
</del><ins>+        for name in (yield self._newStoreObject.listObjectResources()):
</ins><span class="cx">             try:
</span><span class="cx">                 child = yield request.locateChildResource(self, name)
</span><span class="cx">             except TypeError:
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboocrosspodsharingtxdavcaldavdatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/caldav/datastore/sql.py (12120 => 12121)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1294,6 +1294,37 @@
</span><span class="cx">         yield self.setDefaultAlarm(&quot;empty&quot;, False, False)
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def getInviteCopyProperties(self):
+        &quot;&quot;&quot;
+        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.
+        &quot;&quot;&quot;
+        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):
+        &quot;&quot;&quot;
+        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.
+        &quot;&quot;&quot;
+        # 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()])
+
+
</ins><span class="cx">     # FIXME: this is DAV-ish.  Data store calendar objects don't have
</span><span class="cx">     # mime types.  -wsv
</span><span class="cx">     def contentType(self):
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboocrosspodsharingtxdavcarddavdatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/carddav/datastore/sql.py (12120 => 12121)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -568,6 +568,37 @@
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def getInviteCopyProperties(self):
+        &quot;&quot;&quot;
+        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.
+        &quot;&quot;&quot;
+        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):
+        &quot;&quot;&quot;
+        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.
+        &quot;&quot;&quot;
+        # 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()])
+
+
</ins><span class="cx">     def contentType(self):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         The content type of addressbook objects is text/vcard.
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboocrosspodsharingtxdavcommondatastorepoddingconduitpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/conduit.py (12120 => 12121)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -163,7 +163,7 @@
</span><span class="cx">     #
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def send_shareinvite(self, txn, homeType, ownerUID, ownerID, ownerName, shareeUID, shareUID, bindMode, summary, supported_components):
</del><ins>+    def send_shareinvite(self, txn, homeType, ownerUID, ownerID, ownerName, shareeUID, shareUID, bindMode, summary, copy_properties, supported_components):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         Send a sharing invite cross-pod message.
</span><span class="cx"> 
</span><span class="lines">@@ -183,6 +183,8 @@
</span><span class="cx">         @type bindMode: C{str}
</span><span class="cx">         @param summary: sharing message
</span><span class="cx">         @type summary: C{str}
</span><ins>+        @param copy_properties: C{str} name/value for properties to be copied
+        @type copy_properties: C{dict}
</ins><span class="cx">         @param supported_components: supproted components, may be C{None}
</span><span class="cx">         @type supported_components: C{str}
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -199,6 +201,7 @@
</span><span class="cx">             &quot;share_id&quot;: shareUID,
</span><span class="cx">             &quot;mode&quot;: bindMode,
</span><span class="cx">             &quot;summary&quot;: summary,
</span><ins>+            &quot;properties&quot;: copy_properties,
</ins><span class="cx">         }
</span><span class="cx">         if supported_components is not None:
</span><span class="cx">             action[&quot;supported-components&quot;] = supported_components
</span><span class="lines">@@ -232,6 +235,7 @@
</span><span class="cx">                 message[&quot;share_id&quot;],
</span><span class="cx">                 message[&quot;mode&quot;],
</span><span class="cx">                 message[&quot;summary&quot;],
</span><ins>+                message[&quot;properties&quot;],
</ins><span class="cx">                 supported_components=message.get(&quot;supported-components&quot;)
</span><span class="cx">             )
</span><span class="cx">         except ExternalShareFailed as e:
</span><span class="lines">@@ -507,7 +511,7 @@
</span><span class="cx">     #
</span><span class="cx"> 
</span><span class="cx">     @inlineCallbacks
</span><del>-    def _simple_send(self, actionName, shareeView, objectResource=None, args=None, kwargs=None):
</del><ins>+    def _simple_send(self, actionName, shareeView, objectResource=None, transform=None, args=None, kwargs=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         A simple send operation that returns a value.
</span><span class="cx"> 
</span><span class="lines">@@ -532,7 +536,7 @@
</span><span class="cx">             action[&quot;keywords&quot;] = kwargs
</span><span class="cx">         result = yield self.sendRequest(shareeView._txn, recipient, action)
</span><span class="cx">         if result[&quot;result&quot;] == &quot;ok&quot;:
</span><del>-            returnValue(result[&quot;value&quot;])
</del><ins>+            returnValue(result[&quot;value&quot;] if transform is None else transform(result[&quot;value&quot;], shareeView, objectResource))
</ins><span class="cx">         elif result[&quot;result&quot;] == &quot;exception&quot;:
</span><span class="cx">             raise namedClass(result[&quot;class&quot;])(result[&quot;message&quot;])
</span><span class="cx"> 
</span><span class="lines">@@ -652,12 +656,17 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><del>-    def _result_string(value, shareeView, objectResource):
</del><ins>+    def _to_tuple(value, shareeView, objectResource):
+        return tuple(value)
+
+
+    @staticmethod
+    def _to_string(value, shareeView, objectResource):
</ins><span class="cx">         return str(value)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @staticmethod
</span><del>-    def _result_externalize(value, shareeView, objectResource):
</del><ins>+    def _to_externalize(value, shareeView, objectResource):
</ins><span class="cx">         if isinstance(value, shareeView._objectResourceClass):
</span><span class="cx">             value = value.externalize()
</span><span class="cx">         elif value is not None:
</span><span class="lines">@@ -666,34 +675,34 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def _make_simple_homechild_action(cls, action, method):
</del><ins>+    def _make_simple_homechild_action(cls, action, method, transform_recv=None, transform_send=None):
</ins><span class="cx">         setattr(
</span><span class="cx">             cls,
</span><span class="cx">             &quot;send_{}&quot;.format(action),
</span><span class="cx">             lambda self, shareeView, *args, **kwargs:
</span><del>-                self._simple_send(action, shareeView, args=args, kwargs=kwargs)
</del><ins>+                self._simple_send(action, shareeView, transform=transform_send, args=args, kwargs=kwargs)
</ins><span class="cx">         )
</span><span class="cx">         setattr(
</span><span class="cx">             cls,
</span><span class="cx">             &quot;recv_{}&quot;.format(action),
</span><span class="cx">             lambda self, txn, message:
</span><del>-                self._simple_recv(txn, action, message, method)
</del><ins>+                self._simple_recv(txn, action, message, method, transform=transform_recv)
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     @classmethod
</span><del>-    def _make_simple_object_action(cls, action, method, transform_result=None):
</del><ins>+    def _make_simple_object_action(cls, action, method, transform_recv=None, transform_send=None):
</ins><span class="cx">         setattr(
</span><span class="cx">             cls,
</span><span class="cx">             &quot;send_{}&quot;.format(action),
</span><span class="cx">             lambda self, shareeView, objectResource, *args, **kwargs:
</span><del>-                self._simple_send(action, shareeView, objectResource, args=args, kwargs=kwargs)
</del><ins>+                self._simple_send(action, shareeView, objectResource, transform=transform_send, args=args, kwargs=kwargs)
</ins><span class="cx">         )
</span><span class="cx">         setattr(
</span><span class="cx">             cls,
</span><span class="cx">             &quot;recv_{}&quot;.format(action),
</span><span class="cx">             lambda self, txn, message:
</span><del>-                self._simple_recv(txn, action, message, method, onHomeChild=False, transform=transform_result)
</del><ins>+                self._simple_recv(txn, action, message, method, onHomeChild=False, transform=transform_recv)
</ins><span class="cx">         )
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -701,15 +710,15 @@
</span><span class="cx"> PoddingConduit._make_simple_homechild_action(&quot;countobjects&quot;, &quot;countObjectResources&quot;)
</span><span class="cx"> PoddingConduit._make_simple_homechild_action(&quot;listobjects&quot;, &quot;listObjectResources&quot;)
</span><span class="cx"> PoddingConduit._make_simple_homechild_action(&quot;synctoken&quot;, &quot;syncToken&quot;)
</span><del>-PoddingConduit._make_simple_homechild_action(&quot;resourcenamessincerevision&quot;, &quot;resourceNamesSinceRevision&quot;)
</del><ins>+PoddingConduit._make_simple_homechild_action(&quot;resourcenamessincerevision&quot;, &quot;resourceNamesSinceRevision&quot;, transform_send=PoddingConduit._to_tuple)
</ins><span class="cx"> PoddingConduit._make_simple_homechild_action(&quot;resourceuidforname&quot;, &quot;resourceUIDForName&quot;)
</span><span class="cx"> PoddingConduit._make_simple_homechild_action(&quot;resourcenameforuid&quot;, &quot;resourceNameForUID&quot;)
</span><span class="cx"> 
</span><span class="cx"> # Calls on L{CommonObjectResource} objects
</span><del>-PoddingConduit._make_simple_object_action(&quot;loadallobjects&quot;, &quot;loadAllObjects&quot;, transform_result=PoddingConduit._result_externalize)
-PoddingConduit._make_simple_object_action(&quot;loadallobjectswithnames&quot;, &quot;loadAllObjectsWithNames&quot;, transform_result=PoddingConduit._result_externalize)
-PoddingConduit._make_simple_object_action(&quot;objectwith&quot;, &quot;objectWith&quot;, transform_result=PoddingConduit._result_externalize)
-PoddingConduit._make_simple_object_action(&quot;create&quot;, &quot;create&quot;, transform_result=PoddingConduit._result_externalize)
</del><ins>+PoddingConduit._make_simple_object_action(&quot;loadallobjects&quot;, &quot;loadAllObjects&quot;, transform_recv=PoddingConduit._to_externalize)
+PoddingConduit._make_simple_object_action(&quot;loadallobjectswithnames&quot;, &quot;loadAllObjectsWithNames&quot;, transform_recv=PoddingConduit._to_externalize)
+PoddingConduit._make_simple_object_action(&quot;objectwith&quot;, &quot;objectWith&quot;, transform_recv=PoddingConduit._to_externalize)
+PoddingConduit._make_simple_object_action(&quot;create&quot;, &quot;create&quot;, transform_recv=PoddingConduit._to_externalize)
</ins><span class="cx"> PoddingConduit._make_simple_object_action(&quot;setcomponent&quot;, &quot;setComponent&quot;)
</span><del>-PoddingConduit._make_simple_object_action(&quot;component&quot;, &quot;component&quot;, transform_result=PoddingConduit._result_string)
</del><ins>+PoddingConduit._make_simple_object_action(&quot;component&quot;, &quot;component&quot;, transform_recv=PoddingConduit._to_string)
</ins><span class="cx"> PoddingConduit._make_simple_object_action(&quot;remove&quot;, &quot;remove&quot;)
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboocrosspodsharingtxdavcommondatastorepoddingtesttest_conduitpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/podding/test/test_conduit.py (12120 => 12121)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -439,13 +439,13 @@
</span><span class="cx">         calendar1 = yield self.calendarUnderTest(home=&quot;user01&quot;, name=&quot;calendar&quot;)
</span><span class="cx">         token1_2 = yield calendar1.syncToken()
</span><span class="cx">         names1 = yield calendar1.resourceNamesSinceToken(token1_1)
</span><del>-        self.assertEqual(names1, ([&quot;1.ics&quot;], [],))
</del><ins>+        self.assertEqual(names1, ([u&quot;1.ics&quot;], [],))
</ins><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx">         shared = yield self.calendarUnderTest(txn=self.newOtherTransaction(), home=&quot;puser01&quot;, name=&quot;shared-calendar&quot;)
</span><span class="cx">         token2_2 = yield shared.syncToken()
</span><span class="cx">         names2 = yield shared.resourceNamesSinceToken(token2_1)
</span><del>-        self.assertEqual(names2, ([&quot;1.ics&quot;], [],))
</del><ins>+        self.assertEqual(names2, ([u&quot;1.ics&quot;], [],))
</ins><span class="cx">         yield self.otherCommit()
</span><span class="cx"> 
</span><span class="cx">         calendar1 = yield self.calendarUnderTest(home=&quot;user01&quot;, name=&quot;calendar&quot;)
</span><span class="lines">@@ -458,13 +458,13 @@
</span><span class="cx">         calendar1 = yield self.calendarUnderTest(home=&quot;user01&quot;, name=&quot;calendar&quot;)
</span><span class="cx">         token1_3 = yield calendar1.syncToken()
</span><span class="cx">         names1 = yield calendar1.resourceNamesSinceToken(token1_2)
</span><del>-        self.assertEqual(names1, ([], [&quot;1.ics&quot;],))
</del><ins>+        self.assertEqual(names1, ([], [u&quot;1.ics&quot;],))
</ins><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx">         shared = yield self.calendarUnderTest(txn=self.newOtherTransaction(), home=&quot;puser01&quot;, name=&quot;shared-calendar&quot;)
</span><span class="cx">         token2_3 = yield shared.syncToken()
</span><span class="cx">         names2 = yield shared.resourceNamesSinceToken(token2_2)
</span><del>-        self.assertEqual(names2, ([], [&quot;1.ics&quot;],))
</del><ins>+        self.assertEqual(names2, ([], [u&quot;1.ics&quot;],))
</ins><span class="cx">         yield self.otherCommit()
</span><span class="cx"> 
</span><span class="cx">         calendar1 = yield self.calendarUnderTest(home=&quot;user01&quot;, name=&quot;calendar&quot;)
</span><span class="lines">@@ -518,17 +518,17 @@
</span><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx">         calendar1 = yield self.calendarUnderTest(home=&quot;user01&quot;, name=&quot;calendar&quot;)
</span><del>-        uid = yield calendar1.resourceNameForUID(&quot;uid1&quot;)
-        self.assertEqual(uid, &quot;1.ics&quot;)
-        uid = yield calendar1.resourceNameForUID(&quot;uid2&quot;)
-        self.assertTrue(uid is None)
</del><ins>+        name = yield calendar1.resourceNameForUID(&quot;uid1&quot;)
+        self.assertEqual(name, &quot;1.ics&quot;)
+        name = yield calendar1.resourceNameForUID(&quot;uid2&quot;)
+        self.assertTrue(name is None)
</ins><span class="cx">         yield self.commit()
</span><span class="cx"> 
</span><span class="cx">         shared = yield self.calendarUnderTest(txn=self.newOtherTransaction(), home=&quot;puser01&quot;, name=&quot;shared-calendar&quot;)
</span><del>-        uid = yield shared.resourceNameForUID(&quot;uid1&quot;)
-        self.assertEqual(uid, &quot;1.ics&quot;)
-        uid = yield shared.resourceNameForUID(&quot;uid2&quot;)
-        self.assertTrue(uid is None)
</del><ins>+        name = yield shared.resourceNameForUID(&quot;uid1&quot;)
+        self.assertEqual(name, &quot;1.ics&quot;)
+        name = yield shared.resourceNameForUID(&quot;uid2&quot;)
+        self.assertTrue(name is None)
</ins><span class="cx">         yield self.otherCommit()
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="CalendarServerbranchesuserscdaboocrosspodsharingtxdavcommondatastoresqlpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/branches/users/cdaboo/cross-pod-sharing/txdav/common/datastore/sql.py (12120 => 12121)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1479,7 +1479,7 @@
</span><span class="cx">     # External (cross-pod) sharing - entry point is the sharee's home collection.
</span><span class="cx">     #
</span><span class="cx">     @inlineCallbacks
</span><del>-    def processExternalInvite(self, ownerUID, ownerRID, ownerName, shareUID, bindMode, summary, supported_components=None):
</del><ins>+    def processExternalInvite(self, ownerUID, ownerRID, ownerName, shareUID, bindMode, summary, copy_invite_properties, supported_components=None):
</ins><span class="cx">         &quot;&quot;&quot;
</span><span class="cx">         External invite received.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -1513,11 +1513,13 @@
</span><span class="cx"> 
</span><span class="cx">         # Now carry out the share operation
</span><span class="cx">         if bindMode == _BIND_MODE_DIRECT:
</span><del>-            yield ownerView.directShareWithUser(self.uid(), shareName=shareUID)
</del><ins>+            shareeView = yield ownerView.directShareWithUser(self.uid(), shareName=shareUID)
</ins><span class="cx">         else:
</span><del>-            yield ownerView.inviteUserToShare(self.uid(), bindMode, summary, shareName=shareUID)
</del><ins>+            shareeView = yield ownerView.inviteUserToShare(self.uid(), bindMode, summary, shareName=shareUID)
</ins><span class="cx"> 
</span><ins>+        shareeView.setInviteCopyProperties(copy_invite_properties)
</ins><span class="cx"> 
</span><ins>+
</ins><span class="cx">     @inlineCallbacks
</span><span class="cx">     def processExternalUninvite(self, ownerUID, ownerRID, shareUID):
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="lines">@@ -2630,7 +2632,7 @@
</span><span class="cx">     def revisionFromToken(self, token):
</span><span class="cx">         if token is None:
</span><span class="cx">             return 0
</span><del>-        elif isinstance(token, str):
</del><ins>+        elif isinstance(token, str) or isinstance(token, unicode):
</ins><span class="cx">             _ignore_uuid, revision = token.split(&quot;_&quot;, 1)
</span><span class="cx">             return int(revision)
</span><span class="cx">         else:
</span><span class="lines">@@ -3342,6 +3344,7 @@
</span><span class="cx">             shareeView.shareUID(),
</span><span class="cx">             shareeView.shareMode(),
</span><span class="cx">             shareeView.shareMessage(),
</span><ins>+            self.getInviteCopyProperties(),
</ins><span class="cx">             supported_components=self.getSupportedComponents() if hasattr(self, &quot;getSupportedComponents&quot;) else None,
</span><span class="cx">         )
</span><span class="cx"> 
</span><span class="lines">@@ -3807,6 +3810,24 @@
</span><span class="cx">         return self._bindMessage
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+    def getInviteCopyProperties(self):
+        &quot;&quot;&quot;
+        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.
+        &quot;&quot;&quot;
+        return {}
+
+
+    def setInviteCopyProperties(self, props):
+        &quot;&quot;&quot;
+        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.
+        &quot;&quot;&quot;
+        pass
+
+
</ins><span class="cx">     @classmethod
</span><span class="cx">     def metadataColumns(cls):
</span><span class="cx">         &quot;&quot;&quot;
</span></span></pre>
</div>
</div>

</body>
</html>