[CalendarServer-changes] [3760] CalendarServer/trunk/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Thu Feb 26 19:27:50 PST 2009


Revision: 3760
          http://trac.macosforge.org/projects/calendarserver/changeset/3760
Author:   cdaboo at apple.com
Date:     2009-02-26 19:27:49 -0800 (Thu, 26 Feb 2009)
Log Message:
-----------
Default calendar is now required.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/method/copymove.py
    CalendarServer/trunk/twistedcaldav/method/delete_common.py
    CalendarServer/trunk/twistedcaldav/resource.py
    CalendarServer/trunk/twistedcaldav/schedule.py
    CalendarServer/trunk/twistedcaldav/scheduling/processing.py

Modified: CalendarServer/trunk/twistedcaldav/method/copymove.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/copymove.py	2009-02-27 03:11:59 UTC (rev 3759)
+++ CalendarServer/trunk/twistedcaldav/method/copymove.py	2009-02-27 03:27:49 UTC (rev 3760)
@@ -119,13 +119,14 @@
     result, sourcecal, sourceparent, destination_uri, destination, destinationcal, destinationparent = (yield checkForCalendarAction(self, request))
     if not result:
         is_calendar_collection = isPseudoCalendarCollectionResource(self)
+        defaultCalendar = (yield self.isDefaultCalendar(request)) if is_calendar_collection else False
 
         # Do default WebDAV action
         result = (yield super(CalDAVFile, self).http_MOVE(request))
         
         if is_calendar_collection:
             # Do some clean up
-            yield self.movedCalendar(request, destination, destination_uri)
+            yield self.movedCalendar(request, defaultCalendar, destination, destination_uri)
 
         returnValue(result)
         

Modified: CalendarServer/trunk/twistedcaldav/method/delete_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/delete_common.py	2009-02-27 03:11:59 UTC (rev 3759)
+++ CalendarServer/trunk/twistedcaldav/method/delete_common.py	2009-02-27 03:27:49 UTC (rev 3760)
@@ -13,7 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 ##
-from twistedcaldav.method.report_common import applyToCalendarCollections
 
 
 """
@@ -25,12 +24,15 @@
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.web2 import responsecode
 from twisted.web2.dav.fileop import delete
-from twisted.web2.dav.http import ResponseQueue, MultiStatusResponse
+from twisted.web2.dav.http import ResponseQueue, MultiStatusResponse,\
+    ErrorResponse
 from twisted.web2.dav.util import joinURL
 from twisted.web2.http import HTTPError, StatusResponse
 
+from twistedcaldav.caldavxml import caldav_namespace
 from twistedcaldav.log import Logger
 from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
+from twistedcaldav.method.report_common import applyToCalendarCollections
 from twistedcaldav.resource import isCalendarCollectionResource,\
     isPseudoCalendarCollectionResource
 from twistedcaldav.scheduling.implicit import ImplicitScheduler
@@ -160,6 +162,12 @@
         reported back in a multistatus response.
         """
 
+        # Not allowed to delete the default calendar
+        default = (yield delresource.isDefaultCalendar(self.request))
+        if default:
+            log.err("Cannot DELETE default calendar: %s" % (delresource,))
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "default-calendar-delete-allowed",)))
+
         if self.depth != "infinity":
             msg = "Client sent illegal depth header value for DELETE: %s" % (self.depth,)
             log.err(msg)

Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py	2009-02-27 03:11:59 UTC (rev 3759)
+++ CalendarServer/trunk/twistedcaldav/resource.py	2009-02-27 03:27:49 UTC (rev 3760)
@@ -549,21 +549,11 @@
         if inboxURL:
             inbox = (yield request.locateResource(inboxURL))
             inbox.processFreeBusyCalendar(request.path, False)
-            
-            # Also check the default calendar setting and remove it if the default is deleted
-            default = (yield inbox.readProperty((caldav_namespace, "schedule-default-calendar-URL"), request))
-            if default and len(default.children) == 1:
-                defaultURL = normalizeURL(str(default.children[0]))
-                if normalizeURL(request.path) == defaultURL:
-                    yield inbox.writeProperty(caldavxml.ScheduleDefaultCalendarURL(), request)               
 
     @inlineCallbacks
-    def movedCalendar(self, request, destination, destination_uri):
+    def movedCalendar(self, request, defaultCalendar, destination, destination_uri):
         """
         Calendar has been moved. Need to do some extra clean-up.
-
-        @param request:
-        @type request:
         """
         
         # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
@@ -576,12 +566,9 @@
             inbox.processFreeBusyCalendar(request.path, False)
             inbox.processFreeBusyCalendar(destination_uri, destination.isCalendarOpaque())
             
-            # Also check the default calendar setting and remove it if the default is deleted
-            default = (yield inbox.readProperty((caldav_namespace, "schedule-default-calendar-URL"), request))
-            if default and len(default.children) == 1:
-                defaultURL = normalizeURL(str(default.children[0]))
-                if normalizeURL(request.path) == defaultURL:
-                    yield inbox.writeProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(destination_path)), request)               
+            # Adjust the default calendar setting if necessary
+            if defaultCalendar:
+                yield inbox.writeProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(destination_path)), request)               
 
     def isCalendarOpaque(self):
         
@@ -593,6 +580,24 @@
         else:
             return False
 
+    @inlineCallbacks
+    def isDefaultCalendar(self, request):
+        
+        assert self.isCalendarCollection()
+        
+        # Not allowed to delete the default calendar
+        principal = (yield self.ownerPrincipal(request))
+        inboxURL = principal.scheduleInboxURL()
+        if inboxURL:
+            inbox = (yield request.locateResource(inboxURL))
+            default = (yield inbox.readProperty((caldav_namespace, "schedule-default-calendar-URL"), request))
+            if default and len(default.children) == 1:
+                defaultURL = normalizeURL(str(default.children[0]))
+                myURL = (yield self.canonicalURL(request))
+                returnValue(defaultURL == myURL)
+
+        returnValue(False)
+
     def iCalendar(self, name=None):
         """
         See L{ICalDAVResource.iCalendar}.

Modified: CalendarServer/trunk/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/schedule.py	2009-02-27 03:11:59 UTC (rev 3759)
+++ CalendarServer/trunk/twistedcaldav/schedule.py	2009-02-27 03:27:49 UTC (rev 3760)
@@ -24,7 +24,7 @@
     "IScheduleInboxResource",
 ]
 
-from twisted.internet.defer import succeed, inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.web2 import responsecode
 from twisted.web2.dav import davxml
 from twisted.web2.dav.http import ErrorResponse
@@ -105,6 +105,7 @@
             ),
         )
 
+    @inlineCallbacks
     def readProperty(self, property, request):
         if type(property) is tuple:
             qname = property
@@ -114,13 +115,22 @@
         if qname == (caldav_namespace, "calendar-free-busy-set"):
             # Always return at least an empty list
             if not self.hasDeadProperty(property):
-                return succeed(caldavxml.CalendarFreeBusySet())
+                returnValue(caldavxml.CalendarFreeBusySet())
         elif qname == (caldav_namespace, "schedule-default-calendar-URL"):
-            # Always return at least an empty item
-            if not self.hasDeadProperty(property):
-                return succeed(caldavxml.ScheduleDefaultCalendarURL())
+            # Must have a valid default
+            defaultCalendarProperty = self.readDeadProperty(property)
+            if defaultCalendarProperty and len(defaultCalendarProperty.children) == 1:
+                defaultCalendar = str(defaultCalendarProperty.children[0])
+                cal = (yield request.locateResource(str(defaultCalendar)))
+                if cal is not None and cal.exists() and isCalendarCollectionResource(cal):
+                    returnValue(defaultCalendarProperty) 
             
-        return super(ScheduleInboxResource, self).readProperty(property, request)
+            # Default is not valid - we have to try to pick one
+            defaultCalendarProperty = (yield self.pickNewDefaultCalendar(request))
+            returnValue(defaultCalendarProperty)
+            
+        result = (yield super(ScheduleInboxResource, self).readProperty(property, request))
+        returnValue(result)
 
     @inlineCallbacks
     def writeProperty(self, property, request):
@@ -160,14 +170,21 @@
             # Verify that the calendar added in the PROPPATCH is valid.
             property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children]
             new_calendar = [str(href) for href in property.children]
+            cal = None
             if len(new_calendar) == 1:
+                calURI = str(new_calendar[0])
                 cal = (yield request.locateResource(str(new_calendar[0])))
-                if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
-                    # Validate that href's point to a valid calendar.
-                    raise HTTPError(ErrorResponse(
-                        responsecode.CONFLICT,
-                        (caldav_namespace, "valid-calendar-url")
-                    ))
+            # TODO: check that owner of the new calendar is the same as owner of this inbox
+            if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
+                # Validate that href's point to a valid calendar.
+                raise HTTPError(ErrorResponse(
+                    responsecode.CONFLICT,
+                    (caldav_namespace, "valid-schedule-default-calendar-URL")
+                ))
+            else:
+                # Canonicalize the URL to __uids__ form
+                calURI = (yield cal.canonicalURL(request))
+                property = caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(calURI))
 
         yield super(ScheduleInboxResource, self).writeProperty(property, request)
 
@@ -187,6 +204,22 @@
                 fbset.remove(uri)
                 self.writeDeadProperty(caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in fbset]))
 
+    @inlineCallbacks
+    def pickNewDefaultCalendar(self, request):
+        """
+        First see if "calendar" exists in the calendar home and pick that. Otherwise
+        create "calendar" in the calendar home.
+        """
+        
+        calendarHomeURL = self.parent.url()
+        defaultCalendarURL = (yield joinURL(calendarHomeURL, "calendar"))
+        defaultCalendar = (yield request.locateResource(defaultCalendarURL))
+        if defaultCalendar is None or not defaultCalendar.exists():
+            self.parent.provisionDefaultCalendars()
+        else:
+            self.writeDeadProperty(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(defaultCalendarURL)))
+        returnValue(caldavxml.ScheduleDefaultCalendarURL(davxml.HRef(defaultCalendarURL)))
+
 class ScheduleOutboxResource (CalendarSchedulingCollectionResource):
     """
     CalDAV schedule Outbox resource.

Modified: CalendarServer/trunk/twistedcaldav/scheduling/processing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/processing.py	2009-02-27 03:11:59 UTC (rev 3759)
+++ CalendarServer/trunk/twistedcaldav/scheduling/processing.py	2009-02-27 03:27:49 UTC (rev 3760)
@@ -260,37 +260,33 @@
             else:
                 default = None
             
-            # Must have a calendar if auto-replying
-            if default is None and self.recipient.principal.autoSchedule():
-                log.error("No default calendar for auto-replying recipient: '%s'." % (self.recipient.cuaddr,))
+            # Must have a default calendar
+            if default is None:
+                log.error("No default calendar for recipient: '%s'." % (self.recipient.cuaddr,))
                 raise ImplicitProcessorException(iTIPRequestStatus.NO_USER_SUPPORT)
 
-            if default:
-                log.debug("ImplicitProcessing - originator '%s' to recipient '%s' ignoring METHOD:REQUEST, UID: '%s' - new processed" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
-                autoprocessed = self.recipient.principal.autoSchedule()
-                new_calendar = iTipProcessing.processNewRequest(self.message, self.recipient.cuaddr, autoprocessing=autoprocessed)
-                name =  md5(str(new_calendar) + str(time.time()) + default.fp.path).hexdigest() + ".ics"
-                
-                # Handle auto-reply behavior
-                if autoprocessed:
-                    send_reply, partstat = (yield self.checkAttendeeAutoReply(new_calendar))
+            log.debug("ImplicitProcessing - originator '%s' to recipient '%s' ignoring METHOD:REQUEST, UID: '%s' - new processed" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
+            autoprocessed = self.recipient.principal.autoSchedule()
+            new_calendar = iTipProcessing.processNewRequest(self.message, self.recipient.cuaddr, autoprocessing=autoprocessed)
+            name =  md5(str(new_calendar) + str(time.time()) + default.fp.path).hexdigest() + ".ics"
+            
+            # Handle auto-reply behavior
+            if autoprocessed:
+                send_reply, partstat = (yield self.checkAttendeeAutoReply(new_calendar))
 
-                new_resource = (yield self.writeCalendarResource(defaultURL, default, name, new_calendar))
-                
-                if autoprocessed and send_reply:
-                    reactor.callLater(2.0, self.sendAttendeeAutoReply, *(new_calendar, new_resource, partstat))
+            new_resource = (yield self.writeCalendarResource(defaultURL, default, name, new_calendar))
+            
+            if autoprocessed and send_reply:
+                reactor.callLater(2.0, self.sendAttendeeAutoReply, *(new_calendar, new_resource, partstat))
 
-                # Build the schedule-changes XML element
-                changes = customxml.ScheduleChanges(
-                    customxml.DTStamp(),
-                    customxml.Action(
-                        customxml.Create(),
-                    ),
-                )
-                result = (True, autoprocessed, changes,)
-            else:
-                log.debug("ImplicitProcessing - originator '%s' to recipient '%s' ignoring METHOD:REQUEST, UID: '%s' - new not processed" % (self.originator.cuaddr, self.recipient.cuaddr, self.uid))
-                result = (False, False, None,)
+            # Build the schedule-changes XML element
+            changes = customxml.ScheduleChanges(
+                customxml.DTStamp(),
+                customxml.Action(
+                    customxml.Create(),
+                ),
+            )
+            result = (True, autoprocessed, changes,)
         else:
             # Processing update to existing event
             autoprocessed = self.recipient.principal.autoSchedule()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090226/a95c91b9/attachment-0001.html>


More information about the calendarserver-changes mailing list