[CalendarServer-changes] [4393] CalendarServer/trunk/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Tue Jun 30 08:36:53 PDT 2009
Revision: 4393
http://trac.macosforge.org/projects/calendarserver/changeset/4393
Author: cdaboo at apple.com
Date: 2009-06-30 08:36:52 -0700 (Tue, 30 Jun 2009)
Log Message:
-----------
If processing of an attendee's iTIP message fails because of inconsistent data with the organizer, we try
to "self-heal" by replacing the attendee's current data with the full data from the organizer for that
attendee, then we try re-applying the iTIP message changes.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/method/delete_common.py
CalendarServer/trunk/twistedcaldav/scheduling/implicit.py
CalendarServer/trunk/twistedcaldav/scheduling/processing.py
Added Paths:
-----------
CalendarServer/trunk/twistedcaldav/scheduling/utils.py
Modified: CalendarServer/trunk/twistedcaldav/method/delete_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/delete_common.py 2009-06-30 01:17:13 UTC (rev 4392)
+++ CalendarServer/trunk/twistedcaldav/method/delete_common.py 2009-06-30 15:36:52 UTC (rev 4393)
@@ -168,7 +168,7 @@
yield parent.updateCTag()
# Do scheduling
- if scheduler:
+ if scheduler and not self.internal_request:
yield scheduler.doImplicitScheduling()
except MemcacheLockTimeoutError:
Modified: CalendarServer/trunk/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/implicit.py 2009-06-30 01:17:13 UTC (rev 4392)
+++ CalendarServer/trunk/twistedcaldav/scheduling/implicit.py 2009-06-30 15:36:52 UTC (rev 4393)
@@ -16,7 +16,7 @@
from twext.web2.dav.davxml import ErrorResponse
-from twisted.internet.defer import inlineCallbacks, returnValue, succeed
+from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.web2 import responsecode
from twisted.web2.dav import davxml
from twisted.web2.dav.util import joinURL
@@ -35,6 +35,7 @@
from twistedcaldav.scheduling.icaldiff import iCalDiff
from twistedcaldav.scheduling.itip import iTipGenerator
from twistedcaldav.scheduling.scheduler import CalDAVScheduler
+from twistedcaldav.scheduling.utils import getCalendarObjectForPrincipals
__all__ = [
"ImplicitScheduler",
@@ -88,7 +89,7 @@
yield self.checkImplicitState()
# Attendees are not allowed to overwrite one type with another
- if self.state == "attendee" and (existing_type != new_type) and existing_resource:
+ if not self.internal_request and self.state == "attendee" and (existing_type != new_type) and existing_resource:
raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-attendee-change")))
returnValue((self.action != "none", new_type == "schedule",))
@@ -817,28 +818,10 @@
"""
self.organizer_calendar = None
- if self.organizerPrincipal:
- # Get Organizer's calendar-home
- calendar_home = self.organizerPrincipal.calendarHome()
-
- # FIXME: because of the URL->resource request mapping thing, we have to force the request
- # to recognize this resource
- self.request._rememberResource(calendar_home, calendar_home.url())
-
- # Run a UID query against the UID
-
- def queryCalendarCollection(collection, uri):
- rname = collection.index().resourceNameForUID(self.uid)
- if rname:
- self.organizer_calendar = collection.iCalendar(rname)
- return succeed(False)
- else:
- return succeed(True)
-
- # NB We are by-passing privilege checking here. That should be OK as the data found is not
- # exposed to the user.
- yield report_common.applyToCalendarCollections(calendar_home, self.request, calendar_home.url(), "infinity", queryCalendarCollection, None)
-
+ calendar_resource, _ignore_name, _ignore_collection, _ignore_uri = (yield getCalendarObjectForPrincipals(self.request, self.organizerPrincipal, self.uid))
+ if calendar_resource:
+ self.organizer_calendar = calendar_resource.iCalendar()
+
def isAttendeeChangeInsignificant(self):
"""
Check whether the change is significant (PARTSTAT) or allowed
Modified: CalendarServer/trunk/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/processing.py 2009-06-30 01:17:13 UTC (rev 4392)
+++ CalendarServer/trunk/twistedcaldav/scheduling/processing.py 2009-06-30 15:36:52 UTC (rev 4393)
@@ -16,16 +16,19 @@
from hashlib import md5
from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks, returnValue, succeed
+from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.web2.dav.method.report import NumberOfMatchesWithinLimits
from twisted.web2.dav.util import joinURL
+from twisted.web2.http import HTTPError
from twistedcaldav import customxml, caldavxml
from twistedcaldav.caldavxml import caldav_namespace
from twistedcaldav.ical import Property
+from twistedcaldav.instance import InvalidOverriddenInstanceError
from twistedcaldav.log import Logger
from twistedcaldav.method import report_common
from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
from twistedcaldav.scheduling.itip import iTipProcessing, iTIPRequestStatus
+from twistedcaldav.scheduling.utils import getCalendarObjectForPrincipals
from vobject.icalendar import utc
import datetime
import time
@@ -78,7 +81,27 @@
if self.isOrganizerReceivingMessage():
result = (yield self.doImplicitOrganizer())
elif self.isAttendeeReceivingMessage():
- result = (yield self.doImplicitAttendee())
+ try:
+ result = (yield self.doImplicitAttendee())
+ except ImplicitProcessorException:
+ # These we always pass up
+ raise
+ except Exception, e:
+ # We attempt to recover from this. That involves trying to re-write the attendee data
+ # to match that of the organizer assuming we have the organizer's full data available, then
+ # we try the processing operation again.
+ log.error("ImplicitProcessing - originator '%s' to recipient '%s' with UID: '%s' - exception raised will try to fix: %s" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid, e))
+ result = (yield self.doImplicitAttendeeEventFix(e))
+ if result:
+ log.error("ImplicitProcessing - originator '%s' to recipient '%s' with UID: '%s' - restored organizer's copy" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
+ try:
+ result = (yield self.doImplicitAttendee())
+ except Exception, e:
+ log.error("ImplicitProcessing - originator '%s' to recipient '%s' with UID: '%s' - exception raised after fix: %s" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid, e))
+ raise ImplicitProcessorException("5.1;Service unavailable")
+ else:
+ log.error("ImplicitProcessing - originator '%s' to recipient '%s' with UID: '%s' - could not fix" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
+ raise ImplicitProcessorException("5.1;Service unavailable")
else:
log.error("METHOD:%s not supported for implicit scheduling." % (self.method,))
raise ImplicitProcessorException("3.14;Unsupported capability")
@@ -105,32 +128,15 @@
self.recipient_calendar = None
self.recipient_calendar_collection = None
+ self.recipient_calendar_collection_uri = None
self.recipient_calendar_name = None
- if self.recipient.principal:
- # Get Recipient's calendar-home
- calendar_home = self.recipient.principal.calendarHome()
-
- # FIXME: because of the URL->resource request mapping thing, we have to force the request
- # to recognize this resource
- self.request._rememberResource(calendar_home, calendar_home.url())
+ calendar_resource, resource_name, calendar_collection, calendar_collection_uri = (yield getCalendarObjectForPrincipals(self.request, self.recipient.principal, self.uid))
+ if calendar_resource:
+ self.recipient_calendar = calendar_resource.iCalendar()
+ self.recipient_calendar_collection = calendar_collection
+ self.recipient_calendar_collection_uri = calendar_collection_uri
+ self.recipient_calendar_name = resource_name
- # Run a UID query against the UID
-
- def queryCalendarCollection(collection, uri):
- rname = collection.index().resourceNameForUID(self.uid)
- if rname:
- self.recipient_calendar = collection.iCalendar(rname)
- self.recipient_calendar_name = rname
- self.recipient_calendar_collection = collection
- self.recipient_calendar_collection_uri = uri
- return succeed(False)
- else:
- return succeed(True)
-
- # NB We are by-passing privilege checking here. That should be OK as the data found is not
- # exposed to the user.
- yield report_common.applyToCalendarCollections(calendar_home, self.request, calendar_home.url(), "infinity", queryCalendarCollection, None)
-
@inlineCallbacks
def doImplicitOrganizer(self):
@@ -655,3 +661,37 @@
madeChanges = True
return madeChanges
+
+ @inlineCallbacks
+ def doImplicitAttendeeEventFix(self, ex):
+
+ # Only certain types of exception should be handled - ones related to calendar data errors.
+ # All others should result in the scheduling response coming back as a 5.x code
+
+ if type(ex) not in (InvalidOverriddenInstanceError, HTTPError):
+ raise ImplicitProcessorException("5.1;Service unavailable")
+
+ # Check to see whether the originator is hosted on this server
+ if not self.originator.principal:
+ raise ImplicitProcessorException("5.1;Service unavailable")
+
+ # Locate the originator's copy of the event
+ calendar_resource, _ignore_name, _ignore_collection, _ignore_uri = (yield getCalendarObjectForPrincipals(self.request, self.originator.principal, self.uid))
+ if not calendar_resource:
+ raise ImplicitProcessorException("5.1;Service unavailable")
+ originator_calendar = calendar_resource.iCalendar()
+
+ # Get attendee's view of that
+ originator_calendar.attendeesView((self.recipient.cuaddr,))
+
+ # Locate the attendee's copy of the event if it exists.
+ recipient_resource, recipient_resource_name, recipient_collection, recipient_collection_uri = (yield getCalendarObjectForPrincipals(self.request, self.recipient.principal, self.uid))
+
+ # We only need to fix data that already exists
+ if recipient_resource:
+ if originator_calendar.mainType() != None:
+ yield self.writeCalendarResource(recipient_collection_uri, recipient_collection, recipient_resource_name, originator_calendar)
+ else:
+ yield self.deleteCalendarResource(recipient_collection_uri, recipient_collection, recipient_resource_name)
+
+ returnValue(True)
Added: CalendarServer/trunk/twistedcaldav/scheduling/utils.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/utils.py (rev 0)
+++ CalendarServer/trunk/twistedcaldav/scheduling/utils.py 2009-06-30 15:36:52 UTC (rev 4393)
@@ -0,0 +1,56 @@
+#
+# 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.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+from twisted.internet.defer import inlineCallbacks, succeed, returnValue
+from twistedcaldav.method import report_common
+
+ at inlineCallbacks
+def getCalendarObjectForPrincipals(request, principal, uid):
+ """
+ Get a copy of the event for a principal.
+ """
+
+ result = {}
+ result["resource"] = None
+ result["resource_name"] = None
+ result["calendar_collection"] = None
+ result["calendar_collection_uri"] = None
+ if principal:
+ # Get principal's calendar-home
+ calendar_home = principal.calendarHome()
+
+ # FIXME: because of the URL->resource request mapping thing, we have to force the request
+ # to recognize this resource
+ request._rememberResource(calendar_home, calendar_home.url())
+
+ # Run a UID query against the UID
+
+ def queryCalendarCollection(collection, uri):
+ rname = collection.index().resourceNameForUID(uid)
+ if rname:
+ result["resource"] = collection.getChild(rname)
+ result["resource_name"] = rname
+ result["calendar_collection"] = collection
+ result["calendar_collection_uri"] = uri
+ return succeed(False)
+ else:
+ return succeed(True)
+
+ # NB We are by-passing privilege checking here. That should be OK as the data found is not
+ # exposed to the user.
+ yield report_common.applyToCalendarCollections(calendar_home, request, calendar_home.url(), "infinity", queryCalendarCollection, None)
+
+ returnValue((result["resource"], result["resource_name"], result["calendar_collection"], result["calendar_collection_uri"],))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090630/6468d839/attachment-0001.html>
More information about the calendarserver-changes
mailing list