[CalendarServer-changes] [5482] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Thu Apr 15 14:03:22 PDT 2010
Revision: 5482
http://trac.macosforge.org/projects/calendarserver/changeset/5482
Author: cdaboo at apple.com
Date: 2010-04-15 14:03:20 -0700 (Thu, 15 Apr 2010)
Log Message:
-----------
CardDAV global addressbook support. Some addition CardDAV specific clean-up.
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
CalendarServer/trunk/calendarserver/tap/util.py
CalendarServer/trunk/twext/web2/responsecode.py
CalendarServer/trunk/twistedcaldav/carddavxml.py
CalendarServer/trunk/twistedcaldav/customxml.py
CalendarServer/trunk/twistedcaldav/directory/addressbook.py
CalendarServer/trunk/twistedcaldav/directory/calendar.py
CalendarServer/trunk/twistedcaldav/resource.py
CalendarServer/trunk/twistedcaldav/static.py
CalendarServer/trunk/twistedcaldav/stdconfig.py
CalendarServer/trunk/twistedcaldav/test/test_sharing.py
Added Paths:
-----------
CalendarServer/trunk/twistedcaldav/linkresource.py
Modified: CalendarServer/trunk/calendarserver/tap/test/test_caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/test/test_caldav.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/calendarserver/tap/test/test_caldav.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -344,7 +344,7 @@
-class SocketGroupOwnership(BaseTestCase):
+class SocketGroupOwnership(TestCase):
"""
Tests for L{GroupOwnedUNIXServer}.
"""
Modified: CalendarServer/trunk/calendarserver/tap/util.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/util.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/calendarserver/tap/util.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -25,7 +25,7 @@
from time import sleep
from twisted.python.reflect import namedClass
-from twisted.internet import reactor
+from twisted.internet.reactor import addSystemEventTrigger
from twisted.cred.portal import Portal
from twext.web2.http_headers import Headers
from twext.web2.dav import auth
@@ -47,7 +47,8 @@
from twistedcaldav.notify import installNotificationClient
from twistedcaldav.resource import CalDAVResource, AuthenticationWrapper
from twistedcaldav.simpleresource import SimpleResource
-from twistedcaldav.static import CalendarHomeProvisioningFile
+from twistedcaldav.static import CalendarHomeProvisioningFile,\
+ GlobalAddressBookFile
from twistedcaldav.static import IScheduleInboxFile
from twistedcaldav.static import TimezoneServiceFile
from twistedcaldav.static import AddressBookHomeProvisioningFile, DirectoryBackedAddressBookFile
@@ -91,6 +92,7 @@
webAdminResourceClass = WebAdminResource
addressBookResourceClass = AddressBookHomeProvisioningFile
directoryBackedAddressBookResourceClass = DirectoryBackedAddressBookFile
+ globalAddressBookResourceClass = GlobalAddressBookFile
#
# Setup the Directory
@@ -290,10 +292,7 @@
directoryPath,
principalCollections=(principalCollection,)
)
- # do this after process is owned by carddav user, not root. XXX
- # this should be fixed to execute at a different stage of service
- # startup entirely.
- reactor.callLater(1.0, directoryBackedAddressBookCollection.provisionDirectory)
+ addSystemEventTrigger("after", "startup", directoryBackedAddressBookCollection.provisionDirectory)
else:
# remove /directory from previous runs that may have created it
try:
@@ -303,6 +302,16 @@
if e.errno != errno.ENOENT:
log.error("Could not delete: %s : %r" % (directoryPath, e,))
+ if config.GlobalAddressBook.Enabled:
+ log.info("Setting up global address book collection: %r" % (globalAddressBookResourceClass,))
+
+ globalAddressBookCollection = globalAddressBookResourceClass(
+ os.path.join(config.DocumentRoot, config.GlobalAddressBook.Name),
+ principalCollections=(principalCollection,)
+ )
+ if not globalAddressBookCollection.exists():
+ addSystemEventTrigger("after", "startup", globalAddressBookCollection.createAddressBookCollection)
+
log.info("Setting up root resource: %r" % (rootResourceClass,))
root = rootResourceClass(
@@ -322,6 +331,8 @@
root.putChild('addressbooks', addressBookCollection)
if config.DirectoryAddressBook.Enabled:
root.putChild(config.DirectoryAddressBook.name, directoryBackedAddressBookCollection)
+ if config.GlobalAddressBook.Enabled:
+ root.putChild(config.GlobalAddressBook.Name, globalAddressBookCollection)
# /.well-known
if config.EnableWellKnown:
Modified: CalendarServer/trunk/twext/web2/responsecode.py
===================================================================
--- CalendarServer/trunk/twext/web2/responsecode.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/twext/web2/responsecode.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -71,6 +71,7 @@
SERVICE_UNAVAILABLE = 503
GATEWAY_TIMEOUT = 504
HTTP_VERSION_NOT_SUPPORTED = 505
+LOOP_DETECTED = 506
INSUFFICIENT_STORAGE_SPACE = 507
NOT_EXTENDED = 510
@@ -116,7 +117,7 @@
REQUEST_ENTITY_TOO_LARGE: "Request Entity Too Large",
REQUEST_URI_TOO_LONG: "Request-URI Too Long",
UNSUPPORTED_MEDIA_TYPE: "Unsupported Media Type",
- REQUESTED_RANGE_NOT_SATISFIABLE: "Requested Range not satisfiable",
+ REQUESTED_RANGE_NOT_SATISFIABLE: "Requested Range Not Satisfiable",
EXPECTATION_FAILED: "Expectation Failed",
UNPROCESSABLE_ENTITY: "Unprocessable Entity",
LOCKED: "Locked",
@@ -128,7 +129,8 @@
BAD_GATEWAY: "Bad Gateway",
SERVICE_UNAVAILABLE: "Service Unavailable",
GATEWAY_TIMEOUT: "Gateway Time-out",
- HTTP_VERSION_NOT_SUPPORTED: "HTTP Version not supported",
+ HTTP_VERSION_NOT_SUPPORTED: "HTTP Version Not Supported",
+ LOOP_DETECTED: "Loop In Linked or Bound Resource",
INSUFFICIENT_STORAGE_SPACE: "Insufficient Storage Space",
NOT_EXTENDED: "Not Extended"
}
Modified: CalendarServer/trunk/twistedcaldav/carddavxml.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/carddavxml.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/twistedcaldav/carddavxml.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -151,7 +151,7 @@
hidden = True
protected = True
- allowed_children = { (carddav_namespace, "addressbook-data"): (0, None) }
+ allowed_children = { (carddav_namespace, "address-data-type"): (0, None) }
class MaxResourceSize (CardDAVTextElement):
"""
@@ -221,6 +221,19 @@
self.filter = filter
self.limit = limit
+class AddressDataType (CardDAVEmptyElement):
+ """
+ Defines which parts of a address component object should be returned by a
+ report.
+ (CardDAV, section 6.2.2)
+ """
+ name = "address-data-type"
+
+ allowed_attributes = {
+ "content-type": False,
+ "version" : False,
+ }
+
class AddressData (CardDAVElement):
"""
Defines which parts of a address component object should be returned by a
Modified: CalendarServer/trunk/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/customxml.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/twistedcaldav/customxml.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -28,7 +28,7 @@
from twext.web2.dav.element.base import twisted_private_namespace
from twext.web2.dav import davxml
-from twistedcaldav import caldavxml
+from twistedcaldav import caldavxml, carddavxml
from twistedcaldav.ical import Component as iComponent
from vobject.icalendar import utc
@@ -891,4 +891,6 @@
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())
+davxml.ResourceType.sharedownercalendar = davxml.ResourceType(davxml.Collection(), caldavxml.Calendar(), SharedOwner())
+davxml.ResourceType.sharedcalendar = davxml.ResourceType(davxml.Collection(), caldavxml.Calendar(), Shared())
+davxml.ResourceType.sharedaddressbook = davxml.ResourceType(davxml.Collection(), carddavxml.AddressBook(), Shared())
Modified: CalendarServer/trunk/twistedcaldav/directory/addressbook.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/addressbook.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/twistedcaldav/directory/addressbook.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -25,6 +25,7 @@
"DirectoryAddressBookHomeTypeProvisioningResource",
"DirectoryAddressBookHomeUIDProvisioningResource",
"DirectoryAddressBookHomeResource",
+ "GlobalAddressBookResource",
]
from twext.python.log import Logger
@@ -377,3 +378,49 @@
is quota-controlled, or C{None} if not quota controlled.
"""
return config.UserQuota if config.UserQuota != 0 else None
+
+class GlobalAddressBookResource (CalDAVResource):
+ """
+ Global address book. All we care about is making sure permissions are setup.
+ """
+
+ def resourceType(self, request):
+ return succeed(davxml.ResourceType.sharedaddressbook)
+
+ def url(self):
+ return joinURL("/", config.GlobalAddressBook.Name, "/")
+
+ def canonicalURL(self, request):
+ return succeed(self.url())
+
+ def defaultAccessControlList(self):
+
+ aces = (
+ davxml.ACE(
+ davxml.Principal(davxml.Authenticated()),
+ davxml.Grant(
+ davxml.Privilege(davxml.Read()),
+ davxml.Privilege(davxml.ReadCurrentUserPrivilegeSet()),
+ davxml.Privilege(davxml.Write()),
+ ),
+ davxml.Protected(),
+ TwistedACLInheritable(),
+ ),
+ )
+
+ if config.GlobalAddressBook.EnableAnonymousReadAccess:
+ aces += (
+ davxml.ACE(
+ davxml.Principal(davxml.Unauthenticated()),
+ davxml.Grant(
+ davxml.Privilege(davxml.Read()),
+ ),
+ davxml.Protected(),
+ TwistedACLInheritable(),
+ ),
+ )
+ return davxml.ACL(*aces)
+
+ def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
+ # Permissions here are fixed, and are not subject to inheritance rules, etc.
+ return succeed(self.defaultAccessControlList())
Modified: CalendarServer/trunk/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/calendar.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/twistedcaldav/directory/calendar.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -41,7 +41,7 @@
from twistedcaldav.dropbox import DropBoxHomeResource
from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVResource
from twistedcaldav.freebusyurl import FreeBusyURLResource
-from twistedcaldav.resource import CalDAVResource
+from twistedcaldav.resource import CalDAVResource, CalDAVComplianceMixIn
from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource
from twistedcaldav.directory.idirectory import IDirectoryService
from twistedcaldav.directory.wiki import getWikiACL
@@ -57,6 +57,7 @@
class DirectoryCalendarProvisioningResource (
AutoProvisioningResourceMixIn,
ReadOnlyResourceMixIn,
+ CalDAVComplianceMixIn,
DAVResource,
):
def defaultAccessControlList(self):
Added: CalendarServer/trunk/twistedcaldav/linkresource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/linkresource.py (rev 0)
+++ CalendarServer/trunk/twistedcaldav/linkresource.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -0,0 +1,114 @@
+##
+# 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 twext.python.log import LoggingMixIn
+
+from twisted.internet.defer import inlineCallbacks, returnValue, maybeDeferred
+
+from twistedcaldav.resource import CalDAVComplianceMixIn
+from twext.web2.http import HTTPError
+from twext.web2 import responsecode
+from twext.web2.resource import WrapperResource
+
+__all__ = [
+ "LinkResource",
+]
+
+"""
+A resource that is a soft-link to another.
+"""
+
+class LinkResource(CalDAVComplianceMixIn, WrapperResource, LoggingMixIn):
+ """
+ This is similar to a WrapperResource except that we locate our resource dynamically.
+ """
+
+ def __init__(self, parent, link_url):
+ self.parent = parent
+ self.linkURL = link_url
+ super(LinkResource, self).__init__(self.parent.principalCollections())
+
+ @inlineCallbacks
+ def linkedResource(self, request):
+
+ if not hasattr(self, "_linkedResource"):
+ self._linkedResource = (yield request.locateResource(self.linkURL))
+
+ if self._linkedResource is None:
+ raise HTTPError(responsecode.NOT_FOUND)
+
+ returnValue(self._linkedResource)
+
+ def isCollection(self):
+ return True
+
+ @inlineCallbacks
+ def resourceType(self, request):
+ hosted = (yield self.linkedResource(request))
+ result = (yield hosted.resourceType(request))
+ returnValue(result)
+
+ def locateChild(self, request, segments):
+
+ def _defer(result):
+ return (result, segments)
+ d = self.linkedResource(request)
+ d.addCallback(_defer)
+ return d
+
+ def renderHTTP(self, request):
+ return self.linkedResource(request)
+
+ def getChild(self, name):
+ return self._hostedResource.getChild(name)
+
+ @inlineCallbacks
+ def hasProperty(self, property, request):
+ hosted = (yield self.linkedResource(request))
+ result = (yield hosted.hasProperty(property, request))
+ returnValue(result)
+
+ @inlineCallbacks
+ def readProperty(self, property, request):
+ hosted = (yield self.linkedResource(request))
+ result = (yield hosted.readProperty(property, request))
+ returnValue(result)
+
+ @inlineCallbacks
+ def writeProperty(self, property, request):
+ hosted = (yield self.linkedResource(request))
+ result = (yield hosted.writeProperty(property, request))
+ returnValue(result)
+
+class LinkFollowerMixIn(object):
+
+ @inlineCallbacks
+ def locateChild(self, req, segments):
+
+ resource, path = (yield maybeDeferred(super(LinkFollowerMixIn, self).locateChild, req, segments))
+ MAX_LINK_DEPTH = 10
+ ctr = 0
+ seenResource = set()
+ while isinstance(resource, LinkResource):
+ seenResource.add(resource)
+ ctr += 1
+ resource = (yield resource.linkedResource(req))
+
+ if ctr > MAX_LINK_DEPTH or resource in seenResource:
+ raise HTTPError(responsecode.LOOP_DETECTED)
+
+ returnValue((resource, path))
+
Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/twistedcaldav/resource.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -160,10 +160,22 @@
def liveProperties(self):
baseProperties = (
davxml.Owner.qname(), # Private Events needs this but it is also OK to return empty
- caldavxml.SupportedCalendarComponentSet.qname(),
- caldavxml.SupportedCalendarData.qname(),
)
+ if self.isPseudoCalendarCollection():
+ baseProperties += (
+ caldavxml.SupportedCalendarComponentSet.qname(),
+ caldavxml.SupportedCalendarData.qname(),
+ )
+
+ if self.isAddressBookCollection():
+ baseProperties += (
+ carddavxml.SupportedAddressData.qname(),
+ )
+
+ if config.EnableSyncReport and (self.isPseudoCalendarCollection() or self.isAddressBookCollection()):
+ baseProperties += (davxml.SyncToken.qname(),)
+
if config.EnableAddMember and (self.isCalendarCollection() or self.isAddressBookCollection()):
baseProperties += (davxml.AddMember.qname(),)
@@ -285,6 +297,11 @@
owner = (yield self.owner(request))
returnValue(davxml.Owner(owner))
+ elif qname == davxml.SyncToken.qname() and config.EnableSyncReport and (
+ self.isPseudoCalendarCollection() or self.isAddressBookCollection()
+ ):
+ returnValue(davxml.SyncToken.fromString(self.getSyncToken()))
+
elif qname == davxml.AddMember.qname() and config.EnableAddMember and (
self.isCalendarCollection() or self.isAddressBookCollection()
):
@@ -331,6 +348,15 @@
opaque = url in fbset
self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque() if opaque else caldavxml.Transparent()))
+ elif qname == carddavxml.SupportedAddressData.qname():
+ # CardDAV, section 6.2.2
+ returnValue(carddavxml.SupportedAddressData(
+ carddavxml.AddressDataType(**{
+ "content-type": "text/vcard",
+ "version" : "3.0",
+ }),
+ ))
+
elif qname == customxml.Invite.qname():
result = (yield self.inviteProperty(request))
returnValue(result)
Modified: CalendarServer/trunk/twistedcaldav/static.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/static.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/twistedcaldav/static.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -38,6 +38,7 @@
"AddressBookHomeUIDProvisioningFile",
"AddressBookHomeFile",
"DirectoryBackedAddressBookFile",
+ "GLobalAddressBookFile",
]
import datetime
@@ -73,6 +74,7 @@
from twistedcaldav.customxml import TwistedCalendarAccessProperty, TwistedScheduleMatchETags
from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
from twistedcaldav.extensions import DAVFile, CachingPropertyStore
+from twistedcaldav.linkresource import LinkResource, LinkFollowerMixIn
from twistedcaldav.memcachelock import MemcacheLock, MemcacheLockTimeoutError
from twistedcaldav.memcacheprops import MemcachePropertyCollection
from twistedcaldav.freebusyurl import FreeBusyURLResource
@@ -85,7 +87,8 @@
from twistedcaldav.datafilters.privateevents import PrivateEventFilter
from twistedcaldav.dropbox import DropBoxHomeResource, DropBoxCollectionResource
from twistedcaldav.directorybackedaddressbook import DirectoryBackedAddressBookResource
-from twistedcaldav.directory.addressbook import uidsResourceName as uidsResourceNameAddressBook
+from twistedcaldav.directory.addressbook import uidsResourceName as uidsResourceNameAddressBook,\
+ GlobalAddressBookResource
from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeProvisioningResource
from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeTypeProvisioningResource
from twistedcaldav.directory.addressbook import DirectoryAddressBookHomeUIDProvisioningResource
@@ -107,7 +110,21 @@
log = Logger()
-class CalDAVFile (CalDAVResource, DAVFile):
+class ReadOnlyResourceMixIn(object):
+
+ def http_PUT (self, request): return responsecode.FORBIDDEN
+ def http_COPY (self, request): return responsecode.FORBIDDEN
+ def http_MOVE (self, request): return responsecode.FORBIDDEN
+ def http_DELETE (self, request): return responsecode.FORBIDDEN
+ def http_MKCOL (self, request): return responsecode.FORBIDDEN
+
+ def http_MKCALENDAR(self, request):
+ return ErrorResponse(
+ responsecode.FORBIDDEN,
+ (caldav_namespace, "calendar-collection-location-ok")
+ )
+
+class CalDAVFile (LinkFollowerMixIn, CalDAVResource, DAVFile):
"""
CalDAV-accessible L{DAVFile} resource.
"""
@@ -555,6 +572,14 @@
except:
return fail(Failure())
+ def getSyncToken(self):
+ """
+ Return current sync-token value.
+ """
+ assert self.isCollection()
+
+ return str(self.readDeadProperty(customxml.GETCTag))
+
def updateCTag(self, token=None):
assert self.isCollection()
@@ -738,7 +763,7 @@
if test(parent):
returnValue(parent)
-class AutoProvisioningFileMixIn (AutoProvisioningResourceMixIn):
+class AutoProvisioningFileMixIn (LinkFollowerMixIn, AutoProvisioningResourceMixIn):
def provision(self):
self.provisionFile()
return super(AutoProvisioningFileMixIn, self).provision()
@@ -1050,7 +1075,7 @@
return super(CalendarHomeFile, self).readProperty(property, request)
-class ScheduleFile (AutoProvisioningFileMixIn, CalDAVFile):
+class ScheduleFile (ReadOnlyResourceMixIn, AutoProvisioningFileMixIn, CalDAVFile):
def __init__(self, path, parent):
super(ScheduleFile, self).__init__(path, principalCollections=parent.principalCollections())
@@ -1072,17 +1097,6 @@
"""
return IndexSchedule(self)
- def http_COPY (self, request): return responsecode.FORBIDDEN
- def http_MOVE (self, request): return responsecode.FORBIDDEN
- def http_DELETE (self, request): return responsecode.FORBIDDEN
- def http_MKCOL (self, request): return responsecode.FORBIDDEN
-
- def http_MKCALENDAR(self, request):
- return ErrorResponse(
- responsecode.FORBIDDEN,
- (caldav_namespace, "calendar-collection-location-ok")
- )
-
class ScheduleInboxFile (ScheduleInboxResource, ScheduleFile):
"""
Calendar scheduling inbox collection resource.
@@ -1136,7 +1150,7 @@
def supportedPrivileges(self, request):
return succeed(sendSchedulePrivilegeSet)
-class IScheduleInboxFile (IScheduleInboxResource, CalDAVFile):
+class IScheduleInboxFile (ReadOnlyResourceMixIn, IScheduleInboxResource, CalDAVFile):
"""
Server-to-server scheduling inbox resource.
"""
@@ -1156,18 +1170,6 @@
else:
return responsecode.NOT_FOUND
- def http_PUT (self, request): return responsecode.FORBIDDEN
- def http_COPY (self, request): return responsecode.FORBIDDEN
- def http_MOVE (self, request): return responsecode.FORBIDDEN
- def http_DELETE (self, request): return responsecode.FORBIDDEN
- def http_MKCOL (self, request): return responsecode.FORBIDDEN
-
- def http_MKCALENDAR(self, request):
- return ErrorResponse(
- responsecode.FORBIDDEN,
- (caldav_namespace, "calendar-collection-location-ok")
- )
-
def deadProperties(self):
if not hasattr(self, "_dead_properties"):
self._dead_properties = NonePropertyStore(self)
@@ -1188,7 +1190,7 @@
-class FreeBusyURLFile (AutoProvisioningFileMixIn, FreeBusyURLResource, CalDAVFile):
+class FreeBusyURLFile (ReadOnlyResourceMixIn, AutoProvisioningFileMixIn, FreeBusyURLResource, CalDAVFile):
"""
Free-busy URL resource.
"""
@@ -1208,18 +1210,6 @@
else:
return responsecode.NOT_FOUND
- def http_PUT (self, request): return responsecode.FORBIDDEN
- def http_COPY (self, request): return responsecode.FORBIDDEN
- def http_MOVE (self, request): return responsecode.FORBIDDEN
- def http_DELETE (self, request): return responsecode.FORBIDDEN
- def http_MKCOL (self, request): return responsecode.FORBIDDEN
-
- def http_MKCALENDAR(self, request):
- return ErrorResponse(
- responsecode.FORBIDDEN,
- (caldav_namespace, "calendar-collection-location-ok")
- )
-
##
# ACL
##
@@ -1268,7 +1258,7 @@
else:
return responsecode.NOT_FOUND
-class TimezoneServiceFile (TimezoneServiceResource, CalDAVFile):
+class TimezoneServiceFile (ReadOnlyResourceMixIn, TimezoneServiceResource, CalDAVFile):
def __init__(self, path, parent):
CalDAVFile.__init__(self, path, principalCollections=parent.principalCollections())
TimezoneServiceResource.__init__(self, parent)
@@ -1281,18 +1271,6 @@
else:
return responsecode.NOT_FOUND
- def http_PUT (self, request): return responsecode.FORBIDDEN
- def http_COPY (self, request): return responsecode.FORBIDDEN
- def http_MOVE (self, request): return responsecode.FORBIDDEN
- def http_DELETE (self, request): return responsecode.FORBIDDEN
- def http_MKCOL (self, request): return responsecode.FORBIDDEN
-
- def http_MKCALENDAR(self, request):
- return ErrorResponse(
- responsecode.FORBIDDEN,
- (caldav_namespace, "calendar-collection-location-ok")
- )
-
def deadProperties(self):
if not hasattr(self, "_dead_properties"):
self._dead_properties = NonePropertyStore(self)
@@ -1307,7 +1285,7 @@
def checkPrivileges(self, request, privileges, recurse=False, principal=None, inherited_aces=None):
return succeed(None)
-class NotificationCollectionFile(AutoProvisioningFileMixIn, NotificationCollectionResource, CalDAVFile):
+class NotificationCollectionFile(ReadOnlyResourceMixIn, AutoProvisioningFileMixIn, NotificationCollectionResource, CalDAVFile):
"""
Notification collection resource.
"""
@@ -1492,6 +1470,21 @@
CalDAVFile.__init__(self, path)
DirectoryAddressBookHomeResource.__init__(self, parent, record)
+ def provision(self):
+ result = super(AddressBookHomeFile, self).provision()
+ self.provisionLinks()
+ return result
+
+ def provisionLinks(self):
+
+ if not hasattr(self, "_provisionedLinks"):
+ if config.GlobalAddressBook.Enabled:
+ self.putChild(
+ config.GlobalAddressBook.Name,
+ LinkResource(self, joinURL("/", config.GlobalAddressBook.Name, "/")),
+ )
+ self._provisionedLinks = True
+
def provisionChild(self, name):
if config.Sharing.Enabled:
@@ -1578,7 +1571,7 @@
return super(AddressBookHomeFile, self).readProperty(property, request)
-class DirectoryBackedAddressBookFile (DirectoryBackedAddressBookResource, CalDAVFile):
+class DirectoryBackedAddressBookFile (ReadOnlyResourceMixIn, DirectoryBackedAddressBookResource, CalDAVFile):
"""
Directory-backed address book, supporting directory vcard search.
"""
@@ -1617,6 +1610,22 @@
).getChild(name)
+class GlobalAddressBookFile (ReadOnlyResourceMixIn, GlobalAddressBookResource, CalDAVFile):
+ """
+ Directory-backed address book, supporting directory vcard search.
+ """
+ def __init__(self, path, principalCollections):
+ CalDAVFile.__init__(self, path, principalCollections=principalCollections)
+ self.clientNotifier = ClientNotifier(self)
+
+ def createSimilarFile(self, path):
+ if self.comparePath(path):
+ return self
+ else:
+ similar = CalDAVFile(path, principalCollections=self.principalCollections())
+ similar.clientNotifier = self.clientNotifier
+ return similar
+
##
# Utilities
##
Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -349,6 +349,12 @@
},
"AnonymousDirectoryAddressBookAccess": False, # Anonymous users may access directory address book
+ "GlobalAddressBook": {
+ "Enabled": True,
+ "Name": "global-addressbook",
+ "EnableAnonymousReadAccess": False,
+ },
+
"MaxAddressBookQueryResults":1000,
"MaxAddressBookMultigetHrefs":5000,
Modified: CalendarServer/trunk/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_sharing.py 2010-04-15 20:58:40 UTC (rev 5481)
+++ CalendarServer/trunk/twistedcaldav/test/test_sharing.py 2010-04-15 21:03:20 UTC (rev 5482)
@@ -102,7 +102,7 @@
yield self.resource.upgradeToShare(request)
rtype = (yield self.resource.resourceType(request))
- self.assertEquals(rtype, davxml.ResourceType.sharedcalendar)
+ self.assertEquals(rtype, davxml.ResourceType.sharedownercalendar)
propInvite = (yield self.resource.readProperty(customxml.Invite, request))
self.assertEquals(propInvite, customxml.Invite())
@@ -123,7 +123,7 @@
yield self.resource.upgradeToShare(request)
rtype = (yield self.resource.resourceType(request))
- self.assertEquals(rtype, davxml.ResourceType.sharedcalendar)
+ self.assertEquals(rtype, davxml.ResourceType.sharedownercalendar)
propInvite = (yield self.resource.readProperty(customxml.Invite, request))
self.assertEquals(propInvite, customxml.Invite())
@@ -136,10 +136,10 @@
def test_downgradeFromShare(self):
request = SimpleRequest(self.site, "PROPPATCH", "/calendar/")
- self.resource.writeDeadProperty(davxml.ResourceType.sharedcalendar)
+ self.resource.writeDeadProperty(davxml.ResourceType.sharedownercalendar)
self.resource.writeDeadProperty(customxml.Invite())
rtype = (yield self.resource.resourceType(request))
- self.assertEquals(rtype, davxml.ResourceType.sharedcalendar)
+ self.assertEquals(rtype, davxml.ResourceType.sharedownercalendar)
propInvite = (yield self.resource.readProperty(customxml.Invite, None))
self.assertEquals(propInvite, customxml.Invite())
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100415/d801297a/attachment-0001.html>
More information about the calendarserver-changes
mailing list