[CalendarServer-changes] [5231] CalendarServer/branches/users/cdaboo/shared-calendars-5187/ twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Tue Mar 2 13:23:49 PST 2010


Revision: 5231
          http://trac.macosforge.org/projects/calendarserver/changeset/5231
Author:   cdaboo at apple.com
Date:     2010-03-02 13:23:49 -0800 (Tue, 02 Mar 2010)
Log Message:
-----------
Split sharing pieces into their own mix-in class with tests. Add proper compliance header. Make extended
MKCOL work.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/customxml.py
    CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/method/mkcol.py
    CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/resource.py
    CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/static.py
    CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/util.py

Added Paths:
-----------
    CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/sharing.py
    CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py

Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/customxml.py	2010-03-02 21:20:30 UTC (rev 5230)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/customxml.py	2010-03-02 21:23:49 UTC (rev 5231)
@@ -1,5 +1,5 @@
 ##
-# Copyright (c) 2006-2009 Apple Inc. All rights reserved.
+# Copyright (c) 2006-2010 Apple 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.
@@ -28,6 +28,7 @@
 from twext.web2.dav.element.base import twisted_private_namespace
 from twext.web2.dav import davxml
 
+from twistedcaldav import caldavxml
 from twistedcaldav.ical import Component as iComponent
 
 from vobject.icalendar import utc
@@ -49,10 +50,14 @@
     "calendarserver-private-comments",
 )
 
-calendarserver_principal_property_search = (
+calendarserver_principal_property_search_compliance = (
     "calendarserver-principal-property-search",
 )
 
+calendarserver_sharing_compliance = (
+    "calendarserver-sharing",
+)
+
 class TwistedCalendarAccessProperty (davxml.WebDAVTextElement):
     """
     Contains the calendar access level (private events) for the resource.
@@ -806,3 +811,4 @@
 davxml.ResourceType.ischeduleinbox = davxml.ResourceType(IScheduleInbox())
 davxml.ResourceType.freebusyurl = davxml.ResourceType(FreeBusyURL())
 davxml.ResourceType.notification = davxml.ResourceType(davxml.Collection(), Notification())
+davxml.ResourceType.sharedcalendar = davxml.ResourceType(davxml.Collection(), caldavxml.Calendar(), SharedOwner())

Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/method/mkcol.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/method/mkcol.py	2010-03-02 21:20:30 UTC (rev 5230)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/method/mkcol.py	2010-03-02 21:23:49 UTC (rev 5231)
@@ -165,11 +165,10 @@
             # Now handle other properties
             for property in mkcol.children[0].children[0].children:
                 try:
-                    if rtype == "calendar":
-                        if property.qname() == (caldavxml.caldav_namespace, "supported-calendar-component-set"):
-                            self.writeDeadProperty(property)
-                        elif not isinstance(property, davxml.ResourceType):
-                            yield self.writeProperty(property, request)
+                    if rtype == "calendar" and property.qname() == (caldavxml.caldav_namespace, "supported-calendar-component-set"):
+                        self.writeDeadProperty(property)
+                    else:
+                        yield self.writeProperty(property, request)
                 except HTTPError:
                     errors.add(Failure(), property)
                     got_an_error = True

Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/resource.py	2010-03-02 21:20:30 UTC (rev 5230)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/resource.py	2010-03-02 21:23:49 UTC (rev 5231)
@@ -69,6 +69,7 @@
 from twistedcaldav.ical import Component as iComponent
 from twistedcaldav.ical import allowedComponents
 from twistedcaldav.icaldav import ICalDAVResource, ICalendarPrincipalResource
+from twistedcaldav.sharing import SharingMixin
 from twistedcaldav.vcard import Component as vComponent
 
 
@@ -110,9 +111,11 @@
             extra_compliance += customxml.calendarserver_private_events_compliance
         if config.Scheduling.CalDAV.get("EnablePrivateComments", True):
             extra_compliance += customxml.calendarserver_private_comments_compliance
-        extra_compliance += customxml.calendarserver_principal_property_search
+        extra_compliance += customxml.calendarserver_principal_property_search_compliance
         if config.EnableCardDAV:
             extra_compliance += carddavxml.carddav_compliance
+        if config.EnableSharing:
+            extra_compliance += customxml.calendarserver_sharing_compliance
         return tuple(super(CalDAVComplianceMixIn, self).davComplianceClasses()) + extra_compliance
 
 
@@ -132,7 +135,7 @@
     return fun
 
 
-class CalDAVResource (CalDAVComplianceMixIn, DAVResource, LoggingMixIn):
+class CalDAVResource (CalDAVComplianceMixIn, SharingMixin, DAVResource, LoggingMixIn):
     """
     CalDAV resource.
 
@@ -277,7 +280,8 @@
         isvirt = (yield self.isVirtualShare(request))
         if self.isShadowableProperty(qname):
             if isvirt:
-                p = self.deadProperties().get(qname, uid=request.authzPrincipal.principalUID())
+                ownerPrincipal = (yield self.ownerPrincipal(request))
+                p = self.deadProperties().get(qname, uid=ownerPrincipal.principalUID())
                 if p is not None:
                     returnValue(p)
             else:
@@ -285,7 +289,8 @@
                 returnValue(res)
             
         elif (not self.isGlobalProperty(qname)) and isvirt:
-            p = self.deadProperties().get(qname, uid=request.authzPrincipal.principalUID())
+            ownerPrincipal = (yield self.ownerPrincipal(request))
+            p = self.deadProperties().get(qname, uid=ownerPrincipal.principalUID())
             if p is not None:
                 returnValue(p)
 
@@ -347,24 +352,8 @@
         elif namespace == calendarserver_namespace:
             if name == "invite":
                 shared = (yield self.isShared(request))
-                if shared:
-                    userlist = []
-                    accesses = (yield self.getInviteUsers(request))
-                    if accesses:
-                        for access in accesses:
-                            acl = access()
-                            for principal, metaData in accesses[access]:
-                                children = []
-                                mailtoemail = "mailto:" + metaData["email"]
-                                children.append(davxml.HRef(mailtoemail))
-                                children.append(customxml.InviteAccess(acl))
-                                if "inviteStatus" in metaData and metaData["inviteStatus"]:
-                                    children.append(shareAcceptStatesByXML[metaData["inviteStatus"]])
-                                else: 
-                                    children.append(customxml.InviteStatusNoResponse())
-                                userlist.append(customxml.InviteUser(*children))
-                    result = customxml.Invite(*userlist)
-                    returnValue(result)
+                if not shared:
+                    returnValue(None)
 
         result = (yield super(CalDAVResource, self).readProperty(property, request))
         returnValue(result)
@@ -378,7 +367,8 @@
         # Per-user Dav props currently only apply to a sharee's copy of a calendar
         isvirt = (yield self.isVirtualShare(request))
         if isvirt and (self.isShadowableProperty(property.qname()) or (not self.isGlobalProperty(property.qname()))):
-            p = (yield self.deadProperties().set(property, uid=request.authzPrincipal.principalUID()))
+            ownerPrincipal = (yield self.ownerPrincipal(request))
+            p = (yield self.deadProperties().set(property, uid=ownerPrincipal.principalUID()))
             returnValue(p)
  
         res = (yield self._writeGlobalProperty(property, request))
@@ -434,7 +424,14 @@
                 inbox.processFreeBusyCalendar(myurl, property.children[0] == caldavxml.Opaque())
 
         elif property.qname() == (dav_namespace, "resourcetype"):
-            if self.isCalendarCollection() and config.EnableSharing:
+            if self.isCalendarCollection():
+                sawShare = [child for child in property.children if child.qname() == (calendarserver_namespace, "shared-owner")]
+                if not config.EnableSharing:
+                    raise HTTPError(StatusResponse(
+                        responsecode.FORBIDDEN,
+                        "Cannot create shared calendars on this server.",
+                    ))
+
                 # Check if adding or removing share
                 shared = (yield self.isShared(request))
                 sawShare = [child for child in property.children if child.qname() == (calendarserver_namespace, "shared-owner")]
@@ -963,47 +960,8 @@
         """
         Quota root only ever set on calendar homes.
         """
-        return None
+        return None 
 
-    ##
-    # Sharing operations
-    ##
-
-    def upgradeToShare(self, request):
-        """ Upgrade this collection to a shared state """
-        return succeed(True)
-    
-    def downgradeFromShare(self, request):
-        return succeed(True)
-
-    def addUserToShare(self, userid, request, ace):
-        """ Add a user to this shared calendar """
-        return succeed(True)
-
-    def removeUserFromShare(self, userid, request):
-        """ Remove a user from this shared calendar """
-        return succeed(True)
-
-    def isShared(self, request):
-        """ Return True if this is an owner shared calendar collection """
-        succeed(False)
-
-    def isVirtualShare(self, request):
-        """ Return True if this is a shared calendar collection """
-        succeed(False)
-
-    def removeVirtualShare(self, request):
-        """ As user of a shared calendar, unlink this calendar collection """
-        succeed(False) 
-
-    def getInviteUsers(self, request):
-        succeed(True)
-
-    def sendNotificationOnChange(self, icalendarComponent, request, state="added"):
-        """ Possibly send a push and or email notification on a change to a resource in a shared collection """
-        succeed(True)
- 
-
 class CalendarPrincipalCollectionResource (DAVPrincipalCollectionResource, CalDAVResource):
     """
     CalDAV principal collection.

Added: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/sharing.py	                        (rev 0)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/sharing.py	2010-03-02 21:23:49 UTC (rev 5231)
@@ -0,0 +1,83 @@
+##
+# Copyright (c) 2010 Apple 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.
+##
+from twisted.internet.defer import succeed
+
+__all__ = [
+    "SharingMixin",
+]
+
+from twistedcaldav import customxml
+from twext.web2.dav import davxml
+
+"""
+Sharing behavior
+"""
+
+class SharingMixin(object):
+    
+    def upgradeToShare(self, request):
+        """ Upgrade this collection to a shared state """
+        
+        # Change resourcetype
+        rtype = self.resourceType()
+        rtype = davxml.ResourceType(*(rtype.children + (customxml.SharedOwner(),)))
+        self.writeDeadProperty(rtype)
+        
+        # Create empty invite property
+        self.writeDeadProperty(customxml.Invite())
+
+        return succeed(True)
+    
+    def downgradeFromShare(self, request):
+        
+        # Change resource type
+        rtype = self.resourceType()
+        rtype = davxml.ResourceType(*([child for child in rtype.children if child != customxml.SharedOwner()]))
+        self.writeDeadProperty(rtype)
+        
+        # Remove all invitees
+
+        # Remove invite property
+        self.removeDeadProperty(customxml.Invite)
+    
+        return succeed(True)
+
+    def addUserToShare(self, userid, request, ace):
+        """ Add a user to this shared calendar """
+        return succeed(True)
+
+    def removeUserFromShare(self, userid, request):
+        """ Remove a user from this shared calendar """
+        return succeed(True)
+
+    def isShared(self, request):
+        """ Return True if this is an owner shared calendar collection """
+        return succeed(self.isSpecialCollection(customxml.SharedOwner))
+
+    def isVirtualShare(self, request):
+        """ Return True if this is a shared calendar collection """
+        return succeed(self.isSpecialCollection(customxml.Shared))
+
+    def removeVirtualShare(self, request):
+        """ As user of a shared calendar, unlink this calendar collection """
+        return succeed(False) 
+
+    def getInviteUsers(self, request):
+        return succeed(True)
+
+    def sendNotificationOnChange(self, icalendarComponent, request, state="added"):
+        """ Possibly send a push and or email notification on a change to a resource in a shared collection """
+        return succeed(True)

Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/static.py	2010-03-02 21:20:30 UTC (rev 5230)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/static.py	2010-03-02 21:23:49 UTC (rev 5231)
@@ -181,12 +181,6 @@
     # CalDAV
     ##
 
-    def resourceType(self):
-        if self.isCalendarCollection():
-            return davxml.ResourceType.calendar
-        else:
-            return super(CalDAVFile, self).resourceType()
-
     def createCalendar(self, request):
         #
         # request object is required because we need to validate against parent

Added: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py	                        (rev 0)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py	2010-03-02 21:23:49 UTC (rev 5231)
@@ -0,0 +1,66 @@
+##
+# Copyright (c) 2010 Apple 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.
+##
+
+
+from twistedcaldav.test.util import InMemoryPropertyStore
+from twistedcaldav.test.util import TestCase
+from twext.web2.dav import davxml
+from twistedcaldav.static import CalDAVFile
+from twistedcaldav import customxml
+from twisted.internet.defer import inlineCallbacks
+import os
+
+
+class SharingTests(TestCase):
+    def setUp(self):
+        TestCase.setUp(self)
+        collection = self.mktemp()
+        os.mkdir(collection)
+        self.resource = CalDAVFile(collection)
+        self.resource._dead_properties = InMemoryPropertyStore()
+
+    @inlineCallbacks
+    def test_upgradeToShare(self):
+        self.resource.writeDeadProperty(davxml.ResourceType.calendar)
+        self.assertEquals(self.resource.resourceType(), davxml.ResourceType.calendar)
+        self.assertFalse(self.resource.hasDeadProperty(customxml.Invite()))
+
+        yield self.resource.upgradeToShare(None)
+
+        self.assertEquals(self.resource.resourceType(), davxml.ResourceType.sharedcalendar)
+        self.assertEquals(self.resource.readDeadProperty(customxml.Invite), customxml.Invite())
+        
+        isShared = (yield self.resource.isShared(None))
+        self.assertTrue(isShared)
+        isVShared = (yield self.resource.isVirtualShare(None))
+        self.assertFalse(isVShared)
+
+    @inlineCallbacks
+    def test_downgradeFromShare(self):
+        self.resource.writeDeadProperty(davxml.ResourceType.sharedcalendar)
+        self.resource.writeDeadProperty(customxml.Invite())
+        self.assertEquals(self.resource.resourceType(), davxml.ResourceType.sharedcalendar)
+        self.assertEquals(self.resource.readDeadProperty(customxml.Invite), customxml.Invite())
+
+        yield self.resource.downgradeFromShare(None)
+
+        self.assertEquals(self.resource.resourceType(), davxml.ResourceType.calendar)
+        self.assertFalse(self.resource.hasDeadProperty(customxml.Invite()))
+        
+        isShared = (yield self.resource.isShared(None))
+        self.assertFalse(isShared)
+        isVShared = (yield self.resource.isVirtualShare(None))
+        self.assertFalse(isVShared)

Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/util.py	2010-03-02 21:20:30 UTC (rev 5230)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/util.py	2010-03-02 21:23:49 UTC (rev 5231)
@@ -214,6 +214,9 @@
         except KeyError:
             pass
 
+    def contains(self, qname, uid=None):
+        qnameuid = qname + (uid,)
+        return qnameuid in self._properties
 
     def list(self, uid=None, filterByUID=True):
         results = self._properties.iterkeys()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100302/1f3f0553/attachment-0001.html>


More information about the calendarserver-changes mailing list