[CalendarServer-changes] [8474] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Tue Dec 20 08:46:40 PST 2011


Revision: 8474
          http://trac.macosforge.org/projects/calendarserver/changeset/8474
Author:   cdaboo at apple.com
Date:     2011-12-20 08:46:39 -0800 (Tue, 20 Dec 2011)
Log Message:
-----------
Make sure a default calendar is always present - forcibly re-provision if not.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/schedule.py
    CalendarServer/trunk/twistedcaldav/test/test_schedule.py
    CalendarServer/trunk/txdav/caldav/datastore/file.py
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/file.py

Modified: CalendarServer/trunk/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/schedule.py	2011-12-20 16:45:15 UTC (rev 8473)
+++ CalendarServer/trunk/twistedcaldav/schedule.py	2011-12-20 16:46:39 UTC (rev 8474)
@@ -296,20 +296,32 @@
         defaultCalendarURL = joinURL(calendarHomeURL, test_name)
         defaultCalendar = (yield request.locateResource(defaultCalendarURL))
         if defaultCalendar is None or not defaultCalendar.exists():
-            # FIXME: the back-end should re-provision a default calendar here.
             # Really, the dead property shouldn't be necessary, and this should
             # be entirely computed by a back-end method like 'defaultCalendar()'
-            for calendarName in (yield self.parent._newStoreHome.listCalendars()):  # These are only unshared children
-                if calendarName == "inbox":
-                    continue
-                calendar = (yield self.parent._newStoreHome.calendarWithName(calendarName))
-                if not calendar.isSupportedComponent(componentType):
-                    continue
-                break
-            else:
-                raise RuntimeError("No valid calendars to use as a default %s calendar." % (componentType,))
+            
+            @inlineCallbacks
+            def _findDefault():
+                for calendarName in (yield self.parent._newStoreHome.listCalendars()):  # These are only unshared children
+                    if calendarName == "inbox":
+                        continue
+                    calendar = (yield self.parent._newStoreHome.calendarWithName(calendarName))
+                    if not calendar.isSupportedComponent(componentType):
+                        continue
+                    break
+                else:
+                    calendarName = None
+                returnValue(calendarName)
+            
+            foundName = yield _findDefault()
+            if foundName is None:
+                # Create a default and try and get its name again
+                yield self.parent._newStoreHome.ensureDefaultCalendarsExist()
+                foundName = yield _findDefault()
+                if foundName is None:
+                    # Failed to even create a default - bad news...
+                    raise RuntimeError("No valid calendars to use as a default %s calendar." % (componentType,))
 
-            defaultCalendarURL = joinURL(calendarHomeURL, calendarName)
+            defaultCalendarURL = joinURL(calendarHomeURL, foundName)
 
         prop = prop_to_set(davxml.HRef(defaultCalendarURL))
         self.writeDeadProperty(prop)
@@ -322,7 +334,7 @@
         not exist, automatically provision it. 
         """
 
-        # Check any default calendar property first
+        # Check any default calendar property first - this will create if none exists
         default = (yield self.readProperty(caldavxml.ScheduleDefaultCalendarURL.qname(), request))
         if len(default.children) == 1:
             defaultURL = str(default.children[0])
@@ -353,7 +365,7 @@
             if default is None:
                 new_name = "%ss" % (componentType.lower()[1:],)
                 default = yield self.parent._newStoreHome.createCalendarWithName(new_name)
-                default.setSupportedComponents(componentType.upper())
+                yield default.setSupportedComponents(componentType.upper())
             
             # Need L{DAVResource} object to return not new store object
             default = (yield request.locateResource(joinURL(self.parent.url(), default.name())))

Modified: CalendarServer/trunk/twistedcaldav/test/test_schedule.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_schedule.py	2011-12-20 16:45:15 UTC (rev 8473)
+++ CalendarServer/trunk/twistedcaldav/test/test_schedule.py	2011-12-20 16:46:39 UTC (rev 8474)
@@ -101,7 +101,7 @@
     @inlineCallbacks
     def test_pick_default_vevent_calendar(self):
         """
-        Make calendar
+        Test that pickNewDefaultCalendar will choose the correct calendar.
         """
         
         request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
@@ -129,9 +129,10 @@
     @inlineCallbacks
     def test_pick_default_vtodo_calendar(self):
         """
-        Make calendar
+        Test that pickNewDefaultCalendar will choose the correct tasks calendar.
         """
         
+        
         request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
         inbox = yield request.locateResource("/calendars/users/wsanchez/inbox")
 
@@ -155,6 +156,75 @@
         request._newStoreTransaction.abort()
 
     @inlineCallbacks
+    def test_missing_default_vevent_calendar(self):
+        """
+        Test that pickNewDefaultCalendar will create a missing default calendar.
+        """
+        
+        
+        request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
+        home = yield request.locateResource("/calendars/users/wsanchez/")
+        inbox = yield request.locateResource("/calendars/users/wsanchez/inbox")
+
+        # default property initially not present
+        try:
+            inbox.readDeadProperty(caldavxml.ScheduleDefaultCalendarURL)
+        except HTTPError:
+            pass
+        else:
+            self.fail("caldavxml.ScheduleDefaultCalendarURL is not empty")
+
+        # Forcibly remove the one we need
+        yield home._newStoreHome.removeChildWithName("calendar")
+        names = [calendarName for calendarName in (yield home._newStoreHome.listCalendars())]
+        self.assertTrue("calendar" not in names)
+
+        yield inbox.pickNewDefaultCalendar(request)
+
+        try:
+            default = inbox.readDeadProperty(caldavxml.ScheduleDefaultCalendarURL)
+        except HTTPError:
+            self.fail("caldavxml.ScheduleDefaultCalendarURL is not present")
+        else:
+            self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar")
+
+        request._newStoreTransaction.abort()
+
+    @inlineCallbacks
+    def test_missing_default_vtodo_calendar(self):
+        """
+        Test that pickNewDefaultCalendar will create a missing default tasks calendar.
+        """
+        
+        request = SimpleRequest(self.site, "GET", "/calendars/users/wsanchez/")
+        home = yield request.locateResource("/calendars/users/wsanchez/")
+        inbox = yield request.locateResource("/calendars/users/wsanchez/inbox")
+
+        # default property initially not present
+        try:
+            inbox.readDeadProperty(customxml.ScheduleDefaultTasksURL)
+        except HTTPError:
+            pass
+        else:
+            self.fail("caldavxml.ScheduleDefaultTasksURL is not empty")
+
+        # Forcibly remove the one we need
+        yield home._newStoreHome.removeChildWithName("tasks")
+        names = [calendarName for calendarName in (yield home._newStoreHome.listCalendars())]
+        self.assertTrue("tasks" not in names)
+
+        yield inbox.pickNewDefaultCalendar(request, tasks=True)
+
+        try:
+            default = inbox.readDeadProperty(customxml.ScheduleDefaultTasksURL)
+        except HTTPError:
+            self.fail("caldavxml.ScheduleDefaultTasksURL is not present")
+        else:
+            self.assertEqual(str(default.children[0]), "/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/tasks")
+
+        request._newStoreTransaction.abort()
+
+    @inlineCallbacks
     def test_pick_default_other(self):
         """
         Make calendar

Modified: CalendarServer/trunk/txdav/caldav/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/file.py	2011-12-20 16:45:15 UTC (rev 8473)
+++ CalendarServer/trunk/txdav/caldav/datastore/file.py	2011-12-20 16:46:39 UTC (rev 8474)
@@ -28,6 +28,7 @@
 ]
 
 import hashlib
+import uuid
 
 from errno import ENOENT
 
@@ -199,7 +200,34 @@
             
         self.createCalendarWithName("inbox")
 
+    def ensureDefaultCalendarsExist(self):
+        """
+        Double check that we have calendars supporting at least VEVENT and VTODO,
+        and create if missing.
+        """
 
+        # Double check that we have calendars supporting at least VEVENT and VTODO
+        if config.RestrictCalendarsToOneComponentType:
+            supported_components = set()
+            names = set()
+            for calendar in self.calendars():
+                if calendar.name() == "inbox":
+                    continue
+                names.add(calendar.name())
+                result = calendar.getSupportedComponents()
+                supported_components.update(result.split(","))
+
+            def _requireCalendarWithType(support_component, tryname):
+                if support_component not in supported_components:
+                    newname = tryname
+                    if newname in names:
+                        newname = str(uuid.uuid4())
+                    newcal = self.createCalendarWithName(newname)
+                    newcal.setSupportedComponents(support_component)
+            
+            _requireCalendarWithType("VEVENT", "calendar")
+            _requireCalendarWithType("VTODO", "tasks")
+
 class Calendar(CommonHomeChild):
     """
     File-based implementation of L{ICalendar}.

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2011-12-20 16:45:15 UTC (rev 8473)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2011-12-20 16:46:39 UTC (rev 8474)
@@ -225,11 +225,11 @@
         
         # Check whether components type must be separate
         if config.RestrictCalendarsToOneComponentType:
-            defaultCal.setSupportedComponents("VEVENT")
+            yield defaultCal.setSupportedComponents("VEVENT")
             
             # Default tasks
             defaultTasks = yield self.createCalendarWithName("tasks")
-            defaultTasks.setSupportedComponents("VTODO")
+            yield defaultTasks.setSupportedComponents("VTODO")
             
         yield self.createCalendarWithName("inbox")
 
@@ -250,6 +250,15 @@
             split_count = yield calendar.splitCollectionByComponentTypes()
             self.log_warn("  Calendar: '%s', split into %d" % (calendar.name(), split_count+1,))
 
+        yield self.ensureDefaultCalendarsExist()
+
+    @inlineCallbacks
+    def ensureDefaultCalendarsExist(self):
+        """
+        Double check that we have calendars supporting at least VEVENT and VTODO,
+        and create if missing.
+        """
+
         # Double check that we have calendars supporting at least VEVENT and VTODO
         if config.RestrictCalendarsToOneComponentType:
             supported_components = set()
@@ -269,7 +278,7 @@
                     if newname in names:
                         newname = str(uuid.uuid4())
                     newcal = yield self.createCalendarWithName(newname)
-                    newcal.setSupportedComponents(support_component)
+                    yield newcal.setSupportedComponents(support_component)
             
             yield _requireCalendarWithType("VEVENT", "calendar")
             yield _requireCalendarWithType("VTODO", "tasks")

Modified: CalendarServer/trunk/txdav/common/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/file.py	2011-12-20 16:45:15 UTC (rev 8473)
+++ CalendarServer/trunk/txdav/common/datastore/file.py	2011-12-20 16:46:39 UTC (rev 8474)
@@ -391,7 +391,8 @@
         return set(self._newChildren.itervalues()) | set(
             self.childWithName(name)
             for name in self._path.listdir()
-            if not name.startswith(".")
+            if not name.startswith(".") and
+                name not in self._removedChildren
         )
 
     # For file store there is no efficient "bulk" load of all children so just
@@ -408,7 +409,9 @@
         ) | set(
             name
             for name in self._path.listdir()
-            if not name.startswith(".") and self._path.child(name).isdir()
+            if not name.startswith(".") and 
+                self._path.child(name).isdir() and
+                name not in self._removedChildren
         ))
 
 
@@ -500,7 +503,10 @@
         try:
             child.remove()
         finally:
-            self._removedChildren.add(name)
+            if name in self._newChildren:
+                del self._newChildren[name]
+            else:
+                self._removedChildren.add(name)
 
     @inlineCallbacks
     def syncToken(self):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20111220/9be3f1b2/attachment-0001.html>


More information about the calendarserver-changes mailing list