[CalendarServer-changes] [7506] CalendarServer/trunk/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Thu May 19 17:21:05 PDT 2011


Revision: 7506
          http://trac.macosforge.org/projects/calendarserver/changeset/7506
Author:   cdaboo at apple.com
Date:     2011-05-19 17:21:05 -0700 (Thu, 19 May 2011)
Log Message:
-----------
Fix bug where VTODO time-ranges were not calculated according to the spec.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/ical.py
    CalendarServer/trunk/twistedcaldav/instance.py

Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py	2011-05-20 00:19:15 UTC (rev 7505)
+++ CalendarServer/trunk/twistedcaldav/ical.py	2011-05-20 00:21:05 UTC (rev 7506)
@@ -1,6 +1,6 @@
 # -*- test-case-name: twistedcaldav.test.test_icalendar -*-
 ##
-# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2011 Apple Inc. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -135,6 +135,10 @@
 
 ignoredComponents = ("VTIMEZONE", "X-CALENDARSERVER-PERUSER",)
 
+# Used for min/max time-range query limits
+minDateTime = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+maxDateTime = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+
 class InvalidICalendarDataError(ValueError):
     pass
 
@@ -658,6 +662,26 @@
 
         return due.duplicateAsUTC() if due is not None else None
  
+    def getCompletedDateUTC(self):
+        """
+        Return the completed date or date-time for the specified component
+        converted to UTC.
+        @param component: the Component whose start should be returned.
+        @return: the datetime.date or datetime.datetime for the start.
+        """
+        completed = self.propertyValue("COMPLETED")
+        return completed.duplicateAsUTC() if completed is not None else None
+ 
+    def getCreatedDateUTC(self):
+        """
+        Return the created date or date-time for the specified component
+        converted to UTC.
+        @param component: the Component whose start should be returned.
+        @return: the datetime.date or datetime.datetime for the start.
+        """
+        created = self.propertyValue("CREATED")
+        return created.duplicateAsUTC() if created is not None else None
+ 
     def getRecurrenceIDUTC(self):
         """
         Return the recurrence-id for the specified component.

Modified: CalendarServer/trunk/twistedcaldav/instance.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/instance.py	2011-05-20 00:19:15 UTC (rev 7505)
+++ CalendarServer/trunk/twistedcaldav/instance.py	2011-05-20 00:21:05 UTC (rev 7506)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2006-2011 Apple Inc. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -165,16 +165,14 @@
         if len(self.instances) > max_allowed_instances:
             raise TooManyInstancesError()
 
-    def _addMasterEventComponent(self, component, limit):
+    def _getMasterEventDetails(self, component):
         """
-        Add the specified master VEVENT Component to the instance list, expanding it
-        within the supplied time range.
-        @param component: the Component to expand
-        @param limit: the end L{PyCalendarDateTime} for expansion
+        Logic here comes from RFC4791 Section 9.9
         """
+
         start = component.getStartDateUTC()
         if start is None:
-            return
+            return None
         rulestart = component.propertyValue("DTSTART")
 
         end = component.getEndDateUTC()
@@ -189,7 +187,22 @@
             end = start + duration
         else:
             duration = differenceDateTime(start, end)
+        
+        return (rulestart, start, end, duration,)
 
+    def _addMasterEventComponent(self, component, limit):
+        """
+        Add the specified master VEVENT Component to the instance list, expanding it
+        within the supplied time range.
+        @param component: the Component to expand
+        @param limit: the end L{PyCalendarDateTime} for expansion
+        """
+        
+        details = self._getMasterEventDetails(component)
+        if details is None:
+            return
+        rulestart, start, end, duration = details
+
         self._addMasterComponent(component, limit, rulestart, start, end, duration)
 
     def _addOverrideEventComponent(self, component, limit, got_master):
@@ -202,23 +215,58 @@
         
         #TODO: This does not take into account THISANDPRIOR - only THISANDFUTURE
         
-        start = component.getStartDateUTC()
-        if start is None:
+        details = self._getMasterEventDetails(component)
+        if details is None:
             return
+        _ignore_rulestart, start, end, _ignore_duration = details
 
-        end = component.getEndDateUTC()
-        duration = None
-        if end is None:
-            if not start.isDateOnly():
-                # Timed event with zero duration
-                duration = PyCalendarDuration(days=0)
+        self._addOverrideComponent(component, limit, start, end, got_master)
+
+    def _getMasterToDoDetails(self, component):
+        """
+        Logic here comes from RFC4791 Section 9.9
+        """
+
+        dtstart = component.getStartDateUTC()
+        dtend = component.getEndDateUTC()
+        dtdue = component.getDueDateUTC()
+
+        # DTSTART and DURATION or DUE case
+        if dtstart is not None:
+            rulestart = component.propertyValue("DTSTART")
+            start = dtstart
+            if dtend is not None:
+                end = dtend
+            elif dtdue is not None:
+                end = dtdue
             else:
-                # All day event default duration is one day
-                duration = PyCalendarDuration(days=1)
-            end = start + duration
+                end = dtstart
+        
+        # DUE case
+        elif dtdue is not None:
+            rulestart = component.propertyValue("DUE")
+            start = end = dtdue
+        
+        # Fall back to COMPLETED or CREATED - cannot be recurring
+        else:
+            rulestart = None
+            from twistedcaldav.ical import maxDateTime, minDateTime
+            dtcreated = component.getCreatedDateUTC()
+            dtcompleted = component.getCompletedDateUTC()
+            if dtcompleted:
+                end = dtcompleted
+                start = dtcreated if dtcreated else dtend
+            elif dtcreated:
+                start = dtcreated
+                end = maxDateTime
+            else:
+                start = minDateTime
+                end = maxDateTime
 
-        self._addOverrideComponent(component, limit, start, end, got_master)
+        duration = differenceDateTime(start, end)
 
+        return (rulestart, start, end, duration,)
+
     def _addMasterToDoComponent(self, component, limit):
         """
         Add the specified master VTODO Component to the instance list, expanding it
@@ -226,22 +274,13 @@
         @param component: the Component to expand
         @param limit: the end L{PyCalendarDateTime} for expansion
         """
-        start = component.getStartDateUTC()
-        due = component.getDueDateUTC()
-
-        if start is None and due is None:
+        details = self._getMasterToDoDetails(component)
+        if details is None:
             return
+        rulestart, start, end, duration = details
 
-        rulestart = component.propertyValue("DTSTART")
-        if start is None:
-            start = due
-            rulestart = component.propertyValue("DUE")
-        elif due is None:
-            due = start
-        duration = differenceDateTime(start, due)
+        self._addMasterComponent(component, limit, rulestart, start, end, duration)
 
-        self._addMasterComponent(component, limit, rulestart, start, due, duration)
-
     def _addOverrideToDoComponent(self, component, limit, got_master):
         """
         Add the specified overridden VTODO Component to the instance list, replacing 
@@ -252,23 +291,17 @@
         
         #TODO: This does not take into account THISANDPRIOR - only THISANDFUTURE
         
-        start = component.getStartDateUTC()
-        due = component.getDueDateUTC()
-
-        if start is None and due is None:
+        details = self._getMasterToDoDetails(component)
+        if details is None:
             return
+        _ignore_rulestart, start, end, _ignore_duration = details
 
-        if start is None:
-            start = due
-        elif due is None:
-            due = start
+        self._addOverrideComponent(component, limit, start, end, got_master)
 
-        self._addOverrideComponent(component, limit, start, due, got_master)
-
     def _addMasterComponent(self, component, limit, rulestart, start, end, duration):
         
         rrules = component.getRecurrenceSet()
-        if rrules is not None:
+        if rrules is not None and rulestart is not None:
             # Do recurrence set expansion
             expanded = []
             limited = rrules.expand(rulestart, PyCalendarPeriod(start, limit), expanded)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110519/4c49b7ca/attachment.html>


More information about the calendarserver-changes mailing list