[CalendarServer-changes] [6720] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Jan 6 16:58:37 PST 2011


Revision: 6720
          http://trac.macosforge.org/projects/calendarserver/changeset/6720
Author:   sagen at apple.com
Date:     2011-01-06 16:58:30 -0800 (Thu, 06 Jan 2011)
Log Message:
-----------
First pass at fixing DTSTART/UNTIL type mismatches in existing data as it's read in from .ics files.  We can improve the logic for how UNTIL is modified if we need to.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/ical.py
    CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
    CalendarServer/trunk/txdav/caldav/datastore/file.py

Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py	2011-01-06 22:36:44 UTC (rev 6719)
+++ CalendarServer/trunk/twistedcaldav/ical.py	2011-01-07 00:58:30 UTC (rev 6720)
@@ -1279,9 +1279,10 @@
 
         self.validateComponentsForCalDAV(False)
 
-    def validateComponentsForCalDAV(self, method):
+    def validateComponentsForCalDAV(self, method, fix=False):
         """
         @param method:     True if METHOD property is allowed, False otherwise.
+        @param fix:        True to try and fix bogus data
         @raise InvalidICalendarDataError: if the given calendar component is not valid for
             use as a X{CalDAV} resource.
         """
@@ -1374,19 +1375,39 @@
                 # If they're not both date or both date-time, raise error
                 if (subcomponent.hasProperty("DTSTART") and
                     subcomponent.hasProperty("RRULE")):
-                    dtType = type(subcomponent.getProperty("DTSTART").value())
+                    # dtValue may be datetime or date, or unicode in which case
+                    # we look at the length to see if it's datetime or date.
+                    dtValue = subcomponent.getProperty("DTSTART").value()
+                    dtType = type(dtValue)
+                    if dtType is unicode:
+                        dtType = datetime.date if len(dtValue) == 8 else datetime.datetime
                     for rrule in subcomponent.properties("RRULE"):
                         indexedTokens = {}
                         indexedTokens.update([valuePart.split("=")
                             for valuePart in rrule.value().split(";")])
-                        until = indexedTokens.get('UNTIL', None)
+                        until = indexedTokens.get("UNTIL", None)
+                        # FIXME: can "until" ever be anything but a unicode?
                         if until:
                             untilType = datetime.date if len(until) == 8 else datetime.datetime
                             if untilType is not dtType:
                                 msg = "Calendar resources must have matching type for DTSTART and UNTIL"
                                 log.debug(msg)
-                                raise InvalidICalendarDataError(msg)
+                                if fix:
+                                    log.debug("Fixing mismatch")
+                                    if dtType is datetime.datetime:
+                                        # TODO: does this need to be smarter?
+                                        indexedTokens["UNTIL"] = "%sT000000" % (until,)
+                                    else:
+                                        # TODO: does this need to be smarter?
+                                        # It's just stripping off the time.
+                                        indexedTokens["UNTIL"] = until[:8]
 
+                                    # Update rrule
+                                    newValue = u";".join(["%s=%s" % (k,v) for k,v in indexedTokens.iteritems()])
+                                    rrule.setValue(newValue)
+                                else:
+                                    raise InvalidICalendarDataError(msg)
+
                 timezone_refs.update(subcomponent.timezoneIDs())
         
         #

Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py	2011-01-06 22:36:44 UTC (rev 6719)
+++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py	2011-01-07 00:58:30 UTC (rev 6720)
@@ -81,6 +81,96 @@
             try: calendar.validateForCalDAV()
             except ValueError: self.fail("Resource iCalendar %s didn't validate for CalDAV" % (filename,))
 
+    def test_component_validate_and_fix(self):
+        """
+        CalDAV resource validation and fixing.
+        """
+        data = """BEGIN:VCALENDAR
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20110105T191945Z
+UID:5D70FD7E-3DFA-4981-8B91-E9E6CD5FCE28
+DTEND;TZID=America/Los_Angeles:20110107T141500
+RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20110121
+TRANSP:OPAQUE
+SUMMARY:test
+DTSTART;TZID=America/Los_Angeles:20110107T123000
+DTSTAMP:20110105T192229Z
+END:VEVENT
+END:VCALENDAR
+"""
+        # Ensure it starts off invalid
+        calendar = Component.fromString(data)
+        try: calendar.validateComponentsForCalDAV(False)
+        except InvalidICalendarDataError: pass
+        else: self.fail("Shouldn't validate for CalDAV")
+
+        # Fix it
+        calendar.validateComponentsForCalDAV(False, fix=True)
+
+        # Now it should pass without fixing
+        calendar.validateComponentsForCalDAV(False, fix=False)
+
+        data = """BEGIN:VCALENDAR
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+DTSTART;VALUE=DATE:20110107
+DTEND;VALUE=DATE:20110108
+DTSTAMP:20110106T231917Z
+RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20110131T123456
+TRANSP:TRANSPARENT
+SUMMARY:test
+CREATED:20110105T191945Z
+UID:5D70FD7E-3DFA-4981-8B91-E9E6CD5FCE28
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+"""
+        # Ensure it starts off invalid
+        calendar = Component.fromString(data)
+        try: calendar.validateComponentsForCalDAV(False)
+        except InvalidICalendarDataError: pass
+        else: self.fail("Shouldn't validate for CalDAV")
+
+        # Fix it
+        calendar.validateComponentsForCalDAV(False, fix=True)
+
+        # Now it should pass without fixing
+        calendar.validateComponentsForCalDAV(False, fix=False)
+
+
     def test_component_timeranges(self):
         """
         Component time range query.

Modified: CalendarServer/trunk/txdav/caldav/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/file.py	2011-01-06 22:36:44 UTC (rev 6719)
+++ CalendarServer/trunk/txdav/caldav/datastore/file.py	2011-01-07 00:58:30 UTC (rev 6720)
@@ -311,6 +311,8 @@
 
         try:
             component = VComponent.fromString(text)
+            # Fix any bogus data we can
+            component.validateComponentsForCalDAV(False, fix=True)
         except InvalidICalendarDataError, e:
             raise InternalDataStoreError(
                 "File corruption detected (%s) in file: %s"
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110106/99c27374/attachment.html>


More information about the calendarserver-changes mailing list