[CalendarServer-changes] [12021] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Mar 12 11:23:25 PDT 2014


Revision: 12021
          http://trac.calendarserver.org//changeset/12021
Author:   cdaboo at apple.com
Date:     2013-12-03 11:35:19 -0800 (Tue, 03 Dec 2013)
Log Message:
-----------
Rejection of PUT with duplicate private comments.

Modified Paths:
--------------
    CalendarServer/trunk/conf/caldavd-test.plist
    CalendarServer/trunk/twistedcaldav/ical.py
    CalendarServer/trunk/twistedcaldav/stdconfig.py
    CalendarServer/trunk/twistedcaldav/storebridge.py
    CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/caldav/icalendarstore.py

Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist	2013-12-03 19:33:06 UTC (rev 12020)
+++ CalendarServer/trunk/conf/caldavd-test.plist	2013-12-03 19:35:19 UTC (rev 12021)
@@ -826,6 +826,10 @@
     <!-- Private Events -->
     <key>EnablePrivateEvents</key>
     <true/>
+    
+    <!-- Private Comment fix off for testing -->
+    <key>RemoveDuplicatePrivateComments</key>
+    <false/>
 
     <!-- Timezone Service -->
     <key>EnableTimezoneService</key>

Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py	2013-12-03 19:33:06 UTC (rev 12020)
+++ CalendarServer/trunk/twistedcaldav/ical.py	2013-12-03 19:35:19 UTC (rev 12021)
@@ -3418,7 +3418,33 @@
         return False
 
 
+    def hasDuplicatePrivateComments(self, doFix=False):
+        """
+        Test and optionally remove "X-CALENDARSERVER-ATTENDEE-COMMENT" properties that have the same
+        "X-CALENDARSERVER-ATTENDEE-REF" parameter values in the same component.
 
+        @return: C{True} if there are duplicates that were not fixed.
+        """
+        if self.name() == "VCALENDAR":
+            for component in self.subcomponents():
+                if component.name() in ("VTIMEZONE",):
+                    continue
+                if component.hasDuplicatePrivateComments(doFix):
+                    return True
+        else:
+            attendee_refs = set()
+            for prop in tuple(self.properties("X-CALENDARSERVER-ATTENDEE-COMMENT")):
+                ref = prop.parameterValue("X-CALENDARSERVER-ATTENDEE-REF")
+                if ref in attendee_refs:
+                    if doFix:
+                        self.removeProperty(prop)
+                    else:
+                        return True
+                attendee_refs.add(ref)
+        return False
+
+
+
 # #
 # Timezones
 # #

Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py	2013-12-03 19:33:06 UTC (rev 12020)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py	2013-12-03 19:35:19 UTC (rev 12021)
@@ -619,6 +619,8 @@
     "EnableDefaultAlarms" : True, # Support for default alarms generated by the server
     "RemoveDuplicateAlarms": True, # Remove duplicate alarms on PUT
 
+    "RemoveDuplicatePrivateComments": True, # Remove duplicate private comments on PUT
+
     # CardDAV Features
     "DirectoryAddressBook": {
         "Enabled": True,

Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py	2013-12-03 19:33:06 UTC (rev 12020)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py	2013-12-03 19:35:19 UTC (rev 12021)
@@ -58,7 +58,7 @@
     TooManyAttendeesError, InvalidCalendarAccessError, ValidOrganizerError, \
     InvalidPerUserDataMerge, \
     AttendeeAllowedError, ResourceDeletedError, InvalidAttachmentOperation, \
-    ShareeAllowedError
+    ShareeAllowedError, DuplicatePrivateCommentsError
 from txdav.carddav.iaddressbookstore import KindChangeNotAllowedError, \
     GroupWithUnsharedAddressNotAllowedError
 from txdav.common.datastore.sql_tables import _BIND_MODE_READ, _BIND_MODE_WRITE, \
@@ -2647,6 +2647,7 @@
         TooManyInstancesError: MaxInstances.fromString(str(config.MaxAllowedInstances)),
         AttachmentStoreValidManagedID: (caldav_namespace, "valid-managed-id"),
         ShareeAllowedError: (calendarserver_namespace, "sharee-privilege-needed",),
+        DuplicatePrivateCommentsError: (calendarserver_namespace, "no-duplicate-private-comments",),
     }
 
     StoreMoveExceptionsStatusErrors = set((

Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py	2013-12-03 19:33:06 UTC (rev 12020)
+++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py	2013-12-03 19:35:19 UTC (rev 12021)
@@ -10128,3 +10128,322 @@
             ical2 = Component.fromString(calendar)
             ical2.onlyPastInstances(rid)
             self.assertEqual(str(ical2), split_past.replace("\n", "\r\n"), "Failed past: %s" % (title,))
+
+
+    def test_hasDuplicatePrivateComments(self):
+        """
+        Test that L{Component.hasDuplicatePrivateComments} correctly detects, but does not fix, duplicate private comments.
+        """
+
+        data = (
+            (
+                "No comments",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                False,
+            ),
+
+            (
+                "One comment",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+END:VEVENT
+END:VCALENDAR
+""",
+                False,
+            ),
+
+            (
+                "Two different comments",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+END:VEVENT
+END:VCALENDAR
+""",
+                False,
+            ),
+
+            (
+                "Two duplicates, one different",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+END:VEVENT
+END:VCALENDAR
+""",
+                True,
+            ),
+
+            (
+                "No duplicates in two components",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user03";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message3
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+END:VEVENT
+END:VCALENDAR
+""",
+                False,
+            ),
+
+            (
+                "Two duplicates in one component, three different in another",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user03";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message3
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+END:VEVENT
+END:VCALENDAR
+""",
+                True,
+            ),
+        )
+
+        for title, txt, result in data:
+            component = Component.fromString(txt)
+            self.assertEqual(component.hasDuplicatePrivateComments(doFix=False), result, msg=title)
+            self.assertEqual(normalize_iCalStr(component), normalize_iCalStr(txt), msg=title)
+
+
+    def test_hasDuplicatePrivateComments_withFix(self):
+        """
+        Test that L{Component.hasDuplicatePrivateComments} correctly removes duplicate comments.
+        """
+
+        data = (
+            (
+                "No comments",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                False,
+            ),
+
+            (
+                "One comment",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+END:VEVENT
+END:VCALENDAR
+""",
+                False,
+            ),
+
+            (
+                "Two different comments",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+END:VEVENT
+END:VCALENDAR
+""",
+                False,
+            ),
+
+            (
+                "Two duplicates, one different",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+RRULE:FREQ=DAILY
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20080602T120000Z
+DTSTART:20080602T120000Z
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+SUMMARY:Test
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user01";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message1
+X-CALENDARSERVER-ATTENDEE-COMMENT;X-CALENDARSERVER-ATTENDEE-REF="urn:uuid:user02";X-CALENDARSERVER-DTSTAMP=20130606T152554Z:Message2
+END:VEVENT
+END:VCALENDAR
+""",
+                False,
+            ),
+        )
+
+        for title, txt, result, result_changed in data:
+            component = Component.fromString(txt)
+            changed = component.hasDuplicatePrivateComments(doFix=True)
+            self.assertEqual(sorted(normalize_iCalStr(component).splitlines()), sorted(normalize_iCalStr(result).splitlines()), msg=title)
+            self.assertEqual(changed, result_changed, msg=title)

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2013-12-03 19:33:06 UTC (rev 12020)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2013-12-03 19:35:19 UTC (rev 12021)
@@ -73,7 +73,7 @@
     AttendeeAllowedError, InvalidPerUserDataMerge, ComponentUpdateState, \
     ValidOrganizerError, ShareeAllowedError, ComponentRemoveState, \
     InvalidDefaultCalendar, \
-    InvalidAttachmentOperation
+    InvalidAttachmentOperation, DuplicatePrivateCommentsError
 from txdav.caldav.icalendarstore import QuotaExceeded
 from txdav.common.datastore.sql import CommonHome, CommonHomeChild, \
     CommonObjectResource, ECALENDARTYPE
@@ -1790,7 +1790,14 @@
 
             self.hasPrivateComment = new_has_private_comments
 
+            # Some clients appear to be buggy and are duplicating the "X-CALENDARSERVER-ATTENDEE-COMMENT" comment. We want
+            # to raise an error to prevent that so the client bugs can be tracked down.
 
+            # Look for properties with duplicate "X-CALENDARSERVER-ATTENDEE-REF" values in the same component
+            if component.hasDuplicatePrivateComments(doFix=config.RemoveDuplicatePrivateComments):
+                raise DuplicatePrivateCommentsError("Duplicate X-CALENDARSERVER-ATTENDEE-COMMENT properties present.")
+
+
     @inlineCallbacks
     def replaceMissingToDoProperties(self, calendar, inserting, internal_state):
         """

Modified: CalendarServer/trunk/txdav/caldav/icalendarstore.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/icalendarstore.py	2013-12-03 19:33:06 UTC (rev 12020)
+++ CalendarServer/trunk/txdav/caldav/icalendarstore.py	2013-12-03 19:35:19 UTC (rev 12021)
@@ -740,6 +740,13 @@
 
 
 
+class DuplicatePrivateCommentsError(CommonStoreError):
+    """
+    Calendar data cannot contain duplicate private comment properties.
+    """
+
+
+
 class InvalidPerUserDataMerge(CommonStoreError):
     """
     Per-user data merge failed.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140312/f384112d/attachment.html>


More information about the calendarserver-changes mailing list