[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