[CalendarServer-changes] [3313] CalendarServer/branches/users/cdaboo/implicit-if-match-3306/ twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Mon Nov 3 19:10:04 PST 2008


Revision: 3313
          http://trac.macosforge.org/projects/calendarserver/changeset/3313
Author:   cdaboo at apple.com
Date:     2008-11-03 19:10:03 -0800 (Mon, 03 Nov 2008)
Log Message:
-----------
Schedule-Tag/If-Schedule-Tag-Match header behavior. Attendee logic for when tag changes is not quite
right.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/__init__.py
    CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/caldavxml.py
    CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/method/get.py
    CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/method/put_common.py

Modified: CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/__init__.py	2008-11-04 00:33:58 UTC (rev 3312)
+++ CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/__init__.py	2008-11-04 03:10:03 UTC (rev 3313)
@@ -65,8 +65,17 @@
 File.contentTypes = loadMimeTypes(("/etc/apache2/mime.types", "/etc/httpd/mime.types",))
 
 import twisted.web2.dav.davxml
+from twisted.web2.http_headers import DefaultHTTPHandler, last, singleHeader, tokenize
 import twistedcaldav.caldavxml
 import twistedcaldav.customxml
 
 twisted.web2.dav.davxml.registerElements(twistedcaldav.caldavxml)
 twisted.web2.dav.davxml.registerElements(twistedcaldav.customxml)
+
+DefaultHTTPHandler.updateParsers({
+    'If-Schedule-Tag-Match':(last, str),
+})
+DefaultHTTPHandler.updateGenerators({
+    'Schedule-Tag':(str, singleHeader),
+})
+

Modified: CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/caldavxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/caldavxml.py	2008-11-04 00:33:58 UTC (rev 3312)
+++ CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/caldavxml.py	2008-11-04 03:10:03 UTC (rev 3313)
@@ -1664,6 +1664,15 @@
 
     allowed_children = { (davxml.dav_namespace, "href"): (0, None) } # NB Minimum is zero because this is a property name
 
+class ScheduleTag (CalDAVTextElement):
+    """
+    Property on scheduling resources.
+    (CalDAV-schedule, section x.x.x)
+    """
+    name = "schedule-tag"
+    hidden = True
+    protected = True
+
 class ScheduleInbox (CalDAVEmptyElement):
     """
     Denotes the resource type of a calendar schedule Inbox.

Modified: CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/method/get.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/method/get.py	2008-11-04 00:33:58 UTC (rev 3312)
+++ CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/method/get.py	2008-11-04 03:10:03 UTC (rev 3313)
@@ -28,6 +28,7 @@
 from twisted.web2.stream import MemoryStream
 
 from twistedcaldav import caldavxml
+from twistedcaldav.caldavxml import ScheduleTag
 from twistedcaldav.customxml import TwistedCalendarAccessProperty
 from twistedcaldav.ical import Component
 
@@ -59,6 +60,14 @@
                 response.headers.setHeader("content-type", MimeType.fromString("text/calendar; charset=utf-8"))
                 returnValue(response)
 
+
     # Do normal GET behavior
     response = (yield super(CalDAVFile, self).http_GET(request))
+    
+    # Add Schedule-Tag header if property is present
+    if self.exists() and self.hasDeadProperty(ScheduleTag):
+        scheduletag = self.readDeadProperty(ScheduleTag)
+        if scheduletag:
+            response.headers.setHeader("Schedule-Tag", str(scheduletag))
+
     returnValue(response)

Modified: CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/method/put_common.py	2008-11-04 00:33:58 UTC (rev 3312)
+++ CalendarServer/branches/users/cdaboo/implicit-if-match-3306/twistedcaldav/method/put_common.py	2008-11-04 03:10:03 UTC (rev 3313)
@@ -22,6 +22,7 @@
 
 import os
 import types
+import uuid
 
 from twisted.internet import reactor
 from twisted.internet.defer import Deferred, inlineCallbacks, succeed
@@ -44,7 +45,7 @@
 from twisted.web2.stream import MemoryStream
 
 from twistedcaldav.config import config
-from twistedcaldav.caldavxml import NoUIDConflict
+from twistedcaldav.caldavxml import NoUIDConflict, ScheduleTag
 from twistedcaldav.caldavxml import NumberOfRecurrencesWithinLimits
 from twistedcaldav.caldavxml import caldav_namespace
 from twistedcaldav.customxml import calendarserver_namespace ,\
@@ -273,6 +274,7 @@
 
         # Basic validation
         yield self.validCopyMoveOperation()
+        self.validIfScheduleMatch()
 
         if self.destinationcal:
             # Valid resource name check
@@ -366,6 +368,24 @@
                     log.debug(msg)
                     raise HTTPError(StatusResponse(responsecode.FORBIDDEN, msg))
 
+    def validIfScheduleMatch(self):
+        """
+        Check for If-ScheduleTag-Match header behavior.
+        """
+        
+        # Only when a direct request
+        if not self.isiTIP and not self.internal_request:
+            header = self.request.headers.getHeader("If-Schedule-Tag-Match")
+            if header:
+                # Do "precondition" test
+                matched = False
+                if self.destination.exists() and self.destination.hasDeadProperty(ScheduleTag):
+                    scheduletag = self.destination.readDeadProperty(ScheduleTag)
+                    matched = (scheduletag == header)
+                if not matched:
+                    log.debug("If-Schedule-Tag-Match: header value '%s' does not match resource value '%s'" % (header, scheduletag,))
+                    raise HTTPError(responsecode.PRECONDITION_FAILED)
+
     def validResourceName(self):
         """
         Make sure that the resource name for the new resource is valid.
@@ -606,6 +626,15 @@
 
     @inlineCallbacks
     def doImplicitScheduling(self):
+
+        # Get any existing scheduletag property on the resource
+        if self.destination.exists() and self.destination.hasDeadProperty(ScheduleTag):
+            self.scheduletag = self.destination.readDeadProperty(ScheduleTag)
+            if self.scheduletag:
+                self.scheduletag = str(self.scheduletag)
+        else:
+            self.scheduletag = None
+
         data_changed = False
 
         # Do scheduling
@@ -862,8 +891,29 @@
             # Check for scheduling object resource and write property
             if is_scheduling_resource:
                 self.destination.writeDeadProperty(TwistedSchedulingObjectResource())
-            elif not self.destinationcal:
+
+                # Need to figure out when to change the schedule tag:
+                #
+                # 1. If this is not an internal request then the resource is being explicitly changed
+                # 2. If it is an internal request for the Organizer, schedule tag never changes
+                # 3. If it is an internal request for an Attendee and the message being processed came
+                #    from the Organizer then the schedule tag changes.
+
+                change_scheduletag = True
+                if self.internal_request:
+                    # TODO: Organizer vs Attendee logic
+                    change_scheduletag = False
+
+                if change_scheduletag or self.scheduletag is None:
+                    self.scheduletag = str(uuid.uuid4())
+                self.destination.writeDeadProperty(ScheduleTag.fromString(self.scheduletag))
+
+                # Add a response header
+                response.headers.setHeader("Schedule-Tag", self.scheduletag)                
+
+            else:
                 self.destination.removeDeadProperty(TwistedSchedulingObjectResource)                
+                self.destination.removeDeadProperty(ScheduleTag)                
 
             # Check for existence of private comments and write property
             if config.Scheduling["CalDAV"].get("EnablePrivateComments", True):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20081103/ff5715e8/attachment.html>


More information about the calendarserver-changes mailing list