[CalendarServer-changes] [804] CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Mon Dec 11 21:33:12 PST 2006


Revision: 804
          http://trac.macosforge.org/projects/calendarserver/changeset/804
Author:   wsanchez at apple.com
Date:     2006-12-11 21:33:11 -0800 (Mon, 11 Dec 2006)

Log Message:
-----------
Add actual dropbox resources and move dropbox logic to those classes
instead of CalDAVFile, which shouldn't care.

Start on Notifications resource as well, but I'm not sure what to make
of doNotifications() yet.

Modified Paths:
--------------
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/caldavxml.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/customxml.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/directory/principal.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/dropbox.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/__init__.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/delete.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/mkcol.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/put.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/notifications.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/resource.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/schedule.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/static.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/tap.py

Removed Paths:
-------------
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/x_apple_subscribe.py
    CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/x_apple_unsubscribe.py

Modified: CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/caldavxml.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/caldavxml.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/caldavxml.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/customxml.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/customxml.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/directory/principal.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/directory/principal.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/dropbox.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/dropbox.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/dropbox.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -22,80 +22,173 @@
 """
 
 __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))
         
-        # 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/branches/users/wsanchez/dropbox/twistedcaldav/method/__init__.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/__init__.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/__init__.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -32,6 +32,4 @@
     "report_calquery",
     "report_freebusy",
     "report_multiget",
-    "x_apple_subscribe",
-    "x_apple_unsubscribe",
 ]

Modified: CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/delete.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/delete.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/delete.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/method/mkcol.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/mkcol.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/mkcol.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/method/put.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/put.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/put.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/method/x_apple_subscribe.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/x_apple_subscribe.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/x_apple_subscribe.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/method/x_apple_unsubscribe.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/x_apple_unsubscribe.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/method/x_apple_unsubscribe.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/notifications.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/notifications.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/notifications.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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,30 @@
         
     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.
     """
+    # FIXME: These don't appear to be in use
+    # liveProperties = DAVResource.liveProperties + (
+    #     (calendarserver_namespace, "time-stamp"),
+    #     (calendarserver_namespace, "changed"   ),
+    # )
 
-    liveProperties = DAVResource.liveProperties + (
-        (apple_namespace, "time-stamp"  ),
-        (apple_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 +174,6 @@
         """
         Create the resource, fill out the body, and add properties.
         """
-        
         # Create body XML
         elements = []
         elements.append(customxml.TimeStamp.fromString(notification.timestamp))

Modified: CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/resource.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/resource.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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,18 @@
         """
         
         # 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 = newaces
         
         # Do inherited with possibly modified set of aces
-        super(CalDAVResource, self).writeNewACEs(newaces)
+        super(CalDAVResource, self).writeNewACEs(edited_aces)
 
     ##
     # Utilities
@@ -535,6 +535,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 +575,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 +661,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/branches/users/wsanchez/dropbox/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/schedule.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/schedule.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/static.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/static.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -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/branches/users/wsanchez/dropbox/twistedcaldav/tap.py
===================================================================
--- CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/tap.py	2006-12-12 05:29:36 UTC (rev 803)
+++ CalendarServer/branches/users/wsanchez/dropbox/twistedcaldav/tap.py	2006-12-12 05:33:11 UTC (rev 804)
@@ -41,7 +41,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
@@ -84,16 +83,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'])
 
         #

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


More information about the calendarserver-changes mailing list