Skip to content
Permalink
Browse files

Store calendar data by GUID.

  • Loading branch information...
wsanchez committed Mar 6, 2008
1 parent e7dc8d2 commit 3554eda3cabcac5cfbdc481cc39ab9d9171a90f0
@@ -19,8 +19,10 @@
"""

__all__ = [
"uidsResourceName",
"DirectoryCalendarHomeProvisioningResource",
"DirectoryCalendarHomeTypeProvisioningResource",
"DirectoryCalendarHomeUIDProvisioningResource",
"DirectoryCalendarHomeResource",
]

@@ -39,6 +41,9 @@
from twistedcaldav.directory.idirectory import IDirectoryService
from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn

# Use __underbars__ convention to avoid conflicts with directory resource types.
uidsResourceName = "__uids__"

class DirectoryCalendarHomeProvisioningResource (AutoProvisioningResourceMixIn, ReadOnlyResourceMixIn, DAVResource):
"""
Resource which provisions calendar home collections as needed.
@@ -59,9 +64,16 @@ def __init__(self, directory, url):
# FIXME: Smells like a hack
directory.calendarHomesCollection = self

#
# Create children
#
def provisionChild(name):
self.putChild(name, self.provisionChild(name))

for recordType in self.directory.recordTypes():
self.putChild(recordType, self.provisionChild(recordType))
provisionChild(recordType)

provisionChild(uidsResourceName)

def provisionChild(self, recordType):
raise NotImplementedError("Subclass must implement provisionChild()")
@@ -86,11 +98,11 @@ def principalForRecord(self, record):
return self.directory.principalCollection.principalForRecord(record)

def homeForDirectoryRecord(self, record):
typeResource = self.getChild(record.recordType)
if typeResource is None:
uidResource = self.getChild(uidsResourceName)
if uidResource is None:
return None
else:
return typeResource.getChild(record.shortName)
return uidResource.getChild(record.guid)

##
# DAV
@@ -113,8 +125,7 @@ class DirectoryCalendarHomeTypeProvisioningResource (AutoProvisioningResourceMix
"""
def __init__(self, parent, recordType):
"""
@param path: the path to the file which will back the resource.
@param directory: an L{IDirectoryService} to provision calendars from.
@param parent: the parent of this resource
@param recordType: the directory record type to provision.
"""
assert parent is not None
@@ -131,19 +142,15 @@ def url(self):

def getChild(self, name, record=None):
self.provision()

if name == "":
return self

if record is None:
record = self.directory.recordWithShortName(self.recordType, name)
if record is None:
return None
else:
assert name is None
name = record.shortName

return self.provisionChild(name)
return self._parent.homeForDirectoryRecord(record)

def listChildren(self):
return (
@@ -173,6 +180,61 @@ def principalForRecord(self, record):
return self._parent.principalForRecord(record)


class DirectoryCalendarHomeUIDProvisioningResource (AutoProvisioningResourceMixIn, ReadOnlyResourceMixIn, DAVResource):
def __init__(self, parent):
"""
@param parent: the parent of this resource
"""
assert parent is not None

DAVResource.__init__(self)

self.directory = parent.directory
self.parent = parent

def url(self):
return joinURL(self.parent.url(), uidsResourceName)

def getChild(self, name, record=None):
self.provision()
if name == "":
return self

if record is None:
record = self.directory.recordWithGUID(name)
if record is None:
return None

return self.provisionChild(name)

def listChildren(self):
return (
record.guid
for record in self.directory.listRecords(self.recordType)
if record.enabledForCalendaring
)

##
# DAV
##

def isCollection(self):
return True

##
# ACL
##

def defaultAccessControlList(self):
return readOnlyACL

def principalCollections(self):
return self.parent.principalCollections()

def principalForRecord(self, record):
return self.parent.principalForRecord(record)


class DirectoryCalendarHomeResource (AutoProvisioningResourceMixIn, CalDAVResource):
"""
Calendar home collection resource.
@@ -187,7 +249,7 @@ def __init__(self, parent, record):
CalDAVResource.__init__(self)

self.record = record
self._parent = parent
self.parent = parent

# Cache children which must be of a specific type
childlist = (
@@ -243,7 +305,13 @@ def provisionChild(self, name):
raise NotImplementedError("Subclass must implement provisionChild()")

def url(self):
return joinURL(self._parent.url(), self.record.shortName)
return joinURL(self.parent.url(), self.record.guid)
##
## While the underlying primary location is GUID-based, we want
## the canonical user-facing location to be recordType &
## shortName-based, because that's friendlier.
##
#return joinURL(self.parent.parent.getChild(self.record.recordType).url(), self.record.shortName)

##
# DAV
@@ -260,8 +328,6 @@ def owner(self, request):
return succeed(davxml.HRef(self.principalForRecord().principalURL()))

def defaultAccessControlList(self):
# FIXME: directory.principalCollection smells like a hack
# See DirectoryPrincipalProvisioningResource.__init__()
myPrincipal = self.principalForRecord()

aces = (
@@ -306,10 +372,10 @@ def defaultAccessControlList(self):
return davxml.ACL(*aces)

def principalCollections(self):
return self._parent.principalCollections()
return self.parent.principalCollections()

def principalForRecord(self):
return self._parent.principalForRecord(self.record)
return self.parent.principalForRecord(self.record)

##
# Quota
@@ -19,8 +19,10 @@
"""

__all__ = [
"DirectoryProvisioningResource",
"DirectoryPrincipalProvisioningResource",
"DirectoryPrincipalTypeProvisioningResource",
"DirectoryPrincipalUIDProvisioningResource",
"DirectoryPrincipalResource",
"DirectoryCalendarPrincipalResource",
]
@@ -58,11 +60,7 @@ class PermissionsMixIn (ReadOnlyResourceMixIn):
def defaultAccessControlList(self):
return authReadACL

def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
# Permissions here are fixed, and are not subject to inherritance rules, etc.
return succeed(self.defaultAccessControlList())

class DirectoryProvisioningResource(
class DirectoryProvisioningResource (
AutoProvisioningFileMixIn,
PermissionsMixIn,
CalendarPrincipalCollectionResource,
@@ -184,6 +182,8 @@ def principalForCalendarUserAddress(self, address):
if record is not None:
return self.principalForRecord(record)

log.err("No principal for calendar user address: %r" % (address,))

return None

##
@@ -620,6 +620,10 @@ class ReadOnlyResourceMixIn (ReadOnlyWritePropertiesResourceMixIn):
def writeProperty(self, property, request):
raise HTTPError(self.readOnlyResponse)

def accessControlList(self, request, inheritance=True, expanding=False, inherited_aces=None):
# Permissions here are fixed, and are not subject to inherritance rules, etc.
return succeed(self.defaultAccessControlList())

class XMLResponse (Response):
"""
XML L{Response} object.
@@ -35,7 +35,6 @@
from twisted.web2.dav.util import joinURL

from twistedcaldav import caldavxml
from twistedcaldav import customxml
from twistedcaldav import itip
from twistedcaldav import logging
from twistedcaldav.resource import CalDAVResource
@@ -355,7 +354,7 @@ def http_POST(self, request):
# Map recipient to their inbox
inbox = None
if principal is None:
logging.err("No principal for calendar user address: %s" % (recipient,), system="CalDAV Outbox POST")
logging.err("No schedulable principal for calendar user address: %r" % (recipient,), system="CalDAV Outbox POST")
else:
inboxURL = principal.scheduleInboxURL()
if inboxURL:
@@ -22,7 +22,9 @@
"CalDAVFile",
"AutoProvisioningFileMixIn",
"CalendarHomeProvisioningFile",
"CalendarHomeUIDProvisioningFile",
"CalendarHomeFile",
"ScheduleFile",
"ScheduleInboxFile",
"ScheduleOutboxFile",
"DropBoxHomeFile",
@@ -62,8 +64,10 @@
from twistedcaldav.resource import CalDAVResource, isCalendarCollectionResource, isPseudoCalendarCollectionResource
from twistedcaldav.schedule import ScheduleInboxResource, ScheduleOutboxResource
from twistedcaldav.dropbox import DropBoxHomeResource, DropBoxCollectionResource, DropBoxChildResource
from twistedcaldav.directory.calendar import uidsResourceName
from twistedcaldav.directory.calendar import DirectoryCalendarHomeProvisioningResource
from twistedcaldav.directory.calendar import DirectoryCalendarHomeTypeProvisioningResource
from twistedcaldav.directory.calendar import DirectoryCalendarHomeUIDProvisioningResource
from twistedcaldav.directory.calendar import DirectoryCalendarHomeResource
from twistedcaldav.directory.resource import AutoProvisioningResourceMixIn

@@ -439,43 +443,68 @@ def __init__(self, path, directory, url):
DirectoryCalendarHomeProvisioningResource.__init__(self, directory, url)

def provisionChild(self, name):
if name == uidsResourceName:
return CalendarHomeUIDProvisioningFile(self.fp.child(name).path, self)

return CalendarHomeTypeProvisioningFile(self.fp.child(name).path, self, name)

def createSimilarFile(self, path):
raise HTTPError(responsecode.NOT_FOUND)

class CalendarHomeTypeProvisioningFile (AutoProvisioningFileMixIn, DirectoryCalendarHomeTypeProvisioningResource, DAVFile):
"""
Resource which provisions calendar home collections of a specific
record type as needed.
"""
def __init__(self, path, parent, recordType):
"""
@param path: the path to the file which will back the resource.
@param directory: an L{IDirectoryService} to provision calendars from.
@param parent: the parent of this resource
@param recordType: the directory record type to provision.
"""
DAVFile.__init__(self, path)
DirectoryCalendarHomeTypeProvisioningResource.__init__(self, parent, recordType)

class CalendarHomeUIDProvisioningFile (AutoProvisioningFileMixIn, DirectoryCalendarHomeUIDProvisioningResource, DAVFile):
def __init__(self, path, parent):
"""
@param path: the path to the file which will back the resource.
"""
DAVFile.__init__(self, path)
DirectoryCalendarHomeUIDProvisioningResource.__init__(self, parent)

def provisionChild(self, name):
record = self.directory.recordWithShortName(self.recordType, name)
record = self.directory.recordWithGUID(name)

if record is None:
log.msg("No directory record %r of type %r" % (name, self.recordType))
log.msg("No directory record with GUID %r" % (name,))
return None

if not record.enabledForCalendaring:
log.msg("Directory record %r of type %r is not enabled for calendaring" % (name, self.recordType))
log.msg("Directory record %r is not enabled for calendaring" % (record,))
return None

child = CalendarHomeFile(self.fp.child(name).path, self, record)
childPath = self.fp.child(name)
child = CalendarHomeFile(childPath.path, self, record)
if not child.exists():
# NOTE: provisionDefaultCalendars() returns a deferred, which we are ignoring.
# The result being that the default calendars will be present at some point
# in the future, not necessarily right now, and we don't have a way to wait
# on that to finish.
child.provisionDefaultCalendars()
#
# Find out if the child exists at the old (pre-1.2)
# location (ie. in the types hierarchy instead of the GUID
# hierarchy).
#
oldPath = self.parent.getChild(record.recordType).fp.child(record.shortName)
if oldPath.exists():
log.msg("Moving calendar home from old location %r to new location %r." % (oldPath, childPath))
try:
oldPath.moveTo(childPath)
except (OSError, IOError), e:
log.err("Error moving calendar home %r: %s" % (oldPath, e))
raise HTTPError(StatusResponse(
responsecode.INTERNAL_SERVER_ERROR,
"Unable to move calendar home."
))
else:
# NOTE: provisionDefaultCalendars() returns a deferred, which we are ignoring.
# The result being that the default calendars will be present at some point
# in the future, not necessarily right now, and we don't have a way to wait
# on that to finish.
child.provisionDefaultCalendars()
return child

def createSimilarFile(self, path):
@@ -674,7 +703,7 @@ def __repr__(self):
http_MKCOL = NotificationsCollectionResource.http_MKCOL
http_MKCALENDAR = NotificationsCollectionResource.http_MKCALENDAR

class NotificationFile(NotificationResource, DAVFile):
class NotificationFile (NotificationResource, DAVFile):
def __init__(self, path, parent):
super(NotificationFile, self).__init__(path, principalCollections=parent.principalCollections())

0 comments on commit 3554eda

Please sign in to comment.
You can’t perform that action at this time.