[CalendarServer-changes] [2563] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Mon Jun 16 17:25:11 PDT 2008
Revision: 2563
http://trac.macosforge.org/projects/calendarserver/changeset/2563
Author: wsanchez at apple.com
Date: 2008-06-16 17:25:09 -0700 (Mon, 16 Jun 2008)
Log Message:
-----------
/principals now has no on-disk presence.
Add EnablePrincipalListings option.
Modified Paths:
--------------
CalendarServer/trunk/conf/caldavd-test.plist
CalendarServer/trunk/conf/caldavd.plist
CalendarServer/trunk/twistedcaldav/config.py
CalendarServer/trunk/twistedcaldav/directory/calendar.py
CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/trunk/twistedcaldav/directory/principal.py
CalendarServer/trunk/twistedcaldav/directory/test/test_calendar.py
CalendarServer/trunk/twistedcaldav/directory/test/test_guidchange.py
CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py
CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipalmembers.py
CalendarServer/trunk/twistedcaldav/directory/util.py
CalendarServer/trunk/twistedcaldav/extensions.py
CalendarServer/trunk/twistedcaldav/tap.py
CalendarServer/trunk/twistedcaldav/test/test_root.py
CalendarServer/trunk/twistedcaldav/test/util.py
CalendarServer/trunk/twistedcaldav/util.py
Added Paths:
-----------
CalendarServer/trunk/lib-patches/Twisted/twisted.web2.static.patch
Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/conf/caldavd-test.plist 2008-06-17 00:25:09 UTC (rev 2563)
@@ -225,7 +225,7 @@
<key>Kerberos</key>
<dict>
<key>Enabled</key>
- <true/>
+ <false/>
<key>ServicePrincipal</key>
<string></string>
</dict>
@@ -253,6 +253,10 @@
<key>LogLevels</key>
<dict>
+<!--
+ <key>twistedcaldav.directory.appleopendirectory.OpenDirectoryService</key>
+ <string>debug</string>
+ -->
</dict>
<!-- Accounting -->
@@ -389,6 +393,10 @@
<key>ResponseCompression</key>
<false/>
+ <!-- Enables directory listings for principals -->
+ <key>EnablePrincipalListings</key>
+ <true/>
+
<!-- Support for Memcached -->
<key>Memcached</key>
<dict>
@@ -402,7 +410,7 @@
<string>../memcached-1.2.5/_root/bin/memcached</string>
<key>Options</key>
<array>
- <string>-vv</string>
+ <!--<string>-vv</string>-->
</array>
</dict>
Modified: CalendarServer/trunk/conf/caldavd.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd.plist 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/conf/caldavd.plist 2008-06-17 00:25:09 UTC (rev 2563)
@@ -254,6 +254,19 @@
<!--
+ Miscellaneous items
+ -->
+
+ <!-- Support for Content-Encoding compression options as specified in RFC2616 Section 3.5 -->
+ <key>ResponseCompression</key>
+ <false/>
+
+ <!-- Enables directory listings for principals -->
+ <key>EnablePrincipalListings</key>
+ <true/>
+
+
+ <!--
Non-standard CalDAV extensions
-->
Added: CalendarServer/trunk/lib-patches/Twisted/twisted.web2.static.patch
===================================================================
--- CalendarServer/trunk/lib-patches/Twisted/twisted.web2.static.patch (rev 0)
+++ CalendarServer/trunk/lib-patches/Twisted/twisted.web2.static.patch 2008-06-17 00:25:09 UTC (rev 2563)
@@ -0,0 +1,16 @@
+Index: twisted/web2/static.py
+===================================================================
+--- twisted/web2/static.py (revision 19773)
++++ twisted/web2/static.py (working copy)
+@@ -200,7 +200,10 @@
+ super(File, self).__init__()
+
+ self.putChildren = {}
+- self.fp = filepath.FilePath(path)
++ if isinstance(path, FilePath):
++ self.fp = path
++ else:
++ self.fp = filepath.FilePath(path)
+ # Remove the dots from the path to split
+ self.defaultType = defaultType
+ self.ignoredExts = list(ignoredExts)
Modified: CalendarServer/trunk/twistedcaldav/config.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/config.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/config.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -152,6 +152,11 @@
"EnableSACLs": False,
#
+ # Enables directory listings for principals
+ #
+ "EnablePrincipalListings": True,
+
+ #
# Non-standard CalDAV extensions
#
"EnableDropBox" : False, # Calendar Drop Box
@@ -189,7 +194,6 @@
# RFC2616 Section 3.5
"ResponseCompression": True,
-
# Set the maximum number of outstanding requests to this server.
"MaxRequests": 600,
Modified: CalendarServer/trunk/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/calendar.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/directory/calendar.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -154,11 +154,15 @@
return self._parent.homeForDirectoryRecord(record)
def listChildren(self):
- return (
- record.shortName
- for record in self.directory.listRecords(self.recordType)
- if record.enabledForCalendaring
- )
+ if config.EnablePrincipalListings:
+ return (
+ record.shortName
+ for record in self.directory.listRecords(self.recordType)
+ if record.enabledForCalendaring
+ )
+ else:
+ # Not a listable collection
+ raise HTTPError(responsecode.FORBIDDEN)
def createSimilarFile(self, path):
raise HTTPError(responsecode.NOT_FOUND)
Modified: CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -25,19 +25,20 @@
from twisted.internet.defer import returnValue
from twisted.internet.defer import succeed, inlineCallbacks
from twisted.web2 import responsecode
+from twisted.web2.http import HTTPError, StatusResponse
from twisted.web2.dav import davxml
from twisted.web2.dav.element.base import dav_namespace
from twisted.web2.dav.util import joinURL
-from twisted.web2.http import HTTPError, StatusResponse
+from twisted.web2.dav.noneprops import NonePropertyStore
from twistedcaldav.config import config
from twistedcaldav.extensions import DAVFile, DAVPrincipalResource
from twistedcaldav.extensions import ReadOnlyWritePropertiesResourceMixIn
from twistedcaldav.memcacher import Memcacher
from twistedcaldav.resource import CalDAVComplianceMixIn
+from twistedcaldav.directory.util import NotFilePath
from twistedcaldav.sql import AbstractSQLDatabase
from twistedcaldav.sql import db_prefix
-from twistedcaldav.static import AutoProvisioningFileMixIn
import itertools
import os
@@ -72,14 +73,12 @@
# Permissions here are fixed, and are not subject to inherritance rules, etc.
return succeed(self.defaultAccessControlList())
-class CalendarUserProxyPrincipalResource (CalDAVComplianceMixIn, AutoProvisioningFileMixIn, PermissionsMixIn, DAVPrincipalResource, DAVFile):
+class CalendarUserProxyPrincipalResource (CalDAVComplianceMixIn, PermissionsMixIn, DAVPrincipalResource, DAVFile):
"""
Calendar user proxy principal resource.
"""
-
- def __init__(self, path, parent, proxyType):
+ def __init__(self, parent, proxyType):
"""
- @param path: the path to the file which will back this resource.
@param parent: the parent of this resource.
@param proxyType: a C{str} containing the name of the resource.
"""
@@ -90,7 +89,7 @@
url = joinURL(parent.principalURL(), proxyType) + slash
- super(CalendarUserProxyPrincipalResource, self).__init__(path, url)
+ super(CalendarUserProxyPrincipalResource, self).__init__(NotFilePath(isdir=True), url)
self.parent = parent
self.proxyType = proxyType
@@ -111,10 +110,6 @@
if url.startswith("/")
)
- # Provision in __init__() because principals are used prior to request
- # lookups.
- self.provision()
-
def __str__(self):
return "%s [%s]" % (self.parent, self.proxyType)
@@ -127,7 +122,7 @@
# The db is located in the principal collection root
if not hasattr(self.pcollection, "calendar_user_proxy_db"):
- setattr(self.pcollection, "calendar_user_proxy_db", CalendarUserProxyDatabase(self.pcollection.fp.path))
+ setattr(self.pcollection, "calendar_user_proxy_db", CalendarUserProxyDatabase(config.DataRoot))
return self.pcollection.calendar_user_proxy_db
def resourceType(self):
@@ -141,6 +136,14 @@
def isCollection(self):
return True
+ def etag(self):
+ return None
+
+ def deadProperties(self):
+ if not hasattr(self, "_dead_properties"):
+ self._dead_properties = NonePropertyStore(self)
+ return self._dead_properties
+
def writeProperty(self, property, request):
assert isinstance(property, davxml.WebDAVElement)
@@ -332,7 +335,7 @@
"""
dbType = "CALENDARUSERPROXY"
- dbFilename = db_prefix + "calendaruserproxy"
+ dbFilename = "calendaruserproxy.sqlite"
dbFormatVersion = "4"
class ProxyDBMemcacher(Memcacher):
Modified: CalendarServer/trunk/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/principal.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/directory/principal.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -40,6 +40,7 @@
from twisted.web2.dav import davxml
from twisted.web2.dav.element.base import twisted_private_namespace
from twisted.web2.dav.util import joinURL
+from twisted.web2.dav.noneprops import NonePropertyStore
from twistedcaldav.config import config
from twistedcaldav.cache import DisabledCacheNotifier, PropfindCacheMixin
@@ -47,9 +48,9 @@
from twistedcaldav.directory.calendaruserproxy import CalendarUserProxyDatabase
from twistedcaldav.directory.calendaruserproxy import CalendarUserProxyPrincipalResource
from twistedcaldav.directory.directory import DirectoryService
+from twistedcaldav.directory.util import NotFilePath
from twistedcaldav.extensions import ReadOnlyResourceMixIn, DAVFile, DAVPrincipalResource
from twistedcaldav.resource import CalendarPrincipalCollectionResource, CalendarPrincipalResource
-from twistedcaldav.static import AutoProvisioningFileMixIn
from twistedcaldav.directory.idirectory import IDirectoryService
from twistedcaldav.log import Logger
@@ -70,25 +71,38 @@
# Permissions here are fixed, and are not subject to inherritance rules, etc.
return succeed(self.defaultAccessControlList())
+
class DirectoryProvisioningResource (
- AutoProvisioningFileMixIn,
PermissionsMixIn,
CalendarPrincipalCollectionResource,
DAVFile,
):
- def __init__(self, path, url, directory):
+ def __init__(self, url, directory):
"""
- @param path: the path to the file which will back the resource.
@param url: the canonical URL for the resource.
@param directory: an L{IDirectoryService} to provision principals from.
"""
assert url.endswith("/"), "Collection URL must end in '/'"
CalendarPrincipalCollectionResource.__init__(self, url)
- DAVFile.__init__(self, path)
+ DAVFile.__init__(self, NotFilePath(isdir=True))
self.directory = IDirectoryService(directory)
+ def locateChild(self, req, segments):
+ child = self.getChild(segments[0])
+ if child is not None:
+ return (child, segments[1:])
+ return (None, ())
+
+ def deadProperties(self):
+ if not hasattr(self, "_dead_properties"):
+ self._dead_properties = NonePropertyStore(self)
+ return self._dead_properties
+
+ def etag(self):
+ return None
+
def principalForShortName(self, recordType, name):
return self.principalForRecord(self.directory.recordWithShortName(recordType, name))
@@ -113,8 +127,8 @@
"""
Collection resource which provisions directory principals as its children.
"""
- def __init__(self, path, url, directory):
- DirectoryProvisioningResource.__init__(self, path, url, directory)
+ def __init__(self, url, directory):
+ DirectoryProvisioningResource.__init__(self, url, directory)
# FIXME: Smells like a hack
self.directory.principalCollection = self
@@ -205,8 +219,6 @@
raise HTTPError(responsecode.NOT_FOUND)
def getChild(self, name):
- self.provision()
-
if name == "":
return self
else:
@@ -229,13 +241,11 @@
"""
def __init__(self, parent, recordType):
"""
- @param path: the path to the file which will back the resource.
@param parent: the parent L{DirectoryPrincipalProvisioningResource}.
@param recordType: the directory record type to provision.
"""
DirectoryProvisioningResource.__init__(
self,
- parent.fp.child(recordType).path,
joinURL(parent.principalCollectionURL(), recordType) + "/",
parent.directory
)
@@ -258,14 +268,17 @@
raise HTTPError(responsecode.NOT_FOUND)
def getChild(self, name):
- self.provision()
if name == "":
return self
else:
return self.principalForShortName(self.recordType, name)
def listChildren(self):
- return (record.shortName for record in self.directory.listRecords(self.recordType))
+ if config.EnablePrincipalListings:
+ return (record.shortName for record in self.directory.listRecords(self.recordType))
+ else:
+ # Not a listable collection
+ raise HTTPError(responsecode.FORBIDDEN)
##
# ACL
@@ -279,16 +292,13 @@
Collection resource which provisions directory principals indexed
by UID.
"""
- # FIXME: Remove path argument
def __init__(self, parent):
"""
- @param path: the path to the file which will back the resource.
@param directory: an L{IDirectoryService} to provision calendars from.
@param recordType: the directory record type to provision.
"""
DirectoryProvisioningResource.__init__(
self,
- parent.fp.child(uidsResourceName).path,
joinURL(parent.principalCollectionURL(), uidsResourceName) + "/",
parent.directory
)
@@ -310,8 +320,6 @@
raise HTTPError(responsecode.NOT_FOUND)
def getChild(self, name):
- self.provision()
-
if name == "":
return self
@@ -328,13 +336,10 @@
log.err("No principal found for UID: %s" % (name,))
return None
- assert len(name) > 4
- childPath = self.fp.child(name[0:2]).child(name[2:4]).child(name)
-
if record.enabledForCalendaring:
- primaryPrincipal = DirectoryCalendarPrincipalResource(childPath.path, self, record)
+ primaryPrincipal = DirectoryCalendarPrincipalResource(self, record)
else:
- primaryPrincipal = DirectoryPrincipalResource(childPath.path, self, record)
+ primaryPrincipal = DirectoryPrincipalResource(self, record)
if subType is None:
return primaryPrincipal
@@ -352,19 +357,18 @@
def principalCollections(self):
return self.parent.principalCollections()
-class DirectoryPrincipalResource (PropfindCacheMixin, AutoProvisioningFileMixIn, PermissionsMixIn, DAVPrincipalResource, DAVFile):
+class DirectoryPrincipalResource (PropfindCacheMixin, PermissionsMixIn, DAVPrincipalResource, DAVFile):
"""
Directory principal resource.
"""
cacheNotifierFactory = DisabledCacheNotifier
- def __init__(self, path, parent, record):
+ def __init__(self, parent, record):
"""
- @param path: them path to the file which will back this resource.
@param parent: the parent of this resource.
@param record: the L{IDirectoryRecord} that this resource represents.
"""
- super(DirectoryPrincipalResource, self).__init__(path)
+ super(DirectoryPrincipalResource, self).__init__(NotFilePath(isdir=True))
self.cacheNotifier = self.cacheNotifierFactory(self)
@@ -373,7 +377,7 @@
else:
slash = ""
- assert record is not None, "Principal must have a directory record: %s" % (path,)
+ assert record is not None, "Principal must have a directory record"
url = joinURL(parent.principalCollectionURL(), record.guid) + slash
@@ -385,10 +389,6 @@
joinURL(parent.parent.principalCollectionURL(), record.recordType, record.shortName) + slash,
)
- # Provision in __init__() because principals are used prior to request
- # lookups.
- self.provision()
-
def __str__(self):
return "(%s) %s" % (self.record.recordType, self.record.shortName)
@@ -399,6 +399,14 @@
self.writeDeadProperty(RecordTypeProperty(self.record.recordType))
return result
+ def deadProperties(self):
+ if not hasattr(self, "_dead_properties"):
+ self._dead_properties = NonePropertyStore(self)
+ return self._dead_properties
+
+ def etag(self):
+ return None
+
##
# HTTP
##
@@ -471,7 +479,7 @@
# The db is located in the principal collection root
if not hasattr(pcollection, "calendar_user_proxy_db"):
- setattr(pcollection, "calendar_user_proxy_db", CalendarUserProxyDatabase(pcollection.fp.path))
+ setattr(pcollection, "calendar_user_proxy_db", CalendarUserProxyDatabase(config.DataRoot))
return pcollection.calendar_user_proxy_db
def alternateURIs(self):
@@ -538,7 +546,6 @@
yield groups
-
def principalCollections(self):
return self.parent.principalCollections()
@@ -563,8 +570,6 @@
return ()
-
-
class DirectoryCalendarPrincipalResource (DirectoryPrincipalResource, CalendarPrincipalResource):
"""
Directory calendar principal resource.
@@ -698,7 +703,7 @@
return self
if config.EnableProxyPrincipals and name in ("calendar-proxy-read", "calendar-proxy-write"):
- return CalendarUserProxyPrincipalResource(self.fp.child(name).path, self, name)
+ return CalendarUserProxyPrincipalResource(self, name)
else:
return None
Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_calendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_calendar.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_calendar.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -44,14 +44,9 @@
# Set up a principals hierarchy for each service we're testing with
name = "principals"
url = "/" + name + "/"
- path = os.path.join(self.docroot, url[1:])
- if os.path.exists(path):
- rmdir(path)
- os.mkdir(path)
+ provisioningResource = DirectoryPrincipalProvisioningResource(url, self.directoryService)
- provisioningResource = DirectoryPrincipalProvisioningResource(path, url, self.directoryService)
-
self.site.resource.putChild("principals", provisioningResource)
self.setupCalendars()
Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_guidchange.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_guidchange.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_guidchange.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -47,14 +47,9 @@
# Set up a principals hierarchy for each service we're testing with
name = "principals"
url = "/" + name + "/"
- path = os.path.join(self.docroot, url[1:])
- if os.path.exists(path):
- rmdir(path)
- os.mkdir(path)
+ provisioningResource = DirectoryPrincipalProvisioningResource(url, self.directoryService)
- provisioningResource = DirectoryPrincipalProvisioningResource(path, url, self.directoryService)
-
self.site.resource.putChild("principals", provisioningResource)
self.setupCalendars()
Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_principal.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -56,14 +56,9 @@
for directory in directoryServices:
name = directory.__class__.__name__
url = "/" + name + "/"
- path = os.path.join(self.docroot, url[1:])
- if os.path.exists(path):
- rmdir(path)
- os.mkdir(path)
+ provisioningResource = DirectoryPrincipalProvisioningResource(url, directory)
- provisioningResource = DirectoryPrincipalProvisioningResource(path, url, directory)
-
self.site.resource.putChild(name, provisioningResource)
self.principalRootResources[directory.__class__.__name__] = provisioningResource
Modified: CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipalmembers.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipalmembers.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/directory/test/test_proxyprincipalmembers.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -41,14 +41,9 @@
self.principalRootResources = {}
name = directoryService.__class__.__name__
url = "/" + name + "/"
- path = os.path.join(self.docroot, url[1:])
- if os.path.exists(path):
- rmdir(path)
- os.mkdir(path)
+ provisioningResource = DirectoryPrincipalProvisioningResource(url, directoryService)
- provisioningResource = DirectoryPrincipalProvisioningResource(path, url, directoryService)
-
self.site.resource.putChild(name, provisioningResource)
self.principalRootResources[directoryService.__class__.__name__] = provisioningResource
@@ -240,8 +235,7 @@
def changed(self):
self.changedCount += 1
- user = self._getPrincipalByShortName(directoryService.recordType_users,
- "cdaboo")
+ user = self._getPrincipalByShortName(directoryService.recordType_users, "cdaboo")
proxyGroup = user.getChild("calendar-proxy-write")
Modified: CalendarServer/trunk/twistedcaldav/directory/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/util.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/directory/util.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -62,3 +62,144 @@
# Convert from long integer to string representation
uuid = "%032x" % (uuid,)
return "%s-%s-%s-%s-%s" % (uuid[:8], uuid[8:12], uuid[12:16], uuid[16:20], uuid[20:])
+
+import errno
+import time
+from twisted.python.filepath import FilePath
+
+class NotFilePath(FilePath):
+ """
+ Dummy placeholder for FilePath for when we don't actually want a file.
+ Pretends to be an empty file or directory.
+ """
+ def __init__(self, isfile=False, isdir=False, islink=False):
+ assert isfile or isdir or islink
+
+ self._isfile = isfile
+ self._isdir = isdir
+ self._islink = islink
+
+ self._time = time.time()
+
+ def __cmp__(self, other):
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+ return cmp(
+ ( self.isdir(), self.isfile(), self.islink()),
+ (other.isdir(), other.isfile(), other.islink()),
+ )
+
+ def __repr__(self):
+ types = []
+ if self.isdir():
+ types.append("dir")
+ if self.isfile():
+ types.append("file")
+ if self.islink():
+ types.append("link")
+ if types:
+ return "<%s (%s)>" % (self.__class__.__name__, ",".join(types))
+ else:
+ return "<%s>" % (self.__class__.__name__,)
+
+ def _unimplemented(self, *args):
+ try:
+ raise NotImplementedError("NotFilePath isn't really a FilePath: psych!")
+ except NotImplementedError:
+ from twisted.python.failure import Failure
+ Failure().printTraceback()
+ raise
+
+ child = _unimplemented
+ preauthChild = _unimplemented
+ siblingExtensionSearch = _unimplemented
+ siblingExtension = _unimplemented
+ open = _unimplemented
+ clonePath = _unimplemented # Cuz I think it's dumb
+
+ def childSearchPreauth(self, *paths):
+ return ()
+
+ def splitext(self):
+ return ("", "")
+
+ def basename(self):
+ return ""
+
+ def dirname(self):
+ return ""
+
+ def restat(self, reraise=True):
+ pass
+
+ def getsize(self):
+ return 0
+
+ def _time(self):
+ return self._time
+
+ # FIXME: Maybe we should have separate ctime, mtime, atime. Meh.
+ getModificationTime = _time
+ getStatusChangeTime = _time
+ getAccessTime = _time
+
+ def exists(self):
+ return True
+
+ def isdir(self):
+ return self._isdir
+
+ def isfile(self):
+ return self._isfile
+
+ def islink(self):
+ return self._islink
+
+ def isabs(self):
+ return True
+
+ def listdir(self):
+ return ()
+
+ def touch(self):
+ self._time = time.time()
+
+ def _notAllowed(self):
+ raise OSError(errno.EACCES, "Permission denied")
+
+ remove = _notAllowed
+ setContent = _notAllowed
+
+ def globChildren(self, pattern):
+ return ()
+
+ def parent(self):
+ return self.__class__(isdir=True)
+
+ def createDirectory(self):
+ if self.isdir():
+ raise OSError(errno.EEXIST, "File exists")
+ else:
+ return self._notAllowed
+
+ makedirs = createDirectory
+
+ def create(self):
+ if self.isfile():
+ raise OSError(errno.EEXIST, "File exists")
+ else:
+ return self._notAllowed
+
+ def temporarySibling(self):
+ return self.__class__(isfile=True)
+
+ def copyTo(self, destination):
+ if self.isdir():
+ if not destination.isdir():
+ destination.createDirectory()
+ elif self.isfile():
+ destination.open("w").close()
+ else:
+ raise NotImplementedError()
+
+ moveTo = _notAllowed
Modified: CalendarServer/trunk/twistedcaldav/extensions.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/extensions.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/extensions.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -50,7 +50,7 @@
from twisted.web2.dav.xattrprops import xattrPropertyStore
from twistedcaldav.log import Logger, LoggingMixIn
-from twistedcaldav.util import submodule, Alternator
+from twistedcaldav.util import submodule, Alternator, printTracebacks
from twistedcaldav.directory.sudo import SudoDirectoryService
from twistedcaldav.directory.directory import DirectoryService
@@ -560,6 +560,7 @@
d.addCallback(gotBody)
return d
+ @printTracebacks
def renderDirectoryBody(self, request):
"""
Generate a directory listing table in HTML.
@@ -606,10 +607,13 @@
def gotProperties(qnames):
ds = []
+ noneValue = object()
+ accessDeniedValue = object()
+
def gotProperty(property):
if property is None:
name = "{%s}%s" % qname
- value = "** None **"
+ value = noneValue
else:
name = property.sname()
value = property.toxml()
@@ -628,7 +632,7 @@
return (name, None)
if code == responsecode.UNAUTHORIZED:
- return (name, "(access forbidden)")
+ return (name, accessDeniedValue)
return f
@@ -641,19 +645,34 @@
even = Alternator()
def gotValues(items):
- output.append("".join(
- """<tr class="%(even)s">"""
- """<td valign="top">%(name)s</td>"""
- """<td><pre>%(value)s</pre></td>"""
- """</tr>"""
- % {
- "even": even.state() and "even" or "odd",
- "name": name,
- "value": cgi.escape(value),
- }
- for result, (name, value) in items
- if result and value is not None
- ))
+ for result, (name, value) in items:
+ if not result:
+ continue
+
+ if value is None:
+ # An AssertionError might be appropriate, but
+ # we may as well continue rendering.
+ log.err("Unexpected None value for property: %s" % (name,))
+ continue
+ elif value is noneValue:
+ value = "<i>(no value)</i>"
+ elif value is accessDeniedValue:
+ value = "<i>(access forbidden)</i>"
+ else:
+ value = cgi.escape(value)
+
+ output.append(
+ """<tr class="%(even)s">"""
+ """<td valign="top">%(name)s</td>"""
+ """<td><pre>%(value)s</pre></td>"""
+ """</tr>"""
+ % {
+ "even": even.state() and "even" or "odd",
+ "name": name,
+ "value": value,
+ }
+ )
+
output.append("</div>")
return "".join(output)
Modified: CalendarServer/trunk/twistedcaldav/tap.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/tap.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/tap.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -499,10 +499,7 @@
log.info("Setting up document root at: %s" % (config.DocumentRoot,))
log.info("Setting up principal collection: %r" % (self.principalResourceClass,))
- principalCollection = self.principalResourceClass(
- os.path.join(config.DocumentRoot, "principals"),
- "/principals/", directory
- )
+ principalCollection = self.principalResourceClass("/principals/", directory)
log.info("Setting up calendar collection: %r" % (self.calendarResourceClass,))
Modified: CalendarServer/trunk/twistedcaldav/test/test_root.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_root.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/test/test_root.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -53,24 +53,17 @@
class RootTests(TestCase):
def setUp(self):
self.docroot = self.mktemp()
+ os.mkdir(self.docroot)
RootResource.CheckSACL = FakeCheckSACL(sacls={
'calendar': ['dreid']})
directory = XMLDirectoryService(xmlFile)
- principals = DirectoryPrincipalProvisioningResource(
- os.path.join(self.docroot, 'principals'),
- '/principals/',
- directory)
+ principals = DirectoryPrincipalProvisioningResource('/principals/', directory)
- # Otherwise the tests that never touch the root resource will
- # fail on teardown.
- principals.provision()
+ root = RootResource(self.docroot, principalCollections=[principals])
- root = RootResource(self.docroot,
- principalCollections=[principals])
-
root.putChild('principals',
principals)
@@ -103,9 +96,9 @@
resrc, segments = resrc.locateChild(request, ['principals'])
self.failUnless(
- isinstance(resrc,
- DirectoryPrincipalProvisioningResource),
- "Did not get a DirectoryPrincipalProvisioningResource: %s" % (resrc,))
+ isinstance(resrc, DirectoryPrincipalProvisioningResource),
+ "Did not get a DirectoryPrincipalProvisioningResource: %s" % (resrc,)
+ )
self.assertEquals(segments, [])
@@ -131,9 +124,9 @@
def _Cb((resrc, segments)):
self.failUnless(
- isinstance(resrc,
- DirectoryPrincipalProvisioningResource),
- "Did not get a DirectoryPrincipalProvisioningResource: %s" % (resrc,))
+ isinstance(resrc, DirectoryPrincipalProvisioningResource),
+ "Did not get a DirectoryPrincipalProvisioningResource: %s" % (resrc,)
+ )
self.assertEquals(segments, [])
@@ -163,8 +156,7 @@
'Authorization': ['basic', '%s' % (
'wsanchez:zehcnasw'.encode('base64'),)]}))
- resrc, segments = self.root.locateChild(request,
- ['principals'])
+ resrc, segments = self.root.locateChild(request, ['principals'])
def _Eb(failure):
failure.trap(HTTPError)
Modified: CalendarServer/trunk/twistedcaldav/test/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/util.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/test/util.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -14,18 +14,28 @@
# limitations under the License.
##
-import twisted.web2.dav.test.util
-from twisted.web2.http import HTTPError, StatusResponse
+import os
from twisted.internet.defer import succeed
+from twisted.web2.http import HTTPError, StatusResponse
+from twistedcaldav.config import config
from twistedcaldav.static import CalDAVFile
+import twisted.web2.dav.test.util
+
class TestCase(twisted.web2.dav.test.util.TestCase):
resource_class = CalDAVFile
+ def setUp(self):
+ super(TestCase, self).setUp()
+ dataroot = self.mktemp()
+ os.mkdir(dataroot)
+ config.DataRoot = dataroot
+
+
class InMemoryPropertyStore(object):
def __init__(self):
class _FauxPath(object):
Modified: CalendarServer/trunk/twistedcaldav/util.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/util.py 2008-06-16 21:41:40 UTC (rev 2562)
+++ CalendarServer/trunk/twistedcaldav/util.py 2008-06-17 00:25:09 UTC (rev 2563)
@@ -59,7 +59,7 @@
raise NotImplementedError("getNCPU not supported on %s%s" % (sys.platform, msg))
##
-#
+# Module management
##
def submodule(module, name):
@@ -75,6 +75,25 @@
return submodule
+##
+# Tracebacks
+##
+
+from twisted.python.failure import Failure
+
+def printTracebacks(f):
+ def wrapper(*args, **kwargs):
+ try:
+ return f(*args, **kwargs)
+ except:
+ Failure().printTraceback()
+ raise
+ return wrapper
+
+##
+# Helpers
+##
+
class Alternator (object):
"""
Object that alternates between True and False states.
@@ -89,4 +108,3 @@
state = self._state
self._state = not state
return state
-
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080616/c02c530a/attachment-0001.htm
More information about the calendarserver-changes
mailing list