[CalendarServer-changes] [3584] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Fri Jan 9 13:52:22 PST 2009
Revision: 3584
http://trac.macosforge.org/projects/calendarserver/changeset/3584
Author: cdaboo at apple.com
Date: 2009-01-09 13:52:22 -0800 (Fri, 09 Jan 2009)
Log Message:
-----------
Merge partial partstat response branch to trunk.
Modified Paths:
--------------
CalendarServer/trunk/run
CalendarServer/trunk/twistedcaldav/instance.py
CalendarServer/trunk/twistedcaldav/scheduling/processing.py
Modified: CalendarServer/trunk/run
===================================================================
--- CalendarServer/trunk/run 2009-01-09 21:50:56 UTC (rev 3583)
+++ CalendarServer/trunk/run 2009-01-09 21:52:22 UTC (rev 3584)
@@ -692,7 +692,7 @@
caldavtester="${top}/CalDAVTester";
-svn_get "CalDAVTester" "${caldavtester}" "${svn_uri_base}/CalDAVTester/trunk" 3563;
+svn_get "CalDAVTester" "${caldavtester}" "${svn_uri_base}/CalDAVTester/trunk" 3583;
#
# Calendar Server
Modified: CalendarServer/trunk/twistedcaldav/instance.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/instance.py 2009-01-09 21:50:56 UTC (rev 3583)
+++ CalendarServer/trunk/twistedcaldav/instance.py 2009-01-09 21:52:22 UTC (rev 3584)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2006-2007 Apple Inc. All rights reserved.
+# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
from vobject.icalendar import utc
-# The maximum number of instances we will ezpand out to.
+# The maximum number of instances we will expand out to.
# Raise a TooManyInstancesError exception if we exceed this.
max_allowed_instances = 1000
@@ -300,7 +300,7 @@
rid = component.getRecurrenceIDUTC()
range = component.getRange()
- # Now add this instance, effectively overridding the one with the matching R-ID
+ # Now add this instance, effectively overriding the one with the matching R-ID
start = normalizeForIndex(start)
end = normalizeForIndex(end)
rid = normalizeForIndex(rid)
@@ -322,7 +322,7 @@
for key in sorted(x for x in self.instances.keys() if x > str(rid)):
oldinstance = self.instances[key]
- # Do not override instance that is alreday overridden
+ # Do not override instance that is already overridden
if oldinstance.overridden:
continue
@@ -372,7 +372,7 @@
Add the specified master VAVAILABILITY Component to the instance list, expanding it
within the supplied time range. VAVAILABILITY components are not recurring, they have an
optional DTSTART and DTEND/DURATION defining a single time-range which may be bounded
- depedning on the presence of the properties. If unbounded at one or both ends, we will
+ depending on the presence of the properties. If unbounded at one or both ends, we will
set the time to 1/1/1900 in the past and 1/1/3000 in the future.
@param component: the Component to expand
@param limit: the end datetime.datetime for expansion
Modified: CalendarServer/trunk/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/processing.py 2009-01-09 21:50:56 UTC (rev 3583)
+++ CalendarServer/trunk/twistedcaldav/scheduling/processing.py 2009-01-09 21:52:22 UTC (rev 3584)
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005-2008 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2009 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -449,54 +449,94 @@
for calURL in calendars:
testcal = (yield self.request.locateResource(calURL))
- # First list is BUSY, second BUSY-TENTATIVE, third BUSY-UNAVAILABLE
- fbinfo = ([], [], [])
-
# Now do search for overlapping time-range
for instance in instances.instances.itervalues():
- try:
- tr = caldavxml.TimeRange(start="20000101", end="20000101")
- tr.start = instance.start
- tr.end = instance.end
- yield report_common.generateFreeBusyInfo(self.request, testcal, fbinfo, tr, 0, uid)
-
- # If any fbinfo entries exist we have an overlap
- if len(fbinfo[0]) or len(fbinfo[1]) or len(fbinfo[2]):
+ if instance_states[instance]:
+ try:
+ # First list is BUSY, second BUSY-TENTATIVE, third BUSY-UNAVAILABLE
+ fbinfo = ([], [], [])
+
+ tr = caldavxml.TimeRange(start="20000101", end="20000101")
+ tr.start = instance.start
+ tr.end = instance.end
+ yield report_common.generateFreeBusyInfo(self.request, testcal, fbinfo, tr, 0, uid)
+
+ # If any fbinfo entries exist we have an overlap
+ if len(fbinfo[0]) or len(fbinfo[1]) or len(fbinfo[2]):
+ instance_states[instance] = False
+ except NumberOfMatchesWithinLimits:
instance_states[instance] = False
- except NumberOfMatchesWithinLimits:
- instance_states[instance] = False
- log.info("Exceeded number of matches whilst trying to find free-time.")
+ log.info("Exceeded number of matches whilst trying to find free-time.")
# If everything is declined we can exit now
- if all([not state for state in instance_states.itervalues()]):
+ if not any(instance_states.itervalues()):
break
# TODO: here we should do per-instance ACCEPT/DECLINE behavior
# For now we will assume overall ACCEPT/DECLINE
# Collect all the accepted and declined states
- accepted = all(instance_states.itervalues())
+ all_accepted = all(instance_states.itervalues())
+ all_declined = not any(instance_states.itervalues())
- # Extract the ATTENDEE property matching current recipient from the calendar data
+ # Do the simple case of all accepted or decline separately
cuas = self.recipient.principal.calendarUserAddresses()
- attendeeProps = calendar.getAttendeeProperties(cuas)
- if not attendeeProps:
- returnValue((False, "",))
+ if all_accepted or all_declined:
+ # Extract the ATTENDEE property matching current recipient from the calendar data
+ attendeeProps = calendar.getAttendeeProperties(cuas)
+ if not attendeeProps:
+ returnValue((False, "",))
+
+ if all_accepted:
+ partstat = "ACCEPTED"
+ else:
+ partstat = "DECLINED"
+ calendar.replacePropertyInAllComponents(Property("TRANSP", "OPAQUE" if all_accepted else "TRANSPARENT"))
- if accepted:
- partstat = "ACCEPTED"
+ made_changes = self.changeAttendeePartstat(attendeeProps, partstat)
+
else:
- partstat = "DECLINED"
+ # Hard case: some accepted some declined
+ # What we will do is mark any master instance as accepted, then mark each existing
+ # overridden instance as accepted or declined, and generate new overridden instances for
+ # any other declines.
- # Make sure declined events are TRANSPARENT on the calendar
- calendar.replacePropertyInAllComponents(Property("TRANSP", "TRANSPARENT"))
+ made_changes = False
+ partstat = "MIXED RESPONSE"
- made_changes = False
- for attendeeProp in attendeeProps:
- if attendeeProp.params().get("PARTSTAT", ("NEEDS-ACTION",))[0] != partstat:
- attendeeProp.params()["PARTSTAT"] = [partstat]
- made_changes = True
-
+ # See if there is a master component first
+ master = calendar.masterComponent()
+ if master:
+ attendee = master.getAttendeeProperty(cuas)
+ if attendee:
+ made_changes |= self.changeAttendeePartstat(attendee, "ACCEPTED")
+ master.replaceProperty(Property("TRANSP", "OPAQUE"))
+
+ # Look at expanded instances and change partstat accordingly
+ for instance, accepted in instance_states.iteritems():
+
+ overridden = calendar.overriddenComponent(instance.rid)
+ if not overridden and accepted:
+ # Nothing to do as master is always ACCEPTED
+ continue
+
+ if overridden:
+ # Change ATTENDEE property to match new state
+ attendee = overridden.getAttendeeProperty(cuas)
+ if attendee:
+ made_changes |= self.changeAttendeePartstat(attendee, "ACCEPTED" if accepted else "DECLINED")
+ overridden.replaceProperty(Property("TRANSP", "OPAQUE" if accepted else "TRANSPARENT"))
+ else:
+ # Derive a new overridden component and change partstat
+ derived = calendar.deriveInstance(instance.rid)
+ if derived:
+ attendee = derived.getAttendeeProperty(cuas)
+ if attendee:
+ self.changeAttendeePartstat(attendee, "ACCEPTED" if accepted else "DECLINED")
+ derived.replaceProperty(Property("TRANSP", "OPAQUE" if accepted else "TRANSPARENT"))
+ calendar.addComponent(derived)
+ made_changes = True
+
# Fake a SCHEDULE-STATUS on the ORGANIZER property
if made_changes:
calendar.setParameterToValueForPropertyWithValue("SCHEDULE-STATUS", iTIPRequestStatus.MESSAGE_DELIVERED, "ORGANIZER", None)
@@ -565,3 +605,26 @@
# Change CTag on the parent calendar collection
yield collection.updateCTag()
+
+ def changeAttendeePartstat(self, attendees, partstat):
+ """
+ Change the PARTSTAT on any ATTENDEE properties passed in.
+
+ @param attendees: a single ATTENDEE property or a list of them
+ @type attendees: L{Property}, C{list} or C{tuple}
+ @param partstat: new PARTSTAT to set
+ @type partstat: C{str}
+
+ @return: C{True} if any change was made, C{False} otherwise
+ """
+
+ if isinstance(attendees, Property):
+ attendees = (attendees,)
+
+ madeChanges = False
+ for attendee in attendees:
+ if attendee.params().get("PARTSTAT", ("NEEDS-ACTION",))[0] != partstat:
+ attendee.params()["PARTSTAT"] = [partstat]
+ madeChanges = True
+
+ return madeChanges
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090109/1622baa3/attachment-0001.html>
More information about the calendarserver-changes
mailing list