[CalendarServer-changes] [8002] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Aug 22 10:57:28 PDT 2011


Revision: 8002
          http://trac.macosforge.org/projects/calendarserver/changeset/8002
Author:   sagen at apple.com
Date:     2011-08-22 10:57:27 -0700 (Mon, 22 Aug 2011)
Log Message:
-----------
calendarserver_purge_principals now has a --completely option which will delete all events, even those in the past.  Empty collections and homes are now deleted as well.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/tools/purge.py
    CalendarServer/trunk/calendarserver/tools/test/test_purge_old_events.py
    CalendarServer/trunk/contrib/migration/calendarmigrator.py
    CalendarServer/trunk/doc/calendarserver_purge_principals.8
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/carddav/datastore/sql.py

Modified: CalendarServer/trunk/calendarserver/tools/purge.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/purge.py	2011-08-19 18:10:34 UTC (rev 8001)
+++ CalendarServer/trunk/calendarserver/tools/purge.py	2011-08-22 17:57:27 UTC (rev 8002)
@@ -101,6 +101,7 @@
     print "  Remove a principal's events and contacts from the calendar server"
     print ""
     print "options:"
+    print "  -c --completely: By default, only future events are canceled; this option cancels all events"
     print "  -h --help: print this help and exit"
     print "  -f --config <path>: Specify caldavd.plist configuration path"
     print "  -n --dry-run: calculate how many events and contacts to purge, but do not purge data"
@@ -190,13 +191,15 @@
     guids = None
     dryrun = False
     verbose = False
+    completely = False
 
     @inlineCallbacks
     def doWork(self):
         rootResource = self.rootResource()
         directory = rootResource.getDirectory()
         total = (yield purgeGUIDs(directory, rootResource, self.guids,
-            verbose=self.verbose, dryrun=self.dryrun))
+            verbose=self.verbose, dryrun=self.dryrun,
+            completely=self.completely))
         if self.verbose:
             amount = "%d event%s" % (total, "s" if total > 1 else "")
             if self.dryrun:
@@ -348,7 +351,8 @@
 
     try:
         (optargs, args) = getopt(
-            sys.argv[1:], "f:hnv", [
+            sys.argv[1:], "cf:hnv", [
+                "completely",
                 "dry-run",
                 "config=",
                 "help",
@@ -364,11 +368,15 @@
     configFileName = None
     dryrun = False
     verbose = False
+    completely = False
 
     for opt, arg in optargs:
         if opt in ("-h", "--help"):
             usage_purge_principal()
 
+        elif opt in ("-c", "--completely"):
+            completely = True
+
         elif opt in ("-v", "--verbose"):
             verbose = True
 
@@ -383,6 +391,7 @@
 
     # args is a list of guids
     PurgePrincipalService.guids = args
+    PurgePrincipalService.completely = completely
     PurgePrincipalService.dryrun = dryrun
     PurgePrincipalService.verbose = verbose
 
@@ -487,14 +496,15 @@
 
 
 @inlineCallbacks
-def purgeGUIDs(directory, root, guids, verbose=False, dryrun=False):
+def purgeGUIDs(directory, root, guids, verbose=False, dryrun=False,
+    completely=False):
     total = 0
 
     allAssignments = { }
 
     for guid in guids:
         count, allAssignments[guid] = (yield purgeGUID(guid, directory, root,
-            verbose=verbose, dryrun=dryrun))
+            verbose=verbose, dryrun=dryrun, completely=completely))
         total += count
 
     # TODO: figure out what to do with the purged proxy assignments...
@@ -607,7 +617,7 @@
 
 @inlineCallbacks
 def purgeGUID(guid, directory, root, verbose=False, dryrun=False, proxies=True,
-    when=None):
+    when=None, completely=False):
 
     if when is None:
         when = PyCalendarDateTime.getNowUTC()
@@ -661,11 +671,26 @@
         collection = (yield calendarHome.getChild(collName))
         if collection.isCalendarCollection():
 
-            for childName, childUid, childType in (yield collection.index().indexedSearch(filter)):
+            childNames = []
+
+            if completely:
+                # all events
+                for childName in (yield collection.listChildren()):
+                    childNames.append(childName)
+            else:
+                # events matching filter
+                for childName, childUid, childType in (yield collection.index().indexedSearch(filter)):
+                    childNames.append(childName)
+
+            for childName in childNames:
+
                 childResource = (yield collection.getChild(childName))
-                event = (yield childResource.iCalendar())
-                event = perUserFilter.filter(event)
-                action = cancelEvent(event, when, cua)
+                if completely:
+                    action = CANCELEVENT_SHOULD_DELETE
+                else:
+                    event = (yield childResource.iCalendar())
+                    event = perUserFilter.filter(event)
+                    action = cancelEvent(event, when, cua)
 
                 uri = "/calendars/__uids__/%s/%s/%s" % (guid, collName, childName)
                 request.path = uri
@@ -705,6 +730,34 @@
 
     txn = request._newStoreTransaction
 
+    # Remove empty calendar collections (and calendar home if no more
+    # calendars)
+    calHome = (yield txn.calendarHomeWithUID(guid))
+    if calHome is not None:
+        calendars = list((yield calHome.calendars()))
+        remainingCalendars = len(calendars)
+        for calColl in calendars:
+            if len(list((yield calColl.calendarObjects()))) == 0:
+                remainingCalendars -= 1
+                calendarName = calColl.name()
+                if verbose:
+                    if dryrun:
+                        print "Would delete calendar: %s" % (calendarName,)
+                    else:
+                        print "Deleting calendar: %s" % (calendarName,)
+                if not dryrun:
+                    (yield calHome.removeChildWithName(calendarName))
+
+        if not remainingCalendars:
+            if verbose:
+                if dryrun:
+                    print "Would delete calendar home"
+                else:
+                    print "Deleting calendar home"
+            if not dryrun:
+                (yield calHome.remove())
+
+
     # Remove VCards
     abHome = (yield txn.addressbookHomeWithUID(guid))
     if abHome is not None:
@@ -720,10 +773,24 @@
                 if not dryrun:
                     (yield abColl.removeObjectResourceWithName(cardName))
                 count += 1
+            if verbose:
+                abName = abColl.name()
+                if dryrun:
+                    print "Would delete addressbook: %s" % (abName,)
+                else:
+                    print "Deleting addressbook: %s" % (abName,)
             if not dryrun:
                 # Also remove the addressbook collection itself
                 (yield abHome.removeChildWithName(abColl.name()))
 
+        if verbose:
+            if dryrun:
+                print "Would delete addressbook home"
+            else:
+                print "Deleting addressbook home"
+        if not dryrun:
+            (yield abHome.remove())
+
     # Commit
     (yield txn.commit())
 

Modified: CalendarServer/trunk/calendarserver/tools/test/test_purge_old_events.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_purge_old_events.py	2011-08-19 18:10:34 UTC (rev 8001)
+++ CalendarServer/trunk/calendarserver/tools/test/test_purge_old_events.py	2011-08-22 17:57:27 UTC (rev 8002)
@@ -543,8 +543,46 @@
         abColl = (yield abHome.addressbookWithName("addressbook"))
         self.assertEquals(abColl, None)
 
+        calHome = (yield txn.calendarHomeWithUID("home1"))
+        calColl = (yield calHome.calendarWithName("calendar1"))
+        self.assertEquals(len( (yield calColl.calendarObjects()) ), 2)
 
+
     @inlineCallbacks
+    def test_purgeGUIDCompletely(self):
+        txn = self._sqlCalendarStore.newTransaction()
+
+        # Create an addressbook and one CardDAV resource
+        abHome = (yield txn.addressbookHomeWithUID("home1", create=True))
+        abColl = (yield abHome.addressbookWithName("addressbook"))
+        (yield abColl.createAddressBookObjectWithName("card1",
+            VCardComponent.fromString(VCARD_1)))
+        self.assertEquals(len( (yield abColl.addressbookObjects()) ), 1)
+
+        # Verify there are 3 events in calendar1
+        calHome = (yield txn.calendarHomeWithUID("home1"))
+        calColl = (yield calHome.calendarWithName("calendar1"))
+        self.assertEquals(len( (yield calColl.calendarObjects()) ), 3)
+
+        # Make the newly created objects available to the purgeGUID transaction
+        (yield txn.commit())
+
+        # Purge home1 completely
+        total, ignored = (yield purgeGUID("home1", self.directory,
+            self.rootResource, verbose=False, proxies=False, completely=True))
+
+        # 4 items deleted: 3 events and 1 vcard
+        self.assertEquals(total, 4)
+
+        # Homes have been deleted as well
+        txn = self._sqlCalendarStore.newTransaction()
+        abHome = (yield txn.addressbookHomeWithUID("home1"))
+        self.assertEquals(abHome, None)
+        calHome = (yield txn.calendarHomeWithUID("home1"))
+        self.assertEquals(calHome, None)
+
+
+    @inlineCallbacks
     def test_purgeOrphanedAttachments(self):
 
         (yield self._addAttachment())

Modified: CalendarServer/trunk/contrib/migration/calendarmigrator.py
===================================================================
--- CalendarServer/trunk/contrib/migration/calendarmigrator.py	2011-08-19 18:10:34 UTC (rev 8001)
+++ CalendarServer/trunk/contrib/migration/calendarmigrator.py	2011-08-22 17:57:27 UTC (rev 8002)
@@ -157,7 +157,7 @@
 SSLPort
 """.split()
 
-ignoredKkeys = """
+ignoredKeys = """
 ControlSocket
 EnableAnonymousReadRoot
 EnableFindSharedReport

Modified: CalendarServer/trunk/doc/calendarserver_purge_principals.8
===================================================================
--- CalendarServer/trunk/doc/calendarserver_purge_principals.8	2011-08-19 18:10:34 UTC (rev 8001)
+++ CalendarServer/trunk/doc/calendarserver_purge_principals.8	2011-08-22 17:57:27 UTC (rev 8002)
@@ -22,6 +22,7 @@
 .Nd Darwin Calendar Server deprovisioned user clean-up utility
 .Sh SYNOPSIS
 .Nm
+.Op Fl -completely
 .Op Fl -config Ar file
 .Op Fl -dry-run
 .Op Fl -verbose
@@ -30,7 +31,7 @@
 .Op guid ...
 .Sh DESCRIPTION
 .Nm
-is a tool for removing one or more principals' future events, proxy assignments, and contacts from the calendar server.  Events in the past are retained, but any ongoing events are canceled.
+is a tool for removing one or more principals' future events, proxy assignments, and contacts from the calendar server.  By default, events in the past are retained, but any ongoing events are canceled.
 .Pp
 .Nm
 should be run as a user with the same priviledges as the Calendar
@@ -40,6 +41,8 @@
 .Bl -tag -width flag
 .It Fl h, -help
 Display usage information
+.It Fl c, -completely
+Delete/cancel all events
 .It Fl f, -config Ar FILE
 Use the Calendar Server configuration specified in the given file.  Defaults to /etc/caldavd/caldavd.plist.
 .It Fl n, -dry-run

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2011-08-19 18:10:34 UTC (rev 8001)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2011-08-22 17:57:27 UTC (rev 8002)
@@ -116,7 +116,35 @@
     listCalendars = CommonHome.listChildren
     loadCalendars = CommonHome.loadChildren
 
+    @inlineCallbacks
+    def remove(self):
+        ch = schema.CALENDAR_HOME
+        cb = schema.CALENDAR_BIND
+        chm = schema.CALENDAR_HOME_METADATA
+        cor = schema.CALENDAR_OBJECT_REVISIONS
 
+        yield Delete(
+            From=chm,
+            Where=chm.RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
+        yield Delete(
+            From=cb,
+            Where=cb.CALENDAR_HOME_RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
+        yield Delete(
+            From=cor,
+            Where=cor.CALENDAR_HOME_RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
+        yield Delete(
+            From=ch,
+            Where=ch.RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
+        yield self._cacher.delete(str(self._ownerUID))
+
     @inlineCallbacks
     def hasCalendarResourceUIDSomewhereElse(self, uid, ok_object, type):
 

Modified: CalendarServer/trunk/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/sql.py	2011-08-19 18:10:34 UTC (rev 8001)
+++ CalendarServer/trunk/txdav/carddav/datastore/sql.py	2011-08-22 17:57:27 UTC (rev 8002)
@@ -48,6 +48,7 @@
 
 from txdav.common.datastore.sql import CommonHome, CommonHomeChild,\
     CommonObjectResource
+from twext.enterprise.dal.syntax import Delete
 from twext.enterprise.dal.syntax import Insert
 from twext.enterprise.dal.syntax import Update
 from twext.enterprise.dal.syntax import utcNowSQL
@@ -98,6 +99,36 @@
     removeAddressBookWithName = CommonHome.removeChildWithName
 
 
+    @inlineCallbacks
+    def remove(self):
+        ah = schema.ADDRESSBOOK_HOME
+        ab = schema.ADDRESSBOOK_BIND
+        ahm = schema.ADDRESSBOOK_HOME_METADATA
+        aor = schema.ADDRESSBOOK_OBJECT_REVISIONS
+
+        yield Delete(
+            From=ahm,
+            Where=ahm.RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
+        yield Delete(
+            From=ab,
+            Where=ab.ADDRESSBOOK_HOME_RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
+        yield Delete(
+            From=aor,
+            Where=aor.ADDRESSBOOK_HOME_RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
+        yield Delete(
+            From=ah,
+            Where=ah.RESOURCE_ID == self._resourceID
+        ).on(self._txn)
+
+        yield self._cacher.delete(str(self._ownerUID))
+
+
     def createdHome(self):
         return self.createAddressBookWithName("addressbook")
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110822/3139c627/attachment-0001.html>


More information about the calendarserver-changes mailing list