[CalendarServer-changes] [3601] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Tue Jan 20 13:02:18 PST 2009


Revision: 3601
          http://trac.macosforge.org/projects/calendarserver/changeset/3601
Author:   cdaboo at apple.com
Date:     2009-01-20 13:02:18 -0800 (Tue, 20 Jan 2009)
Log Message:
-----------
Make sure entirely cancelled event written by ATTENDEE is ignored rather than generating a 403.

Modified Paths:
--------------
    CalendarServer/trunk/run
    CalendarServer/trunk/twistedcaldav/ical.py
    CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
    CalendarServer/trunk/twistedcaldav/scheduling/implicit.py
    CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py

Modified: CalendarServer/trunk/run
===================================================================
--- CalendarServer/trunk/run	2009-01-20 21:01:01 UTC (rev 3600)
+++ CalendarServer/trunk/run	2009-01-20 21:02:18 UTC (rev 3601)
@@ -692,7 +692,7 @@
 
 caldavtester="${top}/CalDAVTester";
 
-svn_get "CalDAVTester" "${caldavtester}" "${svn_uri_base}/CalDAVTester/trunk" 3587;
+svn_get "CalDAVTester" "${caldavtester}" "${svn_uri_base}/CalDAVTester/trunk" 3600;
 
 #
 # Calendar Server

Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py	2009-01-20 21:01:01 UTC (rev 3600)
+++ CalendarServer/trunk/twistedcaldav/ical.py	2009-01-20 21:02:18 UTC (rev 3601)
@@ -1724,6 +1724,14 @@
                 self.removeProperty(duration)
                 self.addProperty(Property("DTEND", newdtend))
 
+            exdates = self.properties("EXDATE")
+            for exdate in exdates:
+                exdate.setValue([normalizeToUTC(value) for value in exdate.value()])
+                try:
+                    del exdate.params()["TZID"]
+                except KeyError:
+                    pass
+
             rid = self.getProperty("RECURRENCE-ID")
             if rid is not None:
                 rid.setValue(normalizeToUTC(rid.value()))

Modified: CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py	2009-01-20 21:01:01 UTC (rev 3600)
+++ CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py	2009-01-20 21:02:18 UTC (rev 3601)
@@ -14,7 +14,7 @@
 # limitations under the License.
 ##
 
-from twistedcaldav.ical import Component
+from twistedcaldav.ical import Component, Property
 from twistedcaldav.log import Logger
 from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
 from twistedcaldav.scheduling.itip import iTipGenerator
@@ -239,19 +239,19 @@
         self.calendar2 = duplicateAndNormalize(self.calendar2)
 
         if self.calendar1 == self.calendar2:
-            return True, True
+            return True, True, ()
 
         # Need to look at each component and do special comparisons
         
         # Make sure the same VCALENDAR properties match
         if not self._checkVCALENDARProperties():
             self._logDiffError("attendeeDiff: VCALENDAR properties do not match")
-            return False, False
+            return False, False, ()
         
         # Make sure the same VTIMEZONE components appear
         if not self._compareVTIMEZONEs():
             self._logDiffError("attendeeDiff: VTIMEZONEs do not match")
-            return False, False
+            return False, False, ()
         
         # Compare each component instance from the new calendar with each derived
         # component instance from the old one
@@ -377,37 +377,56 @@
         map2 = mapComponents(self.calendar2)
         set2 = set(map2.keys())
 
+        # Ugly case: if an Attendee has a STATUS:CANCELLED meeting and the ORGANIZER does not,
+        # we may need to remove an EXDATE for the cancelled instance from the ORGANIZER's
+        # master instance to ensure that matches
+        cancelled_rids = []
+        master2 = self.calendar2.masterComponent()
+        for key in set2 - set1:
+            component2 = map2[key]
+            if component2.propertyValue("STATUS") == "CANCELLED":
+                rid = component2.getRecurrenceIDUTC()
+                cancelled_rids.append(rid)
+                if master2:
+                    master2.addProperty(Property("EXDATE", [rid,]))
+        
         # All the components in calendar1 must be in calendar2
         result = set1 - set2
         if result:
             log.debug("Missing components from first calendar: %s" % (result,))
-            return False, False
+            return False, False, ()
 
         # Now verify that each component in set1 matches what is in set2
         attendee_unchanged = True
         for key, value in map1.iteritems():
             component1 = value
             component2 = map2[key]
-            
+
             nomismatch, no_attendee_change = self._testComponents(component1, component2)
             if not nomismatch:
-                return False, False
+                return False, False, ()
             attendee_unchanged &= no_attendee_change
         
         # Now verify that each additional component in set2 matches a derived component in set1
         for key in set2 - set1:
+            
+            # First check if the attendee's copy is cancelled
+            component2 = map2[key]
+            if component2.propertyValue("STATUS") == "CANCELLED":
+                continue
+
+            # Now derive the organizer's expected instance and compare
             component1 = self.calendar1.deriveInstance(key[2])
             if component1 is None:
                 log.debug("_compareComponents: Could not derive instance: %s" % (key[2],))
-                return False, False
-            component2 = map2[key]
+                return False, False, ()
             
             nomismatch, no_attendee_change = self._testComponents(component1, component2)
             if not nomismatch:
-                return False, False
+                return False, False, ()
             attendee_unchanged &= no_attendee_change
             
-        return True, attendee_unchanged
+        return True, attendee_unchanged, tuple(cancelled_rids)
 
     def _testComponents(self, comp1, comp2):
         

Modified: CalendarServer/trunk/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/implicit.py	2009-01-20 21:01:01 UTC (rev 3600)
+++ CalendarServer/trunk/twistedcaldav/scheduling/implicit.py	2009-01-20 21:02:18 UTC (rev 3601)
@@ -662,13 +662,39 @@
                     self.oldcalendar = None
 
                 # Determine whether the current change is allowed
-                if self.isAttendeeChangeInsignificant():
+                change_allowed, no_itip, cancelled_rids = self.isAttendeeChangeInsignificant()
+
+                if not change_allowed:
+                    if self.calendar.hasPropertyValueInAllComponents(Property("STATUS", "CANCELLED")):
+                        log.debug("Attendee '%s' is creating CANCELLED event for mismatched UID: '%s' - removing entire event" % (self.attendee, self.uid,))
+                        self.return_status = ImplicitScheduler.STATUS_ORPHANED_CANCELLED_EVENT
+                        returnValue(None)
+                    else:
+                        log.error("Attendee '%s' is not allowed to make an unauthorized change to an organized event: UID:%s" % (self.attendeePrincipal, self.uid,))
+                        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-attendee-change")))
+
+                # Remove orphaned attendee cancelled events
+                if cancelled_rids:
+                    log.debug("Attendee '%s' is creating CANCELLED overridden instances for UID: '%s' - removing instances" % (self.attendee, self.uid,))
+                    master = self.calendar.masterComponent()
+                    for rid in cancelled_rids:
+                        self.calendar.removeComponent(self.calendar.overriddenComponent(rid))
+                        if master:
+                            master.addProperty(Property("EXDATE", [rid,]))
+                    
+                    # If no components left, make sure we delete the orphaned event
+                    if self.calendar.mainType() is None:
+                        log.debug("Attendee '%s' CANCELLED all instances of UID: '%s' - removing entire event" % (self.attendee, self.uid,))
+                        self.return_status = ImplicitScheduler.STATUS_ORPHANED_CANCELLED_EVENT
+                        returnValue(None)
+
+                if no_itip:
                     log.debug("Implicit - attendee '%s' is updating UID: '%s' but change is not significant" % (self.attendee, self.uid))
                     returnValue(None)
             elif isinstance(self.organizerAddress, LocalCalendarUser):
                 # Check to see whether all instances are CANCELLED
                 if self.calendar.hasPropertyValueInAllComponents(Property("STATUS", "CANCELLED")):
-                    log.debug("Attendee '%s' is creating CANCELLED event for UID: '%s' - missing organizer copy" % (self.attendee, self.uid,))
+                    log.debug("Attendee '%s' is creating CANCELLED event for missing UID: '%s' - removing entire event" % (self.attendee, self.uid,))
                     self.return_status = ImplicitScheduler.STATUS_ORPHANED_CANCELLED_EVENT
                     returnValue(None)
                 else:
@@ -732,12 +758,9 @@
             oldcalendar = self.organizer_calendar
             oldcalendar.attendeesView((self.attendee,))
         differ = iCalDiff(oldcalendar, self.calendar, self.do_smart_merge)
-        change_allowed, no_itip = differ.attendeeDiff(self.attendee)
-        if not change_allowed:
-            log.error("Attendee '%s' is not allowed to make an unauthorized change to an organized event: UID:%s" % (self.attendeePrincipal, self.uid,))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-attendee-change")))
+        change_allowed, no_itip, cancelled_rids = differ.attendeeDiff(self.attendee)
 
-        return no_itip
+        return change_allowed, no_itip, cancelled_rids
 
     def scheduleWithOrganizer(self):
 

Modified: CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py	2009-01-20 21:01:01 UTC (rev 3600)
+++ CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py	2009-01-20 21:02:18 UTC (rev 3601)
@@ -506,7 +506,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, True,)
+                (True, True, (),)
             ),
             (
                 "#1.2 Simple component, PARTSTAT change",
@@ -537,7 +537,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, False,)
+                (True, False, (),)
             ),
             (
                 "#1.3 Simple component, bad change",
@@ -568,7 +568,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (False, False,)
+                (False, False, (),)
             ),
             (
                 "#1.4 Simple component, valarm change",
@@ -609,7 +609,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, True,)
+                (True, True, (),)
             ),
             (
                 "#1.5 Simple component, vcalendar props change ok",
@@ -651,7 +651,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, True,)
+                (True, True, (),)
             ),
             (
                 "#1.6 Simple component, vcalendar props change bad",
@@ -693,7 +693,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, True,)
+                (True, True, (),)
             ),
             (
                 "#1.7 Simple component, vtimezone no change",
@@ -760,7 +760,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, True,)
+                (True, True, (),)
             ),
             (
                 "#1.8 Simple component, vtimezone bad change",
@@ -827,7 +827,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (False, False,)
+                (False, False, (),)
             ),
         )
 
@@ -885,7 +885,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, True,)
+                (True, True, (),)
             ),
             (
                 "#1.2 Complex component, alarm change",
@@ -944,7 +944,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, True,)
+                (True, True, (),)
             ),
             (
                 "#1.3 Complex component, missing override",
@@ -985,7 +985,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (False, False,)
+                (False, False, (),)
             ),
             (
                 "#1.4 Complex component, additional override no change ok",
@@ -1043,7 +1043,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, True,)
+                (True, True, (),)
             ),
             (
                 "#1.5 Complex component, additional override change ok",
@@ -1101,7 +1101,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (True, False,)
+                (True, False, (),)
             ),
             (
                 "#1.6 Complex component, additional override bad",
@@ -1159,7 +1159,7 @@
 END:VCALENDAR
 """,
                 "mailto:user2 at example.com",
-                (False, False,)
+                (False, False, (),)
             ),
         )
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090120/3f6a3b09/attachment-0001.html>


More information about the calendarserver-changes mailing list