[CalendarServer-changes] [623]
CalendarServer/branches/users/wsanchez/provisioning-2
source_changes at macosforge.org
source_changes at macosforge.org
Thu Nov 30 15:08:21 PST 2006
Revision: 623
http://trac.macosforge.org/projects/calendarserver/changeset/623
Author: wsanchez at apple.com
Date: 2006-11-30 15:08:20 -0800 (Thu, 30 Nov 2006)
Log Message:
-----------
Clean up principal collections API some more.
Modified Paths:
--------------
CalendarServer/branches/users/wsanchez/provisioning-2/conf/repository.xml
CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.idav.patch
CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.resource.patch
CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.static.patch
CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch
CalendarServer/branches/users/wsanchez/provisioning-2/support/CalendarServer.tmproj
CalendarServer/branches/users/wsanchez/provisioning-2/support/patchmaker.py
CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/directory/principal.py
CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/directory/test/test_principal.py
CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/resource.py
CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/static.py
CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/test/test_mkcalendar.py
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/conf/repository.xml
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/conf/repository.xml 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/conf/repository.xml 2006-11-30 23:08:20 UTC (rev 623)
@@ -26,7 +26,7 @@
<properties>
<acl>
<ace>
- <principal><authenticated/></principal>
+ <principal><all/></principal>
<grant><privilege><read/></privilege></grant>
</ace>
<ace>
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.idav.patch
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.idav.patch 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.idav.patch 2006-11-30 23:08:20 UTC (rev 623)
@@ -20,7 +20,26 @@
@return: An L{Deferred} that fires when all the children have been found
"""
-@@ -180,6 +182,80 @@
+@@ -125,15 +127,10 @@
+ L{responsecode.UNAUTHORIZED}) if not authorized.
+ """
+
+- def principalCollections(request):
++ def principalCollections():
+ """
+- Provides the DAV:HRef's of collection resources which contain principal
+- resources which may be used in access control entries on this resource.
+- (RFC 3744, section 5.8)
+- @param request: the request being processed.
+- @return: a deferred sequence of L{davxml.HRef}s referring to
+- collection resources which implement the
+- C{DAV:principal-property-search} C{REPORT}.
++ @return: an interable of L{IDAVPrincipalCollectionResource}s which
++ contain principals used in ACLs for this resource.
+ """
+
+ def setAccessControlList(acl):
+@@ -180,6 +177,80 @@
the specified principal.
"""
@@ -101,3 +120,18 @@
class IDAVPrincipalResource (IDAVResource):
"""
WebDAV principal resource. (RFC 3744, section 2)
+@@ -212,3 +283,14 @@
+ directly a member. (RFC 3744, section 4.4)
+ @return: a iterable of group principal URLs.
+ """
++
++class IDAVPrincipalCollectionResource (IDAVResource):
++ """
++ WebDAV principal collection resource. (RFC 3744, section 5.8)
++ """
++ def principalCollectionURL():
++ """
++ Provides a URL for this resource which may be used to identify this
++ resource in ACL requests. (RFC 3744, section 5.8)
++ @return: a URL.
++ """
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.resource.patch
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.resource.patch 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.resource.patch 2006-11-30 23:08:20 UTC (rev 623)
@@ -2,8 +2,18 @@
===================================================================
--- twisted/web2/dav/resource.py (revision 18545)
+++ twisted/web2/dav/resource.py (working copy)
-@@ -44,6 +44,8 @@
+@@ -40,10 +40,18 @@
+ "unauthenticatedPrincipal",
+ ]
++import __builtin__
++if not hasattr(__builtin__, "set"):
++ import sets.Set as set
++if not hasattr(__builtin__, "frozenset"):
++ import sets.ImmutableSet as frozenset
++
+ import urllib
+
from zope.interface import implements
from twisted.python import log
+from twisted.python.failure import Failure
@@ -11,7 +21,16 @@
from twisted.internet.defer import Deferred, maybeDeferred, succeed
from twisted.internet.defer import waitForDeferred, deferredGenerator
from twisted.internet import reactor
-@@ -130,6 +132,8 @@
+@@ -57,7 +65,7 @@
+ from twisted.web2.dav import davxml
+ from twisted.web2.dav.davxml import dav_namespace, lookupElement
+ from twisted.web2.dav.davxml import twisted_dav_namespace, twisted_private_namespace
+-from twisted.web2.dav.idav import IDAVResource, IDAVPrincipalResource
++from twisted.web2.dav.idav import IDAVResource, IDAVPrincipalResource, IDAVPrincipalCollectionResource
+ from twisted.web2.dav.http import NeedPrivilegesResponse
+ from twisted.web2.dav.noneprops import NonePropertyStore
+ from twisted.web2.dav.util import unimplemented, parentForURL, joinURL
+@@ -130,6 +138,8 @@
(dav_namespace, "acl-restrictions" ), # RFC 3744, section 5.6
(dav_namespace, "inherited-acl-set" ), # RFC 3744, section 5.7
(dav_namespace, "principal-collection-set" ), # RFC 3744, section 5.8
@@ -20,7 +39,7 @@
(twisted_dav_namespace, "resource-class"),
)
-@@ -166,6 +170,14 @@
+@@ -166,6 +176,14 @@
if qname[0] == twisted_private_namespace:
return succeed(False)
@@ -35,16 +54,34 @@
return succeed(qname in self.liveProperties or self.deadProperties().contains(qname))
def readProperty(self, property, request):
-@@ -253,7 +265,7 @@
+@@ -239,8 +257,10 @@
+ )
+ if name == "supported-report-set":
+- supported = [davxml.SupportedReport(report,) for report in self.supportedReports()]
+- return davxml.SupportedReportSet(*supported)
++ return davxml.SupportedReportSet(*[
++ davxml.SupportedReport(report,)
++ for report in self.supportedReports()
++ ])
+
+ if name == "supported-privilege-set":
+ return self.supportedPrivileges(request)
+@@ -252,9 +272,10 @@
+ return davxml.InheritedACLSet(*self.inheritedACLSet())
+
if name == "principal-collection-set":
- d = self.principalCollections(request)
+- d = self.principalCollections(request)
- d.addCallback(lambda collections: davxml.PrincipalCollectionSet(*collections))
-+ d.addCallback(lambda collections: davxml.PrincipalCollectionSet(*[davxml.HRef.fromString(uri) for uri in collections]))
- return d
+- return d
++ return davxml.PrincipalCollectionSet(*[
++ davxml.HRef(principalCollection.principalCollectionURI())
++ for principalCollection in self.principalCollections()
++ ])
def ifAllowed(privileges, callback):
-@@ -286,7 +298,33 @@
+ def onError(failure):
+@@ -286,7 +307,33 @@
d.addCallback(gotACL)
return d
return ifAllowed((davxml.ReadACL(),), callback)
@@ -78,9 +115,13 @@
elif namespace == twisted_dav_namespace:
if name == "resource-class":
class ResourceClass (davxml.WebDAVTextElement):
-@@ -366,12 +404,26 @@
- # FIXME: A set would be better here, that that's a python 2.4+ feature.
- qnames = list(self.liveProperties)
+@@ -363,15 +410,28 @@
+ """
+ See L{IDAVResource.listProperties}.
+ """
+- # FIXME: A set would be better here, that that's a python 2.4+ feature.
+- qnames = list(self.liveProperties)
++ qnames = set(self.liveProperties)
+ # Add dynamic live properties that exist
+ dynamicLiveProperties = (
@@ -106,7 +147,30 @@
def listAllprop(self, request):
"""
Some DAV properties should not be returned to a C{DAV:allprop} query.
-@@ -509,6 +561,9 @@
+@@ -465,8 +525,22 @@
+ return super(DAVPropertyMixIn, self).displayName()
+
+ class DAVResource (DAVPropertyMixIn, StaticRenderMixin):
++ """
++ WebDAV resource.
++ """
+ implements(IDAVResource)
+
++ def __init__(self, principalCollections=None):
++ """
++ @param principalCollections: an iterable of L{IDAVPrincipalCollectionResource}s
++ which contain principals to be used in ACLs for this resource.
++ """
++ if principalCollections is not None:
++ self._principalCollections = frozenset([
++ IDAVPrincipalCollectionResource(principalCollection)
++ for principalCollection in principalCollections
++ ])
++
+ ##
+ # DAV
+ ##
+@@ -509,6 +583,9 @@
reactor.callLater(0, getChild)
def checkPrivileges(child):
@@ -116,7 +180,7 @@
if privileges is None:
return child
-@@ -517,14 +572,17 @@
+@@ -517,14 +594,17 @@
return d
def gotChild(child, childpath):
@@ -141,7 +205,7 @@
reactor.callLater(0, getChild)
-@@ -535,10 +593,10 @@
+@@ -535,10 +615,10 @@
completionDeferred.callback(None)
else:
childpath = joinURL(basepath, childname)
@@ -156,7 +220,7 @@
getChild()
-@@ -564,19 +622,21 @@
+@@ -564,19 +644,21 @@
See L{IDAVResource.authorize}.
"""
def onError(failure):
@@ -183,7 +247,7 @@
response = UnauthorizedResponse(request.credentialFactories,
request.remoteAddr)
else:
-@@ -587,7 +647,7 @@
+@@ -587,7 +669,7 @@
# class is supposed to be a FORBIDDEN status code and
# "Authorization will not help" according to RFC2616
#
@@ -192,7 +256,7 @@
d = self.checkPrivileges(request, privileges, recurse)
d.addErrback(onErrors)
-@@ -600,16 +660,22 @@
+@@ -600,16 +682,21 @@
def authenticate(self, request):
def loginSuccess(result):
@@ -201,7 +265,6 @@
+ """
+ @param result: returned tuple from auth.DAVRealm.requestAvatar.
+ """
-+
+ request.authnUser = result[1]
+ request.authzUser = result[2]
+ return (request.authnUser, request.authzUser,)
@@ -219,7 +282,7 @@
authHeader = request.headers.getHeader('authorization')
-@@ -625,9 +691,10 @@
+@@ -625,9 +712,10 @@
# Try to match principals in each principal collection on the resource
def gotDetails(details):
@@ -233,7 +296,7 @@
def login(pcreds):
d = request.portal.login(pcreds, None, *request.loginInterfaces)
-@@ -635,13 +702,15 @@
+@@ -635,13 +723,15 @@
return d
@@ -253,7 +316,7 @@
##
# ACL
-@@ -650,10 +719,10 @@
+@@ -650,49 +740,23 @@
def currentPrincipal(self, request):
"""
@param request: the request being processed.
@@ -267,44 +330,37 @@
else:
return unauthenticatedPrincipal
-@@ -666,33 +735,28 @@
- present on this resource, it tries to get it from the parent, unless it
- is the root or has no parent.
+- def principalCollections(self, request):
++ def principalCollections(self):
"""
+ See L{IDAVResource.accessControlList}.
+-
+- This implementation tries to read the L{davxml.PrincipalCollectionSet}
+- from the dead property store of this resource and uses that. If not
+- present on this resource, it tries to get it from the parent, unless it
+- is the root or has no parent.
+ """
- try:
- principalCollections = self.readDeadProperty(davxml.PrincipalCollectionSet).childrenOfType(davxml.HRef)
- except HTTPError, e:
- if e.response.code != responsecode.NOT_FOUND:
- raise
-+ if self.hasDeadProperty(davxml.PrincipalCollectionSet):
-+ return succeed([
-+ str(href) for href in
-+ self.readDeadProperty(davxml.PrincipalCollectionSet).childrenOfType(davxml.HRef)
-+ ])
++ if hasattr(self, "_principalCollections"):
++ return self._principalCollections
++ else:
++ return ()
- principalCollections = []
-+ myURL = request.urlForResource(self)
-+ assert myURL is not None, "Resource %s was not looked up via request" % (self,)
-+ if myURL == "/":
-+ return succeed(())
-
+-
- # Try the parent
- myURL = request.urlForResource(self)
- if myURL != "/":
- parentURL = parentForURL(myURL)
-+ def gotParent(parent):
-+ if parent is None:
-+ return ()
-+ else:
-+ return parent.principalCollections(request)
-
+-
- parent = waitForDeferred(request.locateResource(parentURL))
- yield parent
- parent = parent.getResult()
-+ d = request.locateResource(parentForURL(myURL))
-+ d.addCallback(gotParent)
-+ return d
-
+-
- if parent:
- principalCollections = waitForDeferred(parent.principalCollections(request))
- yield principalCollections
@@ -349,7 +405,25 @@
# Dynamically update privileges for those ace's that are inherited.
if inheritance:
-@@ -1146,49 +1221,96 @@
+@@ -1070,7 +1145,7 @@
+ # Adjust ACE for inherit on this resource
+ children = list(ace.children)
+ children.remove(TwistedACLInheritable())
+- children.append(davxml.Inherited(davxml.HRef.fromString(parentURL)))
++ children.append(davxml.Inherited(davxml.HRef(parentURL)))
+ aces.append(davxml.ACE(*children))
+ else:
+ aces.extend(inherited_aces)
+@@ -1122,7 +1197,7 @@
+ # Adjust ACE for inherit on this resource
+ children = list(ace.children)
+ children.remove(TwistedACLInheritable())
+- children.append(davxml.Inherited(davxml.HRef.fromString(request.urlForResource(self))))
++ children.append(davxml.Inherited(davxml.HRef(request.urlForResource(self))))
+ aces.append(davxml.ACE(*children))
+
+ # Filter out those that do not have a principal match with the current principal
+@@ -1146,49 +1221,69 @@
This implementation returns an empty set.
"""
@@ -378,78 +452,58 @@
It will errback with an HTTPError(responsecode.FORBIDDEN) if
the principal isn't found.
"""
-+ def gotAuthn(authnPrincipal):
-+ if authnPrincipal is None:
-+ log.msg("Could not find the principal resource for user id: %s" % (authid,))
-+ raise HTTPError(responsecode.FORBIDDEN)
-+
-+ def gotAuthz(authzPrincipal):
-+ return (authnPrincipal, authzPrincipal)
-+
-+ d = self.authorizationPrincipal(request, authid, authnPrincipal)
-+ d.addCallback(gotAuthz)
-+ return d
-+
-+ d = self.findPrincipalForAuthID(request, authid)
-+ d.addCallback(gotAuthn)
-+ return d
-+
-+ def findPrincipalForAuthID(self, request, authid):
-+ """
-+ Return authentication and authoirization prinicipal identifiers for the
-+ authentication identifer passed in. In this implementation authn and authz
-+ principals are the same.
-+
-+ @param request: the L{IRequest} for the request in progress.
-+ @param authid: a string containing the
-+ authentication/authorization identifier for the principal
-+ to lookup.
-+ @return: a tuple of C{(principal, principalURI)} where: C{principal} is the L{Principal}
-+ that is found; {principalURI} is the C{str} URI of the principal.
-+ If not found return None.
-+ """
-+ # FIXME: should self.principalCollections() return resources instead of URIs?
-+
- # Try to match principals in each principal collection on the resource
- collections = waitForDeferred(self.principalCollections(request))
- yield collections
- collections = collections.getResult()
+- # Try to match principals in each principal collection on the resource
+- collections = waitForDeferred(self.principalCollections(request))
+- yield collections
+- collections = collections.getResult()
++ authnPrincipal = self.findPrincipalForAuthID(authid)
- for collection in collections:
- principalURI = joinURL(str(collection), authid)
-+ for collectionURI in collections:
-+ collection = waitForDeferred(request.locateResource(collectionURI))
-+ yield collection
-+ collection = collection.getResult()
++ if authnPrincipal is None:
++ log.msg("Could not find the principal resource for user id: %s" % (authid,))
++ raise HTTPError(responsecode.FORBIDDEN)
- principal = waitForDeferred(request.locateResource(principalURI))
- yield principal
- principal = principal.getResult()
-+ assert collection is not None, "Unable to locate principal collection %s" % (collectionURI,)
++ d = self.authorizationPrincipal(request, authid, authnPrincipal)
++ d.addCallback(lambda authzPrincipal: (authnPrincipal, authzPrincipal))
++ return d
- if isPrincipalResource(principal):
- yield (principal, principalURI)
-+ # FIXME: collection = IPrincipalCollectionResource(collection)
-+ principal = collection.principalForUser(authid)
-+
-+ if principal:
-+ yield principal
- return
- else:
+- return
+- else:
- principalCollections = waitForDeferred(self.principalCollections(request))
- yield principalCollections
- principalCollections = principalCollections.getResult()
-+ yield None
-+ return
++ def findPrincipalForAuthID(self, authid):
++ """
++ Return authentication and authoirization prinicipal identifiers for the
++ authentication identifer passed in. In this implementation authn and authz
++ principals are the same.
- if len(principalCollections) == 0:
- log.msg("DAV:principal-collection-set property cannot be found on the resource being authorized: %s" % self)
- else:
- log.msg("Could not find principal matching user id: %s" % authid)
- raise HTTPError(responsecode.FORBIDDEN)
++ @param authid: a string containing the
++ authentication/authorization identifier for the principal
++ to lookup.
++ @return: a tuple of C{(principal, principalURI)} where: C{principal} is the L{Principal}
++ that is found; {principalURI} is the C{str} URI of the principal.
++ If not found return None.
++ """
++ for collection in self.principalCollections():
++ principal = collection.principalForUser(authid)
++ if principal is not None:
++ return principal
++ return None
+
+- findPrincipalForAuthID = deferredGenerator(findPrincipalForAuthID)
-
- findPrincipalForAuthID = deferredGenerator(findPrincipalForAuthID)
-
+ def authorizationPrincipal(self, request, authid, authnPrincipal):
+ """
+ Determine the authorization principal for the given request and authentication principal.
@@ -467,7 +521,7 @@
def samePrincipal(self, principal1, principal2):
"""
Check whether the two prinicpals are exactly the same in terms of
-@@ -1213,7 +1335,6 @@
+@@ -1213,7 +1308,6 @@
return False
def matchPrincipal(self, principal1, principal2, request):
@@ -475,7 +529,7 @@
"""
Check whether the principal1 is a principal in the set defined by
principal2.
-@@ -1238,6 +1359,9 @@
+@@ -1238,6 +1332,9 @@
if isinstance(principal1, davxml.Unauthenticated):
yield False
return
@@ -485,7 +539,7 @@
else:
yield True
return
-@@ -1265,7 +1389,6 @@
+@@ -1265,7 +1362,6 @@
assert principal2 is not None, "principal2 is None"
@@ -493,7 +547,16 @@
# Compare two HRefs and do group membership test as well
if principal1 == principal2:
yield True
-@@ -1511,6 +1634,265 @@
+@@ -1426,7 +1522,7 @@
+ log.err("DAV:self ACE is set on non-principal resource %r" % (self,))
+ yield None
+ return
+- principal = davxml.HRef.fromString(self.principalURL())
++ principal = davxml.HRef(self.principalURL())
+
+ if isinstance(principal, davxml.HRef):
+ yield principal
+@@ -1511,6 +1607,265 @@
return None
##
@@ -639,7 +702,7 @@
+ assert maxsize is None or isinstance(maxsize, int), "maxsize must be an int or None"
+
+ if maxsize is not None:
-+ self.writeDeadProperty(TwistedQuotaRootProperty.fromString(str(maxsize)))
++ self.writeDeadProperty(TwistedQuotaRootProperty(str(maxsize)))
+ else:
+ # Remove both the root and the cached used value
+ self.removeDeadProperty(TwistedQuotaRootProperty)
@@ -729,7 +792,7 @@
+ else:
+ # Do brute force size determination and cache the result in the private property
+ def _defer(result):
-+ self.writeDeadProperty(TwistedQuotaUsedProperty.fromString(str(result)))
++ self.writeDeadProperty(TwistedQuotaUsedProperty(str(result)))
+ return result
+ d = self.quotaSize(request)
+ d.addCallback(_defer)
@@ -749,7 +812,7 @@
+ # Get current value
+ def _defer(size):
+ size += adjust
-+ self.writeDeadProperty(TwistedQuotaUsedProperty.fromString(str(size)))
++ self.writeDeadProperty(TwistedQuotaUsedProperty(str(size)))
+
+ d = self.currentQuotaUse(request)
+ d.addCallback(_defer)
@@ -759,7 +822,7 @@
# HTTP
##
-@@ -1558,7 +1940,7 @@
+@@ -1558,7 +1913,7 @@
"""
DAV resource with no children.
"""
@@ -768,7 +831,32 @@
return succeed(None)
class DAVPrincipalResource (DAVLeafResource):
-@@ -1712,6 +2094,37 @@
+@@ -1673,6 +2028,24 @@
+ else:
+ return uri in self.groupMembers()
+
++class DAVPrincipalCollectionResource (DAVResource):
++ """
++ WebDAV principal collection resource. (RFC 3744, section 5.8)
++ """
++ implements(IDAVPrincipalCollectionResource)
++
++ def __init__(self, url, principalCollections=()):
++ """
++ @param url: This resource's URL.
++ """
++ DAVResource.__init__(self, principalCollections=principalCollections)
++
++ assert url.endswith("/"), "Collection URL must end in '/'"
++ self._url = url
++
++ def principalCollectionURL(self):
++ return self._url
++
+ class AccessDeniedError(Exception):
+ def __init__(self, errors):
+ """
+@@ -1712,6 +2085,37 @@
davxml.registerElement(TwistedACLInheritable)
davxml.ACE.allowed_children[(twisted_dav_namespace, "inheritable")] = (0, 1)
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.static.patch
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.static.patch 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.static.patch 2006-11-30 23:08:20 UTC (rev 623)
@@ -8,10 +8,10 @@
-import os
-
--from twisted.python import log
- from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
++from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
+ from twisted.python import log
+-from twisted.internet.defer import succeed, deferredGenerator, waitForDeferred
-from twisted.web2.static import File
-+from twisted.python import log
+from twisted.web2 import http_headers
from twisted.web2 import responsecode, dirlist
-from twisted.web2.http import RedirectResponse
@@ -24,7 +24,42 @@
try:
from twisted.web2.dav.xattrprops import xattrPropertyStore as DeadPropertyStore
-@@ -75,6 +75,12 @@
+@@ -52,9 +52,11 @@
+
+ Extends twisted.web2.static.File to handle WebDAV methods.
+ """
+- def __init__(self, path,
+- defaultType="text/plain",
+- indexNames=None):
++ def __init__(
++ self, path,
++ defaultType="text/plain", indexNames=None,
++ principalCollections=()
++ ):
+ """
+ @param path: the path of the file backing this resource.
+ @param defaultType: the default mime type (as a string) for this
+@@ -62,11 +64,14 @@
+ @param indexNames: a sequence of index file names.
+ @param acl: an L{IDAVAccessControlList} with the .
+ """
+- super(DAVFile, self).__init__(path,
+- defaultType = defaultType,
+- ignoredExts = (),
+- processors = None,
+- indexNames = indexNames)
++ File.__init__(
++ self, path,
++ defaultType = defaultType,
++ ignoredExts = (),
++ processors = None,
++ indexNames = indexNames,
++ )
++ DAVResource.__init__(self, principalCollections=principalCollections)
+
+ def __repr__(self):
+ return "<%s: %s>" % (self.__class__.__name__, self.fp.path)
+@@ -75,6 +80,12 @@
# WebDAV
##
@@ -37,7 +72,7 @@
def davComplianceClasses(self):
return ("1", "access-control") # Add "2" when we have locking
-@@ -87,7 +93,6 @@
+@@ -87,7 +98,6 @@
"""
See L{IDAVResource.isCollection}.
"""
@@ -45,7 +80,7 @@
return self.fp.isdir()
##
-@@ -98,6 +103,50 @@
+@@ -98,6 +108,50 @@
return succeed(davPrivilegeSet)
##
@@ -96,9 +131,15 @@
# Workarounds for issues with File
##
-@@ -134,61 +183,6 @@
+@@ -132,63 +186,11 @@
+ return (self.createSimilarFile(self.fp.child(path).path), segments[1:])
+
def createSimilarFile(self, path):
- return self.__class__(path, defaultType=self.defaultType, indexNames=self.indexNames[:])
+- return self.__class__(path, defaultType=self.defaultType, indexNames=self.indexNames[:])
++ return self.__class__(
++ path, self.defaultType, self.indexNames[:],
++ principalCollections=self.principalCollections()
++ )
- def render(self, request):
- """
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/lib-patches/Twisted/twisted.web2.dav.test.test_resource.patch 2006-11-30 23:08:20 UTC (rev 623)
@@ -2,7 +2,23 @@
===================================================================
--- twisted/web2/dav/test/test_resource.py (revision 18545)
+++ twisted/web2/dav/test/test_resource.py (working copy)
-@@ -282,7 +282,8 @@
+@@ -192,13 +192,10 @@
+ class AccessTests(TestCase):
+ def setUp(self):
+ gooduser = TestDAVPrincipalResource('/users/gooduser')
++ gooduser.writeDeadProperty(TwistedPasswordProperty('goodpass'))
+
+- gooduser.writeDeadProperty(
+- TwistedPasswordProperty.fromString('goodpass'))
+-
+ baduser = TestDAVPrincipalResource('/users/baduser')
+- baduser.writeDeadProperty(
+- TwistedPasswordProperty.fromString('badpass'))
++ baduser.writeDeadProperty(TwistedPasswordProperty('badpass'))
+
+ protected = TestResource('/protected')
+ protected.setAccessControlList(davxml.ACL(
+@@ -282,7 +279,8 @@
# Has auth; should allow
request = SimpleRequest(site, "GET", "/")
@@ -12,7 +28,22 @@
d = request.locateResource('/')
d.addCallback(_checkPrivileges)
d.addCallback(expectOK)
-@@ -380,8 +381,8 @@
+@@ -348,12 +346,12 @@
+ davxml.Grant(davxml.Privilege(davxml.All())),
+ davxml.Protected()))
+
+- def __init__(self, uri=None, children=None):
++ def __init__(self, uri=None, children=None, principalCollections=()):
+ """
+ @param uri: A string respresenting the URI of the given resource
+ @param children: a dictionary of names to Resources
+ """
+-
++ DAVResource.__init__(self, principalCollections=principalCollections)
+ self.children = children
+ self.uri = uri
+
+@@ -380,8 +378,8 @@
return succeed(davPrivilegeSet)
def currentPrincipal(self, request):
@@ -23,7 +54,7 @@
else:
return davxml.Principal(davxml.Unauthenticated())
-@@ -400,6 +401,8 @@
+@@ -400,17 +398,23 @@
def accessControlList(self, request, **kwargs):
return succeed(self.acl)
@@ -31,11 +62,24 @@
+ return self.children[user]
class AuthAllResource (TestResource):
- """Give Authenticated principals all privileges deny everything else
-@@ -414,3 +417,6 @@
+- """Give Authenticated principals all privileges deny everything else
+ """
++ Give Authenticated principals all privileges and deny everyone else.
++ """
+ acl = davxml.ACL(
+ davxml.ACE(
+ davxml.Principal(davxml.Authenticated()),
+ davxml.Grant(davxml.Privilege(davxml.All())),
+- davxml.Protected()))
+-
++ davxml.Protected()
++ )
++ )
+
class TestDAVPrincipalResource(DAVPrincipalResource, TestResource):
- """Get deadProperties from TestResource
- """
+- """Get deadProperties from TestResource
+- """
++ # Get dead properties from TestResource
+
+ def principalURL(self):
+ return self.uri
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/support/CalendarServer.tmproj
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/support/CalendarServer.tmproj 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/support/CalendarServer.tmproj 2006-11-30 23:08:20 UTC (rev 623)
@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>currentDocument</key>
+ <string>../../Twisted/twisted/web2/dav/resource.py</string>
<key>documents</key>
<array>
<dict>
@@ -15,6 +17,8 @@
<string>../twistedcaldav</string>
</dict>
<dict>
+ <key>expanded</key>
+ <true/>
<key>name</key>
<string>web2</string>
<key>regexFolderFilter</key>
@@ -123,10 +127,60 @@
<key>fileHierarchyDrawerWidth</key>
<integer>325</integer>
<key>metaData</key>
- <dict/>
+ <dict>
+ <key>../../Twisted/twisted/web2/dav/resource.py</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>56</integer>
+ <key>line</key>
+ <integer>1265</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>1246</integer>
+ </dict>
+ <key>../twistedcaldav/resource.py</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
+ <integer>80</integer>
+ <key>line</key>
+ <integer>261</integer>
+ </dict>
+ <key>columnSelection</key>
+ <false/>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>231</integer>
+ <key>selectFrom</key>
+ <dict>
+ <key>column</key>
+ <integer>58</integer>
+ <key>line</key>
+ <integer>261</integer>
+ </dict>
+ <key>selectTo</key>
+ <dict>
+ <key>column</key>
+ <integer>80</integer>
+ <key>line</key>
+ <integer>261</integer>
+ </dict>
+ </dict>
+ </dict>
+ <key>openDocuments</key>
+ <array>
+ <string>../../Twisted/twisted/web2/dav/resource.py</string>
+ <string>../twistedcaldav/resource.py</string>
+ </array>
<key>showFileHierarchyDrawer</key>
<true/>
<key>windowFrame</key>
- <string>{{591, 84}, {1019, 1050}}</string>
+ <string>{{705, 64}, {1019, 1050}}</string>
</dict>
</plist>
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/support/patchmaker.py
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/support/patchmaker.py 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/support/patchmaker.py 2006-11-30 23:08:20 UTC (rev 623)
@@ -30,7 +30,7 @@
cwd = os.getcwd()
libpatches = os.path.join(cwd, "lib-patches")
-svn = "/usr/local/subversion/bin/svn"
+svn = "/usr/bin/svn"
# Stuff we have to manually ignore because our ignore logic cannot cope
ignores = set((
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/directory/principal.py 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/directory/principal.py 2006-11-30 23:08:20 UTC (rev 623)
@@ -115,8 +115,8 @@
# ACL
##
- def principalCollections(self, request):
- return succeed((self.principalCollectionURL(),))
+ def principalCollections(self):
+ return (self,)
class DirectoryPrincipalTypeResource (PermissionsMixIn, CalendarPrincipalCollectionResource, DAVFile):
"""
@@ -178,8 +178,8 @@
# ACL
##
- def principalCollections(self, request):
- return self._parent.principalCollections(request)
+ def principalCollections(self):
+ return self._parent.principalCollections()
class DirectoryPrincipalResource (PermissionsMixIn, CalendarPrincipalFile):
"""
@@ -284,8 +284,8 @@
def groupMemberships(self):
return self._getRelatives("groups")
- def principalCollections(self, request):
- return self._parent.principalCollections(request)
+ def principalCollections(self):
+ return self._parent.principalCollections()
##
# CalDAV
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/directory/test/test_principal.py 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/directory/test/test_principal.py 2006-11-30 23:08:20 UTC (rev 623)
@@ -73,7 +73,6 @@
self.principalRootResources[directory.__class__.__name__] = provisioningResource
- @deferredGenerator
def test_hierarchy(self):
"""
DirectoryPrincipalProvisioningResource.listChildren(),
@@ -95,10 +94,8 @@
provisioningURL = "/" + directory.__class__.__name__ + "/"
self.assertEquals(provisioningURL, provisioningResource.principalCollectionURL())
- principalCollections = waitForDeferred(provisioningResource.principalCollections(None))
- yield principalCollections
- principalCollections = principalCollections.getResult()
- self.assertEquals(set((provisioningURL,)), set(principalCollections))
+ principalCollections = provisioningResource.principalCollections()
+ self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
recordTypes = set(provisioningResource.listChildren())
self.assertEquals(recordTypes, set(directory.recordTypes()))
@@ -111,10 +108,8 @@
typeURL = provisioningURL + recordType + "/"
self.assertEquals(typeURL, typeResource.principalCollectionURL())
- principalCollections = waitForDeferred(typeResource.principalCollections(None))
- yield principalCollections
- principalCollections = principalCollections.getResult()
- self.assertEquals(set((provisioningURL,)), set(principalCollections))
+ principalCollections = typeResource.principalCollections()
+ self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
shortNames = set(typeResource.listChildren())
self.assertEquals(shortNames, set(r.shortName for r in directory.listRecords(recordType)))
@@ -127,10 +122,8 @@
recordURL = typeURL + shortName
self.assertEquals(recordURL, recordResource.principalURL())
- principalCollections = waitForDeferred(recordResource.principalCollections(None))
- yield principalCollections
- principalCollections = principalCollections.getResult()
- self.assertEquals(set((provisioningURL,)), set(principalCollections))
+ principalCollections = recordResource.principalCollections()
+ self.assertEquals(set((provisioningURL,)), set(pc.principalCollectionURL() for pc in principalCollections))
def test_principalForUser(self):
"""
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/resource.py 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/resource.py 2006-11-30 23:08:20 UTC (rev 623)
@@ -33,7 +33,6 @@
"isScheduleOutboxResource",
]
-from weakref import WeakValueDictionary
from zope.interface import implements
from twisted.internet import reactor
@@ -42,7 +41,8 @@
from twisted.python import log
from twisted.web2 import responsecode
from twisted.web2.dav import davxml
-from twisted.web2.dav.resource import AccessDeniedError, DAVPrincipalResource
+from twisted.web2.dav.idav import IDAVPrincipalCollectionResource
+from twisted.web2.dav.resource import AccessDeniedError, DAVPrincipalResource, DAVPrincipalCollectionResource
from twisted.web2.dav.davxml import dav_namespace
from twisted.web2.dav.http import ErrorResponse
from twisted.web2.dav.resource import TwistedACLInheritable
@@ -285,15 +285,6 @@
authorizationPrincipal = deferredGenerator(authorizationPrincipal)
- def principalCollections(self, request):
- # Get the values cached in CalendarPrincipalCollectionResource.
- collections = CalendarPrincipalCollectionResource.principleCollectionSet.keys()
- if collections:
- return succeed(collections)
-
- # Fall back to super's implementation.
- return super(CalDAVResource, self).principalCollections(request)
-
##
# CalDAV
##
@@ -497,13 +488,11 @@
"""
return request.locateResource(parentForURL(uri))
-class CalendarPrincipalCollectionResource (CalDAVResource):
+class CalendarPrincipalCollectionResource (DAVPrincipalCollectionResource, CalDAVResource):
"""
CalDAV principal collection.
"""
- # Use a WeakKeyDictionary to keep track of all instances.
- # A WeakKeySet would be more appropriate, but there is no such class yet.
- principleCollectionSet = WeakValueDictionary()
+ implements(IDAVPrincipalCollectionResource)
@classmethod
def outboxForCalendarUser(clazz, request, address):
@@ -545,18 +534,6 @@
d.addCallback(_defer)
return d
- def __init__(self, url):
- assert url.endswith("/"), "Collection URL must end in '/'"
-
- # FIXME: there is no super implementation of __init__
- #super(CalendarPrincipalCollectionResource, self).__init__()
-
- self._url = url
-
- # Register self with class
- if url not in CalendarPrincipalCollectionResource.principleCollectionSet:
- CalendarPrincipalCollectionResource.principleCollectionSet[url] = self
-
def isCollection(self):
return True
@@ -591,9 +568,6 @@
findCalendarUser = deferredGenerator(findCalendarUser)
- def principalCollectionURL(self):
- return self._url
-
def supportedReports(self):
"""
Principal collections are the only resources supporting the
@@ -625,6 +599,7 @@
),
)
+# FIXME: Replace this
def findAnyCalendarUser(request, address):
"""
Find the calendar user principal associated with the specified calendar
@@ -634,26 +609,18 @@
@return: the L{CalendarPrincipalResource} for the specified calendar
user, or C{None} if the user is not found.
"""
- for url in CalendarPrincipalCollectionResource.principleCollectionSet.keys():
- try:
- # Explicitly locate the prinicpal collection resource to force URL caching in request
- collection = waitForDeferred(request.locateResource(url))
- yield collection
- collection = collection.getResult()
+ for collection in self.principalCollections():
+ if isinstance(collection, CalendarPrincipalCollectionResource):
+ principal = waitForDeferred(collection.findCalendarUser(request, address))
+ yield principal
+ principal = principal.getResult()
- if isinstance(collection, CalendarPrincipalCollectionResource):
- principal = waitForDeferred(collection.findCalendarUser(request, address))
+ if principal is not None:
yield principal
- principal = principal.getResult()
+ return
+ else:
+ yield None
- if principal is not None:
- yield principal
- return
- except ReferenceError:
- pass
-
- yield None
-
findAnyCalendarUser = deferredGenerator(findAnyCalendarUser)
class CalendarPrincipalResource (DAVPrincipalResource):
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/static.py 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/static.py 2006-11-30 23:08:20 UTC (rev 623)
@@ -496,10 +496,10 @@
def listChildren(self):
return self.directory.recordTypes()
- def principalCollections(self, request):
+ def principalCollections(self):
# FIXME: directory.principalCollection smells like a hack
# See DirectoryPrincipalProvisioningResource.__init__()
- return self.directory.principalCollection.principalCollections(request)
+ return self.directory.principalCollection.principalCollections()
def homeForDirectoryRecord(self, record):
return self.getChild(record.recordType).getChild(record.shortName)
@@ -572,8 +572,8 @@
def defaultAccessControlList(self):
return readOnlyACL
- def principalCollections(self, request):
- return self._parent.principalCollections(request)
+ def principalCollections(self):
+ return self._parent.principalCollections()
class CalendarHomeFile (CalDAVFile):
"""
Modified: CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/test/test_mkcalendar.py
===================================================================
--- CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/test/test_mkcalendar.py 2006-11-29 03:07:23 UTC (rev 622)
+++ CalendarServer/branches/users/wsanchez/provisioning-2/twistedcaldav/test/test_mkcalendar.py 2006-11-30 23:08:20 UTC (rev 623)
@@ -122,10 +122,10 @@
mk = caldavxml.MakeCalendar(
davxml.Set(
davxml.PropertyContainer(
- davxml.DisplayName.fromString("Lisa's Events"),
- caldavxml.CalendarDescription.fromString("Calendar restricted to events."), # FIXME: lang=en
+ davxml.DisplayName("Lisa's Events"),
+ caldavxml.CalendarDescription("Calendar restricted to events."), # FIXME: lang=en
caldavxml.SupportedCalendarComponentSet(caldavxml.CalendarComponent(name="VEVENT")),
- caldavxml.CalendarTimeZone.fromString(
+ caldavxml.CalendarTimeZone(
"""BEGIN:VCALENDAR
PRODID:-//Example Corp.//CalDAV Client//EN
VERSION:2.0
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061130/b8c85bc8/attachment.html
More information about the calendarserver-changes
mailing list