[CalendarServer-changes] [4351] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Wed Jun 17 09:50:59 PDT 2009
Revision: 4351
http://trac.macosforge.org/projects/calendarserver/changeset/4351
Author: cdaboo at apple.com
Date: 2009-06-17 09:50:59 -0700 (Wed, 17 Jun 2009)
Log Message:
-----------
SCHEDULE-AGENT support.
Modified Paths:
--------------
CalendarServer/trunk/run
CalendarServer/trunk/twistedcaldav/ical.py
CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
CalendarServer/trunk/twistedcaldav/scheduling/implicit.py
CalendarServer/trunk/twistedcaldav/scheduling/itip.py
CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
Modified: CalendarServer/trunk/run
===================================================================
--- CalendarServer/trunk/run 2009-06-17 16:49:45 UTC (rev 4350)
+++ CalendarServer/trunk/run 2009-06-17 16:50:59 UTC (rev 4351)
@@ -727,7 +727,7 @@
caldavtester="${top}/CalDAVTester";
-svn_get "CalDAVTester" "${caldavtester}" "${svn_uri_base}/CalDAVTester/trunk" 4346;
+svn_get "CalDAVTester" "${caldavtester}" "${svn_uri_base}/CalDAVTester/trunk" 4350;
#
# PyFlakes
Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py 2009-06-17 16:49:45 UTC (rev 4350)
+++ CalendarServer/trunk/twistedcaldav/ical.py 2009-06-17 16:50:59 UTC (rev 4351)
@@ -96,12 +96,12 @@
"TZOFFSETTO": (None, {"VALUE": "UTC-OFFSET"}),
"TZURL": (None, {"VALUE": "URI"}),
"ATTENDEE": (None, {
- "VALUE": "CAL-ADDRESS",
- "CUTYPE": "INDIVIDUAL",
- "ROLE": "REQ-PARTICIPANT",
- "PARTSTAT": "NEEDS-ACTION",
- "RSVP": "FALSE",
-
+ "VALUE": "CAL-ADDRESS",
+ "CUTYPE": "INDIVIDUAL",
+ "ROLE": "REQ-PARTICIPANT",
+ "PARTSTAT": "NEEDS-ACTION",
+ "RSVP": "FALSE",
+ "SCHEDULE-AGENT": "SERVER",
}),
"CONTACT": (None, {"VALUE": "TEXT"}),
"ORGANIZER": (None, {"VALUE": "CAL-ADDRESS"}),
@@ -1510,12 +1510,14 @@
return None
- def getAttendeesByInstance(self, makeUnique=False):
+ def getAttendeesByInstance(self, makeUnique=False, onlyScheduleAgentServer=False):
"""
Get the attendee values for each instance. Optionally remove duplicates.
@param makeUnique: if C{True} remove duplicate ATTENDEEs in each component
@type makeUnique: C{bool}
+ @param onlyScheduleAgentServer: if C{True} only return ATETNDEEs with SCHEDULE-AGENT=SERVER set
+ @type onlyScheduleAgentServer: C{bool}
@return: a list of tuples of (organizer value, recurrence-id)
"""
@@ -1524,13 +1526,19 @@
result = ()
for component in self.subcomponents():
if component.name() != "VTIMEZONE":
- result += component.getAttendeesByInstance(makeUnique)
+ result += component.getAttendeesByInstance(makeUnique, onlyScheduleAgentServer)
return result
else:
result = ()
attendees = set()
rid = self.getRecurrenceIDUTC()
for attendee in tuple(self.properties("ATTENDEE")):
+
+ if onlyScheduleAgentServer:
+ if "SCHEDULE-AGENT" in attendee.params():
+ if attendee.paramValue("SCHEDULE-AGENT") != "SERVER":
+ continue
+
cuaddr = attendee.value()
if makeUnique and cuaddr in attendees:
self.removeProperty(attendee)
@@ -1739,7 +1747,7 @@
for prop in matched.properties(propname):
self.addProperty(prop)
- def attendeesView(self, attendees):
+ def attendeesView(self, attendees, onlyScheduleAgentServer=False):
"""
Filter out any components that all attendees are not present in. Use EXDATEs
on the master to account for changes.
@@ -1756,9 +1764,15 @@
continue
found_all_attendees = True
for attendee in attendees:
- if component.getAttendeeProperty((attendee,)) is None:
+ foundAttendee = component.getAttendeeProperty((attendee,))
+ if foundAttendee is None:
found_all_attendees = False
break
+ if onlyScheduleAgentServer:
+ if "SCHEDULE-AGENT" in foundAttendee.params():
+ if foundAttendee.paramValue("SCHEDULE-AGENT") != "SERVER":
+ found_all_attendees = False
+ break
if not found_all_attendees:
remove_components.append(component)
if component.getRecurrenceIDUTC() is None:
Modified: CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py 2009-06-17 16:49:45 UTC (rev 4350)
+++ CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py 2009-06-17 16:50:59 UTC (rev 4351)
@@ -70,7 +70,7 @@
"LAST-MODIFIED",
))
calendar.removeXProperties()
- calendar.removePropertyParameters("ATTENDEE", ("RSVP", "SCHEDULE-AGENT", "SCHEDULE-STATUS",))
+ calendar.removePropertyParameters("ATTENDEE", ("RSVP", "SCHEDULE-STATUS",))
calendar.normalizeAll()
return calendar
Modified: CalendarServer/trunk/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/implicit.py 2009-06-17 16:49:45 UTC (rev 4350)
+++ CalendarServer/trunk/twistedcaldav/scheduling/implicit.py 2009-06-17 16:50:59 UTC (rev 4351)
@@ -45,8 +45,6 @@
# TODO:
#
# Handle the case where a PUT removes the ORGANIZER property. That should be equivalent to cancelling the entire meeting.
-# Support SCHEDULE-AGENT property
-# Support SCHEDULE-STATUS property
# Support Schedule-Reply header
#
@@ -346,7 +344,7 @@
raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "single-organizer")))
# Get the ATTENDEEs
- self.attendeesByInstance = self.calendar.getAttendeesByInstance(True)
+ self.attendeesByInstance = self.calendar.getAttendeesByInstance(True, onlyScheduleAgentServer=True)
self.attendees = set()
for attendee, _ignore in self.attendeesByInstance:
self.attendees.add(attendee)
@@ -574,7 +572,7 @@
# TODO: the later three will be ignored for now.
- oldAttendeesByInstance = self.oldcalendar.getAttendeesByInstance()
+ oldAttendeesByInstance = self.oldcalendar.getAttendeesByInstance(onlyScheduleAgentServer=True)
mappedOld = set(oldAttendeesByInstance)
mappedNew = set(self.attendeesByInstance)
@@ -617,7 +615,7 @@
if (new_attendee, None) not in mappedNew or rid in addedexdates:
self.cancelledAttendees.add(item)
- master_attendees = self.oldcalendar.masterComponent().getAttendeesByInstance()
+ master_attendees = self.oldcalendar.masterComponent().getAttendeesByInstance(onlyScheduleAgentServer=True)
for attendee, _ignore in master_attendees:
for exdate in addedexdates:
# Don't remove the master attendee's when an EXDATE is added for a removed overridden component
@@ -842,7 +840,7 @@
oldcalendar = self.oldcalendar
if oldcalendar is None:
oldcalendar = self.organizer_calendar
- oldcalendar.attendeesView((self.attendee,))
+ oldcalendar.attendeesView((self.attendee,), onlyScheduleAgentServer=True)
differ = iCalDiff(oldcalendar, self.calendar, self.do_smart_merge)
return differ.attendeeMerge(self.attendee)
Modified: CalendarServer/trunk/twistedcaldav/scheduling/itip.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/itip.py 2009-06-17 16:49:45 UTC (rev 4350)
+++ CalendarServer/trunk/twistedcaldav/scheduling/itip.py 2009-06-17 16:50:59 UTC (rev 4351)
@@ -560,7 +560,7 @@
itip.replacePropertyInAllComponents(Property("DTSTAMP", datetime.datetime.now(tz=utc)))
# Now filter out components that do not contain every attendee
- itip.attendeesView(attendees)
+ itip.attendeesView(attendees, onlyScheduleAgentServer=True)
# Now filter out components except the ones specified
if itip.filterComponents(filter_rids):
@@ -649,7 +649,7 @@
# Property Parameters
itip.removePropertyParameters("ATTENDEE", ("SCHEDULE-AGENT", "SCHEDULE-STATUS",))
- itip.removePropertyParameters("ORGANIZER", ("SCHEDULE-STATUS",))
+ itip.removePropertyParameters("ORGANIZER", ("SCHEDULE-AGENT", "SCHEDULE-STATUS",))
class iTIPRequestStatus(object):
"""
Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2009-06-17 16:49:45 UTC (rev 4350)
+++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2009-06-17 16:50:59 UTC (rev 4351)
@@ -388,6 +388,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
()
),
(
@@ -401,6 +402,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
(
("mailto:user2 at example.com", None),
)
@@ -417,6 +419,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
(
("mailto:user2 at example.com", None),
("mailto:user3 at example.com", None),
@@ -437,22 +440,65 @@
RECURRENCE-ID:20081114T000000Z
DTSTART:20071114T010000Z
ORGANIZER:mailto:user1 at example.com
-ATTENDEE:mailto:user2 at example.com
-ATTENDEE:mailto:user3 at example.com
+ATTENDEE;SCHEDULE-AGENT=NONE:mailto:user2 at example.com
+ATTENDEE;SCHEDULE-AGENT=CLIENT:mailto:user3 at example.com
END:VEVENT
END:VCALENDAR
""",
+ False,
(
("mailto:user2 at example.com", None),
("mailto:user2 at example.com", datetime.datetime(2008, 11, 14, 0, 0, tzinfo=tzutc())),
("mailto:user3 at example.com", datetime.datetime(2008, 11, 14, 0, 0, tzinfo=tzutc()))
)
),
+ (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20071114T000000Z
+ORGANIZER:mailto:user1 at example.com
+ATTENDEE;SCHEDULE-AGENT=NONE:mailto:user2 at example.com
+ATTENDEE:mailto:user3 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ (
+ ("mailto:user3 at example.com", None),
+ )
+ ),
+ (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20071114T000000Z
+ORGANIZER:mailto:user1 at example.com
+ATTENDEE;SCHEDULE-AGENT=SERVER:mailto:user2 at example.com
+RRULE:FREQ=YEARLY
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890
+RECURRENCE-ID:20081114T000000Z
+DTSTART:20071114T010000Z
+ORGANIZER:mailto:user1 at example.com
+ATTENDEE;SCHEDULE-AGENT=NONE:mailto:user2 at example.com
+ATTENDEE;SCHEDULE-AGENT=CLIENT:mailto:user3 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ (
+ ("mailto:user2 at example.com", None),
+ )
+ ),
)
- for caldata, result in data:
+ for caldata, checkScheduleAgent, result in data:
component = Component.fromString(caldata)
- self.assertEqual(component.getAttendeesByInstance(), result)
+ self.assertEqual(component.getAttendeesByInstance(onlyScheduleAgentServer=checkScheduleAgent), result)
def test_set_parameter_value(self):
data = (
@@ -675,6 +721,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -698,6 +745,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -719,6 +767,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -746,6 +795,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -775,6 +825,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -818,6 +869,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -846,6 +898,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -882,6 +935,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -910,6 +964,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -945,6 +1000,7 @@
END:VEVENT
END:VCALENDAR
""",
+ False,
"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//PYVOBJECT//NONSGML Version 1//EN
@@ -952,11 +1008,156 @@
""",
("mailto:user3 at example.com",)
),
+
+ # Simple component, no Attendees - no filtering
+ (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ False,
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ ()
+ ),
+
+ # Simple component, no Attendees - filtering
+ (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-2
+DTSTART:20071114T000000Z
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+END:VCALENDAR
+""",
+ ("mailto:user01 at example.com",)
+ ),
+
+ # Simple component, with one attendee - filtering match
+ (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE:mailto:user2 at example.com
+ORGANIZER:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ ("mailto:user2 at example.com",)
+ ),
+
+ # Simple component, with one attendee - filtering match
+ (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE;SCHEDULE-AGENT=SERVER:mailto:user2 at example.com
+ORGANIZER:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE;SCHEDULE-AGENT=SERVER:mailto:user2 at example.com
+ORGANIZER:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ ("mailto:user2 at example.com",)
+ ),
+
+ # Simple component, with one attendee - filtering match - no schedule-agent match
+ (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE;SCHEDULE-AGENT=CLIENT:mailto:user2 at example.com
+ORGANIZER:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+END:VCALENDAR
+""",
+ ("mailto:user2 at example.com",)
+ ),
+
+ # Simple component, with one attendee - filtering match - no schedule-agent match
+ (
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-3
+DTSTART:20071114T000000Z
+ATTENDEE;SCHEDULE-AGENT=NONE:mailto:user2 at example.com
+ORGANIZER:mailto:user1 at example.com
+END:VEVENT
+END:VCALENDAR
+""",
+ True,
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+END:VCALENDAR
+""",
+ ("mailto:user2 at example.com",)
+ ),
+
)
- for original, filtered, attendees in data:
+ for original, checkScheduleAgent, filtered, attendees in data:
component = Component.fromString(original)
- component.attendeesView(attendees)
+ component.attendeesView(attendees, onlyScheduleAgentServer=checkScheduleAgent)
self.assertEqual(filtered, str(component).replace("\r", ""))
def test_all_but_one_attendee(self):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090617/2517ca7d/attachment-0001.html>
More information about the calendarserver-changes
mailing list