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

source_changes at macosforge.org source_changes at macosforge.org
Fri Sep 5 13:35:08 PDT 2014


Revision: 13942
          http://trac.calendarserver.org//changeset/13942
Author:   cdaboo at apple.com
Date:     2014-09-05 13:35:08 -0700 (Fri, 05 Sep 2014)
Log Message:
-----------
Fix issue with group reconciliation when an attendee is removed as a member of one group but is still a member of another.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/ical.py
    CalendarServer/trunk/twistedcaldav/test/test_icalendar.py

Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py	2014-09-05 20:25:47 UTC (rev 13941)
+++ CalendarServer/trunk/twistedcaldav/ical.py	2014-09-05 20:35:08 UTC (rev 13942)
@@ -3501,16 +3501,16 @@
             # remove attendee or update MEMBER attribute for non-primary attendees in this group,
             for attendeeProp in oldAttendeeProps:
                 if attendeeProp.hasParameter("MEMBER"):
-                    parameterValues = tuple(attendeeProp.parameterValues("MEMBER"))
-                    if groupCUA in parameterValues:
+                    memberValues = attendeeProp.parameterValues("MEMBER")
+                    if groupCUA in tuple(memberValues):
                         if attendeeProp.value() not in memberCUAs:
-                            attendeeProp.removeParameterValue("MEMBER", groupCUA)
-                            if not attendeeProp.parameterValues("MEMBER"):
+                            memberValues.remove(groupCUA)
+                            if len(memberValues) == 0:
                                 component.removeProperty(attendeeProp)
                             changed = True
                     else:
                         if attendeeProp.value() in memberCUAs:
-                            attendeeProp.setParameter("MEMBER", parameterValues + (groupCUA,))
+                            memberValues.append(groupCUA)
                             changed = True
 
         return changed
@@ -3537,10 +3537,10 @@
                     attendeeCUA = attendeeProp.value()
                     if attendeeCUA in allMemberCUAs:
                         # remove orphan member values
-                        parameterValues = tuple(attendeeProp.parameterValues("MEMBER"))
-                        for orphanGroupCUA in set(parameterValues) - nonemptyGroupCUAs:
-                            attendeeProp.removeParameterValue("MEMBER", orphanGroupCUA)
-                            if not attendeeProp.parameterValues("MEMBER"):
+                        memberValues = attendeeProp.parameterValues("MEMBER")
+                        for orphanGroupCUA in set(memberValues) - nonemptyGroupCUAs:
+                            memberValues.remove(orphanGroupCUA)
+                            if len(memberValues) == 0:
                                 component.removeProperty(attendeeProp)
                             changed = True
                     else:

Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py	2014-09-05 20:25:47 UTC (rev 13941)
+++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py	2014-09-05 20:35:08 UTC (rev 13942)
@@ -23,7 +23,7 @@
 
 from twistedcaldav.dateops import normalizeForExpand
 from twistedcaldav.ical import Component, Property, InvalidICalendarDataError, \
-    normalizeCUAddress, normalize_iCalStr
+    normalizeCUAddress, normalize_iCalStr, diff_iCalStrs
 from twistedcaldav.ical import iCalendarProductID
 from twistedcaldav.instance import InvalidOverriddenInstanceError
 import twistedcaldav.test.util
@@ -11082,3 +11082,470 @@
             component = Component.fromString(txt).mainComponent()
             transp = component.adjustedTransp()
             self.assertEqual(transp, result, msg=title)
+
+
+    def test_reconcileGroupAttendees(self):
+        """
+        reconcileGroupAttendees()
+        """
+
+        data = (
+            (
+                "No change",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {},
+                False,
+            ),
+            (
+                "Empty group",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {"urn:uuid:group01": ()},
+                False,
+            ),
+            (
+                "One new member",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {
+                    "urn:uuid:group01": (
+                        Property("ATTENDEE", "mailto:user03 at example.com", {"MEMBER": "urn:uuid:group01"}),
+                    )
+                },
+                True,
+            ),
+            (
+                "One existing member",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {
+                    "urn:uuid:group01": (
+                        Property("ATTENDEE", "mailto:user03 at example.com", {"MEMBER": "urn:uuid:group01"}),
+                    )
+                },
+                False,
+            ),
+            (
+                "One removed member",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {"urn:uuid:group01": ()},
+                True,
+            ),
+            (
+                "Two members: one existing, one new",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user04 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {
+                    "urn:uuid:group01": (
+                        Property("ATTENDEE", "mailto:user03 at example.com", {"MEMBER": "urn:uuid:group01"}),
+                        Property("ATTENDEE", "mailto:user04 at example.com", {"MEMBER": "urn:uuid:group01"}),
+                    )
+                },
+                True,
+            ),
+            (
+                "Two existing members",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user04 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user04 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {
+                    "urn:uuid:group01": (
+                        Property("ATTENDEE", "mailto:user03 at example.com", {"MEMBER": "urn:uuid:group01"}),
+                        Property("ATTENDEE", "mailto:user04 at example.com", {"MEMBER": "urn:uuid:group01"}),
+                    )
+                },
+                False,
+            ),
+            (
+                "One existing, one removed member",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user04 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group01
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user04 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {
+                    "urn:uuid:group01": (
+                        Property("ATTENDEE", "mailto:user04 at example.com", {"MEMBER": "urn:uuid:group01"}),
+                    )
+                },
+                True,
+            ),
+            (
+                "Member with removed group",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {},
+                True,
+            ),
+            (
+                "Member with removed group added to another",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group02
+ATTENDEE;MEMBER="urn:uuid:group01":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group02
+ATTENDEE;MEMBER="urn:uuid:group02":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {
+                    "urn:uuid:group02": (
+                        Property("ATTENDEE", "mailto:user03 at example.com", {"MEMBER": "urn:uuid:group01"}),
+                    )
+                },
+                True,
+            ),
+            (
+                "Member with removed group in another",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group02
+ATTENDEE;MEMBER="urn:uuid:group01","urn:uuid:group02":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;VALUE=DATE:20080601
+DURATION:PT1H
+DTSTAMP:20080601T120000Z
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+ATTENDEE;CUTYPE=X-SERVER-GROUP:urn:uuid:group02
+ATTENDEE;MEMBER="urn:uuid:group02":mailto:user03 at example.com
+ORGANIZER:mailto:user01 at example.com
+SUMMARY:Test
+END:VEVENT
+END:VCALENDAR
+""",
+                {
+                    "urn:uuid:group02": (
+                        Property("ATTENDEE", "mailto:user03 at example.com", {"MEMBER": "urn:uuid:group01"}),
+                    )
+                },
+                True,
+            ),
+        )
+
+        for title, txt, txt_result, propMap, changed in data:
+            cal = Component.fromString(txt)
+            result = cal.reconcileGroupAttendees(propMap)
+            self.assertEqual(result, changed, msg="{}: {}".format(title, "Result mismatch"))
+            self.assertEqual(normalize_iCalStr(cal), normalize_iCalStr(txt_result), msg="{}:{}".format(title, diff_iCalStrs(cal, txt_result)))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140905/d3467c5b/attachment-0001.html>


More information about the calendarserver-changes mailing list