[CalendarServer-changes] [94] CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Fri Sep 1 09:20:55 PDT 2006


Revision: 94
Author:   cdaboo at apple.com
Date:     2006-09-01 09:20:52 -0700 (Fri, 01 Sep 2006)

Log Message:
-----------
Fixes to defer operations in scheduling for new twisted branch merge.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/itip.py
    CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/post.py
    CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/schedule.py
    CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/schedule_common.py
    CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/resource.py

Modified: CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/itip.py
===================================================================
--- CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/itip.py	2006-09-01 16:14:08 UTC (rev 93)
+++ CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/itip.py	2006-09-01 16:20:52 UTC (rev 94)
@@ -55,6 +55,9 @@
     "canAutoRespond",
 ]
 
+class iTipException(Exception):
+    pass
+
 def handleRequest(request, principal, inbox, calendar, child):
     """
     Handle an iTIP response automatically using a deferredGenerator.
@@ -75,7 +78,7 @@
     elif method == "CANCEL":
         f = processCancel
 
-    return maybeDeferred(deferredGenerator(f), request, principal, inbox, calendar, child)
+    return f(request, principal, inbox, calendar, child)
 
 def processRequest(request, principal, inbox, calendar, child):
     """
@@ -128,41 +131,46 @@
         for i in info:
             # For any that are older, delete them.
             if compareSyncInfo(i, newinfo) < 0:
-                d = waitForDeferred(deleteResource(inbox, i[0]))
-                yield d
                 try:
+                    d = waitForDeferred(deleteResource(inbox, i[0]))
+                    yield d
                     d.getResult()
+                    logging.info("[ITIP]: deleted iTIP message %s in Inbox that was older than the new one." % (i[0],))
                 except:
                     log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                    return
-                logging.info("[ITIP]: deleted iTIP message %s in Inbox that was older than the new one." % (i[0],))
+                    raise iTipException
             else:
                 # For any that are newer or the same, mark the new one to be deleted.
                 delete_child = True
 
         # Delete the new one if so marked.
         if delete_child:
-            d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
-            yield d
             try:
+                d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
+                yield d
                 d.getResult()
+                logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than existing ones." % (child.fp.basename(),))
             except:
                 log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                return
-            logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than existing ones." % (child.fp.basename(),))
+                raise iTipException
+            yield None
             return
 
         # Next we want to try and find a match to any components on existing calendars listed as contributing
         # to free-busy as we will need to update those with the new one.
         
         # Find the current recipients calendar-free-busy-set
-        fbset = principal.calendarFreeBusySet(request)
+        fbset = waitForDeferred(principal.calendarFreeBusySet(request))
+        yield fbset
+        fbset = fbset.getResult()
 
         # Find the first calendar in the list with a component matching the one we are processing
         calmatch = None
         for href in fbset.children:
             calURL = str(href)
-            updatecal = inbox.locateSiblingResource(request, calURL)
+            updatecal = waitForDeferred(request.locateResource(calURL))
+            yield updatecal
+            updatecal = updatecal.getResult()
             if updatecal is None or not updatecal.exists() or not isCalendarCollectionResource(updatecal):
                 # We will ignore missing calendars. If the recipient has failed to
                 # properly manage the free busy set that should not prevent us from working.
@@ -173,7 +181,9 @@
                 break
         
         # If we have a match then we need to check whether we are updating etc
-        doreply, replycal, accepted = checkForReply(request, principal, calendar)
+        d = waitForDeferred(checkForReply(request, principal, calendar))
+        yield d
+        doreply, replycal, accepted = d.getResult()
         if calmatch:
             # See whether the current component is older than any existing ones and throw it away if so
             cal = updatecal.iCalendar(calmatch[0])
@@ -181,80 +191,73 @@
             if compareSyncInfo(info, newinfo) < 0:
                 # Re-write existing resource with new one, if accepted, otherwise delete existing as the
                 # update to it was not accepted.
-                if accepted:
-                    d, newchild = writeResource(request, calURL, updatecal, calmatch[0], calendar)
-                    d = waitForDeferred(d)
-                else:
-                    d = waitForDeferred(deleteResource(updatecal, calmatch[0]))
-                yield d
                 try:
-                    d.getResult()
+                    if accepted:
+                        newchild = waitForDeferred(writeResource(request, calURL, updatecal, calmatch[0], calendar))
+                        yield newchild
+                        newchild = newchild.getResult()
+                        logging.info("[ITIP]: replaced calendar component %s with new iTIP message in %s." % (calmatch[0], calURL))
+                    else:
+                        d = waitForDeferred(deleteResource(updatecal, calmatch[0]))
+                        yield d
+                        d.getResult()
+                        logging.info("[ITIP]: deleted calendar component %s in %s as update was not accepted." % (calmatch[0], calURL))
                 except:
                     log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                    return
-                if accepted:
-                    logging.info("[ITIP]: replaced calendar component %s with new iTIP message in %s." % (calmatch[0], calURL))
-                else:
-                    logging.info("[ITIP]: deleted calendar component %s in %s as update was not accepted." % (calmatch[0], calURL))
+                    raise iTipException
+
             else:
                 # Delete new one in Inbox as it is old
-                d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
-                yield d
                 try:
+                    d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
+                    yield d
                     d.getResult()
+                    logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than %s in %s." % (child.fp.basename(), calmatch[0], calURL))
                 except:
                     log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                    return
-                logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than %s in %s." % (child.fp.basename(), calmatch[0], calURL))
+                    raise iTipException
+                yield None
                 return
         else:
             # Write new resource into first calendar in f-b-set
             if len(fbset.children) != 0 and accepted:
                 calURL = str(fbset.children[0])
-                updatecal = inbox.locateSiblingResource(request, calURL)
-                d, newchild = writeResource(request, calURL, updatecal, None, calendar)
-                d = waitForDeferred(d)
-                yield d
+                updatecal = waitForDeferred(request.locateResource(calURL))
+                yield updatecal
+                updatecal = updatecal.getResult()
                 try:
-                    d.getResult()
+                    newchild = waitForDeferred(writeResource(request, calURL, updatecal, None, calendar))
+                    yield newchild
+                    newchild.getResult()
+                    logging.info("[ITIP]: added new calendar component in %s." % (calURL,))
                 except:
                     log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                    return
-                logging.info("[ITIP]: added new calendar component in %s." % (calURL,))
+                    raise iTipException
         
         # If we get here we have a new iTIP message that we want to process. Any previous ones
         # have been removed (so we won't run in to problems when we check that there is free time
         # to book the new one). 
         if doreply:
             logging.info("[ITIP]: sending iTIP REPLY %s" % (("declined","accepted")[accepted],))
-            d, newchild = writeReply(request, principal, replycal, inbox)
-            d = waitForDeferred(d)
-            if d:
-                yield d
-                try:
-                    d.getResult()
-                except:
-                    log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                    return
-                newInboxResource(child, newchild)
+            newchild = waitForDeferred(writeReply(request, principal, replycal, inbox))
+            yield newchild
+            newchild = newchild.getResult()
+            newInboxResource(child, newchild)
             logging.info("[ITIP]: saving iTIP REPLY %s" % (("declined","accepted")[accepted],))
-            d, newchild = saveReply(request, principal, replycal, inbox)
-            d = waitForDeferred(d)
-            if d:
-                yield d
-                try:
-                    d.getResult()
-                except:
-                    log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                    return
+            newchild = waitForDeferred(saveReply(request, principal, replycal, inbox))
+            yield newchild
+            newchild = newchild.getResult()
 
         # Store CALDAV:schedule-state property
         assert child.fp.exists()
         child.writeDeadProperty(caldavxml.ScheduleState(caldavxml.Processed()))
+        yield None
         return
     else:
         raise NotImplementedError
-    
+
+processRequest = deferredGenerator(processRequest)
+
 def processAdd(request, principal, inbox, calendar, child):
     """
     Process a METHOD=ADD.
@@ -270,6 +273,8 @@
 
     raise NotImplementedError
 
+processAdd = deferredGenerator(processAdd)
+
 def processCancel(request, principal, inbox, calendar, child):
     """
     Process a METHOD=CANCEL.
@@ -326,41 +331,46 @@
         for i in info:
             # For any that are older, delete them.
             if compareSyncInfo(i, newinfo) < 0:
-                d = waitForDeferred(deleteResource(inbox, i[0]))
-                yield d
                 try:
+                    d = waitForDeferred(deleteResource(inbox, i[0]))
+                    yield d
                     d.getResult()
+                    logging.info("[ITIP]: deleted iTIP message %s in Inbox that was older than the new one." % (i[0],))
                 except:
                     log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                    return
-                logging.info("[ITIP]: deleted iTIP message %s in Inbox that was older than the new one." % (i[0],))
+                    raise iTipException
             else:
                 # For any that are newer or the same, mark the new one to be deleted.
                 delete_child = True
 
         # Delete the new one if so marked.
         if delete_child:
-            d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
-            yield d
             try:
+                d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
+                yield d
                 d.getResult()
+                logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than existing ones." % (child.fp.basename(),))
             except:
                 log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                return
-            logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than existing ones." % (child.fp.basename(),))
+                raise iTipException
+            yield None
             return
 
         # Next we want to try and find a match to any components on existing calendars listed as contributing
         # to free-busy as we will need to update those with the new one.
         
         # Find the current recipients calendar-free-busy-set
-        fbset = principal.calendarFreeBusySet(request)
+        fbset = waitForDeferred(principal.calendarFreeBusySet(request))
+        yield fbset
+        fbset = fbset.getResult()
 
         # Find the first calendar in the list with a component matching the one we are processing
         calmatch = None
         for href in fbset.children:
             calURL = str(href)
-            updatecal = inbox.locateSiblingResource(request, calURL)
+            updatecal = waitForDeferred(request.locateResource(calURL))
+            yield updatecal
+            updatecal = updatecal.getResult()
             if updatecal is None or not updatecal.exists() or not isCalendarCollectionResource(updatecal):
                 # We will ignore missing calendars. If the recipient has failed to
                 # properly manage the free busy set that should not prevent us from working.
@@ -377,24 +387,25 @@
             info = getSyncInfo(calmatch[0], cal)
             if compareSyncInfo(info, newinfo) < 0:
                 # Re-write existing resource with new one
-                d = waitForDeferred(deleteResource(updatecal, calmatch[0],))
-                yield d
                 try:
+                    d = waitForDeferred(deleteResource(updatecal, calmatch[0],))
+                    yield d
                     d.getResult()
+                    logging.info("[ITIP]: delete calendar component %s in %s as it was cancelled." % (calmatch[0], calURL))
                 except:
                     log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                    return
-                logging.info("[ITIP]: delete calendar component %s in %s as it was cancelled." % (calmatch[0], calURL))
+                    raise iTipException
             else:
                 # Delete new one in Inbox as it is old
-                d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
-                yield d
                 try:
+                    d = waitForDeferred(deleteResource(inbox, child.fp.basename()))
+                    yield d
                     d.getResult()
+                    logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than %s in %s." % (child.fp.basename(), calmatch[0], calURL))
                 except:
                     log.err("Error while auto-processing iTIP: %s" % (failure.Failure(),))
-                    return
-                logging.info("[ITIP]: deleted new iTIP message %s in Inbox because it was older than %s in %s." % (child.fp.basename(), calmatch[0], calURL))
+                    raise iTipException
+                yield None
                 return
         else:
             # Nothing to do
@@ -407,10 +418,13 @@
         # Store CALDAV:schedule-state property
         assert child.fp.exists()
         child.writeDeadProperty(caldavxml.ScheduleState(caldavxml.Processed()))
+        yield None
         return
     else:
         raise NotImplementedError
 
+processCancel = deferredGenerator(processCancel)
+
 def checkForReply(request, principal, calendar):
     """
     Check whether a reply to the given iTIP message is needed. A reply will be needed if the
@@ -438,10 +452,14 @@
     uid = comp.propertyValue("UID")
 
     # Now compare each instance time-range with the index and see if there is an overlap
-    fbset = principal.calendarFreeBusySet(request)
+    fbset = waitForDeferred(principal.calendarFreeBusySet(request))
+    yield fbset
+    fbset = fbset.getResult()
     for href in fbset.children:
         calURL = str(href)
-        testcal = principal.locateSiblingResource(request, calURL)
+        testcal = waitForDeferred(request.locateResource(calURL))
+        yield testcal
+        testcal = testcal.getResult()
         
         # First list is BUSY, second BUSY-TENTATIVE, third BUSY-UNAVAILABLE
         fbinfo = ([], [], [])
@@ -452,7 +470,9 @@
                 tr = caldavxml.TimeRange(start="20000101", end="20000101")
                 tr.start = instance.start
                 tr.end = instance.end
-                report_common.generateFreeBusyInfo(request, testcal, fbinfo, tr, 0, uid)
+                d = waitForDeferred(report_common.generateFreeBusyInfo(request, testcal, fbinfo, tr, 0, uid))
+                yield d
+                d.getResult()
                 
                 # If any fbinfo entries exist we have an overlap
                 if len(fbinfo[0]) or len(fbinfo[1]) or len(fbinfo[2]):
@@ -470,14 +490,17 @@
     cuas = principal.calendarUserAddressSet()
     attendeeProp = calendar.getAttendeeProperty(cuas)
     if attendeeProp is None:
-        return False, None, accepted
+        yield False, None, accepted
+        return
 
     # Look for specific parameters
     if "RSVP" in attendeeProp.params():
         if attendeeProp.params()["RSVP"][0] != "TRUE":
-            return False, None, accepted
+            yield False, None, accepted
+            return
     else:
-        return False, None, accepted
+        yield False, None, accepted
+        return
     
     # Now modify the original component
     del attendeeProp.params()["RSVP"]
@@ -514,8 +537,10 @@
         if (attendee.value() != attendeeProp.value()):
             replycal.mainComponent().removeProperty(attendee)
 
-    return True, replycal, accepted
+    yield True, replycal, accepted
 
+checkForReply = deferredGenerator(checkForReply)
+
 def writeReply(request, principal, replycal, ainbox):
     """
     Write an iTIP message reply into the specified Inbox.
@@ -529,20 +554,32 @@
     # Get the Inbox of the ORGANIZER
     organizer = replycal.getOrganizer()
     assert organizer is not None
-    inboxURL = CalendarPrincipalCollectionResource.inboxForCalendarUser(request, organizer)
+    inboxURL = waitForDeferred(CalendarPrincipalCollectionResource.inboxForCalendarUser(request, organizer))
+    yield inboxURL
+    inboxURL = inboxURL.getResult()
     assert inboxURL
     
     # Determine whether current principal has CALDAV:schedule right on that Inbox
-    inbox = ainbox.locateSiblingResource(request, inboxURL)
+    inbox = waitForDeferred(request.locateResource(inboxURL))
+    yield inbox
+    inbox = inbox.getResult()
 
-    errors = inbox.checkAccess(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef.fromString(principal.principalURL())))
-    if errors:
+    try:
+        d = waitForDeferred(inbox.checkAccess(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef.fromString(principal.principalURL()))))
+        yield d
+        d.getResult()
+    except:
         logging.info("[ITIP]: could not send reply as %s does not have CALDAV:schedule permission on %s Inbox." % (principal.principalURL(), organizer))
-        return None, None
+        yield None
+        return
     
     # Now deposit the new calendar into the inbox
-    return writeResource(request, inboxURL, inbox, None, replycal)
-    
+    d = waitForDeferred(writeResource(request, inboxURL, inbox, None, replycal))
+    yield d
+    yield d.getResult()
+
+writeReply = deferredGenerator(writeReply)
+
 def saveReply(request, principal, replycal, ainbox):
     """
     Write an iTIP message reply into the specified principal's Outbox.
@@ -558,16 +595,26 @@
     assert outboxURL
     
     # Determine whether current principal has CALDAV:schedule right on that Outbox
-    outbox = ainbox.locateSiblingResource(request, outboxURL)
+    outbox = waitForDeferred(request.locateResource(outboxURL))
+    yield outbox
+    outbox = outbox.getResult()
 
-    errors = outbox.checkAccess(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef.fromString(principal.principalURL())))
-    if errors:
+    try:
+        d = waitForDeferred(outbox.checkAccess(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef.fromString(principal.principalURL()))))
+        yield d
+        d.getResult()
+    except:
         logging.info("[ITIP]: could not save reply as %s does not have CALDAV:schedule permission on their Outbox." % (principal.principalURL(),))
-        return None, None
+        yield None
+        return
     
     # Now deposit the new calendar into the inbox
-    return writeResource(request, outboxURL, outbox, None, replycal)
-    
+    d = waitForDeferred(writeResource(request, outboxURL, outbox, None, replycal))
+    yield d
+    yield d.getResult()
+
+saveReply = deferredGenerator(saveReply)    
+
 def writeResource(request, collURL, collection, name, calendar):
     """
     Write out the calendar resource (iTIP) message to the specified calendar, either over-writing the named
@@ -603,6 +650,11 @@
     newchildURL = joinURL(collURL, name)
     
     # Copy calendar to inbox (doing fan-out)
+    def _defer(result):
+        return newchild
+    def _deferErr(f):
+        return None
+
     d = maybeDeferred(
             storeCalendarObjectResource,
             request=request,
@@ -614,7 +666,8 @@
             destinationcal = True,
             isiTIP = itipper
         )
-    return d, newchild
+    d.addCallbacks(_defer, _deferErr)
+    return d
 
 def newInboxResource(child, newchild):
     """

Modified: CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/post.py
===================================================================
--- CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/post.py	2006-09-01 16:14:08 UTC (rev 93)
+++ CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/post.py	2006-09-01 16:20:52 UTC (rev 94)
@@ -24,7 +24,8 @@
 
 __all__ = ["http_POST"]
 
-from twisted.internet.defer import deferredGenerator, maybeDeferred
+from twisted.internet.defer import deferredGenerator, waitForDeferred
+from twisted.web2.dav.util import parentForURL
 
 from twistedcaldav import caldavxml
 from twistedcaldav.method.schedule_common import processScheduleRequest
@@ -43,8 +44,17 @@
     #
     # Check authentication and access controls
     #
-    parent = self.locateParent(request, request.uri)
-    parent.securityCheck(request, (caldavxml.Schedule(),))
+    parent = waitForDeferred(request.locateResource(parentForURL(request.uri)))
+    yield parent
+    parent = parent.getResult()
+
+    d = waitForDeferred(parent.securityCheck(request, (caldavxml.Schedule(),)))
+    yield d
+    d.getResult()
         
     # Initiate deferred generator
-    return maybeDeferred(deferredGenerator(processScheduleRequest), self, "POST", request)
+    d = waitForDeferred(processScheduleRequest(self, "POST", request))
+    yield d
+    yield d.getResult()
+
+http_POST = deferredGenerator(http_POST)

Modified: CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/schedule.py
===================================================================
--- CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/schedule.py	2006-09-01 16:14:08 UTC (rev 93)
+++ CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/schedule.py	2006-09-01 16:20:52 UTC (rev 94)
@@ -15,7 +15,6 @@
 #
 # DRI: Cyrus Daboo, cdaboo at apple.com
 ##
-from twistedcaldav.method.schedule_common import processScheduleRequest
 
 """
 CalDAV SCHEDULE method.
@@ -25,9 +24,11 @@
 
 __all__ = ["http_SCHEDULE"]
 
-from twisted.internet.defer import deferredGenerator, maybeDeferred
+from twisted.internet.defer import deferredGenerator, waitForDeferred
+from twisted.web2.dav.util import parentForURL
 
 from twistedcaldav import caldavxml
+from twistedcaldav.method.schedule_common import processScheduleRequest
 
 def http_SCHEDULE(self, request):
 
@@ -43,8 +44,17 @@
     #
     # Check authentication and access controls
     #
-    parent = self.locateParent(request, request.uri)
-    parent.securityCheck(request, (caldavxml.Schedule(),))
+    parent = waitForDeferred(request.locateResource(parentForURL(request.uri)))
+    yield parent
+    parent = parent.getResult()
+
+    d = waitForDeferred(parent.securityCheck(request, (caldavxml.Schedule(),)))
+    yield d
+    d.getResult()
         
     # Initiate deferred generator
-    return maybeDeferred(deferredGenerator(processScheduleRequest), self, "SCHEDULE", request)
+    d = waitForDeferred(processScheduleRequest(self, "SCHEDULE", request))
+    yield d
+    yield d.getResult()
+
+http_SCHEDULE = deferredGenerator(http_SCHEDULE)

Modified: CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/schedule_common.py
===================================================================
--- CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/schedule_common.py	2006-09-01 16:14:08 UTC (rev 93)
+++ CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/method/schedule_common.py	2006-09-01 16:20:52 UTC (rev 94)
@@ -25,13 +25,14 @@
 __all__ = ["processScheduleRequest"]
 
 from twisted.internet import reactor
-from twisted.internet.defer import maybeDeferred, waitForDeferred
+from twisted.internet.defer import deferredGenerator, maybeDeferred, waitForDeferred
 from twisted.python import failure, log
 from twisted.web2 import responsecode
 from twisted.web2.dav import davxml
 from twisted.web2.dav.http import ErrorResponse
 from twisted.web2.dav.util import joinURL
 from twisted.web2.http import HTTPError
+from twistedcaldav.resource import findAnyCalendarUser
 
 from twistedcaldav import caldavxml
 from twistedcaldav import customxml
@@ -60,38 +61,35 @@
     # Must be targetting an OUTBOX
     if not isScheduleOutboxResource(self):
         log.err("%s must target an schedule Outbox collection: %s" % (method, self,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-collection"))
-        return
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-collection")))
 
     # Must be content-type text/calendar
     content_type = request.headers.getHeader("content-type")
     if content_type is not None and (content_type.mediaType, content_type.mediaSubtype) != ("text", "calendar"):
         log.err("MIME type %s not allowed in calendar collection" % (content_type,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-calendar-data"))
-        return
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-calendar-data")))
     
     # Must have Originator header
     originator = request.headers.getRawHeaders("originator")
     if originator is None or (len(originator) != 1):
         log.err("%s request must have Originator header" % (method,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-specified"))
-        return
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-specified")))
     else:
         originator = originator[0]
     
     # Verify that Originator is a valid calendar user (has an INBOX)
-    inboxURL = CalendarPrincipalCollectionResource.inboxForCalendarUser(request, originator)
+    inboxURL = waitForDeferred(CalendarPrincipalCollectionResource.inboxForCalendarUser(request, originator))
+    yield inboxURL
+    inboxURL = inboxURL.getResult()
     if inboxURL is None:
         log.err("Could not find Inbox for originator: %s" % (originator,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed"))
-        return
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
     
     # Get list of Recipient headers
     rawrecipients = request.headers.getRawHeaders("recipient")
     if rawrecipients is None or (len(rawrecipients) == 0):
         log.err("%s request must have at least one Recipient header" % (method,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-specified"))
-        return
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-specified")))
 
     # Recipient header may be comma separated list
     recipients = []
@@ -105,49 +103,48 @@
     recipients_state = {"OK":0, "BAD":0}
 
     # Parse the calendar object from the HTTP request stream
-    d = waitForDeferred(Component.fromIStream(request.stream))
-    yield d
     try:
+        d = waitForDeferred(Component.fromIStream(request.stream))
+        yield d
         calendar = d.getResult()
     except:
         log.err("Error while handling %s: %s" % (method, failure.Failure(),))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data"))
-        return
-
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
+ 
     # Must be a valid calendar
     try:
         calendar.validCalendarForCalDAV()
     except ValueError:
         log.err("%s request calendar component is not valid: %s" % (method, calendar,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data"))
-        return
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
 
     # Must have a METHOD
     if not calendar.isValidMethod():
         log.err("%s request must have valid METHOD property in calendar component: %s" % (method, calendar,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data"))
-        return
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
         
     # Verify iTIP behaviour
     if not calendar.isValidITIP():
         log.err("%s request must have a calendar component that satisfies iTIP requirements: %s" % (method, calendar,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data"))
-        return
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
     
     # Verify that the ORGANIZER's cu address maps to the request.uri
     organizer = calendar.getOrganizer()
     if organizer:
-        outboxURL = CalendarPrincipalCollectionResource.outboxForCalendarUser(request, organizer)
+        outboxURL = waitForDeferred(CalendarPrincipalCollectionResource.outboxForCalendarUser(request, organizer))
+        yield outboxURL
+        outboxURL = outboxURL.getResult()
     if (organizer is None) or (outboxURL is None):
         log.err("ORGANIZER in calendar data is not valid: %s" % (calendar,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed"))
-        return
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
+
     # Prevent spoofing of ORGANIZER with specific METHODs
     if (calendar.propertyValue("METHOD") in ("PUBLISH", "REQUEST", "ADD", "CANCEL", "DECLINECOUNTER")) and (outboxURL != request.uri):
         log.err("ORGANIZER in calendar data does not match owner of Outbox: %s" % (calendar,))
-        yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed"))
-        return
-    oprincipal = CalendarPrincipalCollectionResource.findAnyCalendarUser(request, organizer)        
+        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
+    oprincipal = waitForDeferred(findAnyCalendarUser(request, organizer))
+    yield oprincipal
+    oprincipal = oprincipal.getResult()
 
     # Prevent spoofing when doing reply-like METHODs
     if calendar.propertyValue("METHOD") in ("REPLY", "COUNTER", "REFRESH"):
@@ -158,15 +155,15 @@
         # Must have only one
         if len(attendees) != 1:
             log.err("ATTENDEE list in calendar data is wrong: %s" % (calendar,))
-            yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed"))
-            return
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
             
         # Attendee's Outbox MUST be the request URI
-        aoutboxURL = CalendarPrincipalCollectionResource.outboxForCalendarUser(request, attendees[0])
+        aoutboxURL = waitForDeferred(CalendarPrincipalCollectionResource.outboxForCalendarUser(request, attendees[0]))
+        yield aoutboxURL
+        aoutboxURL = aoutboxURL.getResult()
         if (aoutboxURL is None) or (aoutboxURL != request.uri):
             log.err("ATTENDEE in calendar data does not match owner of Outbox: %s" % (calendar,))
-            yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed"))
-            return
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
 
     # For free-busy do immediate determination of iTIP result rather than fan-out
     if (calendar.propertyValue("METHOD") == "REQUEST") and (calendar.mainType() == "VFREEBUSY"):
@@ -174,14 +171,12 @@
         vfreebusies = [v for v in calendar.subcomponents() if v.name() == "VFREEBUSY"]
         if len(vfreebusies) != 1:
             log.err("iTIP data is not valid for a VFREEBUSY request: %s" % (calendar,))
-            yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data"))
-            return
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
         dtstart = vfreebusies[0].getStartDateUTC()
         dtend = vfreebusies[0].getEndDateUTC()
         if dtstart is None or dtend is None:
             log.err("VFREEBUSY start/end not valid: %s" % (calendar,))
-            yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data"))
-            return
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
         timerange.start = dtstart
         timerange.end = dtend
 
@@ -223,8 +218,7 @@
             d.getResult()
         except:
             log.err("Error while handling %s: %s" % (method, failure.Failure(),))
-            yield ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "outbox-copy"))
-            return
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "outbox-copy")))
         
         # Store CALDAV:originator property
         child.writeDeadProperty(caldavxml.Originator(davxml.HRef.fromString(originator)))
@@ -240,13 +234,17 @@
     autoresponses = []
     for recipient in recipients:
         # Get the principal resource for this recipient
-        principal = CalendarPrincipalCollectionResource.findAnyCalendarUser(request, recipient)
+        principal = waitForDeferred(findAnyCalendarUser(request, recipient))
+        yield principal
+        principal = principal.getResult()
 
         # Map recipient to their inbox
         if principal is not None:
             inboxURL = principal.scheduleInboxURL()
             if inboxURL:
-                inbox = self.locateSiblingResource(request, inboxURL)
+                inbox = waitForDeferred(request.locateResource(inboxURL))
+                yield inbox
+                inbox = inbox.getResult()
         if principal is None or inboxURL is None or inbox is None:
             log.err("Could not find Inbox for recipient: %s" % (recipient,))
             err = HTTPError(ErrorResponse(responsecode.NOT_FOUND, (caldav_namespace, "recipient-exists")))
@@ -260,8 +258,11 @@
             #
             # Check access controls
             #
-            errors = inbox.checkAccess(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef.fromString(oprincipal)))
-            if errors:
+            try:
+                d = waitForDeferred(inbox.checkAccess(request, (caldavxml.Schedule(),), principal=davxml.Principal(davxml.HRef.fromString(oprincipal))))
+                yield d
+                d.getResult()
+            except:
                 log.err("Could not access Inbox for recipient: %s" % (recipient,))
                 err = HTTPError(ErrorResponse(responsecode.NOT_FOUND, (caldav_namespace, "recipient-permisions")))
                 responses.add(recipient, failure.Failure(exc_value=err), reqstatus="3.8;No authority")
@@ -277,7 +278,9 @@
                 attendeeProp = calendar.getAttendeeProperty(cuas)
             
                 # Find the current recipients calendar-free-busy-set
-                fbset = principal.calendarFreeBusySet(request)
+                fbset = waitForDeferred(principal.calendarFreeBusySet(request))
+                yield fbset
+                fbset = fbset.getResult()
 
                 # First list is BUSY, second BUSY-TENTATIVE, third BUSY-UNAVAILABLE
                 fbinfo = ([], [], [])
@@ -286,14 +289,18 @@
                     matchtotal = 0
                     for href in fbset.children:
                         calURL = str(href)
-                        cal = self.locateSiblingResource(request, calURL)
+                        cal = waitForDeferred(request.locateResource(calURL))
+                        yield cal
+                        cal = cal.getResult()
                         if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
                             # We will ignore missing calendars. If the recipient has failed to
                             # properly manage the free busy set that should not prevent us from working.
                             continue
                          
                         # TODO: make this a waitForDeferred and yield it
-                        matchtotal = report_common.generateFreeBusyInfo(request, cal, fbinfo, timerange, matchtotal)
+                        matchtotal = waitForDeferred(report_common.generateFreeBusyInfo(request, cal, fbinfo, timerange, matchtotal))
+                        yield matchtotal
+                        matchtotal = matchtotal.getResult()
                     
                     # Build VFREEBUSY iTIP reply for this recipient
                     fbresult = report_common.buildFreeBusyResult(fbinfo, timerange, organizer=organizerProp, attendee=attendeeProp, uid=uid)
@@ -367,4 +374,6 @@
 
     # Return with final response if we are done
     yield responses.response()
-    return
+
+processScheduleRequest = deferredGenerator(processScheduleRequest)
+

Modified: CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/resource.py	2006-09-01 16:14:08 UTC (rev 93)
+++ CalendarServer/branches/users/cdaboo/acl-merge/twistedcaldav/resource.py	2006-09-01 16:20:52 UTC (rev 94)
@@ -39,6 +39,7 @@
 
 from twisted.internet import reactor
 from twisted.internet.defer import Deferred, maybeDeferred, succeed
+from twisted.internet.defer import deferredGenerator, waitForDeferred
 from twisted.web2 import responsecode
 from twisted.web2.dav import auth, davxml
 from twisted.web2.dav.acl import DAVPrincipalResource
@@ -385,12 +386,17 @@
         @return: the URI of the calendar outbox, or C{None} if no outbox for
             exists for the user.
         """
-        principal = clazz.findAnyCalendarUser(request, address)
-        if principal:
-            return principal.scheduleOutboxURL()
-        else:
-            return None
+        
+        def _defer(principal):
+            if principal:
+                return principal.scheduleOutboxURL()
+            else:
+                return None
 
+        d = findAnyCalendarUser(request, address)
+        d.addCallback(_defer)
+        return d
+
     @classmethod
     def inboxForCalendarUser(clazz, request, address):
         """
@@ -401,35 +407,17 @@
         @return: the URI of the calendar inbox, or C{None} if no inbox exists
             for the user
         """
-        principal = clazz.findAnyCalendarUser(request, address)
-        if principal:
-            return principal.scheduleInboxURL()
-        else:
-            return None
+        
+        def _defer(principal):
+            if principal:
+                return principal.scheduleInboxURL()
+            else:
+                return None
 
-    @classmethod
-    def findAnyCalendarUser(clazz, request, address):
-        """
-        Find the calendar user principal associated with the specified calendar
-        user address in any of the currently defined principal collections.
-        @param request: an L{IRequest} object for the request being processed.
-        @param address: the calendar user address to look up.
-        @return: the L{CalendarPrincipalResource} for the specified calendar
-            user, or C{None} if the user is not found.
-        """
-        for url in clazz._principleCollectionSet.keys():
-            try:
-                pcollection = clazz._principleCollectionSet[url]
-                if isinstance(pcollection, CalendarPrincipalCollectionResource):
-                    principal = pcollection.findCalendarUser(request, address)
-                    if principal is not None:
-                        return principal
-            except ReferenceError:
-                pass
+        d = findAnyCalendarUser(request, address)
+        d.addCallback(_defer)
+        return d
 
-        return None
-
-
     def __init__(self, url):
         self._url = url
 
@@ -448,14 +436,20 @@
         
         # Look at cuaddress property on each child and do attempt a match
         for childname in self.listChildren():
-            child = self.getChild(childname)
+            child_url = joinURL(self._url, childname)
+            child = waitForDeferred(request.locateResource(child_url))
+            yield child
+            child = child.getResult()
             if not isinstance(child, CalendarPrincipalResource):
                 continue
             if child.matchesCalendarUserAddress(request, address):
-                return child
+                yield child
+                return
         
-        return None
+        yield None
 
+    findCalendarUser = deferredGenerator(findCalendarUser)
+
     def principalCollectionURL(self):
         return self._url
 
@@ -468,6 +462,32 @@
         result.append(davxml.Report(davxml.PrincipalSearchPropertySet(),))
         return result
 
+def findAnyCalendarUser(request, address):
+    """
+    Find the calendar user principal associated with the specified calendar
+    user address in any of the currently defined principal collections.
+    @param request: an L{IRequest} object for the request being processed.
+    @param address: the calendar user address to look up.
+    @return: the L{CalendarPrincipalResource} for the specified calendar
+        user, or C{None} if the user is not found.
+    """
+    for url in CalendarPrincipalCollectionResource._principleCollectionSet.keys():
+        try:
+            pcollection = CalendarPrincipalCollectionResource._principleCollectionSet[url]
+            if isinstance(pcollection, CalendarPrincipalCollectionResource):
+                principal = waitForDeferred(pcollection.findCalendarUser(request, address))
+                yield principal
+                principal = principal.getResult()
+                if principal is not None:
+                    yield principal
+                    return
+        except ReferenceError:
+            pass
+
+    yield None
+
+findAnyCalendarUser = deferredGenerator(findAnyCalendarUser)
+
 class CalendarPrincipalResource (DAVPrincipalResource):
     """
     CalDAV principal resource.
@@ -480,14 +500,14 @@
         """
         @return: a list of calendar user home URLs for this principal.
         """
-        return self.readDeadProperty((caldavxml.caldav_namespace, "calendar-home-set"))
+        return self.readDeadProperty((caldav_namespace, "calendar-home-set"))
 
     def scheduleInboxURL(self):
         """
         @return: the schedule INBOX URL for this principal.
         """
-        if self.hasDeadProperty((caldavxml.caldav_namespace, "schedule-inbox-URL")):
-            inbox = self.readDeadProperty((caldavxml.caldav_namespace, "schedule-inbox-URL"))
+        if self.hasDeadProperty((caldav_namespace, "schedule-inbox-URL")):
+            inbox = self.readDeadProperty((caldav_namespace, "schedule-inbox-URL"))
             assert isinstance(inbox, caldavxml.ScheduleInboxURL)
             inbox.removeWhitespaceNodes()
             if len(inbox.children) == 1:
@@ -499,8 +519,8 @@
         """
         @return: the schedule OUTBOX URL for this principal.
         """
-        if self.hasDeadProperty((caldavxml.caldav_namespace, "schedule-outbox-URL")):
-            outbox = self.readDeadProperty((caldavxml.caldav_namespace, "schedule-outbox-URL"))
+        if self.hasDeadProperty((caldav_namespace, "schedule-outbox-URL")):
+            outbox = self.readDeadProperty((caldav_namespace, "schedule-outbox-URL"))
             assert isinstance(outbox, caldavxml.ScheduleOutboxURL)
             outbox.removeWhitespaceNodes()
             if len(outbox.children) == 1:
@@ -512,8 +532,8 @@
         """
         @return: a list of calendar user addresses for this principal.
         """
-        if self.hasDeadProperty((caldavxml.caldav_namespace, "calendar-user-address-set")):
-            return self.readDeadProperty((caldavxml.caldav_namespace, "calendar-user-address-set"))
+        if self.hasDeadProperty((caldav_namespace, "calendar-user-address-set")):
+            return self.readDeadProperty((caldav_namespace, "calendar-user-address-set"))
             
         # Must have a valid address of some kind so use the principal uri
         return caldavxml.CalendarUserAddressSet(davxml.HRef().fromString(self._url))
@@ -539,25 +559,28 @@
             return True
 
         # Look at the property if URI lookup does not work
-        if self.hasProperty((caldav_namespace, "calendar-user-address-set"), request):
-            addresses = self.readProperty((caldav_namespace, "calendar-user-address-set"), request)
-            for cua in addresses.childrenOfType(davxml.HRef):
-                if str(cua) == address:
-                    return True
+        for cua in self.calendarUserAddressSet().children:
+            if str(cua) == address:
+                return True
         
         return False
 
     def calendarFreeBusySet(self, request):
         """
-        @return: a list of calendars that contribute to free-busy for this
+        @return: L{Deferred} whose result is a list of calendars that contribute to free-busy for this
             principal's calendar user.
         """
-        inbox = self.scheduleInboxURL()
-        resource = self.locateSiblingResource(request, inbox)
-        if resource and resource.hasDeadProperty((caldavxml.caldav_namespace, "calendar-free-busy-set")):
-            return resource.readDeadProperty((caldavxml.caldav_namespace, "calendar-free-busy-set"))
-        return caldavxml.CalendarFreeBusySet()
+        
+        def _defer(inbox):
+            if inbox and inbox.hasDeadProperty((caldav_namespace, "calendar-free-busy-set")):
+                return inbox.readDeadProperty((caldav_namespace, "calendar-free-busy-set"))
+            return caldavxml.CalendarFreeBusySet()
 
+        inbox_url = self.scheduleInboxURL()
+        d = request.locateResource(inbox_url)
+        d.addCallback(_defer)
+        return d
+
 class CalendarSchedulingCollectionResource (CalDAVResource):
     """
     CalDAV principal resource.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20060901/7c05eb71/attachment.html


More information about the calendarserver-changes mailing list