[CalendarServer-changes] [14142] CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav /datastore/scheduling

source_changes at macosforge.org source_changes at macosforge.org
Thu Nov 6 19:02:38 PST 2014


Revision: 14142
          http://trac.calendarserver.org//changeset/14142
Author:   cdaboo at apple.com
Date:     2014-11-06 19:02:38 -0800 (Thu, 06 Nov 2014)
Log Message:
-----------
Fix for leakage of organizer properties into attendee overrides.

Modified Paths:
--------------
    CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/icaldiff.py
    CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/itip.py
    CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/test/test_itip.py

Modified: CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/icaldiff.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/icaldiff.py	2014-11-07 03:01:37 UTC (rev 14141)
+++ CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/icaldiff.py	2014-11-07 03:02:38 UTC (rev 14142)
@@ -765,9 +765,7 @@
         "EXDATE",
         "STATUS",
         "TRANSP",
-        "X-APPLE-TRAVEL-START",
         "X-APPLE-TRAVEL-DURATION",
-        "X-APPLE-TRAVEL-RETURN",
         "X-APPLE-TRAVEL-RETURN-DURATION",
     ))
 

Modified: CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/itip.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/itip.py	2014-11-07 03:01:37 UTC (rev 14141)
+++ CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/itip.py	2014-11-07 03:02:38 UTC (rev 14142)
@@ -67,10 +67,11 @@
             calendar.removeProperty(method)
 
         if recipient:
-            iTipProcessing.addTranspForNeedsAction(calendar.subcomponents(), recipient)
 
             # Check for incoming DECLINED
             if creating:
+                iTipProcessing.addTranspForNeedsAction(calendar.subcomponents(), recipient)
+
                 master = calendar.masterComponent()
                 for component in tuple(calendar.subcomponents()):
                     if component in ignoredComponents or component is master:
@@ -122,10 +123,10 @@
         # overridden components that the organizer added
         current_master = calendar.masterComponent()
         if current_master:
-            master_valarms = [comp for comp in current_master.subcomponents() if comp.name() == "VALARM"]
-            private_comments = current_master.properties("X-CALENDARSERVER-PRIVATE-COMMENT")
-            transps = current_master.properties("TRANSP")
-            completeds = current_master.properties("COMPLETED")
+            valarms = [comp for comp in current_master.subcomponents() if comp.name() == "VALARM"]
+            private_comments = tuple(current_master.properties("X-CALENDARSERVER-PRIVATE-COMMENT"))
+            transps = tuple(current_master.properties("TRANSP"))
+            completeds = tuple(current_master.properties("COMPLETED"))
             organizer = current_master.getProperty("ORGANIZER")
             organizer_schedule_status = organizer.parameterValue("SCHEDULE-STATUS", None) if organizer else None
             attendee = current_master.getAttendeeProperty((recipient,))
@@ -133,10 +134,9 @@
             other_props = {}
             for pname in config.Scheduling.CalDAV.PerAttendeeProperties:
                 props = tuple(current_master.properties(pname))
-                if props:
-                    other_props[pname] = props
+                other_props[pname] = props
         else:
-            master_valarms = ()
+            valarms = ()
             private_comments = ()
             transps = ()
             completeds = ()
@@ -149,31 +149,14 @@
             # Get a new calendar object first
             new_calendar = iTipProcessing.processNewRequest(itip_message, recipient)
 
-            # Copy over master alarms, comments
+            # Copy over master alarms, comments etc
             master_component = new_calendar.masterComponent()
-            for alarm in master_valarms:
-                master_component.addComponent(alarm)
-            for comment in private_comments:
-                master_component.addProperty(comment)
-            for transp in transps:
-                master_component.replaceProperty(transp)
-            for completed in completeds:
-                master_component.replaceProperty(completed)
-            if organizer_schedule_status:
-                organizer = master_component.getProperty("ORGANIZER")
-                if organizer:
-                    organizer.setParameter("SCHEDULE-STATUS", organizer_schedule_status)
-            if attendee_dtstamp:
-                attendee = master_component.getAttendeeProperty((recipient,))
-                if attendee:
-                    attendee.setParameter("X-CALENDARSERVER-DTSTAMP", attendee_dtstamp)
-            for props in other_props.values():
-                [master_component.replaceProperty(prop) for prop in props]
+            iTipProcessing._transferItems(master_component, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient)
 
             # Now try to match recurrences in the new calendar
             for component in tuple(new_calendar.subcomponents()):
                 if component.name() != "VTIMEZONE" and component.getRecurrenceIDUTC() is not None:
-                    iTipProcessing.transferItems(calendar, component, master_valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient)
+                    iTipProcessing.transferItems(calendar, component, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient)
 
             # Now try to match recurrences from the old calendar
             for component in calendar.subcomponents():
@@ -185,10 +168,12 @@
                         new_component = new_calendar.deriveInstance(rid, allowCancelled=allowCancelled and not hidden)
                         if new_component is not None:
                             new_calendar.addComponent(new_component)
-                            iTipProcessing.transferItems(calendar, new_component, master_valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient)
+                            iTipProcessing.transferItems(calendar, new_component, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient)
                             if hidden:
                                 new_component.addProperty(Property(Component.HIDDEN_INSTANCE_PROPERTY, "T"))
 
+            iTipProcessing.addTranspForNeedsAction(new_calendar.subcomponents(), recipient)
+
             # Replace the entire object
             return new_calendar, rids
 
@@ -204,15 +189,15 @@
                         calendar.addComponent(component)
                 else:
                     component = component.duplicate()
-                    missingDeclined = iTipProcessing.transferItems(calendar, component, master_valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient, remove_matched=True)
+                    missingDeclined = iTipProcessing.transferItems(calendar, component, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient, remove_matched=True)
                     if not missingDeclined:
                         # Add the component and make sure to remove any matching EXDATE
                         calendar.addComponent(component)
                         if current_master is not None:
                             current_master.removeExdate(component.getRecurrenceIDUTC())
-                        if recipient:
-                            iTipProcessing.addTranspForNeedsAction((component,), recipient)
 
+            iTipProcessing.addTranspForNeedsAction(calendar.subcomponents(), recipient)
+
             # Write back the modified object
             return calendar, rids
 
@@ -518,7 +503,7 @@
 
 
     @staticmethod
-    def transferItems(from_calendar, to_component, master_valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient, remove_matched=False):
+    def transferItems(from_calendar, to_component, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient, remove_matched=False):
         """
         Transfer properties from a calendar to a component by first trying to match the component in the original calendar and
         use the properties from that, or use the values provided as arguments (which have been derived from the original calendar's
@@ -528,8 +513,8 @@
         @type from_calendar: L{Component}
         @param to_component: the new component to transfer items to
         @type to_component: L{Component}
-        @param master_valarms: a C{list} of VALARM components from the old master to use
-        @type master_valarms: C{list}
+        @param valarms: a C{list} of VALARM components from the old master to use
+        @type valarms: C{list}
         @param private_comments: a C{list} of private comment properties from the old master to use
         @type private_comments: C{list}
         @param transps: a C{list} of TRANSP properties from the old master to use
@@ -555,67 +540,104 @@
         # Is there a matching component
         matched = from_calendar.overriddenComponent(rid)
         if matched:
-            # Copy over VALARMs from existing component
-            [to_component.addComponent(comp) for comp in matched.subcomponents() if comp.name() == "VALARM"]
-            [to_component.addProperty(prop) for prop in matched.properties("X-CALENDARSERVER-ATTENDEE-COMMENT")]
-            [to_component.replaceProperty(prop) for prop in matched.properties("TRANSP")]
-            [to_component.replaceProperty(prop) for prop in matched.properties("COMPLETED")]
-
+            valarms = [comp for comp in matched.subcomponents() if comp.name() == "VALARM"]
+            private_comments = tuple(matched.properties("X-CALENDARSERVER-PRIVATE-COMMENT"))
+            transps = tuple(matched.properties("TRANSP"))
+            completeds = tuple(matched.properties("COMPLETED"))
             organizer = matched.getProperty("ORGANIZER")
             organizer_schedule_status = organizer.parameterValue("SCHEDULE-STATUS", None) if organizer else None
-            if organizer_schedule_status:
-                organizer = to_component.getProperty("ORGANIZER")
-                if organizer:
-                    organizer.setParameter("SCHEDULE-STATUS", organizer_schedule_status)
+            attendee = matched.getAttendeeProperty((recipient,))
+            attendee_dtstamp = attendee.parameterValue("X-CALENDARSERVER-DTSTAMP") if attendee else None
+            other_props = {}
+            for pname in config.Scheduling.CalDAV.PerAttendeeProperties:
+                props = tuple(matched.properties(pname))
+                other_props[pname] = props
 
-            # Remove the old one
-            if remove_matched:
-                from_calendar.removeComponent(matched)
+            iTipProcessing._transferItems(to_component, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient)
 
             # Check for incoming DECLINED
-            attendee = to_component.getAttendeeProperty((recipient,))
-            if attendee and attendee.parameterValue("PARTSTAT", "NEEDS-ACTION") == "DECLINED":
+            to_attendee = to_component.getAttendeeProperty((recipient,))
+            if to_attendee and to_attendee.parameterValue("PARTSTAT", "NEEDS-ACTION") == "DECLINED":
                 # If existing item has HIDDEN property copy that over
                 if matched.hasProperty(Component.HIDDEN_INSTANCE_PROPERTY):
                     to_component.addProperty(Property(Component.HIDDEN_INSTANCE_PROPERTY, "T"))
 
-            if attendee and attendee_dtstamp:
-                attendee.setParameter("X-CALENDARSERVER-DTSTAMP", attendee_dtstamp)
+            # Remove the old one
+            if remove_matched:
+                from_calendar.removeComponent(matched)
 
-            for pname in config.Scheduling.CalDAV.PerAttendeeProperties:
-                [to_component.replaceProperty(prop) for prop in matched.properties(pname)]
-
             # Check to see if the new component is cancelled as that could mean we are copying in the wrong attendee state
             if to_component.propertyValue("STATUS") == "CANCELLED":
-                from_attendee = matched.getAttendeeProperty((recipient,))
-                if attendee and from_attendee:
-                    attendee.setParameter("PARTSTAT", from_attendee.parameterValue("PARTSTAT", "NEEDS-ACTION"))
+                if attendee and to_attendee:
+                    to_attendee.setParameter("PARTSTAT", attendee.parameterValue("PARTSTAT", "NEEDS-ACTION"))
 
         else:
+            iTipProcessing._transferItems(to_component, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient)
+
             # Check for incoming DECLINED
             attendee = to_component.getAttendeeProperty((recipient,))
             if attendee and attendee.parameterValue("PARTSTAT", "NEEDS-ACTION") == "DECLINED":
                 return True
 
-            # It is a new override - copy any valarms on the existing master component
-            # into the new one.
-            [to_component.addComponent(alarm) for alarm in master_valarms]
-            [to_component.addProperty(comment) for comment in private_comments]
-            [to_component.replaceProperty(transp) for transp in transps]
-            [to_component.replaceProperty(completed) for completed in completeds]
+        return False
 
-            if organizer_schedule_status:
-                organizer = to_component.getProperty("ORGANIZER")
-                if organizer:
-                    organizer.setParameter("SCHEDULE-STATUS", organizer_schedule_status)
-            if attendee_dtstamp:
-                attendee = to_component.getAttendeeProperty((recipient,))
-                if attendee:
-                    attendee.setParameter("X-CALENDARSERVER-DTSTAMP", attendee_dtstamp)
 
-            for props in other_props.values():
-                [to_component.replaceProperty(prop) for prop in props]
+    @staticmethod
+    def _transferItems(to_component, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, other_props, recipient):
+        """
+        Transfer properties the key per-attendee properties from one component to another. Note that the key properties are pulled out into separate items, because they
+        may have been derived from the master.
 
+        @param to_component: the new component to transfer items to
+        @type to_component: L{Component}
+        @param valarms: a C{list} of VALARM components from the old master to use
+        @type valarms: C{list}
+        @param private_comments: a C{list} of private comment properties from the old master to use
+        @type private_comments: C{list}
+        @param transps: a C{list} of TRANSP properties from the old master to use
+        @type transps: C{list}
+        @param completeds: a C{list} of COMPLETED properties from the old master to use
+        @type completeds: C{list}
+        @param organizer_schedule_status: a the SCHEDULE-STATUS value for the organizer from the old master to use
+        @type organizer_schedule_status: C{str}
+        @param attendee_dtstamp: an the ATTENDEE DTSTAMP parameter value from the old master to use
+        @type attendee_dtstamp: C{str}
+        @param other_props: other properties from the old master to use
+        @type other_props: C{list}
+        @param recipient: the calendar user address of the attendee whose data is being processed
+        @type recipient: C{str}
+
+        @return: C{True} if an EXDATE match occurred requiring the incoming component to be removed.
+        """
+
+        # It is a new override - copy any valarms on the existing master component
+        # into the new one. But first remove any of the stuff we want to copy from
+        # the component being copied to.
+        to_component.removeAlarms()
+        to_component.removeProperty("X-CALENDARSERVER-PRIVATE-COMMENT")
+        to_component.removeProperty("TRANSP")
+        to_component.removeProperty("COMPLETED")
+        for propname in other_props.keys():
+            to_component.removeProperty(propname)
+
+        [to_component.addComponent(alarm) for alarm in valarms]
+        [to_component.addProperty(comment) for comment in private_comments]
+        [to_component.replaceProperty(transp) for transp in transps]
+        [to_component.replaceProperty(completed) for completed in completeds]
+        for props in other_props.values():
+            [to_component.replaceProperty(prop) for prop in props]
+
+        if organizer_schedule_status:
+            organizer = to_component.getProperty("ORGANIZER")
+            if organizer:
+                organizer.setParameter("SCHEDULE-STATUS", organizer_schedule_status)
+
+        # ATTENDEE property merge
+        attendee = to_component.getAttendeeProperty((recipient,))
+
+        if attendee_dtstamp and attendee:
+            attendee.setParameter("X-CALENDARSERVER-DTSTAMP", attendee_dtstamp)
+
         return False
 
 

Modified: CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/test/test_itip.py
===================================================================
--- CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/test/test_itip.py	2014-11-07 03:01:37 UTC (rev 14141)
+++ CalendarServer/branches/release/CalendarServer-5.3-dev/txdav/caldav/datastore/scheduling/test/test_itip.py	2014-11-07 03:02:38 UTC (rev 14142)
@@ -597,6 +597,582 @@
             self.assertEqual(result, changed, msg="Calendar mismatch: %s" % (title,))
 
 
+    def test_processRequest_overrideOfEXDATE(self):
+        """
+        Test iTIPProcessing.processRequest properly removes an EXDATE when an override is added
+        """
+
+        data = (
+            (
+                "1.1 Single single-value EXDATE",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+EXDATE:20071115T000000Z
+SUMMARY:Test
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+METHOD:REQUEST
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+SUMMARY:Test
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+""",
+            ),
+            (
+                "1.2 Single multi-value EXDATE",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+EXDATE:20071115T000000Z,20071116T000000Z
+SUMMARY:Test
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+METHOD:REQUEST
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+EXDATE:20071116T000000Z
+SUMMARY:Test
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+""",
+            ),
+            (
+                "1.3 Multiple single-value EXDATEs",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+EXDATE:20071115T000000Z
+EXDATE:20071116T000000Z
+SUMMARY:Test
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+METHOD:REQUEST
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+EXDATE:20071116T000000Z
+SUMMARY:Test
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+""",
+            ),
+            (
+                "1.4 Multiple single- and multi-value EXDATEs",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+EXDATE:20071115T000000Z,20071116T000000Z
+EXDATE:20071117T000000Z
+SUMMARY:Test
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+METHOD:REQUEST
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+EXDATE:20071116T000000Z
+EXDATE:20071117T000000Z
+SUMMARY:Test
+TRANSP:TRANSPARENT
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:TRANSPARENT
+END:VEVENT
+END:VCALENDAR
+""",
+            ),
+        )
+
+        for title, calendar_txt, itip_txt, changed_txt in data:
+            calendar = Component.fromString(calendar_txt)
+            itip = Component.fromString(itip_txt)
+            changed = Component.fromString(changed_txt)
+
+            result, _ignore = iTipProcessing.processRequest(itip, calendar, "mailto:user02 at example.com")
+            self.assertEqual(result, changed, msg="Calendar mismatch: %s" % (title,))
+
+
+    def test_processRequest_propertyLeakage(self):
+        """
+        Test iTIPProcessing.processRequest properly ignores properties from organizer that need to be overridden by
+        the attendee
+        """
+
+        data = (
+            (
+                "1.1 All ACCEPTED, no alarm",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+SUMMARY:Test
+TRANSP:TRANSPARENT
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT30M
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+METHOD:REQUEST
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+SUMMARY:Test
+TRANSP:OPAQUE
+X-CALENDARSERVER-PRIVATE-COMMENT:foobar1
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT1H
+X-APPLE-TRAVEL-RETURN-DURATION;VALUE=DURATION:PT1H
+BEGIN:VALARM
+DESCRIPTION:Event reminder
+TRIGGER:-PT1M
+ACTION:DISPLAY
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:OPAQUE
+X-CALENDARSERVER-PRIVATE-COMMENT:foobar2
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT2H
+X-APPLE-TRAVEL-RETURN-DURATION;VALUE=DURATION:PT2H
+BEGIN:VALARM
+DESCRIPTION:Event reminder
+TRIGGER:-PT2M
+ACTION:DISPLAY
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071116T000000Z
+DTSTART:20071116T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:OPAQUE
+X-CALENDARSERVER-PRIVATE-COMMENT:foobar3
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT3H
+X-APPLE-TRAVEL-RETURN-DURATION;VALUE=DURATION:PT3H
+BEGIN:VALARM
+DESCRIPTION:Event reminder
+TRIGGER:-PT3M
+ACTION:DISPLAY
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+SUMMARY:Test
+TRANSP:TRANSPARENT
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT30M
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:TRANSPARENT
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT30M
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071116T000000Z
+DTSTART:20071116T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:TRANSPARENT
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT30M
+END:VEVENT
+END:VCALENDAR
+""",
+            ),
+            (
+                "1.2 All DECLINED, with alarm",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=DECLINED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+SUMMARY:Test
+TRANSP:TRANSPARENT
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT30M
+BEGIN:VALARM
+DESCRIPTION:Attendee reminder
+TRIGGER:-PT1M
+ACTION:DISPLAY
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+METHOD:REQUEST
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=DECLINED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+SUMMARY:Test
+TRANSP:OPAQUE
+X-CALENDARSERVER-PRIVATE-COMMENT:foobar1
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT1H
+X-APPLE-TRAVEL-RETURN-DURATION;VALUE=DURATION:PT1H
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=DECLINED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:OPAQUE
+X-CALENDARSERVER-PRIVATE-COMMENT:foobar2
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT2H
+X-APPLE-TRAVEL-RETURN-DURATION;VALUE=DURATION:PT2H
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071116T000000Z
+DTSTART:20071116T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=DECLINED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:OPAQUE
+X-CALENDARSERVER-PRIVATE-COMMENT:foobar3
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT3H
+X-APPLE-TRAVEL-RETURN-DURATION;VALUE=DURATION:PT3H
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=DECLINED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+RRULE:FREQ=DAILY
+SUMMARY:Test
+TRANSP:TRANSPARENT
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT30M
+BEGIN:VALARM
+DESCRIPTION:Attendee reminder
+TRIGGER:-PT1M
+ACTION:DISPLAY
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071115T000000Z
+DTSTART:20071115T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=DECLINED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:TRANSPARENT
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT30M
+BEGIN:VALARM
+DESCRIPTION:Attendee reminder
+TRIGGER:-PT1M
+ACTION:DISPLAY
+END:VALARM
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20071116T000000Z
+DTSTART:20071116T000000Z
+DURATION:PT1H
+DTSTAMP:20071114T000000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=DECLINED:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test1
+TRANSP:TRANSPARENT
+X-APPLE-TRAVEL-DURATION;VALUE=DURATION:PT30M
+BEGIN:VALARM
+DESCRIPTION:Attendee reminder
+TRIGGER:-PT1M
+ACTION:DISPLAY
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""",
+            ),
+        )
+
+        for title, calendar_txt, itip_txt, changed_txt in data:
+            calendar = Component.fromString(calendar_txt)
+            itip = Component.fromString(itip_txt)
+            changed = Component.fromString(changed_txt)
+
+            result, _ignore = iTipProcessing.processRequest(itip, calendar, "mailto:user02 at example.com")
+            self.assertEqual(result, changed, msg="Calendar mismatch: %s" % (title,))
+
+
     def test_update_attendee_partstat(self):
 
         data = (
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20141106/47838997/attachment-0001.html>


More information about the calendarserver-changes mailing list