[CalendarServer-changes] [2462] CalendarServer/branches/unified-cache/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Fri May 23 15:44:40 PDT 2008


Revision: 2462
          http://trac.macosforge.org/projects/calendarserver/changeset/2462
Author:   dreid at apple.com
Date:     2008-05-23 15:44:39 -0700 (Fri, 23 May 2008)

Log Message:
-----------
Make PROPPATCH, ACL, and DELETE work properly.

Modified Paths:
--------------
    CalendarServer/branches/unified-cache/twistedcaldav/cache.py
    CalendarServer/branches/unified-cache/twistedcaldav/extensions.py
    CalendarServer/branches/unified-cache/twistedcaldav/method/put_common.py
    CalendarServer/branches/unified-cache/twistedcaldav/resource.py
    CalendarServer/branches/unified-cache/twistedcaldav/test/util.py

Modified: CalendarServer/branches/unified-cache/twistedcaldav/cache.py
===================================================================
--- CalendarServer/branches/unified-cache/twistedcaldav/cache.py	2008-05-23 21:02:17 UTC (rev 2461)
+++ CalendarServer/branches/unified-cache/twistedcaldav/cache.py	2008-05-23 22:44:39 UTC (rev 2462)
@@ -65,7 +65,7 @@
         return: A L{Deferred} that fires when the token has been changed.
         """
         self.log_debug("Changing Cache Token for %r" % (
-                self._propertyStore))
+                self._propertyStore.resource.fp))
         property = CacheTokensProperty.fromString(self._newCacheToken())
         self._propertyStore.set(property)
         return succeed(True)

Modified: CalendarServer/branches/unified-cache/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/branches/unified-cache/twistedcaldav/extensions.py	2008-05-23 21:02:17 UTC (rev 2461)
+++ CalendarServer/branches/unified-cache/twistedcaldav/extensions.py	2008-05-23 22:44:39 UTC (rev 2462)
@@ -34,6 +34,7 @@
 import time
 
 from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
+from twisted.internet.defer import maybeDeferred
 from twisted.web2 import responsecode
 from twisted.web2.http import HTTPError, Response, RedirectResponse
 from twisted.web2.http_headers import MimeType
@@ -185,10 +186,42 @@
     authorizationPrincipal = deferredGenerator(authorizationPrincipal)
 
 
+def updateCacheTokenOnCallback(f):
+    def fun(self, *args, **kwargs):
+        def _updateToken(response):
+            return self.cacheNotifier.changed().addCallback(
+                lambda _: response)
+
+        d = maybeDeferred(f, self, *args, **kwargs)
+
+        if hasattr(self, 'cacheNotifier'):
+            d.addCallback(_updateToken)
+
+        return d
+
+    return fun
+
+
 class DAVResource (SudoSACLMixin, SuperDAVResource, LoggingMixIn):
     """
     Extended L{twisted.web2.dav.resource.DAVResource} implementation.
     """
+
+    @updateCacheTokenOnCallback
+    def http_PROPPATCH(self, request):
+        return super(DAVResource, self).http_PROPPATCH(request)
+
+
+    @updateCacheTokenOnCallback
+    def http_DELETE(self, request):
+        return super(DAVResource, self).http_DELETE(request)
+
+
+    @updateCacheTokenOnCallback
+    def http_ACL(self, request):
+        return super(DAVResource, self).http_ACL(request)
+
+
     def findChildrenFaster(self, depth, request, okcallback, badcallback, names, privileges, inherited_aces):
         """
         See L{IDAVResource.findChildren}.

Modified: CalendarServer/branches/unified-cache/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/unified-cache/twistedcaldav/method/put_common.py	2008-05-23 21:02:17 UTC (rev 2461)
+++ CalendarServer/branches/unified-cache/twistedcaldav/method/put_common.py	2008-05-23 22:44:39 UTC (rev 2462)
@@ -22,8 +22,9 @@
 
 from twisted.internet import reactor
 from twisted.internet.defer import Deferred
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import deferredGenerator
 from twisted.internet.defer import maybeDeferred
+from twisted.internet.defer import waitForDeferred
 from twisted.python import failure
 from twisted.python.filepath import FilePath
 from twisted.web2 import responsecode
@@ -44,7 +45,7 @@
 from twistedcaldav.caldavxml import NoUIDConflict
 from twistedcaldav.caldavxml import NumberOfRecurrencesWithinLimits
 from twistedcaldav.caldavxml import caldav_namespace
-from twistedcaldav.customxml import calendarserver_namespace
+from twistedcaldav.customxml import calendarserver_namespace 
 from twistedcaldav.customxml import TwistedCalendarAccessProperty
 from twistedcaldav.fileops import copyToWithXAttrs
 from twistedcaldav.fileops import putWithXAttrs
@@ -56,9 +57,7 @@
 
 log = Logger()
 
-import sys
-
- at inlineCallbacks
+ at deferredGenerator
 def storeCalendarObjectResource(
     request,
     sourcecal, destinationcal,
@@ -70,7 +69,7 @@
 ):
     """
     Function that does common PUT/COPY/MOVE behaviour.
-
+    
     @param request:           the L{twisted.web2.server.Request} for the current HTTP request.
     @param source:            the L{CalDAVFile} for the source resource to copy from, or None if source data
         is to be read from the request.
@@ -86,7 +85,7 @@
     @param isiTIP:            True if relaxed calendar data validation is to be done, False otherwise.
     @return:                  a Deferred with a status response result.
     """
-
+    
     try:
         assert destination is not None and destinationparent is not None and destination_uri is not None
         assert (source is None and sourceparent is None) or (source is not None and sourceparent is not None)
@@ -114,7 +113,7 @@
         transaction, leaving the server state the same as it was before the request was
         processed. The DoRollback method will actually execute the rollback operations.
         """
-
+        
         def __init__(self):
             self.active = True
             self.source_copy = None
@@ -123,7 +122,7 @@
             self.source_deleted = False
             self.source_index_deleted = False
             self.destination_index_deleted = False
-
+        
         def Rollback(self):
             """
             Rollback the server state. Do not allow this to raise another exception. If
@@ -183,7 +182,7 @@
                 self.source_deleted = False
                 self.source_index_deleted = False
                 self.destination_index_deleted = False
-
+    
     rollback = RollbackState()
 
     def validResourceName():
@@ -198,7 +197,7 @@
             message = "File name %s not allowed in calendar collection" % (filename,)
 
         return result, message
-
+        
     def validContentType():
         """
         Make sure that the content-type of the source resource is text/calendar.
@@ -212,7 +211,7 @@
             message = "MIME type %s not allowed in calendar collection" % (content_type,)
 
         return result, message
-
+        
     def validCalendarDataCheck():
         """
         Check that the calendar data is valid iCalendar.
@@ -230,9 +229,9 @@
             except ValueError, e:
                 result = False
                 message = "Invalid calendar data: %s" % (e,)
-
+        
         return result, message
-
+    
     def validCalDAVDataCheck():
         """
         Check that the calendar data is valid as a CalDAV calendar object resource.
@@ -249,9 +248,9 @@
         except ValueError, e:
             result = False
             message = "Calendar data does not conform to CalDAV requirements: %s" % (e,)
-
+        
         return result, message
-
+    
     def validSizeCheck():
         """
         Make sure that the content-type of the source resource is text/calendar.
@@ -267,21 +266,24 @@
 
         return result, message
 
-    @inlineCallbacks
+    @deferredGenerator
     def validAccess():
         """
         Make sure that the X-CALENDARSERVER-ACCESS property is properly dealt with.
         """
-
+        
         if calendar.hasProperty(Component.ACCESS_PROPERTY):
-
+            
             # Must be a value we know about
             access = calendar.accessLevel(default=None)
             if access is None:
                 raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (calendarserver_namespace, "valid-access-restriction")))
-
+                
             # Only DAV:owner is able to set the property to other than PUBLIC
-            parent_owner = yield destinationparent.owner(request)
+            d = waitForDeferred(destinationparent.owner(request))
+            yield d
+            parent_owner = d.getResult()
+            
             authz = destinationparent.currentPrincipal(request)
             if davxml.Principal(parent_owner) != authz and access != Component.ACCESS_PUBLIC:
                 raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (calendarserver_namespace, "valid-access-restriction-change")))
@@ -325,7 +327,7 @@
             # the other PUT tries to reserve and fails but no index entry exists yet.
             if rname is None:
                 rname = "<<Unknown Resource>>"
-
+            
             result = False
             message = "Calendar resource %s already exists with same UID %s" % (rname, uid)
         else:
@@ -336,7 +338,7 @@
                     rname = destination.fp.basename()
                     result = False
                     message = "Cannot overwrite calendar resource %s with different UID %s" % (rname, olduid)
-
+        
         return result, message, rname
 
     try:
@@ -359,7 +361,7 @@
                     if not result:
                         log.err(message)
                         raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "supported-calendar-data")))
-
+                
                     # At this point we need the calendar data to do more tests
                     calendar = source.iCalendar()
                 else:
@@ -368,13 +370,13 @@
                     except ValueError, e:
                         log.err(str(e))
                         raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-
+                        
                 # Valid calendar data check
                 result, message = validCalendarDataCheck()
                 if not result:
                     log.err(message)
                     raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data")))
-
+                    
                 # Valid calendar data for CalDAV check
                 result, message = validCalDAVDataCheck()
                 if not result:
@@ -403,11 +405,13 @@
 
             # Check access
             if destinationcal and config.EnablePrivateEvents:
-                access, calendardata = yield validAccess()
+                d = waitForDeferred(validAccess())
+                yield d
+                access, calendardata = d.getResult()
 
             # Reserve UID
             destination_index = destinationparent.index()
-
+            
             # Lets use a deferred for this and loop a few times if we cannot reserve so that we give
             # time to whoever has the reservation to finish and release it.
             failure_count = 0
@@ -419,16 +423,18 @@
                 except ReservationError:
                     reserved = False
                 failure_count += 1
-
+                
                 d = Deferred()
                 def _timedDeferred():
                     d.callback(True)
                 reactor.callLater(0.1, _timedDeferred)
-                pause = yield d
-
+                pause = waitForDeferred(d)
+                yield pause
+                pause.getResult()
+            
             if destination_uri and not reserved:
                 raise HTTPError(StatusResponse(responsecode.CONFLICT, "Resource: %s currently in use." % (destination_uri,)))
-
+        
             # uid conflict check - note we do this after reserving the UID to avoid a race condition where two requests
             # try to write the same calendar data to two different resource URIs.
             if not isiTIP:
@@ -438,7 +444,7 @@
                     raise HTTPError(ErrorResponse(responsecode.FORBIDDEN,
                         NoUIDConflict(davxml.HRef.fromString(joinURL(parentForURL(destination_uri), rname.encode("utf-8"))))
                     ))
-
+            
         """
         Handle rollback setup here.
         """
@@ -447,18 +453,26 @@
         if request is None:
             destquota = None
         else:
-            destquota = yield destination.quota(request)
+            destquota = waitForDeferred(destination.quota(request))
+            yield destquota
+            destquota = destquota.getResult()
             if destquota is not None and destination.exists():
-                old_dest_size = yield destination.quotaSize(request)
+                old_dest_size = waitForDeferred(destination.quotaSize(request))
+                yield old_dest_size
+                old_dest_size = old_dest_size.getResult()
             else:
                 old_dest_size = 0
-
+            
         if request is None:
             sourcequota = None
         elif source is not None:
-            sourcequota = yield source.quota(request)
+            sourcequota = waitForDeferred(source.quota(request))
+            yield sourcequota
+            sourcequota = sourcequota.getResult()
             if sourcequota is not None and source.exists():
-                old_source_size = yield source.quotaSize(request)
+                old_source_size = waitForDeferred(source.quotaSize(request))
+                yield old_source_size
+                old_source_size = old_source_size.getResult()
             else:
                 old_source_size = 0
         else:
@@ -482,16 +496,16 @@
             rollback.source_copy.path += ".rollback"
             copyToWithXAttrs(source.fp, rollback.source_copy)
             log.debug("Rollback: backing up source %s to %s" % (source.fp.path, rollback.source_copy.path))
-
+    
         """
         Handle actual store operations here.
-
+        
         The order in which this is done is import:
-
+            
             1. Do store operation for new data
             2. Delete source and source index if needed
             3. Do new indexing if needed
-
+            
         Note that we need to remove the source index BEFORE doing the destination index to cover the
         case of a resource being 'renamed', i.e. moved within the same collection. Since the index UID
         column must be unique in SQL, we cannot add the new index before remove the old one.
@@ -499,13 +513,13 @@
 
         # Do put or copy based on whether source exists
         if source is not None:
-            response = yield maybeDeferred(copyWithXAttrs,
-                                           source.fp,
-                                           destination.fp,
-                                           destination_uri)
+            response = maybeDeferred(copyWithXAttrs, source.fp, destination.fp, destination_uri)
         else:
             md5 = MD5StreamWrapper(MemoryStream(calendardata))
-            response = yield maybeDeferred(putWithXAttrs, md5, destination.fp)
+            response = maybeDeferred(putWithXAttrs, md5, destination.fp)
+        response = waitForDeferred(response)
+        yield response
+        response = response.getResult()
 
         # Update the MD5 value on the resource
         if source is not None:
@@ -522,26 +536,26 @@
         # Update calendar-access property value on the resource
         if access:
             destination.writeDeadProperty(TwistedCalendarAccessProperty(access))
-
+            
         # Do not remove the property if access was not specified and we are storing in a calendar.
         # This ensure that clients that do not preserve the iCalendar property do not cause access
         # restrictions to be lost.
         elif not destinationcal:
-            destination.removeDeadProperty(TwistedCalendarAccessProperty)
+            destination.removeDeadProperty(TwistedCalendarAccessProperty)                
 
         response = IResponse(response)
 
         def doDestinationIndex(caltoindex):
             """
             Do destination resource indexing, replacing any index previous stored.
-
+            
             @return: None if successful, ErrorResponse on failure
             """
-
+            
             # Delete index for original item
             if overwrite:
                 doRemoveDestinationIndex()
-
+            
             # Add or update the index for this resource.
             try:
                 destination_index.addResource(destination.fp.basename(), caltoindex)
@@ -563,7 +577,7 @@
             """
             Remove any existing destination index.
             """
-
+            
             # Delete index for original item
             if destinationcal:
                 destination_index.deleteResource(destination.fp.basename())
@@ -586,10 +600,10 @@
             """
             Do source resource indexing. This only gets called when restoring
             the source after its index has been deleted.
-
+            
             @return: None if successful, ErrorResponse on failure
             """
-
+            
             # Add or update the index for this resource.
             try:
                 source_index.addResource(source.fp.basename(), calendar)
@@ -607,32 +621,43 @@
             # Update quota
             if sourcequota is not None:
                 delete_size = 0 - old_source_size
-                _ignore = yield source.quotaSizeAdjust(request, delete_size)
+                d = waitForDeferred(source.quotaSizeAdjust(request, delete_size))
+                yield d
+                d.getResult()
 
             if sourcecal:
                 # Change CTag on the parent calendar collection
-                _ignore = yield sourceparent.updateCTag()
+                d = waitForDeferred(sourceparent.updateCTag())
+                yield d
+                d.getResult()
 
         if destinationcal:
             result = doDestinationIndex(calendar)
             if result is not None:
                 rollback.Rollback()
-                returnValue(result)
+                yield result
+                return
 
         # Do quota check on destination
         if destquota is not None:
             # Get size of new/old resources
-            new_dest_size = yield destination.quotaSize(request)
+            new_dest_size = waitForDeferred(destination.quotaSize(request))
+            yield new_dest_size
+            new_dest_size = new_dest_size.getResult()
             diff_size = new_dest_size - old_dest_size
             if diff_size >= destquota[0]:
                 log.err("Over quota: available %d, need %d" % (destquota[0], diff_size))
                 raise HTTPError(ErrorResponse(responsecode.INSUFFICIENT_STORAGE_SPACE, (dav_namespace, "quota-not-exceeded")))
-            yield destination.quotaSizeAdjust(request, diff_size)
+            d = waitForDeferred(destination.quotaSizeAdjust(request, diff_size))
+            yield d
+            d.getResult()
 
 
         if destinationcal:
             # Change CTag on the parent calendar collection
-            yield destinationparent.updateCTag()
+            d = waitForDeferred(destinationparent.updateCTag())
+            yield d
+            d.getResult()
 
         # Can now commit changes and forget the rollback details
         rollback.Commit()
@@ -641,7 +666,8 @@
             destination_index.unreserveUID(uid)
             reserved = False
 
-        returnValue(response)
+        yield response
+        return
 
     except:
         if reserved:
@@ -652,4 +678,3 @@
         # if the rollback has already ocurred or changes already committed.
         rollback.Rollback()
         raise
-

Modified: CalendarServer/branches/unified-cache/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/unified-cache/twistedcaldav/resource.py	2008-05-23 21:02:17 UTC (rev 2461)
+++ CalendarServer/branches/unified-cache/twistedcaldav/resource.py	2008-05-23 22:44:39 UTC (rev 2462)
@@ -75,6 +75,22 @@
         return tuple(super(CalDAVComplianceMixIn, self).davComplianceClasses()) + extra_compliance
 
 
+def updateCacheTokenOnCallback(f):
+    def fun(self, *args, **kwargs):
+        def _updateToken(response):
+            return self.cacheNotifier.changed().addCallback(
+                lambda _: response)
+
+        d = maybeDeferred(f, self, *args, **kwargs)
+
+        if hasattr(self, 'cacheNotifier'):
+            d.addCallback(_updateToken)
+
+        return d
+
+    return fun
+
+
 class CalDAVResource (CalDAVComplianceMixIn, DAVResource):
     """
     CalDAV resource.
@@ -129,6 +145,19 @@
 
         return response
 
+    @updateCacheTokenOnCallback
+    def http_PROPPATCH(self, request):
+        return super(CalDAVResource, self).http_PROPPATCH(request)
+
+    @updateCacheTokenOnCallback
+    def http_DELETE(self, request):
+        return super(CalDAVResource, self).http_DELETE(request)
+
+    @updateCacheTokenOnCallback
+    def http_ACL(self, request):
+        return super(CalDAVResource, self).http_ACL(request)
+
+
     ##
     # WebDAV
     ##

Modified: CalendarServer/branches/unified-cache/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/branches/unified-cache/twistedcaldav/test/util.py	2008-05-23 21:02:17 UTC (rev 2461)
+++ CalendarServer/branches/unified-cache/twistedcaldav/test/util.py	2008-05-23 22:44:39 UTC (rev 2462)
@@ -28,7 +28,11 @@
 
 class InMemoryPropertyStore(object):
     def __init__(self):
+        class __FauxResource(object):
+            fp = ':memory:'
+
         self._properties = {}
+        self.resource = __FauxResource()
 
     def get(self, qname):
         data = self._properties.get(qname)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080523/aba92097/attachment-0001.htm 


More information about the calendarserver-changes mailing list