[CalendarServer-changes] [10695] CalendarServer/branches/users/gaya/sharedgroups
source_changes at macosforge.org
source_changes at macosforge.org
Mon Feb 11 17:07:09 PST 2013
Revision: 10695
http://trac.calendarserver.org//changeset/10695
Author: gaya at apple.com
Date: 2013-02-11 17:07:09 -0800 (Mon, 11 Feb 2013)
Log Message:
-----------
checkpoint. CalDAV's CardDAV/sharing-addressbooks.xml now work.
Modified Paths:
--------------
CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/iaddressbookstore.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql
Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py 2013-02-12 00:37:11 UTC (rev 10694)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py 2013-02-12 01:07:09 UTC (rev 10695)
@@ -38,7 +38,7 @@
from twisted.internet.defer import succeed, inlineCallbacks, DeferredList, \
returnValue
-from twistedcaldav import customxml, caldavxml, carddavxml
+from twistedcaldav import customxml, caldavxml
from twistedcaldav.config import config
from twistedcaldav.customxml import calendarserver_namespace
from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
@@ -515,12 +515,12 @@
elif self.isAddressBookCollection() or self.isGroup():
shareeHome = yield self._newStoreObject._txn.addressbookHomeWithUID(shareeUID, create=True)
- shareeHomeChild = yield self._newStoreObject.shareWith(shareeHome,
+ shareeStoreObject = yield self._newStoreObject.shareWith(shareeHome,
mode=invitationAccessToBindModeMap[access],
status=_BIND_STATUS_INVITED,
message=summary)
- invitation = Invitation(shareeHomeChild)
+ invitation = Invitation(shareeStoreObject)
returnValue(invitation)
@@ -529,7 +529,7 @@
mode = None if access is None else invitationAccessToBindModeMap[access]
status = None if state is None else invitationStateToBindStatusMap[state]
- yield self._newStoreObject.updateShare(invitation._shareeHomeChild, mode=mode, status=status, message=summary)
+ yield self._newStoreObject.updateShare(invitation._shareeStoreObject, mode=mode, status=status, message=summary)
assert not access or access == invitation.access(), "access=%s != invitation.access()=%s" % (access, invitation.access())
assert not state or state == invitation.state(), "state=%s != invitation.state()=%s" % (state, invitation.state())
assert not summary or summary == invitation.summary(), "summary=%s != invitation.summary()=%s" % (summary, invitation.summary())
@@ -635,9 +635,11 @@
if sharee:
if self.isCalendarCollection():
shareeHomeResource = yield sharee.calendarHome(request)
+ displayName = yield shareeHomeResource.removeShareByUID(request, invitation.uid())
elif self.isAddressBookCollection() or self.isGroup():
shareeHomeResource = yield sharee.addressBookHome(request)
- displayName = (yield shareeHomeResource.removeShareByUID(request, invitation.uid()))
+ yield shareeHomeResource.removeShareByUID(request, invitation.uid())
+ displayName = None
# If current user state is accepted then we send an invite with the new state, otherwise
# we cancel any existing invites for the user
if invitation and invitation.state() != "ACCEPTED":
@@ -646,7 +648,7 @@
yield self.sendInviteNotification(invitation, request, displayName=displayName, notificationState="DELETED")
# Direct shares for with valid sharee principal will already be deleted
- yield self._newStoreObject.unshareWith(invitation._shareeHomeChild.viewerHome())
+ yield self._newStoreObject.unshareWith(invitation._shareeStoreObject.viewerHome())
returnValue(True)
@@ -771,6 +773,7 @@
"%s: %s" % (", ".join(error_text), inviteset,),
))
+
def _handleInviteRemove(inviteremove):
userid = None
access = []
@@ -914,6 +917,7 @@
customxml.InviteReply: _xmlHandleInviteReply,
}
+
def isGroup(self):
try:
return self._newStoreObject._kind == _ABO_KIND_GROUP
@@ -937,6 +941,7 @@
("text", "xml") : xmlRequestHandler,
}
+
invitationAccessMapToXML = {
"read-only" : customxml.ReadAccess,
"read-write" : customxml.ReadWriteAccess,
@@ -966,32 +971,33 @@
}
invitationAccessFromBindModeMap = dict((v, k) for k, v in invitationAccessToBindModeMap.iteritems())
+
class Invitation(object):
"""
Invitation is a read-only wrapper for CommonHomeChild, that uses terms similar LegacyInvite sharing.py code base.
"""
- def __init__(self, shareeHomeChild):
- self._shareeHomeChild = shareeHomeChild
+ def __init__(self, shareeStoreObject):
+ self._shareeStoreObject = shareeStoreObject
def uid(self):
- return self._shareeHomeChild.shareUID()
+ return self._shareeStoreObject.shareUID()
def shareeUID(self):
- return self._shareeHomeChild.viewerHome().uid()
+ return self._shareeStoreObject.viewerHome().uid()
def access(self):
- return invitationAccessFromBindModeMap.get(self._shareeHomeChild.shareMode())
+ return invitationAccessFromBindModeMap.get(self._shareeStoreObject.shareMode())
def state(self):
- return invitationStateFromBindStatusMap.get(self._shareeHomeChild.shareStatus())
+ return invitationStateFromBindStatusMap.get(self._shareeStoreObject.shareStatus())
def summary(self):
- return self._shareeHomeChild.shareMessage()
+ return self._shareeStoreObject.shareMessage()
@@ -1003,19 +1009,19 @@
@inlineCallbacks
def provisionShare(self, child, request=None):
- share = yield self._shareForHomeChild(child._newStoreObject, request)
+ share = yield self._shareForStoreObject(child._newStoreObject, request)
if share:
child.setShare(share)
@inlineCallbacks
- def _shareForHomeChild(self, child, request=None):
- # Try to find a matching share
- if not child or child.owned():
+ def _shareForStoreObject(self, storeObject, request=None):
+ # Find a matching share
+ if not storeObject or storeObject.owned():
returnValue(None)
# get the shared object's URL
- sharer = self.principalForUID(child.ownerHome().uid())
+ sharer = self.principalForUID(storeObject.ownerHome().uid())
if not request:
# FIXEME: Fake up a request that can be used to get the sharer home resource
@@ -1029,17 +1035,18 @@
elif self._newStoreHome._homeType == EADDRESSBOOKTYPE:
sharerHomeCollection = yield sharer.addressBookHome(request)
- sharerHomeChild = yield child.ownerHome().childWithID(child._resourceID)
+ sharerHomeChild = yield storeObject.ownerHome().childWithID(storeObject._resourceID)
if sharerHomeChild:
+ assert sharerHomeChild != storeObject
url = joinURL(sharerHomeCollection.url(), sharerHomeChild.name())
- share = Share(shareeHomeChild=child, sharerHomeChildOrGroup=sharerHomeChild, url=url)
- else:
- for sharerHomeChild in (yield child.ownerHome().children()):
+ share = Share(shareeStoreObject=storeObject, sharerStoreObject=sharerHomeChild, url=url)
+ elif self._newStoreHome._homeType == EADDRESSBOOKTYPE:
+ for sharerHomeChild in (yield storeObject.ownerHome().children()):
if sharerHomeChild.owned():
- sharedGroup = yield sharerHomeChild.objectResourceWithID(child._resourceID)
+ sharedGroup = yield sharerHomeChild.objectResourceWithID(storeObject._resourceID)
if sharedGroup:
url = joinURL(sharerHomeCollection.url(), sharerHomeChild.name(), sharedGroup.name())
- share = Share(shareeHomeChild=child, sharerHomeChildOrGroup=sharedGroup, url=url)
+ share = Share(shareeStoreObject=storeObject, sharerStoreObject=sharedGroup, url=url)
break
returnValue(share)
@@ -1048,17 +1055,16 @@
@inlineCallbacks
def _shareForUID(self, shareUID, request):
- # since child.shareUID() == child.name() for indirect shares
- child = yield self._newStoreHome.childWithBindName(shareUID)
+ child = yield self._newStoreHome.objectWithBindName(shareUID)
if child:
- share = yield self._shareForHomeChild(child, request)
+ share = yield self._shareForStoreObject(child, request)
if share and share.uid() == shareUID:
returnValue(share)
# find direct shares
children = yield self._newStoreHome.children()
for child in children:
- share = yield self._shareForHomeChild(child, request)
+ share = yield self._shareForStoreObject(child, request)
if share and share.uid() == shareUID:
returnValue(share)
@@ -1077,9 +1083,9 @@
share = oldShare
else:
sharedResource = yield request.locateResource(hostUrl)
- shareeHomeChild = yield self._newStoreHome.childWithBindName(inviteUID)
+ shareeStoreObject = yield self._newStoreHome.objectWithBindName(inviteUID)
- share = Share(shareeHomeChild=shareeHomeChild, sharerHomeChildOrGroup=sharedResource._newStoreObject, url=hostUrl)
+ share = Share(shareeStoreObject=shareeStoreObject, sharerStoreObject=sharedResource._newStoreObject, url=hostUrl)
response = yield self._acceptShare(request, not oldShare, share, displayname)
returnValue(response)
@@ -1094,12 +1100,12 @@
share = oldShare
else:
sharedCollection = yield request.locateResource(hostUrl)
- shareeHomeChild = yield sharedCollection._newStoreObject.shareWith(shareeHome=self._newStoreHome,
+ shareeStoreObject = yield sharedCollection._newStoreObject.shareWith(shareeHome=self._newStoreHome,
mode=_BIND_MODE_DIRECT,
status=_BIND_STATUS_ACCEPTED,
message=displayname)
- share = Share(shareeHomeChild=shareeHomeChild, sharerHomeChildOrGroup=sharedCollection._newStoreObject, url=hostUrl)
+ share = Share(shareeStoreObject=shareeStoreObject, sharerStoreObject=sharedCollection._newStoreObject, url=hostUrl)
response = yield self._acceptShare(request, not oldShare, share, displayname)
returnValue(response)
@@ -1110,52 +1116,63 @@
# Get shared collection in non-share mode first
sharedResource = yield request.locateResource(share.url())
+ sharee = self.principalForUID(share.shareeUID())
- # For a direct share we will copy any calendar-color over using the owners view
- color = None
- if share.direct() and isNewShare and sharedResource.isCalendarCollection():
- try:
- color = (yield sharedResource.readProperty(customxml.CalendarColor, request))
- except HTTPError:
- pass
-
- sharee = self.principalForUID(share.shareeUID())
if sharedResource.isCalendarCollection():
shareeHomeResource = yield sharee.calendarHome(request)
- elif sharedResource.isAddressBookCollection() or sharedResource.isGroup():
- shareeHomeResource = yield sharee.addressBookHome(request)
- shareeURL = joinURL(shareeHomeResource.url(), share.name())
- shareeCollection = yield request.locateResource(shareeURL)
- shareeCollection.setShare(share)
+ shareeCalenderURL = joinURL(shareeHomeResource.url(), share.name())
+ shareeCalender = yield request.locateResource(shareeCalenderURL)
+ shareeCalender.setShare(share)
- #FIXME: addcresourceType to dead properties for share groups -
- # it's already there for shared address book and calendars
- if isNewShare and sharedResource.isGroup():
- shareeCollection.writeDeadProperty(carddavxml.ResourceType.addressbook)
+ # For calendars only, per-user displayname and color
+ if displayname:
+ yield shareeCalender.writeProperty(element.DisplayName.fromString(displayname), request)
- # For calendars only, per-user displayname and color
- if displayname and shareeCollection.isCalendarCollection():
- yield shareeCollection.writeProperty(element.DisplayName.fromString(displayname), request)
+ if isNewShare:
+ # For a direct share we will copy any calendar-color over using the owners view
+ if share.direct():
+ try:
+ color = yield sharedResource.readProperty(customxml.CalendarColor, request)
+ except HTTPError:
+ color = None
+ if color:
+ yield shareeCalender.writeProperty(customxml.CalendarColor.fromString(color), request)
- if color:
- yield shareeCollection.writeProperty(customxml.CalendarColor.fromString(color), request)
+ # Calendars always start out transparent and with empty default alarms
+ yield shareeCalender.writeProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Transparent()), request)
+ yield shareeCalender.writeProperty(caldavxml.DefaultAlarmVEventDateTime.fromString(""), request)
+ yield shareeCalender.writeProperty(caldavxml.DefaultAlarmVEventDate.fromString(""), request)
+ yield shareeCalender.writeProperty(caldavxml.DefaultAlarmVToDoDateTime.fromString(""), request)
+ yield shareeCalender.writeProperty(caldavxml.DefaultAlarmVToDoDate.fromString(""), request)
- # Calendars always start out transparent and with empty default alarms
- if isNewShare and shareeCollection.isCalendarCollection():
- yield shareeCollection.writeProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Transparent()), request)
- yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDateTime.fromString(""), request)
- yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDate.fromString(""), request)
- yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVToDoDateTime.fromString(""), request)
- yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVToDoDate.fromString(""), request)
+ elif sharedResource.isAddressBookCollection():
+ shareeHomeResource = yield sharee.addressBookHome(request)
+ shareeAddressBookURL = joinURL(shareeHomeResource.url(), share.sharerUID())
+ shareeAddressBook = yield request.locateResource(shareeAddressBookURL)
+ shareeAddressBook.setShare(share)
+ elif sharedResource.isGroup():
+ shareeHomeResource = yield sharee.addressBookHome(request)
+ shareeGroupURL = joinURL(shareeHomeResource.url(), share.sharerUID(), share.name())
+ shareeGroup = yield request.locateResource(shareeGroupURL)
+ shareeGroup.setShare(share)
+
# Notify client of changes
yield self.notifyChanged()
+ #FIXME: shouldn't sharedAsURLbe the same as shareeCollectionURL ?
+ if sharedResource.isCalendarCollection():
+ sharedAsURL = joinURL(self.url(), share.name())
+ elif sharedResource.isAddressBookCollection():
+ sharedAsURL = joinURL(self.url(), share.sharerUID())
+ elif sharedResource.isGroup():
+ sharedAsURL = joinURL(self.url(), share.sharerUID(), share.name())
+
# Return the URL of the shared collection
returnValue(XMLResponse(
code=responsecode.OK,
element=customxml.SharedAs(
- element.HRef.fromString(joinURL(self.url(), share.name()))
+ element.HRef.fromString(sharedAsURL)
)
))
@@ -1196,7 +1213,6 @@
Remove a shared collection but do not send a decline back. Return the
current display name of the shared collection.
"""
-
shareURL = joinURL(self.url(), share.name())
shared = (yield request.locateResource(shareURL))
displayname = shared.displayName()
@@ -1210,9 +1226,9 @@
inbox.processFreeBusyCalendar(shareURL, False)
if share.direct():
- yield share._sharerHomeChildOrGroup.unshareWith(share._shareeHomeChild.viewerHome())
+ yield share._sharerStoreObject.unshareWith(share._shareeStoreObject.viewerHome())
else:
- yield share._sharerHomeChildOrGroup.updateShare(share._shareeHomeChild, status=_BIND_STATUS_DECLINED)
+ yield share._sharerStoreObject.updateShare(share._shareeStoreObject, status=_BIND_STATUS_DECLINED)
returnValue(displayname)
@@ -1222,9 +1238,7 @@
# Remove it if it is in the DB
yield self.removeShareByUID(request, inviteUID)
-
yield self._changeShare(request, "DECLINED", hostUrl, inviteUID)
-
returnValue(Response(code=responsecode.NO_CONTENT))
@@ -1233,7 +1247,6 @@
"""
Accept or decline an invite to a shared collection.
"""
-
# Change state in sharer invite
ownerPrincipal = (yield self.ownerPrincipal(request))
ownerPrincipalUID = ownerPrincipal.principalUID()
@@ -1298,7 +1311,9 @@
def _handleInviteReply(self, request, invitereplydoc):
- """ Handle a user accepting or declining a sharing invite """
+ """
+ Handle a user accepting or declining a sharing invite
+ """
hostUrl = None
accepted = None
summary = None
@@ -1329,13 +1344,12 @@
return self.declineShare(request, hostUrl, replytoUID)
-
class Share(object):
- def __init__(self, sharerHomeChildOrGroup, shareeHomeChild, url):
- self._shareeHomeChild = shareeHomeChild
- self._sharerHomeChildOrGroup = sharerHomeChildOrGroup
- self._sharedResourceURL = url
+ def __init__(self, sharerStoreObject, shareeStoreObject, url):
+ self._shareeStoreObject = shareeStoreObject
+ self._sharerStoreObject = sharerStoreObject
+ self._sharerResourceURL = url
@classmethod
@@ -1345,27 +1359,31 @@
def uid(self):
# Move to CommonHomeChild shareUID?
- if self._shareeHomeChild.shareMode() == _BIND_MODE_DIRECT:
- return self.directUID(shareeHome=self._shareeHomeChild.viewerHome(), sharerHomeChild=self._sharerHomeChildOrGroup,)
+ if self._shareeStoreObject.shareMode() == _BIND_MODE_DIRECT:
+ return self.directUID(shareeHome=self._shareeStoreObject.viewerHome(), sharerHomeChild=self._sharerStoreObject,)
else:
- return self._shareeHomeChild.shareUID()
+ return self._shareeStoreObject.shareUID()
def direct(self):
- return self._shareeHomeChild.shareMode() == _BIND_MODE_DIRECT
+ return self._shareeStoreObject.shareMode() == _BIND_MODE_DIRECT
def url(self):
- return self._sharedResourceURL
+ return self._sharerResourceURL
def name(self):
- return self._shareeHomeChild.name()
+ return self._shareeStoreObject.name()
def summary(self):
- return self._shareeHomeChild.shareMessage()
+ return self._shareeStoreObject.shareMessage()
def shareeUID(self):
- return self._shareeHomeChild.viewerHome().uid()
+ return self._shareeStoreObject.viewerHome().uid()
+
+
+ def sharerUID(self):
+ return self._shareeStoreObject.ownerHome().uid()
Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py 2013-02-12 00:37:11 UTC (rev 10694)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py 2013-02-12 01:07:09 UTC (rev 10695)
@@ -73,7 +73,7 @@
from twext.web2.filter.location import addLocation
from txdav.carddav.iaddressbookstore import GroupWithUnsharedAddressNotAllowedError, \
- DeleteOfShadowGroupNotAllowedError
+ DeleteOfGroupForSharedAddressBookNotAllowedError
"""
Wrappers to translate between the APIs in L{txdav.caldav.icalendarstore} and
@@ -3010,7 +3010,7 @@
try:
returnValue((yield super(AddressBookObjectResource, self).http_DELETE(request)))
- except DeleteOfShadowGroupNotAllowedError:
+ except DeleteOfGroupForSharedAddressBookNotAllowedError:
raise HTTPError(StatusResponse(
FORBIDDEN,
"Sharee cannot delete group vcard shadowing shared address book",)
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py 2013-02-12 00:37:11 UTC (rev 10694)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py 2013-02-12 01:07:09 UTC (rev 10695)
@@ -44,7 +44,7 @@
from txdav.carddav.datastore.util import validateAddressBookComponent
from txdav.carddav.iaddressbookstore import IAddressBookHome, IAddressBook, \
IAddressBookObject, GroupWithUnsharedAddressNotAllowedError, \
- DeleteOfShadowGroupNotAllowedError
+ DeleteOfGroupForSharedAddressBookNotAllowedError
from txdav.common.datastore.sql import CommonHome, CommonHomeChild, \
CommonObjectResource, EADDRESSBOOKTYPE, SharingMixIn
from txdav.common.datastore.sql_legacy import PostgresLegacyABIndexEmulator
@@ -56,7 +56,8 @@
ADDRESSBOOK_OBJECT_REVISIONS_AND_BIND_TABLE, \
_ABO_KIND_PERSON, _ABO_KIND_GROUP, _ABO_KIND_RESOURCE, \
_ABO_KIND_LOCATION, schema, \
- _BIND_MODE_OWN, _BIND_MODE_WRITE, _BIND_STATUS_ACCEPTED
+ _BIND_MODE_OWN, _BIND_MODE_WRITE, _BIND_STATUS_ACCEPTED, \
+ _BIND_STATUS_DECLINED, _BIND_STATUS_INVITED
from txdav.xml.rfc2518 import ResourceType
from zope.interface.declarations import implements
@@ -102,7 +103,7 @@
removeAddressBookWithName = CommonHome.removeChildWithName
- def childWithBindName(self, name):
+ def objectWithBindName(self, name):
"""
Retrieve the child with the given C{name} contained in this
home.
@@ -112,6 +113,7 @@
"""
return self._childClass.objectWithBindName(self, name)
+
@inlineCallbacks
def remove(self):
ah = schema.ADDRESSBOOK_HOME
@@ -158,13 +160,16 @@
kwds = {"homeResourceID" : self._resourceID}
yield Delete(
From=bind,
- Where=(bind.HOME_RESOURCE_ID == Parameter("homeResourceID")).And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+ Where=(bind.HOME_RESOURCE_ID == Parameter("homeResourceID")
+ ).And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
).on(self._txn, **kwds)
+
@classmethod
def addressbookName(cls):
return "addressbook"
+
@inlineCallbacks
def addressbook(self):
returnValue((yield self.addressbookWithName(self.addressbookName())))
@@ -225,9 +230,11 @@
removeAddressBookObjectWithUID = CommonHomeChild.removeObjectResourceWithUID
addressbookObjectsSinceToken = CommonHomeChild.objectResourcesSinceToken
+
def shareeABName(self):
return self._home.uid()
+
def initPropertyStore(self, props):
# Setup peruser special properties
props.setSpecialProperties(
@@ -247,6 +254,16 @@
return MimeType.fromString("text/vcard; charset=utf-8")
+ @classmethod
+ @inlineCallbacks
+ def create(cls, home, name):
+
+ if name != home.addressbookName():
+ raise NotImplementedError()
+
+ returnValue((yield super(AddressBook, cls).create(home, name)))
+
+
def unshare(self):
"""
Unshares a collection, regardless of which "direction" it was shared.
@@ -258,8 +275,8 @@
def listObjectResources(self):
result = yield super(AddressBook, self).listObjectResources()
- if not self.owned():
- groupForSharedAB = yield self._groupForSharedABName()
+ if not self.owned() and not self.fullyShared():
+ groupForSharedAB = yield self._groupForEntireAB_Name()
if not groupForSharedAB in result:
result.append(groupForSharedAB)
returnValue(result)
@@ -273,44 +290,23 @@
count = rows[0][0]
#add in group for shared address book
- if not self.owned():
+ if not self.owned() and not self.fullyShared():
count += 1
returnValue(count)
returnValue(len(self._objectNames))
@inlineCallbacks
- def _ownerGroupAndAddressBook(self):
- """
- Find the owner shared group and owner address book. owner shared group may be None
- """
- ownerGroup = None
- if self.owned():
- yield None
- ownerAddressBook = self
- else:
- ownerAddressBook = yield self.ownerAddressBookHome().childWithID(self._resourceID)
- if not ownerAddressBook:
- for addressbook in (yield self.ownerAddressBookHome().addressbooks()):
- ownerGroup = yield addressbook.objectResourceWithID(self._resourceID)
- if ownerGroup:
- ownerAddressBook = addressbook
- break
-
- returnValue((ownerGroup, ownerAddressBook))
-
-
- @inlineCallbacks
- def ownerGroup(self):
- if not hasattr(self, "_ownerGroup"):
- self._ownerGroup, self._ownerAddressBook = yield self._ownerGroupAndAddressBook()
- returnValue(self._ownerGroup)
-
-
- @inlineCallbacks
def ownerAddressBook(self):
if not hasattr(self, "_ownerAddressBook"):
- self._ownerGroup, self._ownerAddressBook = yield self._ownerGroupAndAddressBook()
+ if self.owned():
+ yield None
+ self._ownerAddressBook = self
+ else:
+ ownerHome = yield self.ownerAddressBookHome()
+ assert self._home != ownerHome
+ self._ownerAddressBook = yield ownerHome.addressbook()
+ assert self._ownerAddressBook != self
returnValue(self._ownerAddressBook)
@@ -325,13 +321,13 @@
@inlineCallbacks
- def _groupForSharedABRow(self): #@NoSelf
+ def _groupForEntireAB_Row(self): #@NoSelf
returnValue([
self._resourceID, # obj.ADDRESSBOOK_RESOURCE_ID,
self._resourceID, # obj.RESOURCE_ID,
- (yield self._groupForSharedABName()), # obj.RESOURCE_NAME, shared name is UID and thus avoids collisions
- (yield self._groupForSharedABUID()), # obj.UID, shared name is uuid
+ (yield self._groupForEntireAB_Name()), # obj.RESOURCE_NAME, shared name is UID and thus avoids collisions
+ (yield self._groupForEntireAB_UID()), # obj.UID, shared name is uuid
_ABO_KIND_GROUP, # obj.KIND,
"1", # obj.MD5, unused
"1", # Len(obj.TEXT), unused
@@ -341,38 +337,31 @@
@inlineCallbacks
- def _groupForSharedABName(self):
- ownerGroup = yield self.ownerGroup()
- if ownerGroup:
- returnValue(ownerGroup.name())
- else:
- returnValue((yield self.ownerAddressBook()).name() + ".vcf")
+ def _groupForEntireAB_Name(self):
+ returnValue((yield self.ownerAddressBook()).name() + ".vcf")
@inlineCallbacks
- def _groupForSharedABUID(self):
+ def _groupForEntireAB_UID(self):
yield None
returnValue(self.name())
+
@inlineCallbacks
- def _groupForSharedABComponent(self):
+ def _groupForEntireAB_Component(self):
- ownerGroup = yield self.ownerGroup()
- if ownerGroup:
- returnValue((yield ownerGroup.component()))
- else:
- n = (yield self.ownerAddressBook()).shareeABName()
- fn = n
- uid = self.name()
+ n = (yield self.ownerAddressBook()).shareeABName()
+ fn = n
+ uid = self.name()
-# it would be nice to use the owner.displayName() full name here
-# uid = (yield self.ownerAddressBook()).ownerHome().uid()
-# owner = yield self.principalForUID(uid)
-# n = owner.name()
-# fn = owner.displayName()
+ # it would be nice to use the owner.displayName() full name here
+ # uid = (yield self.ownerAddressBook()).ownerHome().uid()
+ # owner = yield self.principalForUID(uid)
+ # n = owner.name()
+ # fn = owner.displayName()
- component = VCard.fromString(
- """BEGIN:VCARD
+ component = VCard.fromString(
+ """BEGIN:VCARD
VERSION:3.0
PRODID:%s
UID:%s
@@ -381,24 +370,25 @@
X-ADDRESSBOOKSERVER-KIND:group
END:VCARD
""".replace("\n", "\r\n") % (vCardProductID, uid, n, fn,)
- )
+ )
- # then get member UIDs
- abo = schema.ADDRESSBOOK_OBJECT
- memberUIDRows = yield self._abObjectColumnsWithAddressBookResourceID(
- [abo.VCARD_UID]).on(
- self._txn, addressbookResourceID=self._resourceID)
- memberUIDs = [memberUIDRow[0] for memberUIDRow in memberUIDRows]
+ # then get member UIDs
+ abo = schema.ADDRESSBOOK_OBJECT
+ memberUIDRows = yield self._abObjectColumnsWithAddressBookResourceID(
+ [abo.VCARD_UID]).on(
+ self._txn, addressbookResourceID=self._resourceID)
+ memberUIDs = [memberUIDRow[0] for memberUIDRow in memberUIDRows]
- # add prefix to get property string
- memberAddresses = ["urn:uuid:" + memberUID for memberUID in memberUIDs]
+ # add prefix to get property string
+ memberAddresses = ["urn:uuid:" + memberUID for memberUID in memberUIDs]
- # now add the properties to the component
- for memberAddress in sorted(memberAddresses):
- component.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", memberAddress))
+ # now add the properties to the component
+ for memberAddress in sorted(memberAddresses):
+ component.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", memberAddress))
- returnValue(component)
+ returnValue(component)
+
@classproperty
def _metadataByIDQuery(cls): #@NoSelf
"""
@@ -446,7 +436,6 @@
returnValue(result)
-
@classmethod
@inlineCallbacks
def loadAllObjects(cls, home):
@@ -462,30 +451,30 @@
# Load from the main table first
dataRows = yield cls._childrenAndMetadataForHomeID.on(home._txn, homeID=home._resourceID)
-
- # TODO: Simplify. Try to do one pass only.
- # get sharedHomeIDs
- sharedHomeIDToDataRowMap = {}
+ # get ownerHomeIDs
+ ownerHomeIDToDataRowMap = {}
for dataRow in dataRows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = dataRow[:6] #@UnusedVariable
- if bindStatus != _BIND_MODE_OWN:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = dataRow[:6] #@UnusedVariable
+ if bindStatus == _BIND_MODE_OWN:
+ ownerHomeIDToDataRowMap[home._resourceID] = dataRow
+ else:
ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
- sharedHomeIDToDataRowMap[ownerHomeID] = dataRow
+ ownerHomeIDToDataRowMap[ownerHomeID] = dataRow
+
# now get group rows:
groupBindRows = yield AddressBookObject._childrenAndMetadataForHomeID.on(home._txn, homeID=home._resourceID)
for groupBindRow in groupBindRows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = groupBindRow[:6] #@UnusedVariable
- ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
- if ownerHomeID in sharedHomeIDToDataRowMap:
- if bindMode == _BIND_MODE_WRITE:
- sharedHomeIDToDataRowMap[ownerHomeID][0] |= _BIND_MODE_WRITE # or together bind modes
- else:
- groupBindRow[3] = None # resourceName or bindName
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = groupBindRow[:6] #@UnusedVariable
+ ownerAddressBookIDRows = yield AddressBookObject._parentIDForObjectID.on(home._txn, objectID=resourceID)
+ ownerHomeID = yield cls.ownerHomeID(home._txn, ownerAddressBookIDRows[0][0])
+ if ownerHomeID not in ownerHomeIDToDataRowMap:
+ groupBindRow[0] = _BIND_MODE_WRITE
+ groupBindRow[3] = None # bindName
groupBindRow[5] = None # bindMessage
- sharedHomeIDToDataRowMap[ownerHomeID] = groupBindRow
+ ownerHomeIDToDataRowMap[ownerHomeID] = groupBindRow
- if dataRows:
+ if ownerHomeIDToDataRowMap:
# Get property stores for all these child resources (if any found)
propertyStores = (yield PropertyStore.forMultipleResources(
@@ -494,70 +483,50 @@
home._resourceID
))
- revisions = (yield cls._revisionsForHomeID.on(home._txn, homeID=home._resourceID))
+ revisions = yield cls._revisionsForHomeID.on(home._txn, homeID=home._resourceID)
revisions = dict(revisions)
- # Create the actual objects merging in properties
- for items in dataRows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = items[:6] #@UnusedVariable
- metadata = items[6:]
+ # Create the actual objects merging in properties
+ for ownerHomeID, dataRow in ownerHomeIDToDataRowMap.iteritems():
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = dataRow[:6] #@UnusedVariable
+ metadata = dataRow[6:]
- if bindStatus == _BIND_MODE_OWN:
- child = cls(
- home=home,
- name=resourceName, resourceID=resourceID,
- mode=bindMode, status=bindStatus,
- message=bindMessage,
- )
- else:
- ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
- ownerAddressBook = yield ownerHome.addressbook()
+ if bindStatus == _BIND_MODE_OWN:
+ child = cls(
+ home=home,
+ name=bindName, resourceID=resourceID,
+ mode=bindMode, status=bindStatus,
+ message=bindMessage,
+ )
+ else:
+ ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
+ ownerAddressBook = yield ownerHome.addressbook()
- child = cls(
- home=home,
- name=ownerAddressBook.shareeABName(), resourceID=ownerAddressBook._resourceID,
- mode=bindMode, status=bindStatus,
- message=bindMessage, ownerHome=ownerHome,
- bindName=resourceName
- )
+ child = cls(
+ home=home,
+ name=ownerAddressBook.shareeABName(), resourceID=ownerAddressBook._resourceID,
+ mode=bindMode, status=bindStatus,
+ message=bindMessage, ownerHome=ownerHome,
+ bindName=bindName
+ )
- for attr, value in zip(cls.metadataAttributes(), metadata):
- setattr(child, attr, value)
- child._syncTokenRevision = revisions[resourceID]
- propstore = propertyStores.get(resourceID, None)
+ for attr, value in zip(cls.metadataAttributes(), metadata):
+ setattr(child, attr, value)
+ child._syncTokenRevision = revisions[resourceID]
+ propstore = propertyStores.get(resourceID, None)
- # We have to re-adjust the property store object to account for possible shared
- # collections as previously we loaded them all as if they were owned
- if bindStatus != _BIND_MODE_OWN:
- propstore._setDefaultUserUID(ownerHome.uid())
- yield child._loadPropertyStore(propstore)
- results.append(child)
+ # We have to re-adjust the property store object to account for possible shared
+ # collections as previously we loaded them all as if they were owned
+ if bindStatus != _BIND_MODE_OWN:
+ propstore._setDefaultUserUID(ownerHome.uid())
+ yield child._loadPropertyStore(propstore)
+ results.append(child)
+
returnValue(results)
-
@classmethod
- def _columnsWithParentIDQuery(cls, columns): #@NoSelf
- obj = cls._objectSchema
- return Select(columns, From=obj,
- Where=obj.PARENT_RESOURCE_ID == Parameter("parentID"))
-
- @classmethod
@inlineCallbacks
- def _columnsWithParent(cls, columns, parent):
- returnValue((yield cls._columnsWithParentIDQuery(columns).on(
- parent._txn, parentID=parent._resourceID)))
-
- @classmethod
- @inlineCallbacks
- def _resourceIDsWithParent(cls, parent):
- obj = cls._objectSchema
- returnValue((yield cls._columnsWithParent([obj.RESOURCE_ID], parent)))
-
-
- @classmethod
- @inlineCallbacks
def objectWithName(cls, home, name):
# replaces objectWithName()
"""
@@ -588,7 +557,7 @@
if rows is None:
# name must be a home uid
- ownerHome = yield home._txn.addressbookHomeWithUID(name, create=True)
+ ownerHome = yield home._txn.addressbookHomeWithUID(name)
if ownerHome:
# see if address book resource id in bind table
ownerAddressBook = yield ownerHome.addressbook()
@@ -596,28 +565,22 @@
sharedABBindRows = yield cls._bindForResourceIDAndHomeID.on(
home._txn, resourceID=ownerAddressBook._resourceID, homeID=home._resourceID)
if sharedABBindRows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = sharedABBindRows[0] #@UnusedVariable
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = sharedABBindRows[0] #@UnusedVariable
if bindStatus == _BIND_STATUS_ACCEPTED:
sharedABBindRows[0].append(ownerHome._resourceID)
rows = [sharedABBindRows[0]]
- # get group binds
- #FIXME: use join
- ownerABObjectIDRows = yield cls._resourceIDsWithParent(ownerAddressBook)
- if ownerABObjectIDRows:
- ownerABObjectIDs = [ownerABObjectIDRow[0] for ownerABObjectIDRow in ownerABObjectIDRows]
- groupBindRows = yield AddressBookObject._bindForGroupIDsAndHomeID(ownerABObjectIDs).on(home._txn, groupIDs=ownerABObjectIDs, homeID=home._resourceID)
- for groupBindRow in groupBindRows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = groupBindRow #@UnusedVariable
- if bindStatus == _BIND_STATUS_ACCEPTED:
- if rows:
- if bindMode == _BIND_MODE_WRITE:
- rows[0][0] |= _BIND_MODE_WRITE
- else:
- groupBindRow[3] = None # resourceName or bindName
- groupBindRow[5] = None # bindMessage
- groupBindRow.append(ownerHome._resourceID)
- rows = [groupBindRow]
+ if not rows:
+ groupBindRows = yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
+ home._txn, homeID=home._resourceID, addressbookID=ownerAddressBook._resourceID
+ )
+ if groupBindRows:
+ groupBindRow = groupBindRows[0]
+ groupBindRow[0] = _BIND_MODE_WRITE
+ groupBindRow[3] = None # bindName
+ groupBindRow[5] = None # bindMessage
+ groupBindRow.append(ownerHome._resourceID)
+ rows = [groupBindRow]
if rows and queryCacher:
# Cache the result
@@ -626,7 +589,7 @@
if not rows:
returnValue(None)
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage, ownerHomeID = rows[0] #@UnusedVariable
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage, ownerHomeID = rows[0] #@UnusedVariable
ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
ownerAddressBook = yield ownerHome.addressbook()
child = cls(
@@ -634,7 +597,7 @@
name=ownerAddressBook.shareeABName(), resourceID=ownerAddressBook._resourceID,
mode=bindMode, status=bindStatus,
message=bindMessage, ownerHome=ownerHome,
- bindName=resourceName,
+ bindName=bindName,
)
yield child.initFromStore()
returnValue(child)
@@ -654,23 +617,25 @@
@return: an L{CommonHomeChild} or C{None} if no such child
exists.
"""
- if bindName == home.addressbookName():
- returnValue((yield cls.objectWithName(home, bindName)))
- else:
- rows = yield cls._childBindForNameAndHomeID.on(home._txn, name=bindName, homeID=home._resourceID)
- if not rows:
- rows = yield AddressBookObject._childBindForNameAndHomeID.on(home._txn, name=bindName, homeID=home._resourceID)
- if rows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+ bindRows = yield cls._acceptedBindForNameAndHomeID.on(home._txn, name=bindName, homeID=home._resourceID)
+ if bindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = bindRows[0] #@UnusedVariable
+ #TODO: use childWithName, since it is cached by querycacher
+ returnValue((yield home.childWithID(resourceID)))
- ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
- ownerAddressBook = yield ownerHome.addressbook()
- #returnValue((yield cls.objectWithName(home, ownerAddressBook.shareeABName())))
- returnValue((yield cls.objectWithID(home, ownerAddressBook._resourceID)))
+ groupBindRows = yield AddressBookObject._acceptedBindForNameAndHomeID.on(home._txn, name=bindName, homeID=home._resourceID)
+ if groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = groupBindRows[0] #@UnusedVariable
+ ownerAddressBookIDRows = yield AddressBookObject._parentIDForObjectID.on(home._txn, objectID=resourceID)
+ #TODO: use childWithName, since it is cached by querycacher
+ sharedAB = yield cls.objectWithID(home, ownerAddressBookIDRows[0][0])
+ #sharedAB = yield home.childWithID(ownerAddressBookIDRows[0][0])
+ result = yield sharedAB.objectResourceWithID(resourceID)
+ returnValue(result)
returnValue(None)
+
@classmethod
@inlineCallbacks
def objectWithID(cls, home, resourceID):
@@ -687,45 +652,43 @@
home._txn, resourceID=resourceID, homeID=home._resourceID)
if rows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = rows[0] #@UnusedVariable
if bindMode == _BIND_MODE_OWN:
child = cls(
home=home,
- name=resourceName, resourceID=resourceID,
+ name=bindName, resourceID=resourceID,
mode=bindMode, status=bindStatus,
- message=bindMessage, ownerHome=home,
+ message=bindMessage,
)
yield child.initFromStore()
returnValue(child)
+ else:
+ groupBindRows = yield AddressBookObject._bindWithHomeIDAndAddressBookID.on(
+ home._txn, homeID=home._resourceID, addressbookID=resourceID
+ )
+ if groupBindRows:
+ #bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = groupBindRows[0] #@UnusedVariable
+ groupBindRow = groupBindRows[0]
+ groupBindRow[0] = _BIND_MODE_WRITE
+ groupBindRow[3] = None # bindName
+ groupBindRow[5] = None # bindMessage
+ rows = [groupBindRow]
+
+ if not rows:
+ returnValue(None)
+
ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
ownerAddressBook = yield ownerHome.addressbook()
- ownerABObjectIDRows = yield cls._resourceIDsWithParent(ownerAddressBook)
- if ownerABObjectIDRows:
- ownerABObjectIDs = [ownerABObjectIDRow[0] for ownerABObjectIDRow in ownerABObjectIDRows]
- groupBindRows = yield AddressBookObject._bindForGroupIDsAndHomeID(ownerABObjectIDs).on(home._txn, groupIDs=ownerABObjectIDs, homeID=home._resourceID)
- for groupBindRow in groupBindRows:
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = groupBindRow #@UnusedVariable
- if rows:
- if bindMode == _BIND_MODE_WRITE:
- rows[0][0] |= _BIND_MODE_WRITE
- else:
- groupBindRow[3] = None # resourceName or bindName
- groupBindRow[5] = None # bindMessage
- rows = [groupBindRow]
-
- if not rows:
- returnValue(None)
-
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = rows[0] #@UnusedVariable
child = cls(
home=home,
name=ownerAddressBook.shareeABName(), resourceID=ownerAddressBook._resourceID,
mode=bindMode, status=bindStatus,
message=bindMessage, ownerHome=ownerHome,
- bindName=resourceName
+ bindName=bindName
)
yield child.initFromStore()
returnValue(child)
@@ -764,39 +727,124 @@
)
- '''
+ def shareUID(self):
+ """
+ @see: L{ICalendar.shareUID}
+ """
+ return self._bindName
+
+
+ def fullyShared(self):
+ return bool(self._bindName)
+
+
@classmethod
@inlineCallbacks
- def invitedObjectWithName(cls, home, name):
+ def listObjects(cls, home):
"""
- Retrieve the child with the given C{name} contained in the given
- C{home}.
+ Retrieve the names of the children with invitations in the given home.
- @param home: a L{CommonHome}.
+ @return: an iterable of C{str}s.
+ """
+ names = set()
+ rows = yield cls._acceptedBindForHomeID.on(
+ home._txn, homeID=home._resourceID
+ )
+ rows.extend((yield AddressBookObject._acceptedBindForHomeID.on(
+ home._txn, homeID=home._resourceID
+ )))
+ for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in rows: #@UnusedVariable
+ if bindMode == _BIND_MODE_OWN:
+ addressbook = yield home.addressbook()
+ names |= set([addressbook.name()])
+ else:
+ ownerHome = yield home._txn.homeWithResourceID(home._homeType, homeID)
+ ownerAddressBook = yield ownerHome.addressbook()
+ names |= set([ownerAddressBook.shareeABName()])
+ returnValue(tuple(names))
- @param name: a string; the name of the L{CommonHomeChild} to retrieve.
- @param owned: a boolean - whether or not to get a shared child
- @return: an L{CommonHomeChild} or C{None} if no such child
- exists.
+ @classmethod
+ def _memberIDsWithGroupIDsQuery(cls, groupIDs): #@NoSelf
"""
+ DAL query to load all object resource names for a home child.
+ """
+ aboMembers = schema.ABO_MEMBERS
+ return Select([aboMembers.MEMBER_ID], From=aboMembers,
+ Where=aboMembers.GROUP_ID.In(Parameter("groupIDs", len(groupIDs))),
+ )
- result = yield super(AddressBook, cls).invitedObjectWithName(home, name)
- if not result:
- result = yield AddressBookObject.invitedObjectWithName(home, name)
-
- returnValue(result)
- '''
-
- def shareUID(self):
+ @classmethod
+ @inlineCallbacks
+ def _objectIDsInExpandedGroupIDs(cls, txn, groupIDs, includeGroupIDs=True):
"""
- @see: L{ICalendar.shareUID}
+ Get all AddressBookObject resource IDs contains in the given shared groups with the given groupIDs
"""
- return self._bindName
+ objectIDs = set(groupIDs) if includeGroupIDs else set()
+ examinedIDs = set()
+ remainingIDs = set(groupIDs)
+ while remainingIDs:
+ memberRows = yield cls._memberIDsWithGroupIDsQuery(remainingIDs).on(txn, groupIDs=remainingIDs)
+ objectIDs |= set([memberRow[0] for memberRow in memberRows])
+ examinedIDs |= remainingIDs
+ remainingIDs = objectIDs - examinedIDs
+ returnValue(tuple(objectIDs))
+
@inlineCallbacks
+ def invitedGroupIDs(self):
+ if self.owned():
+ returnValue([])
+ else:
+ groupBindRows = yield AddressBookObject._invitedBindWithHomeIDAndAddressBookID.on(
+ self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+ )
+ #for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
+ returnValue([groupBindRow[2] for groupBindRow in groupBindRows])
+
+
+ @inlineCallbacks
+ def acceptedGroupIDs(self):
+ if self.owned():
+ returnValue([])
+ else:
+ groupBindRows = yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
+ self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+ )
+ #for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
+ returnValue([groupBindRow[2] for groupBindRow in groupBindRows])
+
+
+ @inlineCallbacks
+ def writeableAcceptedGroupIDs(self):
+ if self.owned():
+ returnValue([])
+ else:
+ groupBindRows = yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
+ self._txn, homeID=self._home._resourceID, addressbookID=self._resourceID
+ )
+ readwriteGroupIDs = []
+ readonlyGroupIDs = []
+ for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
+ if bindMode == _BIND_MODE_WRITE:
+ readwriteGroupIDs.append(resourceID)
+ else:
+ readonlyGroupIDs.append(resourceID)
+
+ if readonlyGroupIDs and readwriteGroupIDs:
+ # expand read-write groups and remove any subgroups from read-only group list
+ allWriteableIDs = yield self._addressbook._objectIDsInExpandedGroupIDs(self._txn, readwriteGroupIDs)
+ adjustedReadOnlyGroupIDs = set(readonlyGroupIDs) - set(allWriteableIDs)
+ adjustedReadWriteGroupIDs = set(readwriteGroupIDs) | (set(readonlyGroupIDs) - adjustedReadOnlyGroupIDs)
+ else:
+ #adjustedReadOnlyGroupIDs = readonlyGroupIDs
+ adjustedReadWriteGroupIDs = readwriteGroupIDs
+ returnValue(tuple(adjustedReadWriteGroupIDs))
+
+
+ @inlineCallbacks
def asShared(self):
"""
Retrieve all the versions of this L{CommonHomeChild} as it is shared to
@@ -811,27 +859,38 @@
if not self.owned():
returnValue([])
- # get all accepted binds
- acceptedRows = yield self._sharedBindForResourceID.on(
+ # get all accepted shared binds
+ rows = yield self._sharedBindForResourceID.on(
self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
)
+ homeIDToBindRowMap = dict([(row[1], row) for row in rows])
+ groupBindRows = yield AddressBookObject._acceptedBindWithAddressBookID.on(
+ self._txn, addressbookID=self._resourceID
+ )
+ for groupBindRow in groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = groupBindRow #@UnusedVariable
+ if homeID not in homeIDToBindRowMap:
+ groupBindRow[0] = _BIND_MODE_WRITE
+ groupBindRow[3] = None # bindName
+ groupBindRow[5] = None # bindMessage
+ homeIDToBindRowMap[homeID] = groupBindRow
+
+ result = []
cls = self._home._childClass # for ease of grepping...
- result = []
- for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in acceptedRows: #@UnusedVariable
- assert bindStatus == _BIND_STATUS_ACCEPTED
- # TODO: this could all be issued in parallel; no need to serialize
- # the loop.
+ for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in homeIDToBindRowMap.values(): #@UnusedVariable
+
home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
new = cls(
home=home,
name=self.shareeABName(), resourceID=self._resourceID,
mode=bindMode, status=bindStatus,
message=bindMessage, ownerHome=self._home,
- bindName=resourceName
+ bindName=bindName
)
yield new.initFromStore()
result.append(new)
+
returnValue(result)
@@ -850,22 +909,35 @@
if not self.owned():
returnValue([])
+ # get all accepted shared binds
rows = yield self._invitedBindForResourceID.on(
- self._txn, resourceID=self._resourceID, homeID=self._home._resourceID,
+ self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
)
+ homeIDToBindRowMap = dict([(row[1], row) for row in rows])
+
+ groupBindRows = yield AddressBookObject._invitedBindWithAddressBookID.on(
+ self._txn, addressbookID=self._resourceID
+ )
+ for groupBindRow in groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = groupBindRow #@UnusedVariable
+ if homeID not in homeIDToBindRowMap:
+ groupBindRow[0] = _BIND_MODE_WRITE
+ groupBindRow[3] = None # bindName
+ groupBindRow[5] = None # bindMessage
+ homeIDToBindRowMap[homeID] = groupBindRow
+ break
+
+ result = []
cls = self._home._childClass # for ease of grepping...
+ for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in homeIDToBindRowMap.values(): #@UnusedVariable
- result = []
- for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in rows: #@UnusedVariable
- # TODO: this could all be issued in parallel; no need to serialize
- # the loop.
home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
new = cls(
home=home,
name=self.shareeABName(), resourceID=self._resourceID,
mode=bindMode, status=bindStatus,
message=bindMessage, ownerHome=self._home,
- bindName=resourceName
+ bindName=bindName
)
yield new.initFromStore()
result.append(new)
@@ -873,55 +945,49 @@
returnValue(result)
- @classmethod
@inlineCallbacks
- def listObjects(cls, home):
+ def unshareWith(self, shareeHome):
"""
- Retrieve the names of the children with invitations in the given home.
+ Remove the shared version of this (owned) L{CommonHomeChild} from the
+ referenced L{CommonHome}.
- @return: an iterable of C{str}s.
- """
- names = set()
- rows = yield cls._childBindForHomeID.on(
- home._txn, homeID=home._resourceID
- )
- rows.extend((yield AddressBookObject._childBindForHomeID.on(
- home._txn, homeID=home._resourceID
- )))
- for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in rows: #@UnusedVariable
- if bindMode == _BIND_MODE_OWN:
- addressbook = yield home.addressbook()
- names |= set([addressbook.name()])
- else:
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, homeID)
- ownerAddressBook = ownerHome.addressbook()
- names |= set([ownerAddressBook.shareeeABName()])
- returnValue(tuple(names))
+ @see: L{CommonHomeChild.shareWith}
+ @param shareeHome: The home with which this L{CommonHomeChild} was
+ previously shared.
- @classmethod
- @inlineCallbacks
- def listInvitedObjects(cls, home):
+ @return: a L{Deferred} which will fire with the previously-used name.
"""
- Retrieve the names of the children with invitations in the given home.
+ sharedAddressBook = yield shareeHome.addressbookWithName(self.shareeABName())
+ if not sharedAddressBook:
+ returnValue(None)
- @return: an iterable of C{str}s.
- """
- names = set()
- rows = yield cls._invitedBindForHomeID.on(
- home._txn, homeID=home._resourceID
- )
- rows.extend((yield AddressBookObject._invitedBindForHomeID.on(
- home._txn, homeID=home._resourceID
- )))
- if rows:
- for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in rows: #@UnusedVariable
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, homeID)
- ownerAddressBook = ownerHome.addressbook()
- names |= set([ownerAddressBook.shareeeABName()])
- returnValue(tuple(names))
+ sharedRemoval = False
+ if sharedAddressBook.fullyShared():
+ groupIDs = yield sharedAddressBook.acceptedGroupIDs()
+ sharedRemoval = not bool(len(groupIDs))
+ if sharedRemoval:
+ sharedAddressBook._deletedSyncToken(sharedRemoval=True)
+ queryCacher = self._txn._queryCacher
+ if queryCacher:
+ cacheKey = queryCacher.keyForObjectWithName(shareeHome._resourceID, self.shareeABName())
+ queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+ rows = yield self._deleteBindWithResourceIDAndHomeID.on(self._txn, resourceID=self._resourceID,
+ homeID=shareeHome._resourceID)
+
+ resourceName = None
+ if rows and sharedRemoval:
+ resourceName = self.shareeABName()
+ shareeHome._children.pop(resourceName, None)
+
+ # Must send notification to ensure cache invalidation occurs
+ yield self.notifyChanged()
+
+ returnValue(resourceName)
+
+
class AddressBookObject(CommonObjectResource, SharingMixIn):
implements(IAddressBookObject)
@@ -967,35 +1033,32 @@
@inlineCallbacks
def remove(self):
- if self._addressbook.owned():
+ if self.owned():
if self._kind == _ABO_KIND_GROUP: # optimization
# need to invalidate queryCacher of sharee's home
queryCacher = self._txn._queryCacher
if queryCacher:
- for shareeAddressBook in (yield self.asShared()):
+ for shareeAddressBook in (yield self._addressbook.asShared()):
cacheKey = queryCacher.keyForObjectWithName(shareeAddressBook._home._resourceID, shareeAddressBook._name)
yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
else:
# sharee cannot delete group representing shared address book
if self._resourceID == self._addressbook._resourceID:
- raise DeleteOfShadowGroupNotAllowedError
+ raise DeleteOfGroupForSharedAddressBookNotAllowedError
-
aboMembers = schema.ABO_MEMBERS
aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
- ownerGroup = yield self._addressbook.ownerGroup()
- if ownerGroup:
+ if not self.owned() and not self._addressbook.fullyShared():
# convert delete in sharee shared group address book to remove of memberships
# that make this object visible to the sharee
- objectIDs = yield ownerGroup._allGroupObjectIDs()
- assert self._ownerAddressBookResourceID not in objectIDs, "self._ownerAddressBookResourceID=%s not in objectIDs=%s" % (self._ownerAddressBookResourceID, objectIDs,)
+ writeableAcceptedGroupIDs = yield self._addressbook.writeableAcceptedGroupIDs()
+ if writeableAcceptedGroupIDs:
+ objectsIDs = yield self._addressbook._objectIDsInExpandedGroupIDs(self._txn, writeableAcceptedGroupIDs)
+ yield self._deleteMembersWithMemberIDAndGroupIDsQuery(self._resourceID, objectsIDs).on(
+ self._txn, groupIDs=objectsIDs)
- if objectIDs:
- yield self._deleteMembersWithMemberIDAndGroupIDsQuery(self._resourceID, objectIDs).on(
- self._txn, groupIDs=objectIDs)
-
ownerAddressBook = yield self._addressbook.ownerAddressBook()
yield self._changeAddressBookRevision(ownerAddressBook)
@@ -1022,8 +1085,9 @@
self._ownerAddressBookResourceID = None
self._component = None
+
@classmethod
- def _allWithResourceIDAnd(cls, resourceIDs, column, paramName):
+ def _allColumnsWithResourceIDsAnd(cls, resourceIDs, column, paramName):
"""
DAL query for all columns where PARENT_RESOURCE_ID matches a parentID
parameter and a given instance column matches a given parameter name.
@@ -1037,17 +1101,17 @@
@classmethod
- def _allWithResourceIDAndName(cls, resourceIDs): #@NoSelf
- return cls._allWithResourceIDAnd(resourceIDs, cls._objectSchema.RESOURCE_NAME, "name")
+ def _allColumnsWithResourceIDsAndName(cls, resourceIDs): #@NoSelf
+ return cls._allColumnsWithResourceIDsAnd(resourceIDs, cls._objectSchema.RESOURCE_NAME, "name")
@classmethod
- def _allWithResourceIDAndUID(cls, resourceIDs): #@NoSelf
- return cls._allWithResourceIDAnd(resourceIDs, cls._objectSchema.UID, "uid")
+ def _allColumnsWithResourceIDsAndUID(cls, resourceIDs): #@NoSelf
+ return cls._allColumnsWithResourceIDsAnd(resourceIDs, cls._objectSchema.UID, "uid")
@classproperty
- def _allWithResourceID(cls): #@NoSelf
+ def _allColumnsWithResourceID(cls): #@NoSelf
obj = cls._objectSchema
return Select(
cls._allColumns, From=obj,
@@ -1064,48 +1128,47 @@
@return: L{self} if object exists in the DB, else C{None}
"""
- ownerGroup = yield self._addressbook.ownerGroup()
- if ownerGroup:
-
- objectIDs = yield ownerGroup._allGroupObjectIDs()
+ rows = None
+ if self.owned() or self._addressbook.fullyShared(): # owned or fully shared
if self._name:
- rows = (yield self._allWithResourceIDAndName(objectIDs).on(
+ rows = yield self._allColumnsWithParentAndName.on(
self._txn, name=self._name,
- resourceIDs=objectIDs,)) if objectIDs else []
- elif self._uid:
- rows = (yield self._allWithResourceIDAndUID(objectIDs).on(
- self._txn, uid=self._uid,
- resourceIDs=objectIDs,)) if objectIDs else []
- elif self._resourceID:
- rows = (yield self._allWithResourceID.on(
- self._txn, resourceID=self._resourceID,)) if (self._resourceID in objectIDs) else []
-
- else:
- if self._name:
- rows = yield self._allWithParentAndName.on(
- self._txn, name=self._name,
parentID=self._parentCollection._resourceID)
elif self._uid:
- rows = yield self._allWithParentAndUID.on(
+ rows = yield self._allColumnsWithParentAndUID.on(
self._txn, uid=self._uid,
parentID=self._parentCollection._resourceID)
elif self._resourceID:
- rows = yield self._allWithParentAndID.on(
+ rows = yield self._allColumnsWithParentAndID.on(
self._txn, resourceID=self._resourceID,
parentID=self._parentCollection._resourceID)
-
- # get special group vCard
- if not rows and not self._addressbook.owned():
+ if not rows and self._addressbook.fullyShared(): # perhaps add special group
+ if self._name:
+ if self._name == (yield self._addressbook._groupForEntireAB_Name()):
+ rows = [(yield self._addressbook._groupForEntireAB_Row())]
+ elif self._uid:
+ if self._uid == (yield self._addressbook._groupForEntireAB_UID()):
+ rows = [(yield self._addressbook._groupForEntireAB_Row())]
+ elif self._resourceID:
+ if self._resourceID == self._addressbook._resourceID:
+ rows = [(yield self._addressbook._groupForEntireAB_Row())]
+ else:
+ acceptedGroupIDs = yield self._addressbook.acceptedGroupIDs()
+ allowedObjectIDs = yield self._addressbook._objectIDsInExpandedGroupIDs(self._txn, acceptedGroupIDs)
if self._name:
- if self._name == (yield self._addressbook._groupForSharedABName()):
- rows = [(yield self._addressbook._groupForSharedABRow())]
+ rows = (yield self._allColumnsWithResourceIDsAndName(allowedObjectIDs).on(
+ self._txn, name=self._name,
+ resourceIDs=allowedObjectIDs,)) if allowedObjectIDs else []
elif self._uid:
- if self._uid == (yield self._addressbook._groupForSharedABUID()):
- rows = [(yield self._addressbook._groupForSharedABRow())]
+ rows = (yield self._allColumnsWithResourceIDsAndUID(allowedObjectIDs).on(
+ self._txn, uid=self._uid,
+ resourceIDs=allowedObjectIDs,)) if allowedObjectIDs else []
elif self._resourceID:
- if self._resourceID == self._addressbook._resourceID:
- rows = [(yield self._addressbook._groupForSharedABRow())]
+ invitedGroupIDs = yield self._addressbook.invitedGroupIDs()
+ allowedObjectIDs = tuple(set(allowedObjectIDs) | set(invitedGroupIDs))
+ rows = (yield self._allColumnsWithResourceID.on(
+ self._txn, resourceID=self._resourceID,)) if (self._resourceID in allowedObjectIDs) else []
if rows:
self._initFromRow(tuple(rows[0]))
@@ -1117,6 +1180,16 @@
self._md5 = hashlib.md5(componentText).hexdigest()
self._size = len(componentText)
+ groupBindRows = yield AddressBookObject._bindForResourceIDAndHomeID.on(
+ self._txn, resourceID=self._resourceID, homeID=self._home._resourceID)
+
+ if groupBindRows:
+ bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = groupBindRows[0] #@UnusedVariable\
+ self._bindMode = bindMode
+ self._bindStatus = bindStatus
+ self._bindMessage = bindMessage
+ self._bindName = bindName
+
yield self._loadPropertyStore()
returnValue(self)
@@ -1124,34 +1197,14 @@
returnValue(None)
- @classmethod
- def _memberIDsWithGroupIDsQuery(cls, groupIDs): #@NoSelf
- """
- DAL query to load all object resource names for a home child.
- """
- aboMembers = schema.ABO_MEMBERS
- return Select([aboMembers.MEMBER_ID], From=aboMembers,
- Where=aboMembers.GROUP_ID.In(Parameter("groupIDs", len(groupIDs))),
- )
-
@inlineCallbacks
- def _allGroupObjectIDs(self):
+ def _objectIDsInExpandedGroup(self):
"""
- Get all addressbookobject resource IDs in this address book
+ Get all AddressBookObject resource IDs contained in this shared group
"""
+ returnValue((yield self._addressbook._objectIDsInExpandedGroupIDs(self._txn, [self._resourceID])))
- objectIDs = set() if self.owned() else set([self._resourceID, ])
- examinedIDs = set()
- remainingIDs = set([self._resourceID, ])
- while remainingIDs:
- memberRows = yield self._memberIDsWithGroupIDsQuery(remainingIDs).on(self._txn, groupIDs=remainingIDs)
- objectIDs |= set([memberRow[0] for memberRow in memberRows])
- examinedIDs |= remainingIDs
- remainingIDs = objectIDs - examinedIDs
- returnValue(tuple(objectIDs))
-
-
@classproperty
def _allColumns(cls): #@NoSelf
"""
@@ -1189,7 +1242,7 @@
@classmethod
- def _abObjectColumnsWithResourceIDsQuery(cls, columns, resourceIDs): #@NoSelf
+ def _columnsWithResourceIDsQuery(cls, columns, resourceIDs): #@NoSelf
"""
DAL statement to retrieve addressbook object rows with given columns.
"""
@@ -1200,19 +1253,16 @@
@classmethod
@inlineCallbacks
- def _allColumnsWithParent(cls, parent): #@NoSelf
-
- ownerGroup = yield parent.ownerGroup()
- if ownerGroup:
- objectIDs = yield ownerGroup._allGroupObjectIDs()
- rows = (yield cls._abObjectColumnsWithResourceIDsQuery(cls._allColumns, objectIDs).on(
- parent._txn, resourceIDs=objectIDs)) if objectIDs else []
+ def _allColumnsWithParent(cls, addressbook): #@NoSelf
+ if addressbook.owned() or addressbook.fullyShared():
+ rows = yield super(AddressBookObject, cls)._allColumnsWithParent(addressbook)
+ if addressbook.fullyShared():
+ rows.append((yield addressbook._groupForEntireAB_Row()))
else:
- rows = yield super(AddressBookObject, cls)._allColumnsWithParent(parent)
- # add group vCard for shared address books
- if not parent.owned():
- rows.append((yield parent._groupForSharedABRow()))
-
+ acceptedGroupIDs = addressbook.acceptedGroupIDs()
+ allowedObjectIDs = yield addressbook._objectIDsInExpandedGroupIDs(addressbook._txn, acceptedGroupIDs)
+ rows = (yield cls._columnsWithResourceIDsQuery(cls._allColumns, allowedObjectIDs).on(
+ addressbook._txn, resourceIDs=allowedObjectIDs))
returnValue(rows)
@@ -1226,20 +1276,17 @@
@classmethod
@inlineCallbacks
- def _allColumnsWithParentAndNames(cls, parent, names): #@NoSelf
+ def _allColumnsWithParentAndNames(cls, addressbook, names): #@NoSelf
- ownerGroup = yield parent.ownerGroup()
- if ownerGroup:
- objectIDs = yield parent._allAddressBookObjectIDs()
- rows = (yield cls._allColumnsWithResourceIDsAndNamesQuery(objectIDs, names).on(
- parent._txn, resourceIDs=objectIDs, names=names)) if objectIDs else []
+ if addressbook.owned() or addressbook.fullyShared():
+ rows = yield super(AddressBookObject, cls)._allColumnsWithParentAndNames(addressbook, names)
+ if addressbook.fullyShared() and (yield addressbook._groupForEntireAB_Name()) in names:
+ rows.append((yield addressbook._groupForEntireAB_Row()))
else:
- rows = yield super(AddressBookObject, cls)._allColumnsWithParentAndNames(parent, names)
-
- # add group vCard for shared address books
- if not parent.owned() and (yield parent._groupForSharedABName()) in names:
- rows.append((yield parent._groupForSharedABRow(parent)))
-
+ acceptedGroupIDs = addressbook.acceptedGroupIDs()
+ allowedObjectIDs = yield addressbook._objectIDsInExpandedGroupIDs(addressbook._txn, acceptedGroupIDs)
+ rows = yield cls._allColumnsWithResourceIDsAndNamesQuery(allowedObjectIDs, names).on(
+ addressbook._txn, resourceIDs=allowedObjectIDs, names=names)
returnValue(rows)
@@ -1260,7 +1307,7 @@
yield self.updateDatabase(component, inserting=inserting)
yield self._changeAddressBookRevision(self._addressbook, inserting)
- if self._addressbook.owned():
+ if self.owned():
# update revision table of the sharee group address book
if self._kind == _ABO_KIND_GROUP: # optimization
for shareeAddressBook in (yield self.asShared()):
@@ -1369,13 +1416,19 @@
foundUIDs = [memberRow[1] for memberRow in memberRows]
foreignMemberAddrs.extend(["urn:uuid:" + missingUID for missingUID in set(memberUIDs) - set(foundUIDs)])
- #in shared group, all members must be inside the shared group
- ownerGroup = yield self._addressbook.ownerGroup()
- if ownerGroup:
- if foreignMemberAddrs or \
- set(memberIDs) - set((yield ownerGroup._allGroupObjectIDs())):
- raise GroupWithUnsharedAddressNotAllowedError
+ if not self.owned():
+ if not self._addressbook.fullyShared():
+ #in shared ab defined by groups, all members must be inside the shared groups
+ #FIXME: does this apply to whole-shared address books too?
+ if foreignMemberAddrs:
+ raise GroupWithUnsharedAddressNotAllowedError
+
+ acceptedGroupIDs = yield self._addressbook.acceptedGroupIDs()
+ allowedObjectIDs = yield self._addressbook._objectIDsInExpandedGroupIDs(self._txn, acceptedGroupIDs)
+ if set(memberIDs) - set(allowedObjectIDs):
+ raise GroupWithUnsharedAddressNotAllowedError
+
# don't store group members in object text
# sort addreses in component text
@@ -1434,14 +1487,13 @@
).on(self._txn)
groupIDs = [groupIDRow[0] for groupIDRow in groupIDRows]
- # add group if of this owner address book
- # groupIDs.append(self._ownerAddressBookResourceID)
+ # FIXME: Is this correct?
+ if not self.owned():
+ if not self._addressbook.fullyShared() or self._addressbook.shareMode() != _BIND_MODE_WRITE:
+ writeableAcceptedGroupIDs = yield self._addressbook.writeableAcceptedGroupIDs()
+ assert writeableAcceptedGroupIDs, "no access"
+ groupIDs.extend(writeableAcceptedGroupIDs)
- # add owner group if there is one
- ownerGroup = yield self._addressbook.ownerGroup()
- if ownerGroup:
- groupIDs.append(ownerGroup._resourceID)
-
# add to member table rows
for groupID in groupIDs:
yield Insert(
@@ -1515,10 +1567,8 @@
if self._component is None:
- if not self._addressbook.owned() and self._resourceID == self._addressbook._resourceID:
-
- component = yield self._addressbook._groupForSharedABComponent()
-
+ if not self.owned() and self._resourceID == self._addressbook._resourceID:
+ component = yield self._addressbook._groupForEntireAB_Component()
else:
text = yield self._text()
@@ -1553,7 +1603,7 @@
# then get member UIDs
abo = schema.ADDRESSBOOK_OBJECT
- memberUIDRows = (yield self._abObjectColumnsWithResourceIDsQuery(
+ memberUIDRows = (yield self._columnsWithResourceIDsQuery(
[abo.VCARD_UID],
memberIDs).on(
self._txn, resourceIDs=memberIDs)
@@ -1571,7 +1621,6 @@
).on(self._txn)
foreignMembers = [foreignMemberRow[0] for foreignMemberRow in foreignMemberRows]
-
# now add the properties to the component
for memberAddress in sorted(memberAddresses + foreignMembers):
component.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", memberAddress))
@@ -1596,13 +1645,51 @@
def ownerHome(self):
return self._addressbook.ownerHome()
+
def viewerHome(self):
return self._addressbook.viewerHome()
- def notifyChanged(self):
- self._addressbook.notifyChanged()
+ def shareMode(self):
+ """
+ @see: L{ICalendar.shareMode}
+ """
+ if hasattr(self, "_bindMode"):
+ return self._bindMode
+ else:
+ return self._addressbook.shareMode()
+
+ def shareStatus(self):
+ """
+ @see: L{ICalendar.shareStatus}
+ """
+ if hasattr(self, "_bindStatus"):
+ return self._bindStatus
+ else:
+ return self._addressbook.shareStatus()
+
+
+ def shareMessage(self):
+ """
+ @see: L{ICalendar.shareMessage}
+ """
+ if hasattr(self, "_bindMessage"):
+ return self._bindMessage
+ else:
+ return self._addressbook.shareMessage()
+
+
+ def shareUID(self):
+ """
+ @see: L{ICalendar.shareUID}
+ """
+ if hasattr(self, "_bindName"):
+ return self._bindName
+ else:
+ return self._addressbook.shareUID()
+
+
@classmethod
@inlineCallbacks
def ownerHomeID(cls, txn, resourceID):
@@ -1617,7 +1704,8 @@
returnValue(ownerHomeRows[0][0])
- # TODO: use class vars and CommonHomeChild._childrenAndMetadataForHomeID() instead
+
+ # TODO: use _homeChildMetaDataSchema and CommonHomeChild._childrenAndMetadataForHomeID() instead
@classproperty
def _childrenAndMetadataForHomeID(cls): #@NoSelf
aboBind = cls._bindSchema
@@ -1639,50 +1727,7 @@
).And(aboBind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
-
- '''
- @classmethod
@inlineCallbacks
- def invitedObjectWithName(cls, home, name):
- """
- Retrieve the child with the given C{name} contained in the given
- C{home}.
-
- @param home: a L{CommonHome}.
-
- @param name: a string; the name of the L{CommonHomeChild} to retrieve.
-
- @param owned: a boolean - whether or not to get a shared child
- @return: an L{CommonHomeChild} or C{None} if no such child
- exists.
- """
-
- rows = yield cls._invitedBindForNameAndHomeID.on(home._txn,
- name=name, homeID=home._resourceID)
- if not rows:
- returnValue(None)
-
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
-
- ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
- ownerAddressBook = yield ownerHome.addressbook()
-
- addressbook = AddressBook(
- home=home,
- name=ownerAddressBook.shareeABName(), resourceID=ownerAddressBook._resourceID,
- mode=bindMode, status=bindStatus,
- message=bindMessage, ownerHome=ownerHome,
- )
- yield addressbook.initFromStore()
-
- group = addressbook.objectResourceWithID(name, resourceID)
-
- returnValue(group)
- '''
-
-
- @inlineCallbacks
def shareWith(self, shareeHome, mode, status=None, message=None):
"""
Share this (owned) L{CommonHomeChild} with another home.
@@ -1706,62 +1751,269 @@
@rtype: L{str}
"""
- bindName = yield self._shareWith(shareeHome, mode, status=status, message=message)
- addressbook = self.addressbook()
+ yield self._shareWith(shareeHome, mode, status=status, message=message)
+ addressbook = yield self.addressbook()
shareeAddressBook = yield shareeHome.childWithID(addressbook._resourceID)
+
sharedGroup = yield shareeAddressBook.objectResourceWithID(self._resourceID)
-
- #FIXME
- sharedGroup._bindName = bindName
+ yield self._addressbook.notifyChanged()
returnValue(sharedGroup)
- def shareMode(self):
+ @inlineCallbacks
+ def asShared(self):
"""
- @see: L{ICalendar.shareMode}
+ Retrieve all the versions of this L{CommonHomeChild} as it is shared to
+ everyone.
+
+ @see: L{ICalendarHome.asShared}
+
+ @return: L{CommonHomeChild} objects that represent this
+ L{CommonHomeChild} as a child of different L{CommonHome}s
+ @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
"""
- if hasattr(self, "_bindMode"):
- return self._bindMode
- else:
- return self._addressbook.shareMode()
+ if not self.owned():
+ returnValue([])
+ # get all accepted shared binds
+ groupBindRows = yield self._sharedBindForResourceID.on(
+ self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+ )
- def shareStatus(self):
+ result = []
+ for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
+ home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+ addressbook = yield home.childWithID(self._addressbook._resourceID)
+ new = yield addressbook.objectResourceWithID(resourceID)
+ result.append(new)
+
+ returnValue(result)
+
+
+ @inlineCallbacks
+ def asInvited(self):
"""
- @see: L{ICalendar.shareStatus}
+ Retrieve all the versions of this L{CommonHomeChild} as it is shared to
+ everyone.
+
+ @see: L{ICalendarHome.asShared}
+
+ @return: L{CommonHomeChild} objects that represent this
+ L{CommonHomeChild} as a child of different L{CommonHome}s
+ @rtype: a L{Deferred} which fires with a L{list} of L{ICalendar}s.
"""
- if hasattr(self, "_bindStatus"):
- return self._bindStatus
- else:
- return self._addressbook.shareStatus()
+ if not self.owned():
+ returnValue([])
+ # get all accepted shared binds
+ groupBindRows = yield self._invitedBindForResourceID.on(
+ self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+ )
- def shareMessage(self):
+ result = []
+ for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
+ home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+ addressbook = yield home.childWithID(self._addressbook._resourceID)
+ new = yield addressbook.objectResourceWithID(resourceID)
+ result.append(new)
+
+ returnValue(result)
+
+
+ @classproperty
+ def _parentIDForObjectID(cls): #@NoSelf
+ #TODO: This query could be part of previously called query using object schema join
+ obj = cls._objectSchema
+ return Select([obj.PARENT_RESOURCE_ID],
+ From=obj,
+ Where=obj.RESOURCE_ID == Parameter("objectID")
+ )
+
+
+ @inlineCallbacks
+ def unshareWith(self, shareeHome):
"""
- @see: L{ICalendar.shareMessage}
+ Remove the shared version of this (owned) L{CommonHomeChild} from the
+ referenced L{CommonHome}.
+
+ @see: L{CommonHomeChild.shareWith}
+
+ @param shareeHome: The home with which this L{CommonHomeChild} was
+ previously shared.
+
+ @return: a L{Deferred} which will fire with the previously-used name.
"""
- if hasattr(self, "_bindMessage"):
- return self._bindMessage
- else:
- return self._addressbook.shareMessage()
+ sharedAddressBook = yield shareeHome.addressbookWithName(self._addressbook.shareeABName())
+ if not sharedAddressBook:
+ returnValue(None)
- def shareUID(self):
+ sharedRemoval = False
+ if not sharedAddressBook.fullyShared():
+ groupIDs = yield sharedAddressBook.acceptedGroupIDs()
+ assert self._resourceID in groupIDs
+ sharedRemoval = len(groupIDs) == 1
+ if sharedRemoval:
+ sharedAddressBook._deletedSyncToken(sharedRemoval=True)
+
+ queryCacher = self._txn._queryCacher
+ if queryCacher:
+ cacheKey = queryCacher.keyForObjectWithName(shareeHome._resourceID, self._addressbook.shareeABName())
+ queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
+ rows = yield self._deleteBindWithResourceIDAndHomeID.on(self._txn, resourceID=self._resourceID,
+ homeID=shareeHome._resourceID)
+
+ resourceName = None
+ if rows and sharedRemoval:
+ resourceName = rows[0][0]
+ shareeHome._children.pop(resourceName, None)
+
+ # Must send notification to ensure cache invalidation occurs
+ yield self._addressbook.notifyChanged()
+
+ returnValue(resourceName)
+
+
+ @inlineCallbacks
+ def updateShare(self, shareeView, mode=None, status=None, message=None, name=None):
"""
- @see: L{ICalendar.shareUID}
+ Update share mode, status, and message for a home child shared with
+ this (owned) L{CommonHomeChild}.
+
+ @param shareeView: The sharee home child that shares this.
+ @type shareeView: L{CommonHomeChild}
+
+ @param mode: The sharing mode; L{_BIND_MODE_READ} or
+ L{_BIND_MODE_WRITE} or None to not update
+ @type mode: L{str}
+
+ @param status: The sharing status; L{_BIND_STATUS_INVITED} or
+ L{_BIND_STATUS_ACCEPTED} or L{_BIND_STATUS_DECLINED} or
+ L{_BIND_STATUS_INVALID} or None to not update
+ @type status: L{str}
+
+ @param message: The proposed message to go along with the share, which
+ will be used as the default display name, or None to not update
+ @type message: L{str}
+
+ @param name: The bind resource name or None to not update
+ @type message: L{str}
+
+ @return: the name of the shared item in the sharee's home.
+ @rtype: a L{Deferred} which fires with a L{str}
"""
- if hasattr(self, "_bindName"):
- return self._bindName
- else:
- return self._addressbook.shareUID()
+ # TODO: raise a nice exception if shareeView is not, in fact, a shared
+ # version of this same L{CommonHomeChild}
- @classmethod
- def _bindForGroupIDsAndHomeID(cls, groupIDs): #@NoSelf
+ #remove None parameters, and substitute None for empty string
+ bind = self._bindSchema
+ columnMap = dict([(k, v if v else None)
+ for k, v in {bind.BIND_MODE:mode,
+ bind.BIND_STATUS:status,
+ bind.MESSAGE:message,
+ bind.RESOURCE_NAME:name}.iteritems() if v is not None])
+
+ if len(columnMap):
+
+ #TODO: with bit of parameter wrangling, call shareWith() here instead.
+ sharedname = yield self._updateBindColumnsQuery(columnMap).on(
+ self._txn,
+ resourceID=self._resourceID, homeID=shareeView._home._resourceID
+ )
+
+ #update affected attributes
+ if mode:
+ shareeView._bindMode = columnMap[bind.BIND_MODE]
+
+ if status:
+ shareeView._bindStatus = columnMap[bind.BIND_STATUS]
+ if shareeView._bindStatus == _BIND_STATUS_ACCEPTED:
+ yield shareeView._addressbook._initSyncToken()
+ elif shareeView._bindStatus == _BIND_STATUS_DECLINED:
+ shareeView._addressbook._deletedSyncToken(sharedRemoval=True)
+ shareeView._home._children.pop(shareeView._addressbook._name, None)
+
+ if message:
+ shareeView._bindMessage = columnMap[bind.MESSAGE]
+
+ queryCacher = self._txn._queryCacher
+ if queryCacher:
+ cacheKey = queryCacher.keyForObjectWithName(shareeView._home._resourceID, shareeView._addressbook._name)
+ queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
+ shareeView._name = sharedname[0][0]
+
+ # Must send notification to ensure cache invalidation occurs
+ yield self._addressbook.notifyChanged()
+
+ returnValue(shareeView._name)
+
+
+ @classproperty
+ def _acceptedBindWithAddressBookID(cls): #@NoSelf
bind = cls._bindSchema
- return cls._bindFor(bind.RESOURCE_ID.In(Parameter("groupIDs", len(groupIDs)))
- .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
- )
+ abo = cls._objectSchema
+ return Select(
+ cls._bindColumns,
+ From=bind.join(abo),
+ Where=(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+ .And(bind.RESOURCE_ID == abo.RESOURCE_ID)
+ .And(abo.ADDRESSBOOK_RESOURCE_ID == Parameter("addressbookID"))
+ )
+ @classproperty
+ def _invitedBindWithAddressBookID(cls): #@NoSelf
+ bind = cls._bindSchema
+ abo = cls._objectSchema
+ return Select(
+ cls._bindColumns,
+ From=bind.join(abo),
+ Where=(bind.BIND_STATUS == _BIND_STATUS_INVITED)
+ .And(bind.RESOURCE_ID == abo.RESOURCE_ID)
+ .And(abo.ADDRESSBOOK_RESOURCE_ID == Parameter("addressbookID"))
+ )
+
+ @classproperty
+ def _acceptedBindWithHomeIDAndAddressBookID(cls): #@NoSelf
+ bind = cls._bindSchema
+ abo = cls._objectSchema
+ return Select(
+ cls._bindColumns,
+ From=bind.join(abo),
+ Where=(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+ .And(bind.RESOURCE_ID == abo.RESOURCE_ID)
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ .And(abo.ADDRESSBOOK_RESOURCE_ID == Parameter("addressbookID"))
+ )
+
+
+ @classproperty
+ def _invitedBindWithHomeIDAndAddressBookID(cls): #@NoSelf
+ bind = cls._bindSchema
+ abo = cls._objectSchema
+ return Select(
+ cls._bindColumns,
+ From=bind.join(abo),
+ Where=(bind.BIND_STATUS == _BIND_STATUS_INVITED)
+ .And(bind.RESOURCE_ID == abo.RESOURCE_ID)
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ .And(abo.ADDRESSBOOK_RESOURCE_ID == Parameter("addressbookID"))
+ )
+
+
+ @classproperty
+ def _bindWithHomeIDAndAddressBookID(cls): #@NoSelf
+ bind = cls._bindSchema
+ abo = cls._objectSchema
+ return Select(
+ cls._bindColumns,
+ From=bind.join(abo),
+ Where=(bind.RESOURCE_ID == abo.RESOURCE_ID)
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ .And(abo.ADDRESSBOOK_RESOURCE_ID == Parameter("addressbookID"))
+ )
+
AddressBook._objectResourceClass = AddressBookObject
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/iaddressbookstore.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/iaddressbookstore.py 2013-02-12 00:37:11 UTC (rev 10694)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/iaddressbookstore.py 2013-02-12 01:07:09 UTC (rev 10695)
@@ -27,7 +27,7 @@
__all__ = [
# Classes
"GroupWithUnsharedAddressNotAllowedError",
- "DeleteOfShadowGroupNotAllowedError",
+ "DeleteOfGroupForSharedAddressBookNotAllowedError",
"IAddressBookTransaction",
"IAddressBookHome",
"IAddressBook",
@@ -38,7 +38,7 @@
"""
Sharee cannot add or modify group vcard such that result contains addresses of unshared vcards.
"""
-class DeleteOfShadowGroupNotAllowedError(CommonStoreError):
+class DeleteOfGroupForSharedAddressBookNotAllowedError(CommonStoreError):
"""
Sharee cannot delete group vcard shadowing shared address book
"""
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py 2013-02-12 00:37:11 UTC (rev 10694)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py 2013-02-12 01:07:09 UTC (rev 10695)
@@ -1486,15 +1486,6 @@
return self._childClass.listObjects(self)
- def listInvitedChildren(self):
- """
- Retrieve the names of the invited children in this home.
-
- @return: an iterable of C{str}s.
- """
- return self._childClass.listInvitedObjects(self)
-
-
@memoizedKey("name", "_children")
def childWithName(self, name):
"""
@@ -1507,7 +1498,7 @@
return self._childClass.objectWithName(self, name)
- def childWithVBindName(self, name):
+ def objectWithBindName(self, name):
"""
Retrieve the child with the given bind identifier contained in this
home.
@@ -1530,17 +1521,6 @@
return self._childClass.objectWithID(self, resourceID)
- def invitedChildWithName(self, name):
- """
- Retrieve the invited child with the given C{name} contained in this
- home.
-
- @param name: a string.
- @return: an L{ICalendar} or C{None} if no such child exists.
- """
- return self._childClass.invitedObjectWithName(self, name)
-
-
@inlineCallbacks
def createChildWithName(self, name):
if name.startswith("."):
@@ -2323,6 +2303,77 @@
bind.MESSAGE: Parameter("message")})
+ @classproperty
+ def _bindColumns(cls): #@NoSelf
+ bind = cls._bindSchema
+ return [
+ bind.BIND_MODE,
+ bind.HOME_RESOURCE_ID,
+ bind.RESOURCE_ID,
+ bind.RESOURCE_NAME,
+ bind.BIND_STATUS,
+ bind.MESSAGE,
+ ]
+
+
+ @classmethod
+ def _bindFor(cls, condition): #@NoSelf
+ bind = cls._bindSchema
+ return Select(
+ cls._bindColumns,
+ From=bind,
+ Where=condition
+ )
+
+
+ @classproperty
+ def _sharedBindForResourceID(cls): #@NoSelf
+ bind = cls._bindSchema
+ return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+ .And(bind.BIND_MODE != _BIND_MODE_OWN)
+ )
+
+ @classproperty
+ def _acceptedBindForHomeID(cls): #@NoSelf
+ bind = cls._bindSchema
+ return cls._bindFor((bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
+
+
+ @classproperty
+ def _invitedBindForResourceID(cls): #@NoSelf
+ bind = cls._bindSchema
+ return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+ )
+
+
+ @classproperty
+ def _bindForResourceIDAndHomeID(cls): #@NoSelf
+ """
+ DAL query that looks up home bind rows by home child
+ resource ID and home resource ID.
+ """
+ bind = cls._bindSchema
+ return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ )
+
+
+ @classproperty
+ def _acceptedBindForNameAndHomeID(cls): #@NoSelf
+ """
+ DAL query that looks up accepted bind rows by home child
+ resource ID and home resource ID.
+ """
+ bind = cls._bindSchema
+ return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+ .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+ )
+
+
@inlineCallbacks
def _shareWith(self, shareeHome, mode, status=None, message=None):
"""
@@ -2369,8 +2420,6 @@
resourceID=self._resourceID, homeID=shareeHome._resourceID
))[0][0]
- # Must send notification to ensure cache invalidation occurs
- yield self.notifyChanged()
returnValue(sharedName)
@@ -2400,6 +2449,7 @@
yield self._shareWith(shareeHome, mode, status=status, message=message)
child = yield shareeHome.childWithID(self._resourceID)
+ yield self.notifyChanged()
returnValue(child)
@@ -2469,6 +2519,7 @@
yield shareeView._initSyncToken()
elif shareeView._bindStatus == _BIND_STATUS_DECLINED:
shareeView._deletedSyncToken(sharedRemoval=True)
+ shareeView._home._children.pop(shareeView._name, None)
if message:
shareeView._bindMessage = columnMap[bind.MESSAGE]
@@ -2486,6 +2537,17 @@
returnValue(shareeView._name)
+ @classproperty
+ def _deleteBindWithResourceIDAndHomeID(cls): #@NoSelf
+ bind = cls._bindSchema
+ return Delete(
+ From=bind,
+ Where=(bind.RESOURCE_ID == Parameter("resourceID"))
+ .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
+ Return=bind.RESOURCE_NAME,
+ )
+
+
@inlineCallbacks
def unshareWith(self, shareeHome):
"""
@@ -2513,13 +2575,7 @@
break
- bind = self._bindSchema
- rows = yield Delete(
- From=bind,
- Where=(bind.RESOURCE_ID == Parameter("resourceID"))
- .And(bind.HOME_RESOURCE_ID == Parameter("homeID")),
- Return=bind.RESOURCE_NAME,
- ).on(self._txn, resourceID=self._resourceID,
+ rows = yield self._deleteBindWithResourceIDAndHomeID.on(self._txn, resourceID=self._resourceID,
homeID=shareeHome._resourceID)
resourceName = None
@@ -2532,31 +2588,6 @@
returnValue(resourceName)
-
- @classmethod
- def _bindFor(cls, condition): #@NoSelf
- bind = cls._bindSchema
- return Select(
- [bind.BIND_MODE,
- bind.HOME_RESOURCE_ID,
- bind.RESOURCE_ID,
- bind.RESOURCE_NAME,
- bind.BIND_STATUS,
- bind.MESSAGE],
- From=bind,
- Where=condition
- )
-
-
- @classproperty
- def _sharedBindForResourceID(cls): #@NoSelf
- bind = cls._bindSchema
- return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
- .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
- .And(bind.BIND_MODE != _BIND_MODE_OWN)
- )
-
-
@inlineCallbacks
def asShared(self):
"""
@@ -2574,7 +2605,7 @@
# get all accepted binds
acceptedRows = yield self._sharedBindForResourceID.on(
- self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+ self._txn, resourceID=self._resourceID,
)
cls = self._home._childClass # for ease of grepping...
@@ -2594,14 +2625,6 @@
returnValue(result)
- @classproperty
- def _invitedBindForResourceID(cls): #@NoSelf
- bind = cls._bindSchema
- return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
- .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
- )
-
-
@inlineCallbacks
def asInvited(self):
"""
@@ -2618,7 +2641,7 @@
returnValue([])
rows = yield self._invitedBindForResourceID.on(
- self._txn, resourceID=self._resourceID, homeID=self._home._resourceID,
+ self._txn, resourceID=self._resourceID,
)
cls = self._home._childClass # for ease of grepping...
@@ -2638,16 +2661,7 @@
returnValue(result)
- @classproperty
- def _childBindForNameAndHomeID(cls): #@NoSelf
- bind = cls._bindSchema
- return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
- .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
- .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
- )
-
-
def shareMode(self):
"""
@see: L{ICalendar.shareMode}
@@ -2682,26 +2696,7 @@
"""
return self.name()
- @classproperty
- def _childBindForHomeID(cls): #@NoSelf
- bind = cls._bindSchema
- return cls._bindFor((bind.HOME_RESOURCE_ID == Parameter("homeID"))
- .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
-
- @classproperty
- def _bindForResourceIDAndHomeID(cls): #@NoSelf
- """
- DAL query that looks up home child names / bind modes by home child
- resource ID and home resource ID.
- """
- bind = cls._bindSchema
- return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
- .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
- )
-
-
-
class CommonHomeChild(LoggingMixIn, FancyEqMixin, _SharedSyncLogic, HomeChildBase, SharingMixIn):
"""
Common ancestor class of AddressBooks and Calendars.
@@ -2796,7 +2791,7 @@
@return: an iterable of C{str}s.
"""
# FIXME: tests don't cover this as directly as they should.
- rows = yield cls._childBindForHomeID.on(
+ rows = yield cls._acceptedBindForHomeID.on(
home._txn, homeID=home._resourceID
)
names = [row[3] for row in rows]
@@ -2804,40 +2799,12 @@
@classproperty
- def _invitedBindForHomeID(cls): #@NoSelf
- bind = cls._bindSchema
- return cls._bindFor((bind.HOME_RESOURCE_ID == Parameter("homeID"))
- .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED))
-
-
- @classmethod
- @inlineCallbacks
- def listInvitedObjects(cls, home):
- """
- Retrieve the names of the children with invitations in the given home.
-
- @return: an iterable of C{str}s.
- """
- rows = yield cls._invitedBindForHomeID.on(
- home._txn, homeID=home._resourceID
- )
- names = [row[3] for row in rows]
- returnValue(names)
-
-
- @classproperty
def _childrenAndMetadataForHomeID(cls): #@NoSelf
bind = cls._bindSchema
child = cls._homeChildSchema
childMetaData = cls._homeChildMetaDataSchema
-
- columns = [bind.BIND_MODE,
- bind.HOME_RESOURCE_ID,
- bind.RESOURCE_ID,
- bind.RESOURCE_NAME,
- bind.BIND_STATUS,
- bind.MESSAGE]
- columns.extend(cls.metadataColumns())
+ columns = cls._bindColumns
+ columns = columns.extend(cls.metadataColumns())
return Select(columns,
From=child.join(
bind, child.RESOURCE_ID == bind.RESOURCE_ID,
@@ -2848,7 +2815,6 @@
).And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
-
@inlineCallbacks
def unshare(self, homeType):
"""
@@ -2942,11 +2908,10 @@
@classproperty
- def _invitedBindForNameAndHomeID(cls): #@NoSelf
+ def _bindForNameAndHomeID(cls): #@NoSelf
bind = cls._bindSchema
return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
.And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
- .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
)
@@ -2959,42 +2924,6 @@
@classmethod
@inlineCallbacks
- def invitedObjectWithName(cls, home, name):
- """
- Retrieve the child with the given C{name} contained in the given
- C{home}.
-
- @param home: a L{CommonHome}.
-
- @param name: a string; the name of the L{CommonHomeChild} to retrieve.
-
- @param owned: a boolean - whether or not to get a shared child
- @return: an L{CommonHomeChild} or C{None} if no such child
- exists.
- """
- rows = yield cls._invitedBindForNameAndHomeID.on(home._txn,
- name=name, homeID=home._resourceID)
-
- if not rows:
- returnValue(None)
-
- bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
-
- ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
- ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
-
- child = ownerHome._childClass(
- home=home,
- name=resourceName, resourceID=resourceID,
- mode=bindMode, status=bindStatus,
- message=bindMessage, ownerHome=ownerHome,
- )
- yield child.initFromStore()
- returnValue(child)
-
-
- @classmethod
- @inlineCallbacks
def objectWithName(cls, home, name):
# replaces objectWithName()
"""
@@ -3018,7 +2947,7 @@
if rows is None:
# No cached copy
- rows = yield cls._childBindForNameAndHomeID.on(home._txn, name=name, homeID=home._resourceID)
+ rows = yield cls._acceptedBindForNameAndHomeID.on(home._txn, name=name, homeID=home._resourceID)
if rows:
bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
@@ -3037,7 +2966,6 @@
returnValue(None)
bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage, ownerHomeID = rows[0] #@UnusedVariable
-
if bindMode == _BIND_MODE_OWN:
ownerHome = home
else:
@@ -3110,12 +3038,10 @@
@classmethod
@inlineCallbacks
def create(cls, home, name):
- child = (yield cls.objectWithName(home, name))
- if child is not None:
+
+ if (yield cls._bindForNameAndHomeID.on(home._txn,
+ name=name, homeID=home._resourceID)):
raise HomeChildNameAlreadyExistsError(name)
- invite = (yield cls.invitedObjectWithName(home, name))
- if invite is not None:
- raise HomeChildNameAlreadyExistsError(name)
if name.startswith("."):
raise HomeChildNameNotAllowedError(name)
@@ -3425,11 +3351,11 @@
if resourceID in self._objects:
return succeed(self._objects[resourceID])
else:
- return self._makeObjectResource(resourceID=resourceID)
+ return self._makeObjectResource(resourceID=resourceID, cache=False)
@inlineCallbacks
- def _makeObjectResource(self, name=None, uid=None, resourceID=None):
+ def _makeObjectResource(self, name=None, uid=None, resourceID=None, cache=True):
"""
We create the empty object first then have it initialize itself from the
store.
@@ -3442,7 +3368,7 @@
objectResource = (
yield self._objectResourceClass.objectWithName(self, name, uid)
)
- if objectResource:
+ if objectResource and cache:
self._objects[objectResource.name()] = objectResource
self._objects[objectResource.uid()] = objectResource
self._objects[objectResource._resourceID] = objectResource
@@ -3987,7 +3913,7 @@
@classmethod
- def _allWithParentAnd(cls, column, paramName):
+ def _allColumnsWithParentAnd(cls, column, paramName):
"""
DAL query for all columns where PARENT_RESOURCE_ID matches a parentID
parameter and a given instance column matches a given parameter name.
@@ -4000,18 +3926,18 @@
@classproperty
- def _allWithParentAndName(cls): #@NoSelf
- return cls._allWithParentAnd(cls._objectSchema.RESOURCE_NAME, "name")
+ def _allColumnsWithParentAndName(cls): #@NoSelf
+ return cls._allColumnsWithParentAnd(cls._objectSchema.RESOURCE_NAME, "name")
@classproperty
- def _allWithParentAndUID(cls): #@NoSelf
- return cls._allWithParentAnd(cls._objectSchema.UID, "uid")
+ def _allColumnsWithParentAndUID(cls): #@NoSelf
+ return cls._allColumnsWithParentAnd(cls._objectSchema.UID, "uid")
@classproperty
- def _allWithParentAndID(cls): #@NoSelf
- return cls._allWithParentAnd(cls._objectSchema.RESOURCE_ID, "resourceID")
+ def _allColumnsWithParentAndID(cls): #@NoSelf
+ return cls._allColumnsWithParentAnd(cls._objectSchema.RESOURCE_ID, "resourceID")
@inlineCallbacks
@@ -4026,15 +3952,15 @@
"""
if self._name:
- rows = yield self._allWithParentAndName.on(
+ rows = yield self._allColumnsWithParentAndName.on(
self._txn, name=self._name,
parentID=self._parentCollection._resourceID)
elif self._uid:
- rows = yield self._allWithParentAndUID.on(
+ rows = yield self._allColumnsWithParentAndUID.on(
self._txn, uid=self._uid,
parentID=self._parentCollection._resourceID)
elif self._resourceID:
- rows = yield self._allWithParentAndID.on(
+ rows = yield self._allColumnsWithParentAndID.on(
self._txn, resourceID=self._resourceID,
parentID=self._parentCollection._resourceID)
if rows:
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql 2013-02-12 00:37:11 UTC (rev 10694)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql 2013-02-12 01:07:09 UTC (rev 10695)
@@ -402,9 +402,9 @@
ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
------------------------------
+------------------------
-- AddressBook Object --
------------------------------
+------------------------
create table ADDRESSBOOK_OBJECT (
RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130211/d5528635/attachment-0001.html>
More information about the calendarserver-changes
mailing list