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

source_changes at macosforge.org source_changes at macosforge.org
Mon Dec 17 09:50:55 PST 2012


Revision: 10179
          http://trac.calendarserver.org//changeset/10179
Author:   cdaboo at apple.com
Date:     2012-12-17 09:50:55 -0800 (Mon, 17 Dec 2012)
Log Message:
-----------
Time stamps added to ATTENDEE properties on PARTSTAT changes.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/customxml.py
    CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
    CalendarServer/trunk/twistedcaldav/scheduling/itip.py
    CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py
    CalendarServer/trunk/twistedcaldav/stdconfig.py

Modified: CalendarServer/trunk/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/customxml.py	2012-12-17 17:50:12 UTC (rev 10178)
+++ CalendarServer/trunk/twistedcaldav/customxml.py	2012-12-17 17:50:55 UTC (rev 10179)
@@ -59,7 +59,6 @@
     "calendarserver-principal-search",
 )
 
-
 calendarserver_sharing_compliance = (
     "calendarserver-sharing",
 )
@@ -69,7 +68,11 @@
     "calendarserver-sharing-no-scheduling",
 )
 
+calendarserver_partstat_changes_compliance = (
+    "calendarserver-partstat-changes",
+)
 
+
 @registerElement
 class TwistedCalendarSupportedComponents (WebDAVTextElement):
     """

Modified: CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py	2012-12-17 17:50:12 UTC (rev 10178)
+++ CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py	2012-12-17 17:50:55 UTC (rev 10179)
@@ -14,17 +14,19 @@
 # limitations under the License.
 ##
 
+from difflib import unified_diff
+
+from pycalendar.datetime import PyCalendarDateTime
+from pycalendar.period import PyCalendarPeriod
+
 from twext.python.log import Logger
 
+from twistedcaldav import accounting
+from twistedcaldav.config import config
 from twistedcaldav.ical import Component, Property
 from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
 from twistedcaldav.scheduling.itip import iTipGenerator
-from twistedcaldav import accounting
 
-from difflib import unified_diff
-from pycalendar.period import PyCalendarPeriod
-from pycalendar.datetime import PyCalendarDateTime
-
 """
 Class that handles diff'ing two calendar objects.
 """
@@ -483,7 +485,13 @@
 
         if serverAttendee.parameterValue("PARTSTAT", "NEEDS-ACTION") != clientAttendee.parameterValue("PARTSTAT", "NEEDS-ACTION"):
             serverAttendee.setParameter("PARTSTAT", clientAttendee.parameterValue("PARTSTAT", "NEEDS-ACTION"))
+
+            # If PARTSTAT was changed by the attendee, add a timestamp if needed
+            if config.Scheduling.Options.TimestampAttendeePartStatChanges:
+                serverAttendee.setParameter("X-CALENDARSERVER-DTSTAMP", PyCalendarDateTime.getNowUTC().getText())
+
             replyNeeded = True
+
         if serverAttendee.parameterValue("RSVP", "FALSE") != clientAttendee.parameterValue("RSVP", "FALSE"):
             if clientAttendee.parameterValue("RSVP", "FALSE") == "FALSE":
                 try:

Modified: CalendarServer/trunk/twistedcaldav/scheduling/itip.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/itip.py	2012-12-17 17:50:12 UTC (rev 10178)
+++ CalendarServer/trunk/twistedcaldav/scheduling/itip.py	2012-12-17 17:50:55 UTC (rev 10179)
@@ -117,12 +117,15 @@
             completeds = 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,))
+            attendee_dtstamp = attendee.parameterValue("X-CALENDARSERVER-DTSTAMP") if attendee else None
         else:
             master_valarms = ()
             private_comments = ()
             transps = ()
             completeds = ()
             organizer_schedule_status = None
+            attendee_dtstamp = None
 
         if itip_message.masterComponent() is not None:
 
@@ -143,11 +146,15 @@
                 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)
 
             # 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, master_valarms, private_comments, transps, completeds, organizer_schedule_status, component, recipient)
+                    iTipProcessing.transferItems(calendar, master_valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, component, recipient)
 
             # Now try to match recurrences from the old calendar
             for component in calendar.subcomponents():
@@ -158,7 +165,7 @@
                         new_component = new_calendar.deriveInstance(rid, allowCancelled=allowCancelled)
                         if new_component:
                             new_calendar.addComponent(new_component)
-                            iTipProcessing.transferItems(calendar, master_valarms, private_comments, transps, completeds, organizer_schedule_status, new_component, recipient)
+                            iTipProcessing.transferItems(calendar, master_valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, new_component, recipient)
 
             # Replace the entire object
             return new_calendar, rids
@@ -175,7 +182,7 @@
                         calendar.addComponent(component)
                 else:
                     component = component.duplicate()
-                    missingDeclined = iTipProcessing.transferItems(calendar, master_valarms, private_comments, transps, completeds, organizer_schedule_status, component, recipient, remove_matched=True)
+                    missingDeclined = iTipProcessing.transferItems(calendar, master_valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, component, recipient, remove_matched=True)
                     if not missingDeclined:
                         calendar.addComponent(component)
                         if recipient:
@@ -486,7 +493,7 @@
 
 
     @staticmethod
-    def transferItems(from_calendar, master_valarms, private_comments, transps, completeds, organizer_schedule_status, to_component, recipient, remove_matched=False):
+    def transferItems(from_calendar, master_valarms, private_comments, transps, completeds, organizer_schedule_status, attendee_dtstamp, to_component, 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
@@ -524,6 +531,8 @@
                 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)
         else:
             # Check for incoming DECLINED
             attendee = to_component.getAttendeeProperty((recipient,))
@@ -540,6 +549,10 @@
                 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)
 
         return False
 
@@ -843,7 +856,7 @@
         itip.removeXProperties(keep_properties=keep_properties)
 
         # Property Parameters
-        itip.removePropertyParameters("ATTENDEE", ("SCHEDULE-AGENT", "SCHEDULE-STATUS", "SCHEDULE-FORCE-SEND",))
+        itip.removePropertyParameters("ATTENDEE", ("SCHEDULE-AGENT", "SCHEDULE-STATUS", "SCHEDULE-FORCE-SEND", "X-CALENDARSERVER-DTSTAMP",))
         itip.removePropertyParameters("ORGANIZER", ("SCHEDULE-AGENT", "SCHEDULE-STATUS", "SCHEDULE-FORCE-SEND",))
 
 

Modified: CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py	2012-12-17 17:50:12 UTC (rev 10178)
+++ CalendarServer/trunk/twistedcaldav/scheduling/test/test_icaldiff.py	2012-12-17 17:50:55 UTC (rev 10179)
@@ -20,6 +20,7 @@
 from difflib import unified_diff
 
 import itertools
+import re
 
 class ICalDiff (twistedcaldav.test.util.TestCase):
     """
@@ -558,7 +559,7 @@
 DTSTART:20080601T120000Z
 DTEND:20080601T130000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -1180,7 +1181,11 @@
                 diffResult[0],
                 diffResult[1],
                 tuple(sorted(diffResult[2])),
-                str(diffResult[3]).replace("\r", "") if diffResult[3] else None,
+                re.sub(
+                    "X-CALENDARSERVER-DTSTAMP=[^Z]+",
+                    "X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXX",
+                    str(diffResult[3]).replace("\r", "").replace("\n ", "")
+                ) if diffResult[3] else None,
             )
             self.assertEqual(diffResult, result, msg="%s: actual result: (%s)" % (description, ", ".join([str(i).replace("\r", "") for i in diffResult]),))
 
@@ -1566,7 +1571,7 @@
 RECURRENCE-ID:20080602T120000Z
 DTSTART:20080602T123000Z
 DTEND:20080602T130000Z
-ATTENDEE;PARTSTAT=ACCEPTED;RSVP=TRUE:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;RSVP=TRUE;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER:mailto:user1 at example.com
 END:VEVENT
 BEGIN:VEVENT
@@ -1575,7 +1580,7 @@
 DTSTART:20080604T120000Z
 DTEND:20080604T130000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=DECLINED;RSVP=TRUE:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=DECLINED;RSVP=TRUE;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -1678,7 +1683,11 @@
                 diffResult[0],
                 diffResult[1],
                 tuple(sorted(diffResult[2])),
-                str(diffResult[3]).replace("\r", "") if diffResult[3] else None,
+                re.sub(
+                    "X-CALENDARSERVER-DTSTAMP=[^Z]+",
+                    "X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXX",
+                    str(diffResult[3]).replace("\r", "").replace("\n ", "")
+                ) if diffResult[3] else None,
             )
             self.assertEqual(diffResult, result, msg="%s: actual result: (%s)" % (description, ", ".join([str(i).replace("\r", "") for i in diffResult]),))
 
@@ -2715,7 +2724,7 @@
 DTSTART:20080601T120000Z
 DTEND:20080601T130000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -2760,7 +2769,7 @@
 DTSTART:20080601T130000Z
 DTEND:20080601T140000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -2805,7 +2814,7 @@
 DTSTART:20080601T130000Z
 DTEND:20080601T140000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -2868,7 +2877,7 @@
 DTSTART:20080601T120000Z
 DTEND:20080601T130000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 BEGIN:VEVENT
@@ -2877,7 +2886,7 @@
 DTSTART:20080602T120000Z
 DTEND:20080602T130000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED;RSVP=TRUE:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;RSVP=TRUE;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -2940,7 +2949,7 @@
 DTSTART:20080601T140000Z
 DTEND:20080601T150000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 BEGIN:VEVENT
@@ -2949,7 +2958,7 @@
 DTSTART:20080602T120000Z
 DTEND:20080602T130000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -3066,7 +3075,7 @@
 DTSTART:20080601T120000Z
 DTEND:20080601T130000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -3134,7 +3143,7 @@
 DTSTART:20080601T120000Z
 DTEND:20080601T130000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -3203,7 +3212,7 @@
 DTSTART:20080601T120000Z
 DTEND:20080601T130000Z
 ATTENDEE:mailto:user1 at example.com
-ATTENDEE;PARTSTAT=ACCEPTED:mailto:user2 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED;X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXXZ:mailto:user2 at example.com
 ORGANIZER;CN=User 01:mailto:user1 at example.com
 END:VEVENT
 END:VCALENDAR
@@ -3218,7 +3227,11 @@
                 diffResult[0],
                 diffResult[1],
                 tuple(sorted(diffResult[2])),
-                str(diffResult[3]).replace("\r", "") if diffResult[3] else None,
+                re.sub(
+                    "X-CALENDARSERVER-DTSTAMP=[^Z]+",
+                    "X-CALENDARSERVER-DTSTAMP=XXXXXXXXTXXXXXX",
+                    str(diffResult[3]).replace("\r", "").replace("\n ", "")
+                ) if diffResult[3] else None,
             )
             self.assertEqual(diffResult, result, msg="%s: actual result: (%s)" % (description, ", ".join([str(i).replace("\r", "") for i in diffResult]),))
 

Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py	2012-12-17 17:50:12 UTC (rev 10178)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py	2012-12-17 17:50:55 UTC (rev 10179)
@@ -694,7 +694,8 @@
             "UIDLockTimeoutSeconds"               : 60, # Time for implicit UID lock timeout
             "UIDLockExpirySeconds"                : 300, # Expiration time for UID lock,
             "V1Compatibility"                     : False, # Allow /path-based CUAs in scheduling replies
-            "PrincipalHostAliases"                : [], # Hostnames matched in http(s) CUAs
+            "PrincipalHostAliases"                : [], # Host names matched in http(s) CUAs
+            "TimestampAttendeePartStatChanges"    : True, # Add a time stamp when an Attendee changes their PARTSTAT
 
             "DelegeteRichFreeBusy"                : True, # Delegates can get extra info in a freebusy request
             "RoomResourceRichFreeBusy"            : True, # Any user can get extra info for rooms/resources in a freebusy request
@@ -1536,6 +1537,8 @@
             compliance += caldavxml.caldav_default_alarms_compliance
         if configDict.EnableManagedAttachments:
             compliance += caldavxml.caldav_managed_attachments_compliance
+        if configDict.Scheduling.Options.TimestampAttendeePartStatChanges:
+            compliance += customxml.calendarserver_partstat_changes_compliance
     else:
         compliance = ()
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20121217/b3512f1d/attachment-0001.html>


More information about the calendarserver-changes mailing list