[CalendarServer-changes] [6431] CalendarServer/branches/users/glyph/more-deferreds-7
source_changes at macosforge.org
source_changes at macosforge.org
Sun Oct 17 01:21:36 PDT 2010
Revision: 6431
http://trac.macosforge.org/projects/calendarserver/changeset/6431
Author: glyph at apple.com
Date: 2010-10-17 01:21:32 -0700 (Sun, 17 Oct 2010)
Log Message:
-----------
unit tests passing again
Modified Paths:
--------------
CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/dav/resource.py
CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/resource.py
CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/static.py
CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/test/test_resource.py
CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/method/put_common.py
CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/resource.py
CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/sharing.py
CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/storebridge.py
CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/sql.py
CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/test/common.py
CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/sql.py
CalendarServer/branches/users/glyph/more-deferreds-7/txdav/common/datastore/sql.py
CalendarServer/branches/users/glyph/more-deferreds-7/txdav/common/datastore/sql_legacy.py
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/dav/resource.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/dav/resource.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/dav/resource.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -51,8 +51,9 @@
from twisted.cred.error import LoginFailed, UnauthorizedLogin
from twisted.python.failure import Failure
-from twisted.internet.defer import Deferred, maybeDeferred, succeed
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import (
+ Deferred, maybeDeferred, succeed, inlineCallbacks, returnValue
+)
from twisted.internet import reactor
from twext.python.log import Logger
@@ -204,10 +205,12 @@
self.deadProperties().contains(qname)
)
+
def readProperty(self, property, request):
"""
See L{IDAVResource.readProperty}.
"""
+ @inlineCallbacks
def defer():
if type(property) is tuple:
qname = property
@@ -222,22 +225,22 @@
if name == "resourcetype":
# Allow live property to be overridden by dead property
if self.deadProperties().contains(qname):
- return self.deadProperties().get(qname)
+ returnValue(self.deadProperties().get(qname))
if self.isCollection():
- return davxml.ResourceType.collection #@UndefinedVariable
- return davxml.ResourceType.empty #@UndefinedVariable
+ returnValue(davxml.ResourceType.collection) #@UndefinedVariable
+ returnValue(davxml.ResourceType.empty) #@UndefinedVariable
if name == "getetag":
- etag = self.etag()
+ etag = yield self.etag()
if etag is None:
- return None
- return davxml.GETETag(etag.generate())
+ returnValue(None)
+ returnValue(davxml.GETETag(etag.generate()))
if name == "getcontenttype":
mimeType = self.contentType()
if mimeType is None:
- return None
- return davxml.GETContentType(generateContentType(mimeType))
+ returnValue(None)
+ returnValue(davxml.GETContentType(generateContentType(mimeType)))
if name == "getcontentlength":
length = self.contentLength()
@@ -245,30 +248,30 @@
# TODO: really we should "render" the resource and
# determine its size from that but for now we just
# return an empty element.
- return davxml.GETContentLength("")
+ returnValue(davxml.GETContentLength(""))
else:
- return davxml.GETContentLength(str(length))
+ returnValue(davxml.GETContentLength(str(length)))
if name == "getlastmodified":
- lastModified = self.lastModified()
+ lastModified = yield self.lastModified()
if lastModified is None:
- return None
- return davxml.GETLastModified.fromDate(lastModified)
+ returnValue(None)
+ returnValue(davxml.GETLastModified.fromDate(lastModified))
if name == "creationdate":
- creationDate = self.creationDate()
+ creationDate = yield self.creationDate()
if creationDate is None:
- return None
- return davxml.CreationDate.fromDate(creationDate)
+ returnValue(None)
+ returnValue(davxml.CreationDate.fromDate(creationDate))
if name == "displayname":
displayName = self.displayName()
if displayName is None:
- return None
- return davxml.DisplayName(displayName)
+ returnValue(None)
+ returnValue(davxml.DisplayName(displayName))
if name == "supportedlock":
- return davxml.SupportedLock(
+ returnValue(davxml.SupportedLock(
davxml.LockEntry(
davxml.LockScope.exclusive, #@UndefinedVariable
davxml.LockType.write #@UndefinedVariable
@@ -277,107 +280,93 @@
davxml.LockScope.shared, #@UndefinedVariable
davxml.LockType.write #@UndefinedVariable
),
- )
+ ))
if name == "supported-report-set":
- return davxml.SupportedReportSet(*[
+ returnValue(davxml.SupportedReportSet(*[
davxml.SupportedReport(report,)
for report in self.supportedReports()
- ])
+ ]))
if name == "supported-privilege-set":
- return self.supportedPrivileges(request)
+ returnValue((yield self.supportedPrivileges(request)))
if name == "acl-restrictions":
- return davxml.ACLRestrictions()
+ returnValue(davxml.ACLRestrictions())
if name == "inherited-acl-set":
- return davxml.InheritedACLSet(*self.inheritedACLSet())
+ returnValue(davxml.InheritedACLSet(*self.inheritedACLSet()))
if name == "principal-collection-set":
- return davxml.PrincipalCollectionSet(*[
+ returnValue(davxml.PrincipalCollectionSet(*[
davxml.HRef(
principalCollection.principalCollectionURL()
)
for principalCollection in self.principalCollections()
- ])
+ ]))
+ @inlineCallbacks
def ifAllowed(privileges, callback):
- def onError(failure):
- failure.trap(AccessDeniedError)
-
+ try:
+ yield self.checkPrivileges(request, privileges)
+ result = yield callback()
+ except AccessDeniedError:
raise HTTPError(StatusResponse(
responsecode.UNAUTHORIZED,
"Access denied while reading property %s."
% (sname,)
))
+ returnValue(result)
- d = self.checkPrivileges(request, privileges)
- d.addCallbacks(lambda _: callback(), onError)
- return d
-
if name == "current-user-privilege-set":
+ @inlineCallbacks
def callback():
- d = self.currentPrivileges(request)
- d.addCallback(
- lambda privs:
- davxml.CurrentUserPrivilegeSet(*privs)
- )
- return d
- return ifAllowed(
+ privs = yield self.currentPrivileges(request)
+ returnValue(davxml.CurrentUserPrivilegeSet(*privs))
+ returnValue((yield ifAllowed(
(davxml.ReadCurrentUserPrivilegeSet(),),
callback
- )
+ )))
if name == "acl":
+ @inlineCallbacks
def callback():
- def gotACL(acl):
- if acl is None:
- acl = davxml.ACL()
- return acl
- d = self.accessControlList(request)
- d.addCallback(gotACL)
- return d
- return ifAllowed((davxml.ReadACL(),), callback)
-
+ acl = yield self.accessControlList(request)
+ if acl is None:
+ acl = davxml.ACL()
+ returnValue(acl)
+ returnValue(
+ (yield ifAllowed((davxml.ReadACL(),), callback))
+ )
+
if name == "current-user-principal":
- return davxml.CurrentUserPrincipal(
+ returnValue(davxml.CurrentUserPrincipal(
self.currentPrincipal(request).children[0]
- )
+ ))
if name == "quota-available-bytes":
- def callback(qvalue):
- if qvalue is None:
- raise HTTPError(StatusResponse(
- responsecode.NOT_FOUND,
- "Property %s does not exist." % (sname,)
- ))
- else:
- return davxml.QuotaAvailableBytes(str(qvalue[0]))
- d = self.quota(request)
- d.addCallback(callback)
- return d
+ qvalue = yield self.quota(request)
+ if qvalue is None:
+ raise HTTPError(StatusResponse(
+ responsecode.NOT_FOUND,
+ "Property %s does not exist." % (sname,)
+ ))
+ else:
+ returnValue(davxml.QuotaAvailableBytes(str(qvalue[0])))
if name == "quota-used-bytes":
- def callback(qvalue):
- if qvalue is None:
- raise HTTPError(StatusResponse(
- responsecode.NOT_FOUND,
- "Property %s does not exist." % (sname,)
- ))
- else:
- return davxml.QuotaUsedBytes(str(qvalue[1]))
- d = self.quota(request)
- d.addCallback(callback)
- return d
+ qvalue = yield self.quota(request)
+ if qvalue is None:
+ raise HTTPError(StatusResponse(
+ responsecode.NOT_FOUND,
+ "Property %s does not exist." % (sname,)
+ ))
+ else:
+ returnValue(davxml.QuotaUsedBytes(str(qvalue[1])))
elif namespace == twisted_dav_namespace:
if name == "resource-class":
- class ResourceClass (davxml.WebDAVTextElement):
- namespace = twisted_dav_namespace
- name = "resource-class"
- hidden = False
- return ResourceClass(self.__class__.__name__)
+ returnValue(ResourceClass(self.__class__.__name__))
elif namespace == twisted_private_namespace:
raise HTTPError(StatusResponse(
@@ -385,10 +374,10 @@
"Properties in the %s namespace are private to the server."
% (sname,)
))
+ returnValue(self.deadProperties().get(qname))
- return self.deadProperties().get(qname)
+ return defer()
- return maybeDeferred(defer)
def writeProperty(self, property, request):
"""
@@ -2677,3 +2666,9 @@
)
unauthenticatedPrincipal = davxml.Principal(davxml.Unauthenticated())
+
+
+class ResourceClass (davxml.WebDAVTextElement):
+ namespace = twisted_dav_namespace
+ name = "resource-class"
+ hidden = False
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/resource.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/resource.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/resource.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -30,6 +30,8 @@
# System Imports
from zope.interface import implements
+from twisted.internet.defer import inlineCallbacks, returnValue
+
from twext.web2 import iweb, http, server, responsecode
class RenderMixin(object):
@@ -71,6 +73,8 @@
if method:
return method(request)
+
+ @inlineCallbacks
def renderHTTP(self, request):
"""
See L{iweb.IResource.renderHTTP}.
@@ -96,17 +100,15 @@
@return: an object adaptable to L{iweb.IResponse}.
"""
method = getattr(self, "http_" + request.method, None)
- if not method:
+ if method is None:
response = http.Response(responsecode.NOT_ALLOWED)
response.headers.setHeader("allow", self.allowedMethods())
- return response
+ returnValue(response)
- d = self.checkPreconditions(request)
- if d is None:
- return method(request)
- else:
- return d.addCallback(lambda _: method(request))
+ yield self.checkPreconditions(request)
+ returnValue((yield method(request)))
+
def http_OPTIONS(self, request):
"""
Respond to a OPTIONS request.
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/static.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/static.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/static.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -35,10 +35,11 @@
# Sibling Imports
from twext.web2 import http_headers, resource
from twext.web2 import http, iweb, stream, responsecode, server, dirlist
+from twext.web2.http import HTTPError
# Twisted Imports
from twext.python.filepath import CachingFilePath as FilePath
-from twisted.internet.defer import maybeDeferred
+from twisted.internet.defer import inlineCallbacks, returnValue
from zope.interface import implements
class MetaDataMixin(object):
@@ -95,21 +96,26 @@
return True
class StaticRenderMixin(resource.RenderMixin, MetaDataMixin):
+
+
+ @inlineCallbacks
def checkPreconditions(self, request):
# This code replaces the code in resource.RenderMixin
if request.method not in ("GET", "HEAD"):
http.checkPreconditions(
request,
entityExists = self.exists(),
- etag = self.etag(),
- lastModified = self.lastModified(),
+ etag = (yield self.etag()),
+ lastModified = (yield self.lastModified()),
)
# Check per-method preconditions
method = getattr(self, "preconditions_" + request.method, None)
if method:
- return method(request)
+ returnValue((yield method(request)))
+
+ @inlineCallbacks
def renderHTTP(self, request):
"""
See L{resource.RenderMixIn.renderHTTP}.
@@ -117,32 +123,27 @@
This implementation automatically sets some headers on the response
based on data available from L{MetaDataMixin} methods.
"""
- def setHeaders(response):
- response = iweb.IResponse(response)
+ try:
+ response = yield super(StaticRenderMixin, self).renderHTTP(request)
+ except HTTPError, he:
+ response = he.response
- # Don't provide additional resource information to error responses
- if response.code < 400:
- # Content-* headers refer to the response content, not
- # (necessarily) to the resource content, so they depend on the
- # request method, and therefore can't be set here.
- for (header, value) in (
- ("etag", self.etag()),
- ("last-modified", self.lastModified()),
- ):
- if value is not None:
- response.headers.setHeader(header, value)
+ response = iweb.IResponse(response)
+ # Don't provide additional resource information to error responses
+ if response.code < 400:
+ # Content-* headers refer to the response content, not
+ # (necessarily) to the resource content, so they depend on the
+ # request method, and therefore can't be set here.
+ for (header, value) in (
+ ("etag", (yield self.etag())),
+ ("last-modified", (yield self.lastModified())),
+ ):
+ if value is not None:
+ response.headers.setHeader(header, value)
+ returnValue(response)
- return response
- def onError(f):
- # If we get an HTTPError, run its response through setHeaders() as
- # well.
- f.trap(http.HTTPError)
- return setHeaders(f.value.response)
- d = maybeDeferred(super(StaticRenderMixin, self).renderHTTP, request)
- return d.addCallbacks(setHeaders, onError)
-
class Data(resource.Resource):
"""
This is a static, in-memory resource.
@@ -575,7 +576,7 @@
"""
import mimetypes
# Grab Python's built-in mimetypes dictionary.
- contentTypes = mimetypes.types_map
+ contentTypes = mimetypes.types_map #@UndefinedVariable
# Update Python's semi-erroneous dictionary with a few of the
# usual suspects.
contentTypes.update(
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/test/test_resource.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/test/test_resource.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/twext/web2/test/test_resource.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -9,7 +9,7 @@
from zope.interface import implements
-from twisted.internet.defer import succeed, fail
+from twisted.internet.defer import succeed, fail, inlineCallbacks
from twisted.trial import unittest
from twext.web2 import responsecode
from twext.web2.iweb import IResource
@@ -78,6 +78,8 @@
self._my_allowed_methods
)
+
+ @inlineCallbacks
def test_checkPreconditions_raises(self):
"""
RenderMixin.checkPreconditions()
@@ -87,11 +89,17 @@
request = SimpleRequest(Site(resource), "BLEARGH", "/")
# Check that checkPreconditions raises as expected
- self.assertRaises(PreconditionError, resource.checkPreconditions, request)
+ self.assertRaises(
+ PreconditionError, resource.checkPreconditions, request
+ )
# Check that renderHTTP calls checkPreconditions
- self.assertRaises(PreconditionError, resource.renderHTTP, request)
+ yield self.failUnlessFailure(
+ resource.renderHTTP(request), PreconditionError
+ )
+
+ @inlineCallbacks
def test_checkPreconditions_none(self):
"""
RenderMixin.checkPreconditions()
@@ -101,8 +109,12 @@
request = SimpleRequest(Site(resource), "SWEETHOOKUPS", "/")
# Check that checkPreconditions without a raise doesn't barf
- self.assertEquals(resource.renderHTTP(request), responsecode.NO_CONTENT)
+ self.assertEquals(
+ (yield resource.renderHTTP(request)),
+ responsecode.NO_CONTENT
+ )
+
def test_checkPreconditions_deferred(self):
"""
RenderMixin.checkPreconditions()
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/method/put_common.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/method/put_common.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -697,13 +697,14 @@
returnValue((is_scheduling_resource, data_changed, did_implicit_action,))
+
@inlineCallbacks
def mergePerUserData(self):
if self.calendar:
accessUID = (yield self.destination.resourceOwnerPrincipal(self.request))
accessUID = accessUID.principalUID() if accessUID else ""
if self.destination.exists() and self.destinationcal:
- oldCal = self.destination.iCalendar()
+ oldCal = yield self.destination.iCalendar()
else:
oldCal = None
@@ -718,7 +719,8 @@
log.err(msg)
raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "valid-calendar-data"), description=msg))
self.calendardata = None
-
+
+
@inlineCallbacks
def doStore(self, implicit):
@@ -733,7 +735,7 @@
sourceProperties = dict(source.newStoreProperties().iteritems())
if not implicit:
# Only needed in implicit case; see below.
- sourceText = source.iCalendarText()
+ sourceText = yield source.iCalendarText()
# Delete the original source if needed (for example, if this is a
# same-calendar MOVE of a calendar object, implemented as an
@@ -761,6 +763,7 @@
returnValue(IResponse(response))
+
@inlineCallbacks
def doStorePut(self):
@@ -934,7 +937,7 @@
etags = self.destination.readDeadProperty(TwistedScheduleMatchETags).children
else:
etags = ()
- etags += (davxml.GETETag.fromString(self.destination.etag().tag),)
+ etags += (davxml.GETETag.fromString((yield self.destination.etag()).tag),)
self.destination.writeDeadProperty(TwistedScheduleMatchETags(*etags))
else:
self.destination.removeDeadProperty(TwistedScheduleMatchETags)
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/resource.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/resource.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -1128,7 +1128,7 @@
).iCalendarForUser(request))
)
- caldata = self.iCalendar()
+ caldata = yield self.iCalendar()
accessUID = (yield self.resourceOwnerPrincipal(request))
if accessUID is None:
@@ -1463,6 +1463,7 @@
+ @inlineCallbacks
def iCalendarTextFiltered(self, isowner, accessUID=None):
try:
access = self.readDeadProperty(TwistedCalendarAccessProperty)
@@ -1470,10 +1471,12 @@
access = None
# Now "filter" the resource calendar data
- caldata = PrivateEventFilter(access, isowner).filter(self.iCalendarText())
+ caldata = PrivateEventFilter(access, isowner).filter(
+ (yield self.iCalendarText())
+ )
if accessUID:
caldata = PerUserDataFilter(accessUID).filter(caldata)
- return str(caldata)
+ returnValue(str(caldata))
def iCalendarText(self):
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/sharing.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/sharing.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -101,15 +101,15 @@
returnValue(True)
+
+ @inlineCallbacks
def removeUserFromInvite(self, userid, request):
""" Remove a user from this shared calendar """
- self.invitesDB().removeRecordForUserID(userid)
+ returnValue((yield self.invitesDB().removeRecordForUserID(userid)))
- return succeed(True)
@inlineCallbacks
def changeUserInviteState(self, request, inviteUID, principalURL, state, summary=None):
-
shared = (yield self.isShared(request))
if not shared:
raise HTTPError(ErrorResponse(
@@ -118,7 +118,7 @@
"invalid share",
))
- record = self.invitesDB().recordForInviteUID(inviteUID)
+ record = yield self.invitesDB().recordForInviteUID(inviteUID)
if record is None or record.principalURL != principalURL:
raise HTTPError(ErrorResponse(
responsecode.FORBIDDEN,
@@ -131,8 +131,9 @@
record.state = state
if summary is not None:
record.summary = summary
- self.invitesDB().addOrUpdateRecord(record)
+ yield self.invitesDB().addOrUpdateRecord(record)
+
@inlineCallbacks
def directShare(self, request):
"""
@@ -196,28 +197,33 @@
# Accept it
response = (yield home.acceptDirectShare(request, request.path, self.resourceID(), self.displayName()))
-
+
# Return the URL of the shared calendar
returnValue(response)
+
+ @inlineCallbacks
def isShared(self, request):
""" Return True if this is an owner shared calendar collection """
- return succeed(self.isSpecialCollection(customxml.SharedOwner))
+ returnValue((yield self.isSpecialCollection(customxml.SharedOwner)))
+
def setVirtualShare(self, shareePrincipal, share):
self._isVirtualShare = True
self._shareePrincipal = shareePrincipal
self._share = share
-
+
if hasattr(self, "_newStoreCalendar"):
self._newStoreCalendar.setSharingUID(self._shareePrincipal.principalUID())
elif hasattr(self, "_newStoreAddressBook"):
self._newStoreAddressBook.setSharingUID(self._shareePrincipal.principalUID())
+
def isVirtualShare(self):
""" Return True if this is a shared calendar collection """
return hasattr(self, "_isVirtualShare")
+
@inlineCallbacks
def removeVirtualShare(self, request):
""" Return True if this is a shared calendar collection """
@@ -229,6 +235,7 @@
shareeHome = yield self._shareePrincipal.addressBookHome(request)
returnValue((yield shareeHome.removeShare(request, self._share)))
+
def resourceType(self):
superObject = super(SharedCollectionMixin, self)
try:
@@ -247,7 +254,8 @@
)
)
return rtype
-
+
+
def sharedResourceType(self):
"""
Return the DAV:resourcetype stripped of any shared elements.
@@ -260,6 +268,7 @@
else:
return ""
+
@inlineCallbacks
def shareeAccessControlList(self, request, *args, **kwargs):
@@ -274,7 +283,9 @@
# Invite shares use access mode from the invite
# Get the invite for this sharee
- invite = self.invitesDB().recordForInviteUID(self._share.shareuid)
+ invite = yield self.invitesDB().recordForInviteUID(
+ self._share.shareuid
+ )
if invite is None:
returnValue(davxml.ACL())
@@ -290,7 +301,7 @@
userprivs.append(davxml.Privilege(davxml.Write()))
proxyprivs = list(userprivs)
proxyprivs.remove(davxml.Privilege(davxml.ReadACL()))
-
+
aces = (
# Inheritable specific access for the resource's associated principal.
davxml.ACE(
@@ -300,7 +311,7 @@
TwistedACLInheritable(),
),
)
-
+
if self.isCalendarCollection():
aces += (
# Inheritable CALDAV:read-free-busy access for authenticated users.
@@ -310,13 +321,13 @@
TwistedACLInheritable(),
),
)
-
+
# Give read access to config.ReadPrincipals
aces += config.ReadACEs
-
+
# Give all access to config.AdminPrincipals
aces += config.AdminACEs
-
+
if config.EnableProxyPrincipals:
aces += (
# DAV:read/DAV:read-current-user-privilege-set access for this principal's calendar-proxy-read users.
@@ -337,7 +348,7 @@
TwistedACLInheritable(),
),
)
-
+
returnValue(davxml.ACL(*aces))
def validUserIDForShare(self, userid):
@@ -401,7 +412,7 @@
for record in records:
if self.validUserIDForShare(record.userid) is None and record.state != "INVALID":
record.state = "INVALID"
- self.invitesDB().addOrUpdateRecord(record)
+ yield self.invitesDB().addOrUpdateRecord(record)
def inviteUserToShare(self, userid, cn, ace, summary, request):
@@ -459,6 +470,7 @@
dl = [self.inviteSingleUserUpdateToShare(user, cn, aceOLD, aceNEW, summary, request) for user, cn in zip(userid, cn)]
return DeferredList(dl).addCallback(_defer)
+
@inlineCallbacks
def inviteSingleUserToShare(self, userid, cn, ace, summary, request):
@@ -482,7 +494,7 @@
yield self.sendInvite(record, request)
# Add to database
- self.invitesDB().addOrUpdateRecord(record)
+ yield self.invitesDB().addOrUpdateRecord(record)
returnValue(True)
@@ -519,7 +531,7 @@
yield self.sendInvite(record, request)
# Remove from database
- self.invitesDB().removeRecordForUserID(record.userid)
+ yield self.invitesDB().removeRecordForUserID(record.userid)
returnValue(True)
@@ -1000,7 +1012,7 @@
share = oldShare
else:
share = SharedCollectionRecord(shareUID, sharetype, hostUrl, str(uuid4()), displayname)
- self.sharesDB().addOrUpdateRecord(share)
+ yield self.sharesDB().addOrUpdateRecord(share)
# Set per-user displayname to whatever was given
sharedCollection = (yield request.locateResource(hostUrl))
@@ -1057,7 +1069,7 @@
inbox = (yield request.locateResource(inboxURL))
inbox.processFreeBusyCalendar(shareURL, False)
- self.sharesDB().removeRecordForShareUID(share.shareuid)
+ yield self.sharesDB().removeRecordForShareUID(share.shareuid)
# Notify client of changes
self.notifyChanged()
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/storebridge.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/twistedcaldav/storebridge.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -160,45 +160,54 @@
def name(self):
return self._newStoreObject.name() if self._newStoreObject is not None else None
+
+ @inlineCallbacks
def etag(self):
# FIXME: far too slow to be used for real, but I needed something to
# placate the etag computation in the case where the file doesn't exist
# yet (an uncommitted transaction creating this calendar file)
if self._newStoreObject is None:
- return None
+ returnValue(None)
# FIXME: direct tests
try:
md5 = self._newStoreObject.md5()
if md5:
- return ETag(md5)
+ returnValue(ETag(md5))
else:
- return ETag(
- hashlib.new("md5", self.text()).hexdigest(),
+ returnValue(ETag(
+ hashlib.new("md5", (yield self.text())).hexdigest(),
weak=False
- )
+ ))
except NoSuchObjectResourceError:
# FIXME: a workaround for the fact that DELETE still rudely vanishes
# the calendar object out from underneath the store, and doesn't
# call storeRemove.
- return None
+ returnValue(None)
+
def contentType(self):
return self._newStoreObject.contentType() if self._newStoreObject is not None else None
+
def contentLength(self):
return self._newStoreObject.size() if self._newStoreObject is not None else None
+
def lastModified(self):
return self._newStoreObject.modified() if self._newStoreObject is not None else None
+
def creationDate(self):
return self._newStoreObject.created() if self._newStoreObject is not None else None
+
def newStoreProperties(self):
return self._newStoreObject.properties() if self._newStoreObject is not None else None
+
+
class _CalendarChildHelper(object):
"""
Methods for things which are like calendars.
@@ -313,7 +322,7 @@
# FIXME: spurious error, sanity check, should not be needed;
# unfortunately, user09's calendar home does not have an inbox, so
# this is a temporary workaround.
- home.createCalendarWithName("inbox")
+ yield home.createCalendarWithName("inbox")
storage = yield home.calendarWithName("inbox")
self._initializeWithCalendar(
storage,
@@ -778,7 +787,7 @@
continue
# Get the access filtered view of the data
- caldata = child.iCalendarTextFiltered(isowner, accessPrincipal.principalUID() if accessPrincipal else "")
+ caldata = yield child.iCalendarTextFiltered(isowner, accessPrincipal.principalUID() if accessPrincipal else "")
try:
subcalendar = vcomponent.VComponent.fromString(caldata)
except ValueError:
@@ -1008,7 +1017,7 @@
"""
Override C{createCalendarCollection} to actually do the work.
"""
- self._newStoreParentHome.createCalendarWithName(self._name)
+ yield self._newStoreParentHome.createCalendarWithName(self._name)
newStoreCalendar = yield self._newStoreParentHome.calendarWithName(
self._name
)
@@ -1094,9 +1103,10 @@
return True
+ @inlineCallbacks
def quotaSize(self, request):
# FIXME: tests
- return succeed(len(self._newStoreObject.iCalendarText()))
+ returnValue(len((yield self.iCalendarText())))
def iCalendarText(self):
@@ -1125,7 +1135,7 @@
component = vcomponent.VComponent.fromString(
(yield allDataFromStream(stream))
)
- self._newStoreObject.setComponent(component)
+ yield self._newStoreObject.setComponent(component)
returnValue(NO_CONTENT)
@@ -1220,7 +1230,7 @@
# FIXME: public attribute please. Should ICalendar maybe just have
# a delete() method?
- storeCalendar.removeCalendarObjectWithName(
+ yield storeCalendar.removeCalendarObjectWithName(
self._newStoreObject.name()
)
@@ -1280,7 +1290,7 @@
component = vcomponent.VComponent.fromString(
(yield allDataFromStream(stream))
)
- self._newStoreParentCalendar.createCalendarObjectWithName(
+ yield self._newStoreParentCalendar.createCalendarObjectWithName(
self.name(), component
)
CalendarObjectResource.transform(
@@ -1534,7 +1544,7 @@
yield self.downgradeFromShare(request)
# Actually delete it.
- self._newStoreParentHome.removeAddressBookWithName(
+ yield self._newStoreParentHome.removeAddressBookWithName(
self._newStoreAddressBook.name()
)
self.__class__ = ProtoAddressBookCollectionResource
@@ -1630,7 +1640,7 @@
"""
Override C{createAddressBookCollection} to actually do the work.
"""
- self._newStoreParentHome.createAddressBookWithName(self._name)
+ yield self._newStoreParentHome.createAddressBookWithName(self._name)
newStoreAddressBook = yield self._newStoreParentHome.addressbookWithName(
self._name
)
@@ -1735,7 +1745,7 @@
component = VCard.fromString(
(yield allDataFromStream(stream))
)
- self._newStoreObject.setComponent(component)
+ yield self._newStoreObject.setComponent(component)
returnValue(NO_CONTENT)
@@ -1758,7 +1768,9 @@
# Do delete
# FIXME: public attribute please
- storeAddressBook.removeAddressBookObjectWithName(self._newStoreObject.name())
+ yield storeAddressBook.removeAddressBookObjectWithName(
+ self._newStoreObject.name()
+ )
# FIXME: clean this up with a 'transform' method
self._newStoreParentAddressBook = storeAddressBook
@@ -1798,13 +1810,14 @@
self._newStoreParentAddressBook = parentAddressBook
self._name = name
+
@inlineCallbacks
def storeStream(self, stream):
# FIXME: direct tests
component = VCard.fromString(
(yield allDataFromStream(stream))
)
- self._newStoreParentAddressBook.createAddressBookObjectWithName(
+ yield self._newStoreParentAddressBook.createAddressBookObjectWithName(
self.name(), component
)
AddressBookObjectResource.transform(
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/sql.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/sql.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -15,6 +15,10 @@
# limitations under the License.
##
+"""
+SQL backend for CalDAV storage.
+"""
+
__all__ = [
"CalendarHome",
"Calendar",
@@ -216,6 +220,8 @@
def _pathToName(path):
return path.rsplit(".", 1)[0]
+
+
class CalendarObject(CommonObjectResource):
implements(ICalendarObject)
@@ -225,17 +231,20 @@
def _calendar(self):
return self._parentCollection
+
def calendar(self):
return self._calendar
+
+ @inlineCallbacks
def setComponent(self, component, inserting=False):
validateCalendarComponent(self, self._calendar, component, inserting)
- self.updateDatabase(component, inserting=inserting)
+ yield self.updateDatabase(component, inserting=inserting)
if inserting:
- self._calendar._insertRevision(self._name)
+ yield self._calendar._insertRevision(self._name)
else:
- self._calendar._updateRevision(self._name)
+ yield self._calendar._updateRevision(self._name)
self._calendar.notifyChanged()
@@ -306,7 +315,7 @@
]
))[0][0]
else:
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
update CALENDAR_OBJECT set
(ICALENDAR_TEXT, ICALENDAR_UID, ICALENDAR_TYPE, ATTACHMENTS_MODE, ORGANIZER, RECURRANCE_MAX, MODIFIED)
@@ -329,7 +338,7 @@
)
# Need to wipe the existing time-range for this and rebuild
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
delete from TIME_RANGE where CALENDAR_OBJECT_RESOURCE_ID = %s
""",
@@ -368,7 +377,7 @@
))[0][0]
peruserdata = component.perUserTransparency(instance.rid)
for useruid, transp in peruserdata:
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
insert into TRANSPARENCY
(TIME_RANGE_INSTANCE_ID, USER_ID, TRANSPARENT)
@@ -409,7 +418,7 @@
))[0][0]
peruserdata = component.perUserTransparency(None)
for useruid, transp in peruserdata:
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
insert into TRANSPARENCY
(TIME_RANGE_INSTANCE_ID, USER_ID, TRANSPARENT)
@@ -459,10 +468,11 @@
returnValue(attachment.store(contentType))
+ @inlineCallbacks
def removeAttachmentWithName(self, name):
attachment = Attachment(self, name)
self._txn.postCommit(attachment._path.remove)
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
delete from ATTACHMENT where CALENDAR_OBJECT_RESOURCE_ID = %s AND
PATH = %s
@@ -479,8 +489,11 @@
returnValue(None)
+ @inlineCallbacks
def attendeesCanManageAttachments(self):
- return self.component().hasPropertyInAnyComponent("X-APPLE-DROPBOX")
+ returnValue((yield self.component()).hasPropertyInAnyComponent(
+ "X-APPLE-DROPBOX"
+ ))
dropboxID = dropboxIDFromCalendarObject
@@ -551,17 +564,21 @@
self.hash.update(data)
+ @inlineCallbacks
def loseConnection(self):
self.attachment._path.setContent(self.buf)
contentTypeString = generateContentType(self.contentType)
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
update ATTACHMENT set CONTENT_TYPE = %s, SIZE = %s, MD5 = %s,
MODIFIED = timezone('UTC', CURRENT_TIMESTAMP) WHERE PATH = %s
""",
- [contentTypeString, len(self.buf), self.hash.hexdigest(), self.attachment.name()]
+ [contentTypeString, len(self.buf),
+ self.hash.hexdigest(), self.attachment.name()]
)
+
+
class Attachment(object):
implements(IAttachment)
@@ -586,7 +603,9 @@
rows = yield self._txn.execSQL(
"""
select CONTENT_TYPE, SIZE, MD5, CREATED, MODIFIED from ATTACHMENT where PATH = %s
- """, [self._name])
+ """,
+ [self._name]
+ )
if not rows:
returnValue(False)
self._contentType = MimeType.fromString(rows[0][0])
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/test/common.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/test/common.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/txdav/caldav/datastore/test/common.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -876,7 +876,7 @@
calendar1 = yield self.calendarUnderTest()
calendarObject = yield calendar1.calendarObjectWithName("1.ics")
- oldComponent = calendarObject.component()
+ oldComponent = yield calendarObject.component()
self.assertNotEqual(component, oldComponent)
yield calendarObject.setComponent(component)
self.assertEquals((yield calendarObject.component()), component)
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/sql.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/txdav/carddav/datastore/sql.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -14,14 +14,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
##
-from twisted.internet.defer import inlineCallbacks, returnValue
+"""
+SQL backend for CardDAV storage.
+"""
+
__all__ = [
"AddressBookHome",
"AddressBook",
"AddressBookObject",
]
+from zope.interface.declarations import implements
+
+from twisted.internet.defer import inlineCallbacks, returnValue
+
from twext.web2.dav.element.rfc2518 import ResourceType
from twext.web2.http_headers import MimeType
@@ -43,10 +50,8 @@
ADDRESSBOOK_OBJECT_TABLE
from txdav.base.propertystore.base import PropertyName
-from zope.interface.declarations import implements
-
class AddressBookHome(CommonHome):
implements(IAddressBookHome)
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/txdav/common/datastore/sql.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/txdav/common/datastore/sql.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -60,7 +60,7 @@
from txdav.common.inotifications import INotificationCollection, \
INotificationObject
from txdav.base.datastore.sql import memoized
-from txdav.base.datastore.util import cached
+
from txdav.idav import AlreadyFinishedError
from txdav.base.propertystore.base import PropertyName
from txdav.base.propertystore.sql import PropertyStore
@@ -274,18 +274,23 @@
return None
+ noisy = False
+
def execSQL(self, *args, **kw):
- def reportResult(results):
- sys.stdout.write("\n".join([
- "",
- "SQL: %r %r" % (args, kw),
- "Results: %r" % (results,),
- "",
- ]))
- return results
- return self._holder.submit(
+ result = self._holder.submit(
lambda : self._reallyExecSQL(*args, **kw)
- )#.addBoth(reportResult)
+ )
+ if self.noisy:
+ def reportResult(results):
+ sys.stdout.write("\n".join([
+ "",
+ "SQL: %r %r" % (args, kw),
+ "Results: %r" % (results,),
+ "",
+ ]))
+ return results
+ result.addBoth(reportResult)
+ return result
def __del__(self):
@@ -582,7 +587,7 @@
child = yield self.childWithName(name)
if not child:
raise NoSuchHomeChildError()
- child._deletedSyncToken()
+ yield child._deletedSyncToken()
yield self._txn.execSQL(
"delete from %(name)s where %(column_RESOURCE_ID)s = %%s" % self._childTable,
@@ -931,10 +936,12 @@
returnValue((changed, deleted))
+
+ @inlineCallbacks
def _initSyncToken(self):
-
+
# Remove any deleted revision entry that uses the same name
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
delete from %(name)s
where %(column_HOME_RESOURCE_ID)s = %%s and %(column_COLLECTION_NAME)s = %%s
""" % self._revisionsTable,
@@ -942,7 +949,7 @@
)
# Insert new entry
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
insert into %(name)s
(%(column_HOME_RESOURCE_ID)s, %(column_RESOURCE_ID)s, %(column_COLLECTION_NAME)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
values (%%s, %%s, %%s, null, nextval('%(sequence)s'), FALSE)
@@ -950,9 +957,11 @@
[self._home._resourceID, self._resourceID, self._name]
)
+
+ @inlineCallbacks
def _updateSyncToken(self):
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s) = (nextval('%(sequence)s'))
where %(column_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s is null
@@ -960,9 +969,11 @@
[self._resourceID,]
)
+
+ @inlineCallbacks
def _renameSyncToken(self):
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s, %(column_COLLECTION_NAME)s) = (nextval('%(sequence)s'), %%s)
where %(column_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s is null
@@ -970,18 +981,20 @@
[self._name, self._resourceID,]
)
+
+ @inlineCallbacks
def _deletedSyncToken(self):
# Remove all child entries
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
delete from %(name)s
where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_ID)s = %%s and %(column_COLLECTION_NAME)s is null
""" % self._revisionsTable,
[self._home._resourceID, self._resourceID,]
)
-
+
# Then adjust collection entry to deleted state
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_RESOURCE_ID)s, %(column_REVISION)s, %(column_DELETED)s)
= (null, nextval('%(sequence)s'), TRUE)
@@ -990,14 +1003,15 @@
[self._resourceID,]
)
+
def _insertRevision(self, name):
- self._changeRevision("insert", name)
+ return self._changeRevision("insert", name)
def _updateRevision(self, name):
- self._changeRevision("update", name)
+ return self._changeRevision("update", name)
def _deleteRevision(self, name):
- self._changeRevision("delete", name)
+ return self._changeRevision("delete", name)
@inlineCallbacks
@@ -1009,14 +1023,14 @@
)
if action == "delete":
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s, %(column_DELETED)s) = (%%s, TRUE)
where %(column_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
""" % self._revisionsTable,
[nextrevision, self._resourceID, name]
)
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s) = (%%s)
where %(column_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s is null
@@ -1024,14 +1038,14 @@
[nextrevision, self._resourceID,]
)
elif action == "update":
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
; update %(name)s
set (%(column_REVISION)s) = (%%s)
where %(column_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
""" % self._revisionsTable,
[nextrevision, self._resourceID, name]
)
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s) = (%%s)
where %(column_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s is null
@@ -1050,7 +1064,7 @@
[self._resourceID, name, ]
)) )
if found:
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s, %(column_DELETED)s) = (%%s, FALSE)
where %(column_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
@@ -1058,14 +1072,14 @@
[nextrevision, self._resourceID, name]
)
else:
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
insert into %(name)s
(%(column_HOME_RESOURCE_ID)s, %(column_RESOURCE_ID)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
values (%%s, %%s, %%s, %%s, FALSE)
""" % self._revisionsTable,
[self._home._resourceID, self._resourceID, name, nextrevision]
)
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s) = (%%s)
where %(column_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s is null
@@ -1088,6 +1102,7 @@
def properties(self):
return self._properties
+
def initPropertyStore(self, props):
"""
A hook for subclasses to override in order to set up their property
@@ -1095,11 +1110,12 @@
@param props: the L{PropertyStore} from C{properties()}.
"""
- pass
+
def _doValidate(self, component):
raise NotImplementedError
+
# IDataStoreResource
def contentType(self):
raise NotImplementedError()
@@ -1113,38 +1129,44 @@
return 0
+ @inlineCallbacks
def created(self):
- created = self._txn.execSQL(
+ created = (yield self._txn.execSQL(
"select %(column_CREATED)s from %(name)s "
"where %(column_RESOURCE_ID)s = %%s" % self._homeChildTable,
[self._resourceID]
- )[0][0]
+ ))[0][0]
utc = datetime.datetime.strptime(created, "%Y-%m-%d %H:%M:%S.%f")
- return datetimeMktime(utc)
+ returnValue(datetimeMktime(utc))
+
+ @inlineCallbacks
def modified(self):
- modified = self._txn.execSQL(
+ modified = (yield self._txn.execSQL(
"select %(column_MODIFIED)s from %(name)s "
"where %(column_RESOURCE_ID)s = %%s" % self._homeChildTable,
[self._resourceID]
- )[0][0]
+ ))[0][0]
utc = datetime.datetime.strptime(modified, "%Y-%m-%d %H:%M:%S.%f")
- return datetimeMktime(utc)
+ returnValue(datetimeMktime(utc))
+
def notifierID(self, label="default"):
if self._notifier:
return self._notifier.getID(label)
else:
return None
+
def notifyChanged(self):
"""
Trigger a notification of a change
"""
if self._notifier:
self._txn.postCommit(self._notifier.notify)
-
+
+
class CommonObjectResource(LoggingMixIn, FancyEqMixin):
"""
@ivar _path: The path of the file on disk
@@ -1227,33 +1249,36 @@
return None
+ @inlineCallbacks
def size(self):
- size = self._txn.execSQL(
+ size = (yield self._txn.execSQL(
"select character_length(%(column_TEXT)s) from %(name)s "
"where %(column_RESOURCE_ID)s = %%s" % self._objectTable,
[self._resourceID]
- )[0][0]
- return size
+ ))[0][0]
+ returnValue(size)
+ @inlineCallbacks
def created(self):
- created = self._txn.execSQL(
+ created = (yield self._txn.execSQL(
"select %(column_CREATED)s from %(name)s "
"where %(column_RESOURCE_ID)s = %%s" % self._objectTable,
[self._resourceID]
- )[0][0]
+ ))[0][0]
utc = datetime.datetime.strptime(created, "%Y-%m-%d %H:%M:%S.%f")
- return datetimeMktime(utc)
+ returnValue(datetimeMktime(utc))
+ @inlineCallbacks
def modified(self):
- modified = self._txn.execSQL(
+ modified = (yield self._txn.execSQL(
"select %(column_MODIFIED)s from %(name)s "
"where %(column_RESOURCE_ID)s = %%s" % self._objectTable,
[self._resourceID]
- )[0][0]
+ ))[0][0]
utc = datetime.datetime.strptime(modified, "%Y-%m-%d %H:%M:%S.%f")
- return datetimeMktime(utc)
+ returnValue(datetimeMktime(utc))
@inlineCallbacks
@@ -1325,6 +1350,7 @@
[self._resourceID])
returnValue(sorted(["%s.xml" % row[0] for row in rows]))
+
def _nameToUID(self, name):
"""
Based on the file-backed implementation, the 'name' is just uid +
@@ -1369,21 +1395,22 @@
def removeNotificationObjectWithName(self, name):
- self.removeNotificationObjectWithUID(self._nameToUID(name))
+ return self.removeNotificationObjectWithUID(self._nameToUID(name))
+ @inlineCallbacks
def removeNotificationObjectWithUID(self, uid):
- self._txn.execSQL(
+ yield self._txn.execSQL(
"delete from NOTIFICATION "
"where NOTIFICATION_UID = %s and NOTIFICATION_HOME_RESOURCE_ID = %s",
[uid, self._resourceID]
)
self._notifications.pop(uid, None)
- self._deleteRevision("%s.xml" % (uid,))
+ yield self._deleteRevision("%s.xml" % (uid,))
def _initSyncToken(self):
- self._txn.execSQL("""
+ return self._txn.execSQL("""
insert into %(name)s
(%(column_HOME_RESOURCE_ID)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
values (%%s, null, nextval('%(sequence)s'), FALSE)
@@ -1428,7 +1455,7 @@
))
]
results.sort(key=lambda x:x[1])
-
+
changed = []
deleted = []
for name, wasdeleted in results:
@@ -1438,13 +1465,12 @@
deleted.append(name)
else:
changed.append(name)
-
+
returnValue((changed, deleted))
def _updateSyncToken(self):
-
- self._txn.execSQL("""
+ return self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s) = (nextval('%(sequence)s'))
where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s is null
@@ -1452,14 +1478,17 @@
[self._resourceID,]
)
+
def _insertRevision(self, name):
- self._changeRevision("insert", name)
+ return self._changeRevision("insert", name)
+
def _updateRevision(self, name):
- self._changeRevision("update", name)
+ return self._changeRevision("update", name)
+
def _deleteRevision(self, name):
- self._changeRevision("delete", name)
+ return self._changeRevision("delete", name)
@inlineCallbacks
@@ -1471,14 +1500,14 @@
)
if action == "delete":
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s, %(column_DELETED)s) = (%%s, TRUE)
where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
""" % self._revisionsTable,
[nextrevision, self._resourceID, name]
)
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s) = (%%s)
where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s is null
@@ -1486,14 +1515,14 @@
[nextrevision, self._resourceID]
)
elif action == "update":
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s) = (%%s)
where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
""" % self._revisionsTable,
[nextrevision, self._resourceID, name]
)
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s) = (%%s)
where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s is null
@@ -1512,7 +1541,7 @@
[self._resourceID, name, ]
)))
if found:
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s, %(column_DELETED)s) = (%%s, FALSE)
where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
@@ -1520,14 +1549,14 @@
[nextrevision, self._resourceID, name]
)
else:
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
insert into %(name)s
(%(column_HOME_RESOURCE_ID)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
values (%%s, %%s, %%s, FALSE)
""" % self._revisionsTable,
[self._resourceID, name, nextrevision]
)
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update %(name)s
set (%(column_REVISION)s) = (%%s)
where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s is null
Modified: CalendarServer/branches/users/glyph/more-deferreds-7/txdav/common/datastore/sql_legacy.py
===================================================================
--- CalendarServer/branches/users/glyph/more-deferreds-7/txdav/common/datastore/sql_legacy.py 2010-10-16 02:18:57 UTC (rev 6430)
+++ CalendarServer/branches/users/glyph/more-deferreds-7/txdav/common/datastore/sql_legacy.py 2010-10-17 08:21:32 UTC (rev 6431)
@@ -91,7 +91,6 @@
-
class SQLLegacyInvites(object):
"""
Emulator for the implicit interface specified by
@@ -111,20 +110,22 @@
for key, value in self._bindTable.iteritems():
self._combinedTable["BIND:%s" % (key,)] = value
+
@property
def _txn(self):
return self._collection._txn
+
def _getHomeWithUID(self, uid):
raise NotImplementedError()
+
def create(self):
"No-op, because the index implicitly always exists in the database."
- pass
+
def remove(self):
"No-op, because the index implicitly always exists in the database."
- pass
@inlineCallbacks
@@ -247,7 +248,7 @@
# it will always contain the UID. The form is '/principals/__uids__/x'
# (and may contain a trailing slash).
principalUID = record.principalURL.split("/")[3]
- shareeHome = self._getHomeWithUID(principalUID)
+ shareeHome = yield self._getHomeWithUID(principalUID)
rows = yield self._txn.execSQL(
"select RESOURCE_ID, HOME_RESOURCE_ID from INVITE where RECIPIENT_ADDRESS = %s",
[record.userid]
@@ -255,7 +256,7 @@
if rows:
[[resourceID, homeResourceID]] = rows
# Invite(inviteuid, userid, principalURL, common_name, access, state, summary)
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
update %(BIND:name)s
set %(BIND:column_BIND_MODE)s = %%s,
@@ -266,7 +267,7 @@
""" % self._combinedTable,
[bindMode, bindStatus, record.summary, resourceID, homeResourceID]
)
- self._txn.execSQL("""
+ yield self._txn.execSQL("""
update INVITE
set NAME = %s, INVITE_UID = %s
where RECIPIENT_ADDRESS = %s
@@ -274,7 +275,7 @@
[record.name, record.inviteuid, record.userid]
)
else:
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
insert into INVITE
(
@@ -289,7 +290,7 @@
shareeHome._resourceID, self._collection._resourceID,
record.userid
])
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
insert into %(BIND:name)s
(
@@ -314,11 +315,13 @@
False,
False,
record.summary
- ])
+ ]
+ )
+ @inlineCallbacks
def removeRecordForUserID(self, userid):
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
delete from %(BIND:name)s using INVITE
where INVITE.RECIPIENT_ADDRESS = %%s
@@ -327,14 +330,15 @@
""" % self._combinedTable,
[userid]
)
- self._txn.execSQL(
+ yield self._txn.execSQL(
"delete from INVITE where RECIPIENT_ADDRESS = %s",
[userid]
)
+ @inlineCallbacks
def removeRecordForInviteUID(self, inviteUID):
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
delete from %(BIND:name)s using INVITE
where INVITE.INVITE_UID = %s
@@ -343,11 +347,13 @@
""" % self._combinedTable,
[inviteUID]
)
- self._txn.execSQL(
+ yield self._txn.execSQL(
"delete from INVITE where INVITE_UID = %s",
[inviteUID]
)
+
+
class SQLLegacyCalendarInvites(SQLLegacyInvites):
"""
Emulator for the implicit interface specified by
@@ -359,6 +365,7 @@
self._bindTable = CALENDAR_BIND_TABLE
super(SQLLegacyCalendarInvites, self).__init__(calendar)
+
def _getHomeWithUID(self, uid):
return self._txn.calendarHomeWithUID(uid, create=True)
@@ -375,9 +382,12 @@
self._bindTable = ADDRESSBOOK_BIND_TABLE
super(SQLLegacyAddressBookInvites, self).__init__(addressbook)
+
def _getHomeWithUID(self, uid):
return self._txn.addressbookHomeWithUID(uid, create=True)
+
+
class SQLLegacyShares(object):
_homeTable = None
@@ -498,6 +508,7 @@
return self._search(shareuid=shareUID)
+ @inlineCallbacks
def addOrUpdateRecord(self, record):
# record.hosturl -> /.../__uids__/<uid>/<name>
splithost = record.hosturl.split('/')
@@ -514,7 +525,7 @@
# just need to update its 'localname', i.e.
# XXX_BIND.XXX_RESOURCE_NAME.
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
update %(name)s
set %(column_RESOURCE_NAME)s = %%s
@@ -526,8 +537,8 @@
elif record.sharetype == 'D':
# There is no bind entry already so add one.
-
- self._txn.execSQL(
+
+ yield self._txn.execSQL(
"""
insert into %(name)s
(
@@ -553,8 +564,9 @@
record.summary,
])
+
def removeRecordForLocalName(self, localname):
- self._txn.execSQL(
+ return self._txn.execSQL(
"""
update %(name)s
set %(column_RESOURCE_NAME)s = NULL
@@ -565,9 +577,10 @@
)
+ @inlineCallbacks
def removeRecordForShareUID(self, shareUID):
if not shareUID.startswith("Direct"):
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
update %(name)s
set %(column_RESOURCE_NAME)s = NULL
@@ -583,7 +596,7 @@
homeID, resourceID = shareUID[len("Direct-"):].split("-")
# Now remove the binding for the direct share
- self._txn.execSQL(
+ yield self._txn.execSQL(
"""
delete from %(name)s
where %(column_HOME_RESOURCE_ID)s = %%s
@@ -591,7 +604,6 @@
""" % self._bindTable,
[homeID, resourceID,]
)
-
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20101017/738884d0/attachment-0001.html>
More information about the calendarserver-changes
mailing list