[CalendarServer-changes] [5342] CalendarServer/branches/users/cdaboo/shared-calendars-5187/ twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Wed Mar 17 11:38:23 PDT 2010
Revision: 5342
http://trac.macosforge.org/projects/calendarserver/changeset/5342
Author: cdaboo at apple.com
Date: 2010-03-17 11:38:23 -0700 (Wed, 17 Mar 2010)
Log Message:
-----------
Fixes for per-user WebDAV property support.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/resource.py
CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py
Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/resource.py 2010-03-17 18:37:34 UTC (rev 5341)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/resource.py 2010-03-17 18:38:23 UTC (rev 5342)
@@ -64,7 +64,8 @@
from twistedcaldav.config import config
from twistedcaldav.customxml import TwistedCalendarAccessProperty
from twistedcaldav.customxml import calendarserver_namespace
-from twistedcaldav.extensions import DAVResource, DAVPrincipalResource
+from twistedcaldav.extensions import DAVResource, DAVPrincipalResource,\
+ PropertyNotFoundError
from twistedcaldav.ical import Component
from twistedcaldav.ical import Component as iComponent
from twistedcaldav.ical import allowedComponents
@@ -220,9 +221,9 @@
##
liveProperties = DAVResource.liveProperties + (
- (dav_namespace, "owner"), # Private Events needs this but it is also OK to return empty
- (caldav_namespace, "supported-calendar-component-set"),
- (caldav_namespace, "supported-calendar-data" ),
+ davxml.Owner.qname(), # Private Events needs this but it is also OK to return empty
+ caldavxml.SupportedCalendarComponentSet.qname(),
+ caldavxml.SupportedCalendarData.qname(),
)
supportedCalendarComponentSet = caldavxml.SupportedCalendarComponentSet(
@@ -237,34 +238,20 @@
elif not enable and qname in clz.liveProperties:
clz.liveProperties = tuple([p for p in clz.liveProperties if p != qname])
- def hasProperty(self, property, request):
- """
- Need to special case schedule-calendar-transp for backwards compatability.
- """
-
- if type(property) is tuple:
- qname = property
- else:
- qname = property.qname()
-
- # Force calendar collections to always appear to have the property
- if qname == (caldav_namespace, "schedule-calendar-transp") and self.isCalendarCollection():
- return succeed(True)
- else:
- return super(CalDAVResource, self).hasProperty(property, request)
-
def isShadowableProperty(self, qname):
"""
Shadowable properties are ones on shared resources where a "default" exists until
a user overrides with their own value.
"""
- return False
+ return qname in (
+ caldavxml.CalendarDescription.qname(),
+ caldavxml.CalendarTimeZone.qname(),
+ )
def isGlobalProperty(self, qname):
"""
A global property is one that is the same for all users.
"""
- if qname == (u'DAV:', u'displayname'): return False # XXX HACK
if qname in self.liveProperties:
if qname in (
davxml.DisplayName.qname(),
@@ -277,13 +264,55 @@
customxml.GETCTag.qname(),
caldavxml.MaxResourceSize.qname(),
caldavxml.MaxAttendeesPerInstance.qname(),
- caldavxml.ScheduleCalendarTransp.qname(),
):
return True
else:
return False
@inlineCallbacks
+ def hasProperty(self, property, request):
+ """
+ Need to special case schedule-calendar-transp for backwards compatability.
+ """
+
+ if type(property) is tuple:
+ qname = property
+ else:
+ qname = property.qname()
+
+ isvirt = (yield self.isVirtualShare(request))
+ if isvirt:
+ if self.isShadowableProperty(qname):
+ ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
+ p = self.deadProperties().contains(qname, uid=ownerPrincipal.principalUID())
+ if p:
+ returnValue(p)
+
+ elif (not self.isGlobalProperty(qname)):
+ ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
+ p = self.deadProperties().contains(qname, uid=ownerPrincipal.principalUID())
+ returnValue(p)
+
+ res = (yield self._hasGlobalProperty(property, request))
+ returnValue(res)
+
+ def _hasGlobalProperty(self, property, request):
+ """
+ Need to special case schedule-calendar-transp for backwards compatability.
+ """
+
+ if type(property) is tuple:
+ qname = property
+ else:
+ qname = property.qname()
+
+ # Force calendar collections to always appear to have the property
+ if qname == caldavxml.ScheduleCalendarTransp.qname() and self.isCalendarCollection():
+ return succeed(True)
+ else:
+ return super(CalDAVResource, self).hasProperty(property, request)
+
+ @inlineCallbacks
def readProperty(self, property, request):
if type(property) is tuple:
qname = property
@@ -291,76 +320,73 @@
qname = property.qname()
isvirt = (yield self.isVirtualShare(request))
- if self.isShadowableProperty(qname):
- if isvirt:
+ if isvirt:
+ if self.isShadowableProperty(qname):
ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
+ try:
+ p = self.deadProperties().get(qname, uid=ownerPrincipal.principalUID())
+ returnValue(p)
+ except PropertyNotFoundError:
+ pass
+
+ elif (not self.isGlobalProperty(qname)):
+ ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
p = self.deadProperties().get(qname, uid=ownerPrincipal.principalUID())
- if p is not None:
- returnValue(p)
- else:
- res = (yield self._readGlobalProperty(qname, property, request))
- returnValue(res)
-
- elif (not self.isGlobalProperty(qname)) and isvirt:
- ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
- p = self.deadProperties().get(qname, uid=ownerPrincipal.principalUID())
- returnValue(p)
+ returnValue(p)
res = (yield self._readGlobalProperty(qname, property, request))
returnValue(res)
@inlineCallbacks
def _readGlobalProperty(self, qname, property, request):
- namespace, name = qname
- if namespace == dav_namespace:
- if name == "owner":
- owner = (yield self.owner(request))
- returnValue(davxml.Owner(owner))
+ if qname == davxml.Owner.qname():
+ owner = (yield self.owner(request))
+ returnValue(davxml.Owner(owner))
- elif namespace == caldav_namespace:
- if name == "supported-calendar-component-set":
- # CalDAV-access-09, section 5.2.3
- if self.hasDeadProperty(qname):
- returnValue(self.readDeadProperty(qname))
- returnValue(self.supportedCalendarComponentSet)
- elif name == "supported-calendar-data":
- # CalDAV-access-09, section 5.2.4
- returnValue(caldavxml.SupportedCalendarData(
- caldavxml.CalendarData(**{
- "content-type": "text/calendar",
- "version" : "2.0",
- }),
+ elif qname == caldavxml.SupportedCalendarComponentSet.qname():
+ # CalDAV-access-09, section 5.2.3
+ if self.hasDeadProperty(qname):
+ returnValue(self.readDeadProperty(qname))
+ returnValue(self.supportedCalendarComponentSet)
+
+ elif qname == caldavxml.SupportedCalendarData.qname():
+ # CalDAV-access-09, section 5.2.4
+ returnValue(caldavxml.SupportedCalendarData(
+ caldavxml.CalendarData(**{
+ "content-type": "text/calendar",
+ "version" : "2.0",
+ }),
+ ))
+
+ elif qname == caldavxml.MaxResourceSize.qname():
+ # CalDAV-access-15, section 5.2.5
+ if config.MaximumAttachmentSize:
+ returnValue(caldavxml.MaxResourceSize.fromString(
+ str(config.MaximumAttachmentSize)
))
- elif name == "max-resource-size":
- # CalDAV-access-15, section 5.2.5
- if config.MaximumAttachmentSize:
- returnValue(caldavxml.MaxResourceSize.fromString(
- str(config.MaximumAttachmentSize)
- ))
- elif name == "max-attendees-per-instance":
- # CalDAV-access-15, section 5.2.9
- if config.MaxAttendeesPerInstance:
- returnValue(caldavxml.MaxAttendeesPerInstance.fromString(
- str(config.MaxAttendeesPerInstance)
- ))
+ elif qname == caldavxml.MaxAttendeesPerInstance.qname():
+ # CalDAV-access-15, section 5.2.9
+ if config.MaxAttendeesPerInstance:
+ returnValue(caldavxml.MaxAttendeesPerInstance.fromString(
+ str(config.MaxAttendeesPerInstance)
+ ))
- elif name == "schedule-calendar-transp":
- # For backwards compatibility, if the property does not exist we need to create
- # it and default to the old free-busy-set value.
- if self.isCalendarCollection() and not self.hasDeadProperty(property):
- # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
- principal = (yield self.resourceOwnerPrincipal(request))
- fbset = (yield principal.calendarFreeBusyURIs(request))
- url = (yield self.canonicalURL(request))
- opaque = url in fbset
- self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque() if opaque else caldavxml.Transparent()))
+ elif qname == caldavxml.ScheduleCalendarTransp.qname():
+ # For backwards compatibility, if the property does not exist we need to create
+ # it and default to the old free-busy-set value.
+ if self.isCalendarCollection() and not self.hasDeadProperty(property):
+ # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
+ principal = (yield self.resourceOwnerPrincipal(request))
+ fbset = (yield principal.calendarFreeBusyURIs(request))
+ url = (yield self.canonicalURL(request))
+ opaque = url in fbset
+ self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque() if opaque else caldavxml.Transparent()))
- elif namespace == calendarserver_namespace:
- if name == "invite":
- result = (yield self.inviteProperty(request))
- returnValue(result)
+ elif qname == customxml.Invite.qname():
+ result = (yield self.inviteProperty(request))
+ returnValue(result)
result = (yield super(CalDAVResource, self).readProperty(property, request))
returnValue(result)
@@ -375,7 +401,7 @@
isvirt = (yield self.isVirtualShare(request))
if isvirt and (self.isShadowableProperty(property.qname()) or (not self.isGlobalProperty(property.qname()))):
ownerPrincipal = (yield self.resourceOwnerPrincipal(request))
- p = (yield self.deadProperties().set(property, uid=ownerPrincipal.principalUID()))
+ p = self.deadProperties().set(property, uid=ownerPrincipal.principalUID())
returnValue(p)
res = (yield self._writeGlobalProperty(property, request))
@@ -383,7 +409,7 @@
@inlineCallbacks
def _writeGlobalProperty(self, property, request):
- if property.qname() == (caldav_namespace, "supported-calendar-component-set"):
+ if property.qname() == caldavxml.SupportedCalendarComponentSet.qname():
if not self.isPseudoCalendarCollection():
raise HTTPError(StatusResponse(
responsecode.FORBIDDEN,
@@ -400,7 +426,7 @@
# server enforces what can be stored, however it need not actually
# exist so we cannot list it in liveProperties on this resource, since its
# its presence there means that hasProperty will always return True for it.
- elif property.qname() == (caldav_namespace, "calendar-timezone"):
+ elif property.qname() == caldavxml.CalendarTimeZone.qname():
if not self.isCalendarCollection():
raise HTTPError(StatusResponse(
responsecode.FORBIDDEN,
@@ -413,7 +439,7 @@
description="Invalid property"
))
- elif property.qname() == (caldav_namespace, "schedule-calendar-transp"):
+ elif property.qname() == caldavxml.ScheduleCalendarTransp.qname():
if not self.isCalendarCollection():
raise HTTPError(StatusResponse(
responsecode.FORBIDDEN,
@@ -430,7 +456,7 @@
myurl = (yield self.canonicalURL(request))
inbox.processFreeBusyCalendar(myurl, property.children[0] == caldavxml.Opaque())
- elif property.qname() == (dav_namespace, "resourcetype"):
+ elif property.qname() == davxml.ResourceType.qname():
if self.isCalendarCollection():
sawShare = [child for child in property.children if child.qname() == (calendarserver_namespace, "shared-owner")]
if not (config.Sharing.Enabled and config.Sharing.Calendars.Enabled):
@@ -469,11 +495,6 @@
result = (yield super(CalDAVResource, self).writeProperty(property, request))
returnValue(result)
- def writeDeadProperty(self, property):
- val = super(CalDAVResource, self).writeDeadProperty(property)
- return val
-
-
##
# ACL
##
@@ -568,11 +589,16 @@
def resourceOwnerPrincipal(self, request):
"""
This is the owner of the resource based on the URI used to access it. For a shared
- collection it will be the sharee, whereas the ownerPrincipal for a shared collection
- will be the sharer.
+ collection it will be the sharee, otherwise it will be the regular the ownerPrincipal.
"""
- return self.ownerPrincipal(request)
+ def _defer(isVirt):
+ return self._shareePrincipal if isVirt else self.ownerPrincipal(request)
+
+ d = self.isVirtualShare(request)
+ d.addCallback(_defer)
+ return d
+
def isOwner(self, request, adminprincipals=False, readprincipals=False):
"""
Determine whether the DAV:owner of this resource matches the currently authorized principal
Modified: CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py 2010-03-17 18:37:34 UTC (rev 5341)
+++ CalendarServer/branches/users/cdaboo/shared-calendars-5187/twistedcaldav/test/test_sharing.py 2010-03-17 18:38:23 UTC (rev 5342)
@@ -47,6 +47,19 @@
self.resource.sendInvite = lambda record, request:succeed(True)
self.resource.removeInvite = lambda record, request:succeed(True)
+ class FakePrincipal(object):
+
+ def __init__(self, cuaddr):
+ self.path = "/principals/__uids__/%s" % (cuaddr[7:].split('@')[0],)
+ self.homepath = "/calendars/__uids__/%s" % (cuaddr[7:].split('@')[0],)
+
+ def calendarHome(self):
+ class FakeHome(object):
+ def removeShareByUID(self, request, uid):pass
+ return FakeHome()
+
+ self.resource.principalForCalendarUserAddress = lambda cuaddr: FakePrincipal(cuaddr)
+
def _fakeValidUserID(self, userid):
if userid.endswith("@example.com"):
return userid
@@ -107,15 +120,15 @@
propInvite = (yield self.resource.readProperty(customxml.Invite, request))
self.assertEquals(propInvite, None)
- self.assertRaises(HTTPError, self.resource.upgradeToShare, request)
+ yield self.resource.upgradeToShare(request)
rtype = (yield self.resource.resourceType(request))
- self.assertEquals(rtype, davxml.ResourceType.calendar)
+ self.assertEquals(rtype, davxml.ResourceType.sharedcalendar)
propInvite = (yield self.resource.readProperty(customxml.Invite, request))
- self.assertEquals(propInvite, None)
+ self.assertEquals(propInvite, customxml.Invite())
isShared = (yield self.resource.isShared(request))
- self.assertFalse(isShared)
+ self.assertTrue(isShared)
isVShared = (yield self.resource.isVirtualShare(request))
self.assertFalse(isVShared)
@@ -183,15 +196,21 @@
<CS:read-write/>
</CS:set>
</CS:share>
-""",
- responsecode.BAD_REQUEST
+"""
)
propInvite = (yield self.resource.readProperty(customxml.Invite, None))
- self.assertEquals(propInvite, None)
+ self.assertEquals(self._clearUIDElementValue(propInvite), customxml.Invite(
+ customxml.InviteUser(
+ customxml.UID.fromString(""),
+ davxml.HRef.fromString("mailto:user02 at example.com"),
+ customxml.InviteAccess(customxml.ReadWriteAccess()),
+ customxml.InviteStatusNoResponse(),
+ )
+ ))
isShared = (yield self.resource.isShared(None))
- self.assertFalse(isShared)
+ self.assertTrue(isShared)
isVShared = (yield self.resource.isVirtualShare(None))
self.assertFalse(isVShared)
@@ -422,7 +441,8 @@
self.assertEqual(
str(response.stream.read()).replace("\r\n", "\n"),
- """<?xml version='1.0' encoding='UTF-8'?><multistatus xmlns='DAV:'>
+ """<?xml version='1.0' encoding='UTF-8'?>
+<multistatus xmlns='DAV:'>
<response>
<href>mailto:bogus at example.net</href>
<status>HTTP/1.1 403 Forbidden</status>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100317/2c282084/attachment-0001.html>
More information about the calendarserver-changes
mailing list