[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