[CalendarServer-changes] [9266] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed May 23 17:25:40 PDT 2012


Revision: 9266
          http://trac.macosforge.org/projects/calendarserver/changeset/9266
Author:   sagen at apple.com
Date:     2012-05-23 17:25:40 -0700 (Wed, 23 May 2012)
Log Message:
-----------
Purge tool now handles shared collections, and removes home resource properties.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tools/purge.py
    CalendarServer/trunk/calendarserver/tools/test/test_purge.py
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/caldav/datastore/test/common.py
    CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py
    CalendarServer/trunk/txdav/carddav/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/sql.py

Modified: CalendarServer/trunk/calendarserver/tools/purge.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/purge.py	2012-05-22 21:29:28 UTC (rev 9265)
+++ CalendarServer/trunk/calendarserver/tools/purge.py	2012-05-24 00:25:40 UTC (rev 9266)
@@ -660,7 +660,42 @@
 
     # See if calendar home is provisioned
     txn = store.newTransaction()
-    calHomeProvisioned = ((yield txn.calendarHomeWithUID(uid)) is not None)
+    storeCalHome = (yield txn.calendarHomeWithUID(uid))
+    calHomeProvisioned = storeCalHome is not None
+
+    # If in "completely" mode, unshare collections, remove notifications
+    if calHomeProvisioned and completely:
+
+        # Process shared-to-me calendars
+        names = list((yield storeCalHome.listSharedChildren()))
+        for name in names:
+            if verbose:
+                if dryrun:
+                    print "Would unshare: %s" % (name,)
+                else:
+                    print "Unsharing: %s" % (name,)
+            if not dryrun:
+                child = (yield storeCalHome.sharedChildWithName(name))
+                (yield child.unshare())
+
+        # Process shared calendars
+        children = list((yield storeCalHome.children()))
+        for child in children:
+            if verbose:
+                if dryrun:
+                    print "Would unshare: %s" % (child.name(),)
+                else:
+                    print "Unsharing: %s" % (child.name(),)
+            if not dryrun:
+                (yield child.unshare())
+
+        if not dryrun:
+            (yield storeCalHome.removeUnacceptedShares())
+            (yield storeCalHome.removeInvites())
+            notificationHome = (yield txn.notificationsWithUID(uid))
+            if notificationHome is not None:
+                (yield notificationHome.remove())
+
     (yield txn.commit())
 
     # Anything in the past is left alone
@@ -686,8 +721,8 @@
             calendarHome = yield principal.calendarHome(request)
             for collName in (yield calendarHome.listChildren()):
                 collection = (yield calendarHome.getChild(collName))
+
                 if collection.isCalendarCollection() or collName == "inbox":
-
                     childNames = []
 
                     if completely:

Modified: CalendarServer/trunk/calendarserver/tools/test/test_purge.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_purge.py	2012-05-22 21:29:28 UTC (rev 9265)
+++ CalendarServer/trunk/calendarserver/tools/test/test_purge.py	2012-05-24 00:25:40 UTC (rev 9266)
@@ -29,6 +29,7 @@
 from twisted.trial import unittest
 from twisted.internet.defer import inlineCallbacks
 from txdav.common.datastore.test.util import buildStore, populateCalendarsFrom, CommonCommonTests
+from txdav.common.datastore.sql_tables import _BIND_MODE_WRITE
 
 from twext.web2.http_headers import MimeType
 
@@ -783,6 +784,7 @@
     Tests for purging the data belonging to a given principal
     """
     uid = "6423F94A-6B76-4A3A-815B-D52CFD77935D"
+    uid2 = "37DB0C90-4DB1-4932-BC69-3DAB66F374F5"
 
     metadata = {
         "accessMode": "PUBLIC",
@@ -798,6 +800,10 @@
                 "attachment.ics" : (ATTACHMENT_ICS, metadata,),
             }
         },
+        uid2 : {
+            "calendar2" : {
+            }
+        },
     }
 
     @inlineCallbacks
@@ -819,8 +825,9 @@
         self.rootResource = getRootResource(config, self._sqlCalendarStore)
         self.directory = self.rootResource.getDirectory()
 
+        txn = self._sqlCalendarStore.newTransaction()
+
         # Add attachment to attachment.ics
-        txn = self._sqlCalendarStore.newTransaction()
         home = (yield txn.calendarHomeWithUID(self.uid))
         calendar = (yield home.calendarWithName("calendar1"))
         event = (yield calendar.calendarObjectWithName("attachment.ics"))
@@ -829,9 +836,25 @@
         t.write("attachment")
         t.write(" text")
         (yield t.loseConnection())
+
+        # Share calendars each way
+        home2 = (yield txn.calendarHomeWithUID(self.uid2))
+        calendar2 = (yield home2.calendarWithName("calendar2"))
+        self.sharedName = (yield calendar2.shareWith(home, _BIND_MODE_WRITE))
+        self.sharedName2 = (yield calendar.shareWith(home2, _BIND_MODE_WRITE))
+
         (yield txn.commit())
 
+        txn = self._sqlCalendarStore.newTransaction()
+        home = (yield txn.calendarHomeWithUID(self.uid))
+        calendar2 = (yield home.sharedChildWithName(self.sharedName))
+        self.assertNotEquals(calendar2, None)
+        home2 = (yield txn.calendarHomeWithUID(self.uid2))
+        calendar1 = (yield home2.sharedChildWithName(self.sharedName2))
+        self.assertNotEquals(calendar1, None)
+        (yield txn.commit())
 
+
     @inlineCallbacks
     def populate(self):
         yield populateCalendarsFrom(self.requirements, self.storeUnderTest())
@@ -865,6 +888,9 @@
         txn = self._sqlCalendarStore.newTransaction()
         home = (yield txn.calendarHomeWithUID(self.uid))
         self.assertEquals(home, None)
+        # Verify calendar1 was unshared to uid2
+        home2 = (yield txn.calendarHomeWithUID(self.uid2))
+        self.assertEquals((yield home2.sharedChildWithName(self.sharedName)), None)
         (yield txn.commit())
 
         count, ignored = (yield purgeUID(self.storeUnderTest(), self.uid, self.directory,

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2012-05-22 21:29:28 UTC (rev 9265)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2012-05-24 00:25:40 UTC (rev 9266)
@@ -60,7 +60,7 @@
     _ATTACHMENTS_MODE_NONE, _ATTACHMENTS_MODE_READ, _ATTACHMENTS_MODE_WRITE,\
     CALENDAR_HOME_TABLE, CALENDAR_HOME_METADATA_TABLE,\
     CALENDAR_AND_CALENDAR_BIND, CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE,\
-    CALENDAR_OBJECT_AND_BIND_TABLE, schema
+    CALENDAR_OBJECT_AND_BIND_TABLE, _BIND_STATUS_INVITED, schema
 from twext.enterprise.dal.syntax import Select, Count, ColumnSyntax
 from twext.enterprise.dal.syntax import Insert
 from twext.enterprise.dal.syntax import Update
@@ -131,6 +131,7 @@
         cb = schema.CALENDAR_BIND
         cor = schema.CALENDAR_OBJECT_REVISIONS
         at = schema.ATTACHMENT
+        rp = schema.RESOURCE_PROPERTY
 
         # delete attachments corresponding to this home, also removing from disk
         rows = (yield Select(
@@ -167,6 +168,11 @@
             Where=ch.RESOURCE_ID == self._resourceID
         ).on(self._txn)
 
+        yield Delete(
+            From=rp,
+            Where=rp.RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
         yield self._cacher.delete(str(self._ownerUID))
 
 
@@ -334,7 +340,52 @@
             yield _requireCalendarWithType("VTODO", "tasks")
 
 
+    @classproperty
+    def _unacceptedSharesQuery(cls): #@NoSelf
+        cb = schema.CALENDAR_BIND
+        return Select([cb.CALENDAR_RESOURCE_NAME],
+            From=cb,
+            Where=(cb.CALENDAR_HOME_RESOURCE_ID == Parameter("homeResourceID")).And(cb.BIND_STATUS == _BIND_STATUS_INVITED))
 
+
+    @inlineCallbacks
+    def removeUnacceptedShares(self):
+        """
+        Unbinds any collections that have been shared to this home but not yet
+        accepted.  Associated invite entries are also removed.
+        """
+        inv = schema.INVITE
+        cb = schema.CALENDAR_BIND
+        rows = yield self._unacceptedSharesQuery.on(self._txn, homeResourceID=self._resourceID)
+        for (resourceName,) in rows:
+            kwds = { "ResourceName" : resourceName }
+            yield Delete(
+                From=inv,
+                Where=(
+                    inv.INVITE_UID == Parameter("ResourceName")
+                ),
+            ).on(self._txn, **kwds)
+
+            yield Delete(
+                From=cb,
+                Where=(
+                    cb.CALENDAR_RESOURCE_NAME == Parameter("ResourceName")
+                ),
+            ).on(self._txn, **kwds)
+
+
+    @inlineCallbacks
+    def removeInvites(self):
+        """
+        Remove all remaining invite entries for this home.
+        """
+        inv = schema.INVITE
+        kwds = { "HomeResourceID" : self._resourceID }
+        yield Delete(
+            From=inv,
+            Where=(inv.HOME_RESOURCE_ID == Parameter("HomeResourceID"))
+        ).on(self._txn, **kwds)
+
 CalendarHome._register(ECALENDARTYPE)
 
 
@@ -663,7 +714,14 @@
             newParentID=newparent._resourceID,
             resourceID=child._resourceID
         )
-        
+
+    def unshare(self):
+        """
+        Unshares a collection, regardless of which "direction" it was shared.
+        """
+        return super(Calendar, self).unshare(ECALENDARTYPE)
+
+
 icalfbtype_to_indexfbtype = {
     "UNKNOWN"         : 0,
     "FREE"            : 1,

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/common.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2012-05-22 21:29:28 UTC (rev 9265)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2012-05-24 00:25:40 UTC (rev 9266)
@@ -1043,8 +1043,6 @@
         L{ICalendar.unshareWith} will remove a previously-shared calendar from
         another user's calendar home.
         """
-        # XXX: ideally this would actually be using the shared calendar object
-        # from the shareee's home and just calling .unshare() on it.
         yield self.test_shareWith()
         if commit:
             yield self.commit()
@@ -1058,8 +1056,49 @@
         shares = yield other.retrieveOldShares().allRecords()
         self.assertEqual(len(shares), 0)
 
+    @inlineCallbacks
+    def test_unshareSharerSide(self, commit=False):
+        """
+        Verify the coll.unshare( ) method works when called from the
+        sharer's copy
+        """
+        yield self.test_shareWith()
+        if commit:
+            yield self.commit()
+        cal = yield self.calendarUnderTest()
+        other = yield self.homeUnderTest(name=OTHER_HOME_UID)
+        otherCal = yield other.sharedChildWithName(self.sharedName)
+        self.assertNotEqual(otherCal, None)
+        yield cal.unshare()
+        otherCal = yield other.sharedChildWithName(self.sharedName)
+        self.assertEqual(otherCal, None)
+        invites = yield cal.retrieveOldInvites().allRecords()
+        self.assertEqual(len(invites), 0)
+        shares = yield other.retrieveOldShares().allRecords()
+        self.assertEqual(len(shares), 0)
 
     @inlineCallbacks
+    def test_unshareShareeSide(self, commit=False):
+        """
+        Verify the coll.unshare( ) method works when called from the
+        sharee's copy
+        """
+        yield self.test_shareWith()
+        if commit:
+            yield self.commit()
+        cal = yield self.calendarUnderTest()
+        other = yield self.homeUnderTest(name=OTHER_HOME_UID)
+        otherCal = yield other.sharedChildWithName(self.sharedName)
+        self.assertNotEqual(otherCal, None)
+        yield otherCal.unshare()
+        otherCal = yield other.sharedChildWithName(self.sharedName)
+        self.assertEqual(otherCal, None)
+        invites = yield cal.retrieveOldInvites().allRecords()
+        self.assertEqual(len(invites), 0)
+        shares = yield other.retrieveOldShares().allRecords()
+        self.assertEqual(len(shares), 0)
+
+    @inlineCallbacks
     def test_unshareWithInDifferentTransaction(self):
         """
         L{ICalendar.unshareWith} will remove a previously-shared calendar from

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py	2012-05-22 21:29:28 UTC (rev 9265)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py	2012-05-24 00:25:40 UTC (rev 9266)
@@ -477,6 +477,8 @@
     test_unshareWith = test_shareWith
     test_unshareWithInDifferentTransaction = test_shareWith
     test_asShared = test_shareWith
+    test_unshareSharerSide = test_shareWith
+    test_unshareShareeSide = test_shareWith
 
 
     def test_init(self):

Modified: CalendarServer/trunk/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/sql.py	2012-05-22 21:29:28 UTC (rev 9265)
+++ CalendarServer/trunk/txdav/carddav/datastore/sql.py	2012-05-24 00:25:40 UTC (rev 9266)
@@ -107,6 +107,7 @@
         ah = schema.ADDRESSBOOK_HOME
         ab = schema.ADDRESSBOOK_BIND
         aor = schema.ADDRESSBOOK_OBJECT_REVISIONS
+        rp = schema.RESOURCE_PROPERTY
 
         yield Delete(
             From=ab,
@@ -123,6 +124,11 @@
             Where=ah.RESOURCE_ID == self._resourceID
         ).on(self._txn)
 
+        yield Delete(
+            From=rp,
+            Where=rp.RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
         yield self._cacher.delete(str(self._ownerUID))
 
 
@@ -201,7 +207,13 @@
         return MimeType.fromString("text/vcard; charset=utf-8")
 
 
+    def unshare(self):
+        """
+        Unshares a collection, regardless of which "direction" it was shared.
+        """
+        return super(AddressBook, self).unshare(EADDRESSBOOKTYPE)
 
+
 class AddressBookObject(CommonObjectResource):
 
     implements(IAddressBookObject)

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2012-05-22 21:29:28 UTC (rev 9265)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2012-05-24 00:25:40 UTC (rev 9266)
@@ -437,7 +437,6 @@
         """
         return NotificationCollection.notificationsWithUID(self, uid)
 
-
     @classproperty
     def _insertAPNSubscriptionQuery(cls): #@NoSelf
         apn = schema.APN_SUBSCRIPTIONS
@@ -2106,6 +2105,28 @@
         return self._bindMode
 
 
+    @inlineCallbacks
+    def unshare(self, homeType):
+        """
+        Unshares a collection, regardless of which "direction" it was shared.
+
+        @param homeType: a valid store type (ECALENDARTYPE or EADDRESSBOOKTYPE)
+        """
+        mode = self.shareMode()
+        if mode == _BIND_MODE_OWN:
+            # This collection may be shared to others
+            for sharedToHome in [x.viewerHome() for x in (yield self.asShared())]:
+                (yield self.unshareWith(sharedToHome))
+        else:
+            # This collection is shared to me
+            sharerHomeID = (yield self.sharerHomeID())
+            sharerHome = (yield self._txn.homeWithResourceID(homeType,
+                sharerHomeID))
+            sharerCollection = (yield sharerHome.childWithID(self._resourceID))
+            (yield sharerCollection.unshareWith(self._home))
+
+
+
     @classproperty
     def _bindEntriesFor(cls):
         bind = cls._bindSchema
@@ -3641,7 +3662,31 @@
         self.notifyChanged()
 
 
+    @inlineCallbacks
+    def remove(self):
+        """
+        Remove DB rows corresponding to this notification home.
+        """
+        # Delete NOTIFICATION rows
+        no = schema.NOTIFICATION
+        kwds = { "ResourceID" : self._resourceID }
+        yield Delete(
+            From=no,
+            Where=(
+                no.NOTIFICATION_HOME_RESOURCE_ID == Parameter("ResourceID")
+            ),
+        ).on(self._txn, **kwds)
 
+        # Delete NOTIFICATION_HOME (will cascade to NOTIFICATION_OBJECT_REVISIONS)
+        nh = schema.NOTIFICATION_HOME
+        yield Delete(
+            From=nh,
+            Where=(
+                nh.RESOURCE_ID == Parameter("ResourceID")
+            ),
+        ).on(self._txn, **kwds)
+
+
 class NotificationObject(LoggingMixIn, FancyEqMixin):
 
     implements(INotificationObject)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120523/d82de579/attachment-0001.html>


More information about the calendarserver-changes mailing list