[CalendarServer-changes] [827] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Dec 14 14:16:47 PST 2006


Revision: 827
          http://trac.macosforge.org/projects/calendarserver/changeset/827
Author:   wsanchez at apple.com
Date:     2006-12-14 14:16:47 -0800 (Thu, 14 Dec 2006)

Log Message:
-----------
merge branches/users/wsanchez/dropbox

Modified Paths:
--------------
    CalendarServer/trunk/testcaldav
    CalendarServer/trunk/twistedcaldav/caldavxml.py
    CalendarServer/trunk/twistedcaldav/customxml.py
    CalendarServer/trunk/twistedcaldav/directory/calendar.py
    CalendarServer/trunk/twistedcaldav/directory/principal.py
    CalendarServer/trunk/twistedcaldav/dropbox.py
    CalendarServer/trunk/twistedcaldav/method/__init__.py
    CalendarServer/trunk/twistedcaldav/method/delete.py
    CalendarServer/trunk/twistedcaldav/method/mkcol.py
    CalendarServer/trunk/twistedcaldav/method/put.py
    CalendarServer/trunk/twistedcaldav/notifications.py
    CalendarServer/trunk/twistedcaldav/resource.py
    CalendarServer/trunk/twistedcaldav/schedule.py
    CalendarServer/trunk/twistedcaldav/static.py
    CalendarServer/trunk/twistedcaldav/tap.py
    CalendarServer/trunk/twistedcaldav/test/data/makelargecalendars.py

Removed Paths:
-------------
    CalendarServer/trunk/twistedcaldav/method/x_apple_subscribe.py
    CalendarServer/trunk/twistedcaldav/method/x_apple_unsubscribe.py

Modified: CalendarServer/trunk/testcaldav
===================================================================
--- CalendarServer/trunk/testcaldav	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/testcaldav	2006-12-14 22:16:47 UTC (rev 827)
@@ -18,9 +18,6 @@
 # DRI: Wilfredo Sanchez, wsanchez at apple.com
 ##
 
-set -e
-set -u
-
 wd="$(cd "$(dirname "$0")" && pwd)";
 cdt="${wd}/../CalDAVTester";
 
@@ -72,6 +69,6 @@
   svn checkout http://svn.macosforge.org/repository/calendarserver/CalDAVTester/trunk "${cdt}"
 fi;
 
-tar -C "${documentroot}/calendars/user/user01/" -x${verbose}zf "${cdt}/Resource/errors/calendar.1000.tgz"
+cd "${documentroot}" && python "makelargecalendars.py";
 
 cd "${cdt}" && python testcaldav.py -s "${serverinfo}" --all;

Modified: CalendarServer/trunk/twistedcaldav/caldavxml.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/caldavxml.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/caldavxml.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -1525,3 +1525,5 @@
 def _isCalendar(self): return bool(self.childrenOfType(Calendar))
 davxml.ResourceType.isCalendar = _isCalendar
 davxml.ResourceType.calendar = davxml.ResourceType(davxml.Collection(), Calendar())
+davxml.ResourceType.scheduleInbox = davxml.ResourceType(davxml.Collection(), ScheduleInbox())
+davxml.ResourceType.scheduleOutbox = davxml.ResourceType(davxml.Collection(), ScheduleOutbox())

Modified: CalendarServer/trunk/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/customxml.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/customxml.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -28,7 +28,7 @@
 from twisted.web2.dav.resource import twisted_dav_namespace
 from twisted.web2.dav import davxml
 
-apple_namespace = "http://apple.com/ns/calendarserver/"
+calendarserver_namespace = "http://org.calendarserver/ns/"
 
 class TwistedGUIDProperty (davxml.WebDAVTextElement):
     """
@@ -86,7 +86,7 @@
     Denotes a drop box home collection (a collection that will contain drop boxes).
     (Apple Extension to CalDAV)
     """
-    namespace = apple_namespace
+    namespace = calendarserver_namespace
     name = "dropbox-home"
 
 class DropBox (davxml.WebDAVEmptyElement):
@@ -94,7 +94,7 @@
     Denotes a drop box collection.
     (Apple Extension to CalDAV)
     """
-    namespace = apple_namespace
+    namespace = calendarserver_namespace
     name = "dropbox"
 
 class Notifications (davxml.WebDAVEmptyElement):
@@ -102,7 +102,7 @@
     Denotes a notifications collection.
     (Apple Extension to CalDAV)
     """
-    namespace = apple_namespace
+    namespace = calendarserver_namespace
     name = "notifications"
 
 class DropBoxHomeURL (davxml.WebDAVElement):
@@ -110,7 +110,7 @@
     A principal property to indicate the location of the drop box home.
     (Apple Extension to CalDAV)
     """
-    namespace = apple_namespace
+    namespace = calendarserver_namespace
     name = "dropbox-home-URL"
     hidden = True
     protected = True
@@ -122,7 +122,7 @@
     A principal property to indicate the location of the notification collection.
     (Apple Extension to CalDAV)
     """
-    namespace = apple_namespace
+    namespace = calendarserver_namespace
     name = "notifications-URL"
     hidden = True
     protected = True
@@ -133,12 +133,12 @@
     """
     Root element for XML data in a notification resource.
     """
-    namespace = apple_namespace
+    namespace = calendarserver_namespace
     name = "notification"
 
     allowed_children = {
-        (apple_namespace, "time-stamp" ): (1, 1),
-        (apple_namespace, "changed"    ): (1, 1),
+        (calendarserver_namespace, "time-stamp" ): (1, 1),
+        (calendarserver_namespace, "changed"    ): (1, 1),
     }
 
 class TimeStamp (davxml.WebDAVTextElement):
@@ -146,7 +146,7 @@
     A property to indicate the timestamp of a notification resource.
     (Apple Extension to CalDAV)
     """
-    namespace = apple_namespace
+    namespace = calendarserver_namespace
     name = "time-stamp"
     hidden = True
     protected = True
@@ -157,7 +157,7 @@
     notification resource.
     (Apple Extension to CalDAV)
     """
-    namespace = apple_namespace
+    namespace = calendarserver_namespace
     name = "changed"
     hidden = True
     protected = True
@@ -169,7 +169,7 @@
     A property to indicate which principals will receive notifications.
     (Apple Extension to CalDAV)
     """
-    namespace = apple_namespace
+    namespace = calendarserver_namespace
     name = "subscribed"
     hidden = True
     protected = True

Modified: CalendarServer/trunk/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/calendar.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/directory/calendar.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -190,6 +190,9 @@
             self.putChild(name, child)
 
     def provision(self):
+        return self.provisionDefaultCalendars()
+
+    def provisionDefaultCalendars(self):
         # Create a calendar collection
 
         childName = "calendar"

Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/principal.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -40,7 +40,6 @@
 from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVFile
 from twistedcaldav.resource import CalendarPrincipalCollectionResource, CalendarPrincipalResource
 from twistedcaldav.static import provisionFile
-from twistedcaldav.dropbox import DropBox
 from twistedcaldav.directory.idirectory import IDirectoryService
 
 # FIXME: These should not be tied to DAVFile
@@ -373,10 +372,10 @@
         return self._homeChildURL("outbox/")
 
     def dropboxURL(self):
-        return self._homeChildURL(DropBox.dropboxName + "/")
+        return self._homeChildURL("dropbox/")
 
     def notificationsURL(self):
-        return self._homeChildURL(DropBox.notificationName + "/")
+        return self._homeChildURL("notifications/")
 
     def _homeChildURL(self, name):
         home = self._calendarHome()

Modified: CalendarServer/trunk/twistedcaldav/dropbox.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/dropbox.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/dropbox.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -22,80 +22,175 @@
 """
 
 __all__ = [
-    "DropBox",
+    "DropBoxHomeResource",
 ]
 
-from twistedcaldav.customxml import davxml, apple_namespace
+from twisted.internet.defer import deferredGenerator, waitForDeferred
+from twisted.python import log
+from twisted.web2 import responsecode
+from twisted.web2.dav import davxml
+from twisted.web2.dav.http import HTTPError, ErrorResponse
+from twisted.web2.dav.resource import DAVResource, TwistedACLInheritable
+from twisted.web2.dav.util import parentForURL
 
-import os
+from twistedcaldav import customxml
+from twistedcaldav.customxml import calendarserver_namespace
+from twistedcaldav.notifications import Notification
 
-class DropBox(object):
-    
-    # These are all options that will be set from a .plist configuration file.
+class DropBoxHomeResource (DAVResource):
+    """
+    Drop box collection resource.
+    """
+    def resourceType(self):
+        return davxml.ResourceType(
+            davxml.ResourceType.collection,
+            davxml.ResourceType.dropboxhome,
+        )
 
-    enabled = True                     # Whether or not drop box functionaility is enabled.
-    dropboxName = "dropbox"            # Name of the collection in which drop boxes can be created.
-    inheritedACLs = True               # Whether or not ACLs set on a drop box collection are automatically
-                                       # inherited by child resources.
-    notifications = True               # Whether to post notification messages into per-user notification collection.
-    notificationName = "notifications" # Name of the collection in which notifications will be stored.
-    
-    @classmethod
-    def enable(clzz, enabled, notifications=None):
-        """
-        This method must be used to enable drop box support as it will setup live properties etc,
-        and turn on the notification system. It must only be called once
+    def isCollection(self):
+        return True
 
-        @param enable: C{True} if drop box feature is enabled, C{False} otherwise
-        @param notifications: C{True} if automatic notifications are to be sent when a drop box changes, C{False} otherwise.
-        """
-        DropBox.enabled = enabled
-        if notifications:
-            DropBox.notifications = notifications
+class DropBoxCollectionResource (DAVResource):
+    """
+    Drop box resource.
+    """
+    def resourceType(self):
+        return davxml.ResourceType(
+            davxml.ResourceType.collection,
+            davxml.ResourceType.dropbox,
+        )
 
-        if DropBox.enabled:
+    def isCollection(self):
+        return True
 
-            # Need to setup live properties
-            from twistedcaldav.resource import CalendarPrincipalResource
-            assert (apple_namespace, "dropbox-home-URL") not in CalendarPrincipalResource.liveProperties, \
-                "DropBox.enable must only be called once"
-
-            CalendarPrincipalResource.liveProperties += (
-                (apple_namespace, "dropbox-home-URL"  ),
-                (apple_namespace, "notifications-URL" ),
-            )
-
-    @classmethod
-    def provision(clzz, cuhome):
+    def writeNewACEs(self, newaces):
         """
-        Provision user account with appropriate collections for drop box
-        and notifications.
+        Write a new ACL to the resource's property store. We override this for calendar collections
+        and force all the ACEs to be inheritable so that all calendar object resources within the
+        calendar collection have the same privileges unless explicitly overridden. The same applies
+        to drop box collections as we want all resources (attachments) to have the same privileges as
+        the drop box collection.
         
-        @param principal: the L{CalendarPrincipalResource} for the principal to provision
-        @param cuhome: L{DAVResource} - resource of user calendar home
+        @param newaces: C{list} of L{ACE} for ACL being set.
         """
+        # Add inheritable option to each ACE in the list
+        edited_aces = []
+        for ace in newaces:
+            if TwistedACLInheritable() not in ace.children:
+                children = list(ace.children)
+                children.append(TwistedACLInheritable())
+                edited_aces.append(davxml.ACE(*children))
+            else:
+                edited_aces.append(ace)
         
-        # Only if enabled
-        if not DropBox.enabled:
-            return
+        # Do inherited with possibly modified set of aces
+        super(DropBoxCollectionResource, self).writeNewACEs(edited_aces)
+
+    def http_DELETE(self, request):
+        #
+        # Handle notificiations
+        #
+        parentURL=parentForURL(request.uri)
+
+        def gotParent(parent):
+            def gotResponse(response):
+                notification = Notification(parentURL=parentURL)
+                d = notification.doNotification(request, parent)
+                d.addCallback(lambda _: response)
+                return d
+
+            d = super(DropBoxCollectionResource, self).http_DELETE(request)
+            d.addCallback(gotResponse)
+            return d
+
+        d = request.locateResource(parentURL)
+        d.addCallback(gotParent)
+        return d
         
-        # Create drop box collection in calendar-home collection resource if not already present.
-        
-        from twistedcaldav.static import CalDAVFile
-        child = CalDAVFile(os.path.join(cuhome.fp.path, DropBox.dropboxName))
-        child_exists = child.exists()
-        if not child_exists:
-            c = child.createSpecialCollection(davxml.ResourceType.dropboxhome)
-            assert c.called
-            c = c.result
-        
-        if not DropBox.notifications:
-            return
-        
-        child = CalDAVFile(os.path.join(cuhome.fp.path, DropBox.notificationName))
-        child_exists = child.exists()
-        if not child_exists:
-            c = child.createSpecialCollection(davxml.ResourceType.notifications)
-            assert c.called
-            c = c.result
-        
\ No newline at end of file
+    def http_PUT(self, request):
+        return ErrorResponse(
+            responsecode.FORBIDDEN,
+            (calendarserver_namespace, "valid-drop-box")
+        )
+
+    def http_X_APPLE_SUBSCRIBE(self, request):
+        d = waitForDeferred(self.authorize(request, (davxml.Read(),)))
+        yield d
+        d.getResult()
+        authid = request.authnUser
+    
+        # Get current list of subscribed principals
+        principals = []
+        if self.hasDeadProperty(customxml.Subscribed):
+            subs = self.readDeadProperty(customxml.Subscribed).children
+            principals.extend(subs)
+    
+        # Error if attempt to subscribe more than once
+        if authid in principals:
+            log.err("Cannot x_apple_subscribe to resource %s as principal %s is already subscribed" % (request.uri, repr(authid),))
+            raise HTTPError(ErrorResponse(
+                responsecode.FORBIDDEN,
+                (calendarserver_namespace, "principal-must-not-be-subscribed"))
+            )
+
+        principals.append(authid)
+        self.writeDeadProperty(customxml.Subscribed(*principals))
+
+        yield responsecode.OK
+
+    http_X_APPLE_SUBSCRIBE = deferredGenerator(http_X_APPLE_SUBSCRIBE)
+
+    def http_X_APPLE_UNSUBSCRIBE(self, request):
+        # We do not check any privileges. If a principal is subscribed we always allow them to
+        # unsubscribe provided they have at least authenticated.
+        d = waitForDeferred(self.authorize(request, ()))
+        yield d
+        d.getResult()
+        authid = request.authnUser
+    
+        # Get current list of subscribed principals
+        principals = []
+        if self.hasDeadProperty(customxml.Subscribed):
+            subs = self.readDeadProperty(customxml.Subscribed).children
+            principals.extend(subs)
+    
+        # Error if attempt to subscribe more than once
+        if authid not in principals:
+            log.err("Cannot x_apple_unsubscribe from resource %s as principal %s is not currently subscribed" % (request.uri, repr(authid),))
+            raise HTTPError(ErrorResponse(
+                responsecode.FORBIDDEN,
+                (calendarserver_namespace, "principal-must-be-subscribed"))
+            )
+
+        principals.remove(authid)
+        self.writeDeadProperty(customxml.Subscribed(*principals))
+
+        yield responsecode.OK
+
+    http_X_APPLE_UNSUBSCRIBE = deferredGenerator(http_X_APPLE_UNSUBSCRIBE)
+
+class DropBoxChildResource (DAVResource):
+    def http_MKCOL(self, request):
+        return responsecode.FORBIDDEN
+
+    def http_PUT(self, request):
+        #
+        # Handle notificiations
+        #
+        parentURL=parentForURL(request.uri)
+
+        def gotParent(parent):
+            def gotResponse(response):
+                if response.code in (responsecode.OK, responsecode.CREATED, responsecode.NO_CONTENT):
+                    notification = Notification(parentURL=parentForURL(request.uri))
+                    d = notification.doNotification(request, parent)
+                    d.addCallback(lambda _: response)
+                    return d
+
+            d = super(DropBoxChildResource, self).http_PUT(request)
+            d.addCallback(gotResponse)
+            return d
+
+        d = request.locateResource(parentURL)
+        d.addCallback(gotParent)
+        return d

Modified: CalendarServer/trunk/twistedcaldav/method/__init__.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/__init__.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/method/__init__.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -32,6 +32,4 @@
     "report_calquery",
     "report_freebusy",
     "report_multiget",
-    "x_apple_subscribe",
-    "x_apple_unsubscribe",
 ]

Modified: CalendarServer/trunk/twistedcaldav/method/delete.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/delete.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/method/delete.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -22,13 +22,9 @@
 
 __all__ = ["http_DELETE"]
 
-from twisted.internet.defer import deferredGenerator, waitForDeferred
 from twisted.web2 import responsecode
 from twisted.web2.dav.util import parentForURL
 
-from twistedcaldav import customxml
-from twistedcaldav.dropbox import DropBox
-from twistedcaldav.notifications import Notification
 from twistedcaldav.resource import isPseudoCalendarCollectionResource
 
 def http_DELETE(self, request):
@@ -36,31 +32,20 @@
     # Override base DELETE request handling to ensure that the calendar
     # index file has the entry for the deleted calendar component removed.
     #
-    # Also handle notifications in a drop box collection.
-    #
+    def gotParent(parent):
+        def gotResponse(response):
+            if response == responsecode.NO_CONTENT:
+                if isPseudoCalendarCollectionResource(parent):
+                    index = parent.index()
+                    index.deleteResource(self.fp.basename())
 
-    parentURL = parentForURL(request.uri)
-    parent = waitForDeferred(request.locateResource(parentURL))
-    yield parent
-    parent = parent.getResult()
+            return response
 
-    d = waitForDeferred(super(CalDAVFile, self).http_DELETE(request))
-    yield d
-    response = d.getResult()
+        d = super(CalDAVFile, self).http_DELETE(request)
+        d.addCallback(gotResponse)
+        return d
 
-    if response == responsecode.NO_CONTENT:
-
-        if isPseudoCalendarCollectionResource(parent):
-            index = parent.index()
-            index.deleteResource(self.fp.basename())
-
-        elif DropBox.enabled and parent.isSpecialCollection(customxml.DropBox):
-            # We need to handle notificiations
-            notification = Notification(parentURL=parentURL)
-            d = waitForDeferred(notification.doNotification(request, parent))
-            yield d
-            d.getResult()
-
-    yield response
-
-http_DELETE = deferredGenerator(http_DELETE)
+    parentURL = parentForURL(request.uri)
+    d = request.locateResource(parentURL)
+    d.addCallback(gotParent)
+    return d

Modified: CalendarServer/trunk/twistedcaldav/method/mkcol.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/mkcol.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/method/mkcol.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -22,49 +22,24 @@
 
 __all__ = ["http_MKCOL"]
 
-from twisted.internet.defer import deferredGenerator, waitForDeferred
 from twisted.web2 import responsecode
-from twisted.web2.dav import davxml
-from twisted.web2.dav.util import parentForURL
-from twisted.web2.http import HTTPError, StatusResponse
+from twisted.web2.http import StatusResponse
 
-from twistedcaldav import customxml
-from twistedcaldav.icaldav import ICalDAVResource
+from twistedcaldav.resource import isPseudoCalendarCollectionResource
 
 def http_MKCOL(self, request):
     #
-    # Don't allow DAV collections in a calendar collection for now
+    # Don't allow DAV collections in a calendar collection
     #
-    def isNonCollectionParentResource(resource):
-        try:
-            resource = ICalDAVResource(resource)
-        except TypeError:
-            return False
-        else:
-            return resource.isPseudoCalendarCollection() or resource.isSpecialCollection(customxml.DropBox)
+    def gotParent(parent):
+        if parent is not None:
+            return StatusResponse(
+                responsecode.FORBIDDEN,
+                "Cannot create collection within calendar collection %s" % (parent,)
+            )
 
-    parent = waitForDeferred(self._checkParents(request, isNonCollectionParentResource))
-    yield parent
-    parent = parent.getResult()
-    if parent is not None:
-        raise HTTPError(StatusResponse(
-            responsecode.FORBIDDEN,
-            "Cannot create collection within special collection %s" % (parent,))
-        )
+        return super(CalDAVFile, self).http_MKCOL(request)
 
-    d = waitForDeferred(super(CalDAVFile, self).http_MKCOL(request))
-    yield d
-    result = d.getResult()
-    
-    # Check for drop box creation and give it a special resource type
-    from twistedcaldav.dropbox import DropBox
-    if result == responsecode.CREATED and DropBox.enabled:
-        parent = waitForDeferred(request.locateResource(parentForURL(request.uri)))
-        yield parent
-        parent = parent.getResult()
-        if parent.isSpecialCollection(customxml.DropBoxHome):
-             self.writeDeadProperty(davxml.ResourceType.dropbox)
-    
-    yield result
-
-http_MKCOL = deferredGenerator(http_MKCOL)
\ No newline at end of file
+    d = self._checkParents(request, isPseudoCalendarCollectionResource)
+    d.addCallback(gotParent)
+    return d

Modified: CalendarServer/trunk/twistedcaldav/method/put.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/put.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/method/put.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -25,16 +25,12 @@
 from twisted.internet.defer import deferredGenerator, waitForDeferred
 from twisted.python import log
 from twisted.web2 import responsecode
-from twisted.web2.dav.element.base import twisted_dav_namespace
 from twisted.web2.dav.http import ErrorResponse
 from twisted.web2.dav.util import allDataFromStream, parentForURL
 from twisted.web2.http import HTTPError, StatusResponse
 
-from twistedcaldav import customxml
 from twistedcaldav.caldavxml import caldav_namespace
-from twistedcaldav.dropbox import DropBox
 from twistedcaldav.method.put_common import storeCalendarObjectResource
-from twistedcaldav.notifications import Notification
 from twistedcaldav.resource import isPseudoCalendarCollectionResource
 
 def http_PUT(self, request):
@@ -81,27 +77,6 @@
             log.err("Error while handling (calendar) PUT: %s" % (e,))
             raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, str(e)))
 
-    elif DropBox.enabled and parent.isSpecialCollection(customxml.DropBoxHome):
-        # Cannot create resources in a drop box home collection
-        raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (twisted_dav_namespace, "valid-drop-box")))
-
-    elif DropBox.enabled and parent.isSpecialCollection(customxml.DropBox):
-        # We need to handle notificiations
-        
-        # Do the normal http_PUT behavior
-        d = waitForDeferred(super(CalDAVFile, self).http_PUT(request))
-        yield d
-        response = d.getResult()
-        
-        if response.code in (responsecode.OK, responsecode.CREATED, responsecode.NO_CONTENT):
-            notification = Notification(parentURL=parentURL)
-            d = waitForDeferred(notification.doNotification(request, parent))
-            yield d
-            d.getResult()
-        
-        yield response
-        return
-
     else:
         d = waitForDeferred(super(CalDAVFile, self).http_PUT(request))
         yield d

Deleted: CalendarServer/trunk/twistedcaldav/method/x_apple_subscribe.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/x_apple_subscribe.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/method/x_apple_subscribe.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -1,70 +0,0 @@
-##
-# Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# DRI: Cyrus Daboo, cdaboo at apple.com
-##
-
-"""
-CalDAV X_APPLE_SUBSCRIBE method.
-"""
-
-__all__ = ["http_X_APPLE_SUBSCRIBE"]
-
-from twisted.internet.defer import deferredGenerator, waitForDeferred
-from twisted.python import log
-from twisted.web2 import responsecode
-from twisted.web2.dav import davxml
-from twisted.web2.dav.element.base import twisted_dav_namespace
-from twisted.web2.dav.http import ErrorResponse
-from twisted.web2.http import HTTPError, StatusResponse
-
-from twistedcaldav import customxml
-from twistedcaldav.dropbox import DropBox
-
-def http_X_APPLE_SUBSCRIBE(self, request):
-    
-    # Only for drop box collections
-    if not DropBox.enabled or not self.isSpecialCollection(customxml.DropBox):
-        log.err("Cannot x-apple-subscribe to resource %s" % (request.uri,))
-        raise HTTPError(StatusResponse(
-            responsecode.FORBIDDEN,
-            "Cannot x-apple-subscribe to resource %s" % (request.uri,))
-        )
-
-    d = waitForDeferred(self.authorize(request, (davxml.Read(),)))
-    yield d
-    d.getResult()
-    authid = request.authnUser
-    
-    # Get current list of subscribed principals
-    principals = []
-    if self.hasDeadProperty(customxml.Subscribed):
-        subs = self.readDeadProperty(customxml.Subscribed).children
-        principals.extend(subs)
-    
-    # Error if attempt to subscribe more than once
-    if authid in principals:
-        log.err("Cannot x_apple_subscribe to resource %s as principal %s is already subscribed" % (request.uri, repr(authid),))
-        raise HTTPError(ErrorResponse(
-            responsecode.FORBIDDEN,
-            (twisted_dav_namespace, "principal-must-not-be-subscribed"))
-        )
-
-    principals.append(authid)
-    self.writeDeadProperty(customxml.Subscribed(*principals))
-
-    yield responsecode.OK
-
-http_X_APPLE_SUBSCRIBE = deferredGenerator(http_X_APPLE_SUBSCRIBE)

Deleted: CalendarServer/trunk/twistedcaldav/method/x_apple_unsubscribe.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/x_apple_unsubscribe.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/method/x_apple_unsubscribe.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -1,71 +0,0 @@
-##
-# Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# DRI: Cyrus Daboo, cdaboo at apple.com
-##
-
-"""
-CalDAV X_APPLE_UNSUBSCRIBE method.
-"""
-
-__all__ = ["http_X_APPLE_UNSUBSCRIBE"]
-
-from twisted.internet.defer import deferredGenerator, waitForDeferred
-from twisted.python import log
-from twisted.web2 import responsecode
-from twisted.web2.dav.element.base import twisted_dav_namespace
-from twisted.web2.dav.http import ErrorResponse
-from twisted.web2.http import HTTPError, StatusResponse
-
-from twistedcaldav import customxml
-from twistedcaldav.dropbox import DropBox
-
-def http_X_APPLE_UNSUBSCRIBE(self, request):
-    
-    # Only for drop box collections
-    if not DropBox.enabled or not self.isSpecialCollection(customxml.DropBox):
-        log.err("Cannot x_apple_unsubscribe to resource %s" % (request.uri,))
-        raise HTTPError(StatusResponse(
-            responsecode.FORBIDDEN,
-            "Cannot x_apple_unsubscribe to resource %s" % (request.uri,))
-        )
-
-    # We do not check any privileges. If a principal is subscribed we always allow them to
-    # unsubscribe provided they have at least authenticated.
-    d = waitForDeferred(self.authorize(request, ()))
-    yield d
-    d.getResult()
-    authid = request.authnUser
-    
-    # Get current list of subscribed principals
-    principals = []
-    if self.hasDeadProperty(customxml.Subscribed):
-        subs = self.readDeadProperty(customxml.Subscribed).children
-        principals.extend(subs)
-    
-    # Error if attempt to subscribe more than once
-    if authid not in principals:
-        log.err("Cannot x_apple_unsubscribe from resource %s as principal %s is not currently subscribed" % (request.uri, repr(authid),))
-        raise HTTPError(ErrorResponse(
-            responsecode.FORBIDDEN,
-            (twisted_dav_namespace, "principal-must-be-subscribed"))
-        )
-
-    principals.remove(authid)
-    self.writeDeadProperty(customxml.Subscribed(*principals))
-
-    yield responsecode.OK
-
-http_X_APPLE_UNSUBSCRIBE = deferredGenerator(http_X_APPLE_UNSUBSCRIBE)

Modified: CalendarServer/trunk/twistedcaldav/notifications.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/notifications.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/notifications.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -23,7 +23,7 @@
 from twisted.web2.dav import davxml
 
 from twistedcaldav import customxml
-from twistedcaldav.customxml import apple_namespace
+from twistedcaldav.customxml import calendarserver_namespace
 from twistedcaldav.extensions import DAVFile
 from twistedcaldav.extensions import DAVResource
 
@@ -54,7 +54,7 @@
 
     def doNotification(self, request, parent):
         """
-        Put the supplied noitification into the notification collection of the specified principal.
+        Put the supplied notification into the notification collection of the specified principal.
         
         @param request: L{Request} for request in progress.
         @param parent: L{DAVResource} for parent of resource trigerring the notification.
@@ -143,19 +143,29 @@
         
     doNotification = deferredGenerator(doNotification)
 
+class NotificationCollectionResource (DAVResource):
+    def resourceType(self):
+        return davxml.ResourceType(
+            davxml.ResourceType.collection,
+            davxml.ResourceType.notifications,
+        )
+
+    def notify(self):
+        # FIXME: Move doNotification() logic from above class to here
+        pass
+
 class NotificationResource(DAVResource):
     """
     Resource that gets stored in a notification collection and which contains
     the notification details in its content as well as via properties.
     """
-
     liveProperties = DAVResource.liveProperties + (
-        (apple_namespace, "time-stamp"  ),
-        (apple_namespace, "changed"     ),
+        (calendarserver_namespace, "time-stamp"),
+        (calendarserver_namespace, "changed"   ),
     )
 
-class NotificationFile(DAVResource, DAVFile):
-
+# FIXME: This needs to be in static.py, but it's referred to in doNotification() above, which is probably incorrect.
+class NotificationFile(NotificationResource, DAVFile):
     def __init__(self, path):
         super(NotificationFile, self).__init__(path)
 
@@ -163,7 +173,6 @@
         """
         Create the resource, fill out the body, and add properties.
         """
-        
         # Create body XML
         elements = []
         elements.append(customxml.TimeStamp.fromString(notification.timestamp))

Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/resource.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -54,9 +54,8 @@
 from twistedcaldav.extensions import DAVResource
 from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
 from twistedcaldav.caldavxml import caldav_namespace
-from twistedcaldav.customxml import apple_namespace
+from twistedcaldav.customxml import calendarserver_namespace
 from twistedcaldav.ical import Component as iComponent
-from twistedcaldav.dropbox import DropBox
 
 if twistedcaldav.__version__:
     serverVersion = twisted.web2.server.VERSION + " TwistedCalDAV/" + twistedcaldav.__version__
@@ -449,17 +448,20 @@
         """
         
         # Do this only for regular calendar collections and Inbox/Outbox
-        if self.isPseudoCalendarCollection() or \
-            DropBox.enabled and self.isSpecialCollection(customxml.DropBox):
-            # Add inheritable option to each ACE in the list
+        if self.isPseudoCalendarCollection():
+            edited_aces = []
             for ace in newaces:
                 if TwistedACLInheritable() not in ace.children:
                     children = list(ace.children)
                     children.append(TwistedACLInheritable())
-                    ace.children = children
+                    edited_aces.append(davxml.ACE(*children))
+                else:
+                    edited_aces.append(ace)
+        else:
+            edited_aces = newaces
         
         # Do inherited with possibly modified set of aces
-        super(CalDAVResource, self).writeNewACEs(newaces)
+        super(CalDAVResource, self).writeNewACEs(edited_aces)
 
     ##
     # Utilities
@@ -535,6 +537,8 @@
         (caldav_namespace, "calendar-user-address-set"),
         (caldav_namespace, "schedule-inbox-URL"       ),
         (caldav_namespace, "schedule-outbox-URL"      ),
+        (calendarserver_namespace, "dropbox-home-URL" ),
+        (calendarserver_namespace, "notifications-URL"),
     )
 
     def readProperty(self, property, request):
@@ -573,7 +577,7 @@
                     else:
                         return caldavxml.ScheduleOutboxURL(davxml.HRef(url))
 
-            elif namespace == apple_namespace:
+            elif namespace == calendarserver_namespace:
                 if name == "dropbox-home-URL":
                     url = self.dropboxURL()
                     if url is None:
@@ -659,19 +663,21 @@
         """
         @return: the drop box home collection URL for this principal.
         """
-        # Use the first calendar home only
-        for home in self.calendarHomeURLs():
-            return joinURL(home, DropBox.dropboxName)
-        return None
+        if self.hasDeadProperty((calendarserver_namespace, "dropbox-home-URL")):
+            inbox = self.readDeadProperty((caldav_namespace, "dropbox-home-URL"))
+            return str(inbox.children[0])
+        else:
+            return None
         
     def notificationsURL(self):
         """
         @return: the notifications collection URL for this principal.
         """
-        # Use the first calendar home only
-        for home in self.calendarHomeURLs():
-            return joinURL(home, DropBox.notificationName)
-        return None
+        if self.hasDeadProperty((calendarserver_namespace, "notifications-URL")):
+            inbox = self.readDeadProperty((caldav_namespace, "notifications-URL"))
+            return str(inbox.children[0])
+        else:
+            return None
 
 ##
 # Utilities

Modified: CalendarServer/trunk/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/schedule.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/schedule.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -79,7 +79,10 @@
     Extends L{DAVResource} to provide CalDAV functionality.
     """
     def resourceType(self):
-        return davxml.ResourceType(davxml.Collection(), caldavxml.ScheduleInbox())
+        return davxml.ResourceType(
+            davxml.ResourceType.collection,
+            davxml.ResourceType.scheduleInbox,
+        )
 
     def defaultAccessControlList(self):
         return davxml.ACL(
@@ -99,7 +102,10 @@
     Extends L{DAVResource} to provide CalDAV functionality.
     """
     def resourceType(self):
-        return davxml.ResourceType(davxml.Collection(), caldavxml.ScheduleOutbox())
+        return davxml.ResourceType(
+            davxml.ResourceType.collection,
+            davxml.ResourceType.scheduleOutbox,
+        )
 
     @deferredGenerator
     def http_POST(self, request):

Modified: CalendarServer/trunk/twistedcaldav/static.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/static.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/static.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -22,11 +22,13 @@
 
 __all__ = [
     "CalDAVFile",
+    "CalendarHomeProvisioningFile",
     "CalendarHomeFile",
-    "CalendarHomeProvisioningFile",
-    "CalendarPrincipalCollectionFile",
     "ScheduleInboxFile",
     "ScheduleOutboxFile",
+    "DropBoxHomeFile",
+    "DropBoxCollectionFile",
+    "DropBoxChildFile",
 ]
 
 import os
@@ -46,14 +48,14 @@
 
 from twistedcaldav import caldavxml
 from twistedcaldav import customxml
+from twistedcaldav.config import config
+from twistedcaldav.extensions import DAVFile
 from twistedcaldav.ical import Component as iComponent
 from twistedcaldav.ical import Property as iProperty
-from twistedcaldav.icaldav import ICalDAVResource
 from twistedcaldav.index import Index, IndexSchedule, db_basename
-from twistedcaldav.resource import CalDAVResource, isCalendarCollectionResource
+from twistedcaldav.resource import CalDAVResource, isCalendarCollectionResource, isPseudoCalendarCollectionResource
 from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource
-from twistedcaldav.extensions import DAVFile
-from twistedcaldav.dropbox import DropBox
+from twistedcaldav.dropbox import DropBoxHomeResource, DropBoxCollectionResource, DropBoxChildResource
 from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
 from twistedcaldav.directory.calendar import DirectoryCalendarHomeTypeProvisioningResource
 from twistedcaldav.directory.calendar import DirectoryCalendarHomeResource
@@ -101,15 +103,7 @@
     
             return self.createCalendarCollection()
             
-        def isNonCalendarCollectionParentResource(resource):
-            try:
-                resource = ICalDAVResource(resource)
-            except TypeError:
-                return False
-            else:
-                return resource.isPseudoCalendarCollection() or resource.isSpecialCollection(customxml.DropBoxHome)
-
-        parent = self._checkParents(request, isNonCalendarCollectionParentResource)
+        parent = self._checkParents(request, isPseudoCalendarCollectionResource)
         parent.addCallback(_defer)
         return parent
 
@@ -430,19 +424,21 @@
         if not provisionFile(self, self._parent):
             return succeed(None)
 
-        d = super(CalendarHomeFile, self).provision()
+        return super(CalendarHomeFile, self).provision()
 
-        # FIXME: This should provision itself also
-        # Provision a drop box
-        if self.record.recordType == "user":
-            DropBox.provision(self)
+    def provisionChild(self, name):
+        if config.DropBoxEnabled:
+            DropBoxHomeFileClass = DropBoxHomeFile
+            #NotificationsCollectionFileClass = NotificationsCollectionFile
+        else:
+            DropBoxHomeFileClass = None
+            #NotificationsCollectionFileClass = None
 
-        return d
-
-    def provisionChild(self, name):
         cls = {
-            "inbox" : ScheduleInboxFile,
-            "outbox": ScheduleOutboxFile,
+            "inbox"        : ScheduleInboxFile,
+            "outbox"       : ScheduleOutboxFile,
+            "dropbox"      : DropBoxHomeFileClass,
+            #"notifications": NotificationsCollectionFileClass,
         }.get(name, None)
 
         if cls is not None:
@@ -526,6 +522,45 @@
     def __repr__(self):
         return "<%s (calendar outbox collection): %s>" % (self.__class__.__name__, self.fp.path)
 
+class DropBoxHomeFile (DropBoxHomeResource, CalDAVFile):
+    def __init__(self, path, parent):
+        DropBoxHomeResource.__init__(self)
+        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
+        self._parent = parent
+
+    def provision(self):
+        provisionFile(self, self._parent)
+
+    def createSimilarFile(self, path):
+        if path == self.fp.path:
+            return self
+        else:
+            return DropBoxCollectionFile(path, self)
+
+class DropBoxCollectionFile (DropBoxCollectionResource, CalDAVFile):
+    def __init__(self, path, parent):
+        DropBoxCollectionResource.__init__(self)
+        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
+
+    def createSimilarFile(self, path):
+        if path == self.fp.path:
+            return self
+        else:
+            return DropBoxChildFile(path, self)
+
+class DropBoxChildFile (DropBoxChildResource, CalDAVFile):
+    def __init__(self, path, parent):
+        DropBoxChildResource.__init__(self)
+        CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
+
+        assert self.fp.isfile() or not self.fp.exists
+
+    def createSimilarFile(self, path):
+        if path == self.fp.path:
+            return self
+        else:
+            return responsecode.NOT_FOUND
+
 ##
 # Utilities
 ##

Modified: CalendarServer/trunk/twistedcaldav/tap.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/tap.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/tap.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -43,7 +43,6 @@
 from twisted.web2.server import Site
 
 from twistedcaldav.config import config, parseConfig
-from twistedcaldav.dropbox import DropBox
 from twistedcaldav.logging import RotatingFileAccessLoggingObserver
 from twistedcaldav.root import RootResource
 from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
@@ -86,16 +85,9 @@
 
     def makeService(self, options):
         #
-        # Turn on drop box support before setting up the repository
-        #
-        DropBox.enable(config.DropBoxEnabled, config.NotificationsEnabled)
-        
-        #
         # Setup the Directory
         #
-
         directoryClass = namedClass(config.DirectoryService['type'])
-
         directory = directoryClass(**config.DirectoryService['params'])
 
         #

Modified: CalendarServer/trunk/twistedcaldav/test/data/makelargecalendars.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/data/makelargecalendars.py	2006-12-14 22:04:25 UTC (rev 826)
+++ CalendarServer/trunk/twistedcaldav/test/data/makelargecalendars.py	2006-12-14 22:16:47 UTC (rev 827)
@@ -23,10 +23,17 @@
 user_max = 20
 calendars = ("calendar.10", "calendar.100", "calendar.1000",)
 
-for calendar in calendars:
-    for ctr in xrange(1, user_max + 1):
-        path = "calendars/user/user%02d" % (ctr,)
-        if not os.path.exists("%s/%s/" % (path, calendar,)):
-            print "Expanding %s to %s" % (calendar, path,)
-            cmd = "cd %s; tar zxf ../../../%s.tgz" % (path, calendar,)
+for ctr in xrange(1, user_max + 1): 
+    path = "calendars/user/user%02d" % (ctr,)
+
+    try: os.makedirs(path)
+    except OSError: pass
+
+    try: os.makedirs(os.path.join(path, "calendar"))
+    except OSError: pass
+
+    for calendar in calendars:
+        if not os.path.isdir(os.path.join(path, calendar)):
+            print "Expanding %s to %s" % (calendar, path)
+            cmd = "tar -C %r -zx -f %r" % (path, calendar + ".tgz")
             os.system(cmd)

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


More information about the calendarserver-changes mailing list