[CalendarServer-changes] [9206] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Apr 26 17:23:37 PDT 2012


Revision: 9206
          http://trac.macosforge.org/projects/calendarserver/changeset/9206
Author:   glyph at apple.com
Date:     2012-04-26 17:23:36 -0700 (Thu, 26 Apr 2012)
Log Message:
-----------
API for sharing a calendar with another user, as if through the invite process.

Modified Paths:
--------------
    CalendarServer/trunk/test
    CalendarServer/trunk/txdav/caldav/datastore/test/common.py
    CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py
    CalendarServer/trunk/txdav/common/datastore/sql.py

Property Changed:
----------------
    CalendarServer/trunk/


Property changes on: CalendarServer/trunk
___________________________________________________________________
Modified: svn:mergeinfo
   - /CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/table-alias:8651-8664
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/wsanchez/transations:5515-5593
   + /CalendarServer/branches/config-separation:4379-4443
/CalendarServer/branches/egg-info-351:4589-4625
/CalendarServer/branches/generic-sqlstore:6167-6191
/CalendarServer/branches/new-store:5594-5934
/CalendarServer/branches/new-store-no-caldavfile:5911-5935
/CalendarServer/branches/new-store-no-caldavfile-2:5936-5981
/CalendarServer/branches/users/cdaboo/batchupload-6699:6700-7198
/CalendarServer/branches/users/cdaboo/cached-subscription-calendars-5692:5693-5702
/CalendarServer/branches/users/cdaboo/component-set-fixes:8130-8346
/CalendarServer/branches/users/cdaboo/directory-cache-on-demand-3627:3628-3644
/CalendarServer/branches/users/cdaboo/implicituidrace:8137-8141
/CalendarServer/branches/users/cdaboo/more-sharing-5591:5592-5601
/CalendarServer/branches/users/cdaboo/partition-4464:4465-4957
/CalendarServer/branches/users/cdaboo/pods:7297-7377
/CalendarServer/branches/users/cdaboo/pycalendar:7085-7206
/CalendarServer/branches/users/cdaboo/pycard:7227-7237
/CalendarServer/branches/users/cdaboo/queued-attendee-refreshes:7740-8287
/CalendarServer/branches/users/cdaboo/relative-config-paths-5070:5071-5105
/CalendarServer/branches/users/cdaboo/shared-calendars-5187:5188-5440
/CalendarServer/branches/users/cdaboo/timezones:7443-7699
/CalendarServer/branches/users/cdaboo/txn-debugging:8730-8743
/CalendarServer/branches/users/glyph/case-insensitive-uid:8772-8805
/CalendarServer/branches/users/glyph/conn-limit:6574-6577
/CalendarServer/branches/users/glyph/contacts-server-merge:4971-5080
/CalendarServer/branches/users/glyph/dalify:6932-7023
/CalendarServer/branches/users/glyph/db-reconnect:6824-6876
/CalendarServer/branches/users/glyph/deploybuild:7563-7572
/CalendarServer/branches/users/glyph/disable-quota:7718-7727
/CalendarServer/branches/users/glyph/dont-start-postgres:6592-6614
/CalendarServer/branches/users/glyph/imip-and-admin-html:7866-7984
/CalendarServer/branches/users/glyph/ipv6-client:9054-9105
/CalendarServer/branches/users/glyph/linux-tests:6893-6900
/CalendarServer/branches/users/glyph/migrate-merge:8690-8713
/CalendarServer/branches/users/glyph/misc-portability-fixes:7365-7374
/CalendarServer/branches/users/glyph/more-deferreds-6:6322-6368
/CalendarServer/branches/users/glyph/more-deferreds-7:6369-6445
/CalendarServer/branches/users/glyph/multiget-delete:8321-8330
/CalendarServer/branches/users/glyph/new-export:7444-7485
/CalendarServer/branches/users/glyph/oracle:7106-7155
/CalendarServer/branches/users/glyph/oracle-nulls:7340-7351
/CalendarServer/branches/users/glyph/other-html:8062-8091
/CalendarServer/branches/users/glyph/parallel-sim:8240-8251
/CalendarServer/branches/users/glyph/parallel-upgrade:8376-8400
/CalendarServer/branches/users/glyph/parallel-upgrade_to_1:8571-8583
/CalendarServer/branches/users/glyph/quota:7604-7637
/CalendarServer/branches/users/glyph/sendfdport:5388-5424
/CalendarServer/branches/users/glyph/shared-pool-fixes:8436-8443
/CalendarServer/branches/users/glyph/shared-pool-take2:8155-8174
/CalendarServer/branches/users/glyph/sharedpool:6490-6550
/CalendarServer/branches/users/glyph/sharing-api:9192-9205
/CalendarServer/branches/users/glyph/skip-lonely-vtimezones:8524-8535
/CalendarServer/branches/users/glyph/sql-store:5929-6073
/CalendarServer/branches/users/glyph/subtransactions:7248-7258
/CalendarServer/branches/users/glyph/table-alias:8651-8664
/CalendarServer/branches/users/glyph/uidexport:7673-7676
/CalendarServer/branches/users/glyph/use-system-twisted:5084-5149
/CalendarServer/branches/users/glyph/xattrs-from-files:7757-7769
/CalendarServer/branches/users/sagen/applepush:8126-8184
/CalendarServer/branches/users/sagen/inboxitems:7380-7381
/CalendarServer/branches/users/sagen/locations-resources:5032-5051
/CalendarServer/branches/users/sagen/locations-resources-2:5052-5061
/CalendarServer/branches/users/sagen/purge_old_events:6735-6746
/CalendarServer/branches/users/sagen/resource-delegates-4038:4040-4067
/CalendarServer/branches/users/sagen/resource-delegates-4066:4068-4075
/CalendarServer/branches/users/sagen/resources-2:5084-5093
/CalendarServer/branches/users/wsanchez/transations:5515-5593

Modified: CalendarServer/trunk/test
===================================================================
--- CalendarServer/trunk/test	2012-04-27 00:09:22 UTC (rev 9205)
+++ CalendarServer/trunk/test	2012-04-27 00:23:36 UTC (rev 9206)
@@ -96,7 +96,7 @@
 fi;
 
 tmp="$(mktemp "/tmp/calendarserver_test_emtpy.XXXXX")";
-find "${wd}" ! '(' -type d '(' -name .svn -o -name data ')' -prune ')' -type f -size 0 > "${tmp}";
+find "${wd}" '!' '(' -type d '(' -path '*/.*' -o -name data ')' -prune ')' -type f -size 0 > "${tmp}";
 if [ -s "${tmp}" ]; then
     echo "**** Empty files: ****";
     cat "${tmp}";

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/common.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2012-04-27 00:09:22 UTC (rev 9205)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2012-04-27 00:23:36 UTC (rev 9206)
@@ -43,6 +43,7 @@
 from txdav.common.icommondatastore import ObjectResourceNameAlreadyExistsError
 from txdav.common.inotifications import INotificationObject
 from txdav.common.datastore.test.util import CommonCommonTests
+from txdav.common.datastore.sql_tables import _BIND_MODE_WRITE
 
 from txdav.caldav.icalendarstore import (
     ICalendarObject, ICalendarHome,
@@ -324,22 +325,22 @@
 
 
     @inlineCallbacks
-    def homeUnderTest(self, txn=None):
+    def homeUnderTest(self, txn=None, name="home1"):
         """
         Get the calendar home detailed by C{requirements['home1']}.
         """
         if txn is None:
             txn = self.transactionUnderTest()
-        returnValue((yield txn.calendarHomeWithUID("home1")))
+        returnValue((yield txn.calendarHomeWithUID(name)))
 
 
     @inlineCallbacks
-    def calendarUnderTest(self, txn=None):
+    def calendarUnderTest(self, txn=None, name="calendar_1", home="home1"):
         """
         Get the calendar detailed by C{requirements['home1']['calendar_1']}.
         """
         returnValue((yield
-            (yield self.homeUnderTest(txn)).calendarWithName("calendar_1"))
+            (yield self.homeUnderTest(txn, home)).calendarWithName(name))
         )
 
 
@@ -984,6 +985,35 @@
 
 
     @inlineCallbacks
+    def test_shareWith(self):
+        """
+        L{ICalendar.shareWith} will share a calendar with a given home UID.
+        """
+        cal = yield self.calendarUnderTest()
+        OTHER_HOME_UID = "home_splits"
+        other = yield self.homeUnderTest(name=OTHER_HOME_UID)
+        newCalName = yield cal.shareWith(other, _BIND_MODE_WRITE)
+        yield self.commit()
+        normalCal = yield self.calendarUnderTest()
+        otherHome = yield self.homeUnderTest(name=OTHER_HOME_UID)
+        otherCal = yield otherHome.sharedChildWithName(newCalName)
+        self.assertNotIdentical(otherCal, None)
+        self.assertEqual(
+            (yield
+             (yield otherCal.calendarObjectWithName("1.ics")).component()),
+            (yield
+             (yield normalCal.calendarObjectWithName("1.ics")).component())
+        )
+        # Check legacy shares database too, since that's what the protocol layer
+        # is still using to list things.
+        self.assertEqual(
+            [(record.shareuid, record.localname) for record in
+             (yield otherHome.retrieveOldShares().allRecords())],
+            [(newCalName, newCalName)]
+        )
+
+
+    @inlineCallbacks
     def test_hasCalendarResourceUIDSomewhereElse(self):
         """
         L{ICalendarHome.hasCalendarResourceUIDSomewhereElse} will determine if

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py	2012-04-27 00:09:22 UTC (rev 9205)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py	2012-04-27 00:23:36 UTC (rev 9206)
@@ -465,6 +465,14 @@
         return self.calendarStore
 
 
+    def test_shareWith(self):
+        """
+        Overridden to be skipped.
+        """
+
+    test_shareWith.skip = "Not implemented for file store yet."
+
+
     def test_init(self):
         """
         L{CalendarStore} has a C{_path} attribute which refers to its

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2012-04-27 00:09:22 UTC (rev 9205)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2012-04-27 00:23:36 UTC (rev 9206)
@@ -25,6 +25,7 @@
     "CommonHome",
 ]
 
+from uuid import uuid4
 
 from zope.interface import implements, directlyProvides
 
@@ -82,6 +83,7 @@
 from twistedcaldav.customxml import NotificationType
 from twistedcaldav.dateops import datetimeMktime, parseSQLTimestamp,\
     pyCalendarTodatetime
+from txdav.xml.rfc2518 import DisplayName
 
 from cStringIO import StringIO
 from sqlparse import parse
@@ -167,22 +169,21 @@
 
     def eachCalendarHome(self):
         """
-        @see L{ICalendarStore.eachCalendarHome}
+        @see: L{ICalendarStore.eachCalendarHome}
         """
         return []
 
 
     def eachAddressbookHome(self):
         """
-        @see L{IAddressbookStore.eachAddressbookHome}
+        @see: L{IAddressbookStore.eachAddressbookHome}
         """
         return []
 
 
-
     def newTransaction(self, label="unlabeled"):
         """
-        @see L{IDataStore.newTransaction}
+        @see: L{IDataStore.newTransaction}
         """
         txn = CommonStoreTransaction(
             self,
@@ -1943,6 +1944,57 @@
         return cls._allHomeChildrenQuery(False)
 
 
+    @classproperty
+    def _insertInviteQuery(cls): #@NoSelf
+        inv = schema.INVITE
+        return Insert(
+            {
+                inv.INVITE_UID: Parameter("uid"),
+                inv.NAME: Parameter("name"),
+                inv.HOME_RESOURCE_ID: Parameter("homeID"),
+                inv.RESOURCE_ID: Parameter("resourceID"),
+                inv.RECIPIENT_ADDRESS: Parameter("recipient")
+            }
+        )
+
+
+    @inlineCallbacks
+    def shareWith(self, shareeHome, mode):
+        """
+        Share this (owned) L{CommonHomeChild} with another home.
+
+        @param shareeHome: The home of the sharee.
+        @type shareeHome: L{CommonHome}
+
+        @param mode: The sharing mode; L{_BIND_MODE_READ} or
+            L{_BIND_MODE_WRITE}.
+        @type mode: L{str}
+
+        @return: the name of the shared calendar in the new calendar home.
+        @rtype: L{str}
+        """
+        dn = PropertyName.fromElement(DisplayName)
+        dnprop = (self.properties().get(dn) or
+                  DisplayName.fromString(self.name()))
+        # FIXME: honor current home type
+        newName = str(uuid4())
+        yield self._bindInsertQuery.on(
+            self._txn, homeID=shareeHome._resourceID,
+            resourceID=self._resourceID, name=newName, mode=mode,
+            seenByOwner=True, seenBySharee=True,
+            bindStatus=_BIND_STATUS_ACCEPTED,
+        )
+        yield self._insertInviteQuery.on(
+            self._txn, uid=newName, name=str(dnprop),
+            homeID=shareeHome._resourceID, resourceID=self._resourceID,
+            recipient=shareeHome.uid()
+        )
+        shareeProps = yield PropertyStore.load(shareeHome.uid(), self._txn,
+                                               self._resourceID)
+        shareeProps[dn] = dnprop
+        returnValue(newName)
+
+
     @classmethod
     @inlineCallbacks
     def loadAllObjects(cls, home, owned):
@@ -2139,18 +2191,21 @@
 
 
     @classproperty
-    def _initialOwnerBind(cls): #@NoSelf
+    def _bindInsertQuery(cls, **kw):
         """
-        DAL statement to create a bind entry for a particular home value.
+        DAL statement to create a bind entry that connects a collection to its
+        owner's home.
         """
         bind = cls._bindSchema
-        return Insert({bind.HOME_RESOURCE_ID: Parameter("homeID"),
-                       bind.RESOURCE_ID: Parameter("resourceID"),
-                       bind.RESOURCE_NAME: Parameter("name"),
-                       bind.BIND_MODE: _BIND_MODE_OWN,
-                       bind.SEEN_BY_OWNER: True,
-                       bind.SEEN_BY_SHAREE: True,
-                       bind.BIND_STATUS: _BIND_STATUS_ACCEPTED})
+        return Insert({
+            bind.HOME_RESOURCE_ID: Parameter("homeID"),
+            bind.RESOURCE_ID: Parameter("resourceID"),
+            bind.RESOURCE_NAME: Parameter("name"),
+            bind.BIND_MODE: Parameter("mode"),
+            bind.BIND_STATUS: Parameter("bindStatus"),
+            bind.SEEN_BY_OWNER: Parameter("seenByOwner"),
+            bind.SEEN_BY_SHAREE: Parameter("seenBySharee"),
+        })
 
 
     @classmethod
@@ -2173,8 +2228,11 @@
                                                   resourceID=resourceID))[0]
 
         # Bind table needs entry
-        yield cls._initialOwnerBind.on(home._txn, homeID=home._resourceID,
-                                       resourceID=resourceID, name=name)
+        yield cls._bindInsertQuery.on(
+            home._txn, homeID=home._resourceID, resourceID=resourceID,
+            name=name, mode=_BIND_MODE_OWN, seenByOwner=True,
+            seenBySharee=True, bindStatus=_BIND_STATUS_ACCEPTED
+        )
 
         # Initialize other state
         child = cls(home, name, resourceID, True)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120426/e59f8702/attachment-0001.html>


More information about the calendarserver-changes mailing list