[CalendarServer-changes] [10002] CalendarServer/branches/users/gaya/sharedgroups
source_changes at macosforge.org
source_changes at macosforge.org
Sat Nov 3 09:05:43 PDT 2012
Revision: 10002
http://trac.calendarserver.org//changeset/10002
Author: gaya at apple.com
Date: 2012-11-03 09:05:43 -0700 (Sat, 03 Nov 2012)
Log Message:
-----------
checkpoint changes
Modified Paths:
--------------
CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/file.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/test/test_sql.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/file.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql
CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/upgrade/test/test_migrate.py
Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py 2012-11-02 20:50:49 UTC (rev 10001)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py 2012-11-03 16:05:43 UTC (rev 10002)
@@ -33,7 +33,7 @@
from txdav.common.datastore.sql_tables import _BIND_MODE_OWN, \
_BIND_MODE_READ, _BIND_MODE_WRITE, _BIND_STATUS_INVITED, \
_BIND_MODE_DIRECT, _BIND_STATUS_ACCEPTED, _BIND_STATUS_DECLINED, \
- _BIND_STATUS_INVALID
+ _BIND_STATUS_INVALID, _ABO_KIND_GROUP
from txdav.xml import element
from twisted.internet.defer import succeed, inlineCallbacks, DeferredList, \
@@ -116,10 +116,12 @@
def upgradeToShare(self):
""" Upgrade this collection to a shared state """
- # Change resourcetype
- rtype = self.resourceType()
- rtype = element.ResourceType(*(rtype.children + (customxml.SharedOwner(),)))
- self.writeDeadProperty(rtype)
+ if self.isCollection():
+ # Change resourcetype
+ rtype = self.resourceType()
+ rtype = element.ResourceType(*(rtype.children + (customxml.SharedOwner(),)))
+ self.writeDeadProperty(rtype)
+ # TODO: set group resource type?
@inlineCallbacks
def downgradeFromShare(self, request):
@@ -202,7 +204,7 @@
# Get the home collection
if self.isCalendarCollection():
shareeHomeResource = yield sharee.calendarHome(request)
- elif self.isAddressBookCollection():
+ elif self.isAddressBookCollection() or self.isGroup():
shareeHomeResource = yield sharee.addressBookHome(request)
else:
raise HTTPError(ErrorResponse(
@@ -232,7 +234,7 @@
@inlineCallbacks
def isShared(self, request):
""" Return True if this is an owner shared calendar collection """
- returnValue((yield self.isSpecialCollection(customxml.SharedOwner)))
+ returnValue((yield self.isSpecialCollection(customxml.SharedOwner)) or (yield self._allInvitations()))
def setShare(self, share):
@@ -253,7 +255,7 @@
# Remove from sharee's calendar/address book home
if self.isCalendarCollection():
shareeHome = yield sharee.calendarHome(request)
- elif self.isAddressBookCollection():
+ elif self.isAddressBookCollection() or self.isGroup():
shareeHome = yield sharee.addressBookHome(request)
returnValue((yield shareeHome.removeShare(request, self._share)))
@@ -287,6 +289,9 @@
return "calendar"
elif self.isAddressBookCollection():
return "addressbook"
+ elif self.isGroup():
+ #TODO: Add group xml resource type ?
+ return "group"
else:
return ""
@@ -501,7 +506,7 @@
'''
if self.isCalendarCollection():
shareeHome = yield self._newStoreObject._txn.calendarHomeWithUID(shareeUID, create=True)
- elif self.isAddressBookCollection():
+ elif self.isAddressBookCollection() or self.isGroup():
shareeHome = yield self._newStoreObject._txn.addressbookHomeWithUID(shareeUID, create=True)
sharedName = yield self._newStoreObject.shareWith(shareeHome,
@@ -622,7 +627,7 @@
if sharee:
if self.isCalendarCollection():
shareeHomeResource = yield sharee.calendarHome(request)
- elif self.isAddressBookCollection():
+ elif self.isAddressBookCollection() or self.isGroup():
shareeHomeResource = yield sharee.addressBookHome(request)
displayName = (yield shareeHomeResource.removeShareByUID(request, invitation.uid()))
# If current user state is accepted then we send an invite with the new state, otherwise
@@ -899,8 +904,22 @@
customxml.InviteReply: _xmlHandleInviteReply,
}
+ def isGroup(self):
+ try:
+ kind = self._newStoreObject._kind
+ except AttributeError:
+ pass
+ else:
+ if kind == _ABO_KIND_GROUP:
+ self.log_info("isGroup():self=%s returning True" % (self,))
+ return True
+
+ self.log_info("isGroup():self=%s returning False" % (self,))
+ return False
+
+
def POST_handler_content_type(self, request, contentType):
- if self.isCollection():
+ if self.isCollection() or self.isGroup():
if contentType:
if contentType in self._postHandlers:
return self._postHandlers[contentType](self, request)
@@ -986,10 +1005,8 @@
if not child or child.owned():
returnValue(None)
- sharerHomeChild = yield child.ownerHome().childWithID(child._resourceID)
-
# get the shared object's URL
- sharer = self.principalForUID(sharerHomeChild.viewerHome().uid())
+ sharer = self.principalForUID(child.ownerHome().uid())
if not request:
# FIXEME: Fake up a request that can be used to get the sharer home resource
@@ -1003,9 +1020,19 @@
elif self._newStoreHome._homeType == EADDRESSBOOKTYPE:
sharerHomeCollection = yield sharer.addressBookHome(request)
- url = joinURL(sharerHomeCollection.url(), sharerHomeChild.name())
- share = Share(shareeHomeChild=child, sharerHomeChild=sharerHomeChild, url=url)
+ itemShared = yield child.ownerHome().childWithID(child._resourceID)
+ if itemShared:
+ url = joinURL(sharerHomeCollection.url(), itemShared.name())
+ else:
+ for sharerHomeChild in (yield child.ownerHome().children()):
+ for objectResource in (yield sharerHomeChild.objectResources()):
+ if objectResource._resourceID == child._resourceID:
+ itemShared = objectResource
+ url = joinURL(sharerHomeCollection.url(), itemShared._parentCollection.name(), itemShared.name())
+ break
+ share = Share(shareeHomeChild=child, sharerHomeChild=itemShared, url=url)
+
returnValue(share)
@inlineCallbacks
@@ -1083,7 +1110,7 @@
sharee = self.principalForUID(share.shareeUID())
if sharedCollection.isCalendarCollection():
shareeHomeResource = yield sharee.calendarHome(request)
- elif sharedCollection.isAddressBookCollection():
+ elif sharedCollection.isAddressBookCollection() or sharedCollection.isGroup():
shareeHomeResource = yield sharee.addressBookHome(request)
shareeURL = joinURL(shareeHomeResource.url(), share.name())
shareeCollection = yield request.locateResource(shareeURL)
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/file.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/file.py 2012-11-02 20:50:49 UTC (rev 10001)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/file.py 2012-11-03 16:05:43 UTC (rev 10002)
@@ -261,14 +261,6 @@
return ResourceType.calendar #@UndefinedVariable
- def asShared(self):
- """
- Stub for interface-compliance tests.
- """
- # TODO: implement me.
- raise NotImplementedError()
-
-
ownerCalendarHome = CommonHomeChild.ownerHome
viewerCalendarHome = CommonHomeChild.viewerHome
calendarObjects = CommonHomeChild.objectResources
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py 2012-11-02 20:50:49 UTC (rev 10001)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py 2012-11-03 16:05:43 UTC (rev 10002)
@@ -44,7 +44,7 @@
from txdav.carddav.iaddressbookstore import IAddressBookHome, IAddressBook, \
IAddressBookObject
from txdav.common.datastore.sql import CommonHome, CommonHomeChild, \
- CommonObjectResource, EADDRESSBOOKTYPE
+ CommonObjectResource, EADDRESSBOOKTYPE, SharingMixIn
from txdav.common.datastore.sql_legacy import PostgresLegacyABIndexEmulator
from txdav.common.datastore.sql_tables import ADDRESSBOOK_TABLE, \
ADDRESSBOOK_BIND_TABLE, ADDRESSBOOK_OBJECT_REVISIONS_TABLE, \
@@ -137,7 +137,7 @@
AddressBookHome._register(EADDRESSBOOKTYPE)
-class _AddressBookObjectCommon(object):
+class AddressBookSharingMixIn(SharingMixIn):
@classproperty
def _insertABObject(cls): #@NoSelf
@@ -160,7 +160,7 @@
abo.MODIFIED))
-class AddressBook(CommonHomeChild, _AddressBookObjectCommon):
+class AddressBook(CommonHomeChild, AddressBookSharingMixIn):
"""
SQL-based implementation of L{IAddressBook}.
"""
@@ -245,12 +245,13 @@
@classmethod
@inlineCallbacks
- def _createChild(cls, home, name):
+ def _createChild(cls, home, name): #@NoSelf
# Create this object
# TODO: N, FN, set to resource name for now,
# but "may" have to change when shared
# and perhaps will need to reflect a per-user property
+ uid = str(uuid4())
component = VCard.fromString(
"""BEGIN:VCARD
VERSION:3.0
@@ -260,13 +261,13 @@
N:%s;;;;
X-ADDRESSBOOKSERVER-KIND:group
END:VCARD
-""".replace("\n", "\r\n") % (vCardProductID, uuid4(), name, name)
+""".replace("\n", "\r\n") % (vCardProductID, uid, name, name)
)
componentText = str(component)
md5 = hashlib.md5(componentText).hexdigest()
- resourceID, created, modified = (
+ resourceID, created, modified = (#@UnusedVariable
yield cls._insertABObject.on(
home._txn,
addressbookResourceID=None,
@@ -289,16 +290,78 @@
-class AddressBookObject(CommonObjectResource, _AddressBookObjectCommon):
+ @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 _addressBookObjectIDs(self):
+ """
+ Get all addressbookobject resource IDs in this address book
+
+ TODO: optimize
+ """
+ # TODO: if shared, self is a member
+ # allMemberIDs = set() if self.owned() else set([self._resourceID])
+ allMemberIDs = set()
+ examinedIDs = set()
+ remainingIDs = set([self._resourceID])
+ while remainingIDs:
+ memberRows = yield self._memberIDsWithGroupIDsQuery(remainingIDs).on(self._txn, groupIDs=remainingIDs)
+ allMemberIDs |= set([memberRow[0] for memberRow in memberRows])
+ examinedIDs |= remainingIDs
+ remainingIDs = allMemberIDs - examinedIDs
+ print("_addressBookObjectIDs:self=%s, examinedIDs=%s, remainingIDs=%s, allMemberIDs=%s" % (self, examinedIDs, remainingIDs, allMemberIDs,))
+
+ returnValue(tuple(allMemberIDs))
+
+
+ @classmethod
+ def _objectResourceNamesWithResourceIDsQuery(cls, resourceIDs): #@NoSelf
+ """
+ DAL query to load all object resource names for a home child.
+ """
+ abo = schema.ADDRESSBOOK_OBJECT
+ return Select([abo.RESOURCE_NAME], From=abo,
+ Where=abo.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs)))
+ )
+
+
+ @inlineCallbacks
+ def listObjectResources(self):
+ if self._objectNames is None:
+ memberIDs = yield self._addressBookObjectIDs()
+ rows = (yield self._objectResourceNamesWithResourceIDsQuery(memberIDs).on(
+ self._txn, resourceIDs=memberIDs)) if memberIDs else []
+ self._objectNames = sorted([row[0] for row in rows])
+
+ returnValue(self._objectNames)
+
+
+ @inlineCallbacks
+ def countObjectResources(self):
+ returnValue(len((yield self._addressBookObjectIDs())))
+
+
+class AddressBookObject(CommonObjectResource, AddressBookSharingMixIn):
+
implements(IAddressBookObject)
_objectTable = ADDRESSBOOK_OBJECT_TABLE
_objectSchema = schema.ADDRESSBOOK_OBJECT
+ _bindSchema = schema.ADDRESSBOOK_BIND
+
def __init__(self, addressbook, name, uid, resourceID=None, metadata=None):
self._kind = None
+ self._ownerAddressBookResourceID = None
super(AddressBookObject, self).__init__(addressbook, name, uid, resourceID)
@@ -319,6 +382,11 @@
aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
aboMembers = schema.ABO_MEMBERS
+ if not self._addressbook.owned():
+ ownerGroup, ownerAddressBook = yield self._ownerGroupAndAddressBook() #@UnusedVariable
+ if ownerGroup:
+ assert False, "updateDatabase() remove of vcard in shared group: need to modify shared group vCard text"
+
# delete members table row for this object
groupIDs = yield Delete(
aboMembers,
@@ -327,29 +395,19 @@
).on(self._txn)
# add to foreign member table row by UID
+ assert self._ownerAddressBookResourceID
for groupID in groupIDs:
- yield Insert(
- {aboForeignMembers.GROUP_ID: groupID,
- aboForeignMembers.ADDRESSBOOK_ID: self._addressbook._resourceID,
- aboForeignMembers.MEMBER_ADDRESS: "urn:uuid:" + self._uid, }
- ).on(self._txn)
+ if groupID[0] != self._ownerAddressBookResourceID:
+ # remove on address book, add aboForeignMembers row to local groups only
+ yield Insert(
+ {aboForeignMembers.GROUP_ID: groupID,
+ aboForeignMembers.ADDRESSBOOK_ID: self._ownerAddressBookResourceID,
+ aboForeignMembers.MEMBER_ADDRESS: "urn:uuid:" + self._uid, }
+ ).on(self._txn)
- if self._kind == _ABO_KIND_GROUP:
-
- # delete this group's members
- yield Delete(
- aboMembers,
- Where=aboMembers.GROUP_ID == self._resourceID,
- ).on(self._txn)
-
- # delete this group's foreign members
- yield Delete(
- aboForeignMembers,
- Where=aboForeignMembers.GROUP_ID == self._resourceID,
- ).on(self._txn)
-
yield super(AddressBookObject, self).remove()
self._kind = None
+ self._ownerAddressBookResourceID = None
@classproperty
def _allColumns(cls): #@NoSelf
@@ -359,6 +417,7 @@
"""
obj = cls._objectSchema
return [
+ obj.ADDRESSBOOK_RESOURCE_ID,
obj.RESOURCE_ID,
obj.RESOURCE_NAME,
obj.UID,
@@ -375,7 +434,8 @@
Given a select result using the columns from L{_allColumns}, initialize
the object resource state.
"""
- (self._resourceID,
+ (self._ownerAddressBookResourceID,
+ self._resourceID,
self._name,
self._uid,
self._kind,
@@ -384,7 +444,48 @@
self._created,
self._modified,) = tuple(row)
+ print("_initFromRow:self=%s, row=%s, self._ownerAddressBookResourceID=%s, self._addressbook=%s" % (self, row, self._ownerAddressBookResourceID, self._addressbook))
+
+ @classmethod
+ def _allColumnsWithResourceIDsQuery(cls, resourceIDs): #@NoSelf
+ obj = cls._objectSchema
+ return Select(cls._allColumns, From=obj,
+ Where=obj.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs))))
+
+ @classmethod
@inlineCallbacks
+ def _allColumnsWithParent(cls, parent): #@NoSelf
+
+ memberIDs = yield parent._addressBookObjectIDs()
+ print("_allColumnsWithParent:cls=%s, parent=%s, memberIDs=%s" % (cls, parent, memberIDs,))
+
+ rows = (yield cls._allColumnsWithResourceIDsQuery(memberIDs).on(
+ parent._txn, resourceIDs=memberIDs)) if memberIDs else []
+
+ print("_allColumnsWithParent:cls=%s, parent=%s, rows=%s" % (cls, parent, rows,))
+ returnValue(rows)
+
+
+ @classmethod
+ def _allColumnsWithResourceIDsAndNamesQuery(cls, resourceIDs, names): #@NoSelf
+ obj = cls._objectSchema
+ return Select(cls._allColumns, From=obj,
+ Where=(obj.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs))).And(
+ obj.RESOURCE_NAME.In(Parameter("names", len(names))))))
+
+
+ @classmethod
+ @inlineCallbacks
+ def _allColumnsWithParentAndNames(cls, parent, names): #@NoSelf
+ memberIDs = yield parent._addressBookObjectIDs()
+
+ rows = (yield cls._allColumnsWithResourceIDsAndNamesQuery(memberIDs, names).on(
+ parent._txn, resourceIDs=memberIDs, names=names)) if memberIDs else []
+
+ returnValue(rows)
+
+
+ @inlineCallbacks
def setComponent(self, component, inserting=False):
validateAddressBookComponent(self, self._addressbook, component, inserting)
@@ -399,6 +500,24 @@
@inlineCallbacks
+ def _ownerGroupAndAddressBook(self):
+ # find the owning address book
+ ownerGroup = None
+ ownerAddressBook = None
+ if self._addressbook.owned():
+ ownerAddressBook = self._addressbook
+ else:
+ ownerAddressBook = yield self._addressbook.ownerHome().childWithID(self._addressbook._resourceID)
+ if not ownerAddressBook:
+ for addressbook in (yield self._addressbook.ownerHome().children()):
+ for addressBookObject in (yield addressbook.objectResources()):
+ if addressBookObject._resourceID == self._addressbook._resourceID:
+ ownerGroup = addressBookObject
+ ownerAddressBook = addressbook
+ break
+ returnValue((ownerGroup, ownerAddressBook))
+
+ @inlineCallbacks
def updateDatabase(self, component, expand_until=None, reCreate=False,
inserting=False):
"""
@@ -437,11 +556,18 @@
assert inserting or self._kind == kind # can't change kind. Should be checked in upper layers
self._kind = kind
+ print("updateDatabase:self=%s self._addressbook.=%s self._ownerAddressBookResourceID=%s" % (self, self._addressbook, self._ownerAddressBookResourceID,))
+ print("updateDatabase:self=%s insert=%s, component=%s" % (self, inserting, component))
if inserting:
+
+ ownerGroup, ownerAddressBook = yield self._ownerGroupAndAddressBook()
+ assert ownerAddressBook
+ self._ownerAddressBookResourceID = ownerAddressBook._resourceID
+
self._resourceID, self._created, self._modified = (
yield self._insertABObject.on(
self._txn,
- addressbookResourceID=self._addressbook._resourceID,
+ addressbookResourceID=self._ownerAddressBookResourceID,
name=self._name,
text=componentText,
uid=self._uid,
@@ -449,6 +575,18 @@
kind=self._kind,
))[0]
+ if ownerGroup:
+ assert False, "updateDatabase() insert for shared group: need to modify shared group vCard text"
+ else:
+ # add row on this address book group table
+ print("updateDatabase1:self=%s Insert(aboMembers.GROUP_ID:%s, aboMembers.ADDRESSBOOK_ID:%s, aboMembers.MEMBER_ID:%s" % (
+ self, self._ownerAddressBookResourceID, self._ownerAddressBookResourceID, self._resourceID))
+ yield Insert(
+ {aboMembers.GROUP_ID: self._ownerAddressBookResourceID,
+ aboMembers.ADDRESSBOOK_ID: self._ownerAddressBookResourceID,
+ aboMembers.MEMBER_ID: self._resourceID, }
+ ).on(self._txn)
+
# update existing group member tables for this new object
# delete foreign members table row for this object
groupIDs = yield Delete(
@@ -459,9 +597,11 @@
# add to member table row by resourceID
for groupID in groupIDs:
+ print("updateDatabase2:self=%s Insert(aboMembers.GROUP_ID:%s, aboMembers.ADDRESSBOOK_ID:%s, aboMembers.MEMBER_ID:%s" % (
+ self, groupID[0], self._ownerAddressBookResourceID, self._resourceID))
yield Insert(
- {aboMembers.GROUP_ID: groupID,
- aboMembers.ADDRESSBOOK_ID: self._addressbook._resourceID,
+ {aboMembers.GROUP_ID: groupID[0],
+ aboMembers.ADDRESSBOOK_ID: self._ownerAddressBookResourceID,
aboMembers.MEMBER_ID: self._resourceID, }
).on(self._txn)
@@ -475,6 +615,7 @@
if self._kind == _ABO_KIND_GROUP:
+ assert self._ownerAddressBookResourceID
# get member resource ID for each member string, or keep as string
memberIDs = []
foreignMemberAddrs = []
@@ -484,7 +625,7 @@
memberUID = memberAddr[len("urn:uuid:"):]
memberRow = yield Select([abo.RESOURCE_ID],
From=abo,
- Where=((abo.ADDRESSBOOK_RESOURCE_ID == self._addressbook._resourceID)
+ Where=((abo.ADDRESSBOOK_RESOURCE_ID == self._ownerAddressBookResourceID)
).And(abo.VCARD_UID == memberUID)).on(self._txn)
if memberRow:
memberIDs.append(memberRow[0][0])
@@ -492,9 +633,10 @@
foreignMemberAddrs.append(memberAddr)
#get current members
- currentMemberIDs = yield Select([aboMembers.MEMBER_ID],
+ currentMemberRows = yield Select([aboMembers.MEMBER_ID],
From=aboMembers,
Where=(aboMembers.GROUP_ID == self._resourceID)).on(self._txn)
+ currentMemberIDs = [currentMemberRow[0] for currentMemberRow in currentMemberRows]
memberIDsToDelete = set(currentMemberIDs) - set(memberIDs)
memberIDsToAdd = set(memberIDs) - set(currentMemberIDs)
@@ -506,9 +648,11 @@
).on(self._txn)
for memberIDToAdd in memberIDsToAdd:
+ print("updateDatabase3:self=%s Insert(aboMembers.GROUP_ID:%s, aboMembers.ADDRESSBOOK_ID:%s, aboMembers.MEMBER_ID:%s" % (
+ self, self._resourceID, self._ownerAddressBookResourceID, memberIDToAdd))
yield Insert(
{aboMembers.GROUP_ID: self._resourceID,
- aboMembers.ADDRESSBOOK_ID: self._addressbook._resourceID,
+ aboMembers.ADDRESSBOOK_ID: self._ownerAddressBookResourceID,
aboMembers.MEMBER_ID: memberIDToAdd, }
).on(self._txn)
@@ -527,9 +671,11 @@
).on(self._txn)
for foreignMemberAddrToAdd in foreignMemberAddrsToAdd:
+ print("updateDatabase4:self=%s Insert(foreignMemberAddrToAdd.GROUP_ID:%s, foreignMemberAddrToAdd.ADDRESSBOOK_ID:%s, foreignMemberAddrToAdd.MEMBER_ID:%s" % (
+ self, self._resourceID, self._ownerAddressBookResourceID, foreignMemberAddrToAdd))
yield Insert(
{aboForeignMembers.GROUP_ID: self._resourceID,
- aboForeignMembers.ADDRESSBOOK_ID: self._addressbook._resourceID,
+ aboForeignMembers.ADDRESSBOOK_ID: self._ownerAddressBookResourceID,
aboForeignMembers.MEMBER_ADDRESS: foreignMemberAddrToAdd, }
).on(self._txn)
@@ -573,5 +719,14 @@
return MimeType.fromString("text/vcard; charset=utf-8")
+ def owned(self):
+ return True
+ def ownerHome(self):
+ return self._addressbook.ownerHome()
+
+ def notifyChanged(self):
+ self._addressbook.notifyChanged()
+
+
AddressBook._objectResourceClass = AddressBookObject
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/test/test_sql.py 2012-11-02 20:50:49 UTC (rev 10001)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/test/test_sql.py 2012-11-03 16:05:43 UTC (rev 10002)
@@ -488,7 +488,7 @@
aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
aboMembers = schema.ABO_MEMBERS
memberRows = yield Select([aboMembers.GROUP_ID, aboMembers.MEMBER_ID], From=aboMembers,).on(txn)
- self.assertEqual(memberRows, [])
+ self.assertEqual(sorted(memberRows), sorted([[adbk._resourceID, personObject._resourceID], [adbk._resourceID, groupObject._resourceID]]))
foreignMemberRows = yield Select([aboForeignMembers.GROUP_ID, aboForeignMembers.MEMBER_ADDRESS], From=aboForeignMembers).on(txn)
self.assertEqual(foreignMemberRows, [[groupObject._resourceID, "urn:uuid:uid3"]])
@@ -509,7 +509,13 @@
subgroupObject = yield adbk.createAddressBookObjectWithName("sg.vcf", subgroup)
memberRows = yield Select([aboMembers.GROUP_ID, aboMembers.MEMBER_ID], From=aboMembers,).on(txn)
- self.assertEqual(memberRows.sort(), [[groupObject._resourceID, subgroupObject._resourceID], [subgroupObject._resourceID, personObject._resourceID]].sort())
+ self.assertEqual(sorted(memberRows), sorted([
+ [groupObject._resourceID, subgroupObject._resourceID],
+ [subgroupObject._resourceID, personObject._resourceID],
+ [adbk._resourceID, personObject._resourceID],
+ [adbk._resourceID, subgroupObject._resourceID],
+ [adbk._resourceID, groupObject._resourceID],
+ ]))
foreignMemberRows = yield Select([aboForeignMembers.GROUP_ID, aboForeignMembers.MEMBER_ADDRESS], From=aboForeignMembers).on(txn)
self.assertEqual(foreignMemberRows, [])
@@ -517,9 +523,11 @@
yield adbk.removeAddressBookObjectWithName("sg.vcf")
memberRows = yield Select([aboMembers.GROUP_ID, aboMembers.MEMBER_ID], From=aboMembers,).on(txn)
- self.assertEqual(memberRows, [])
+ self.assertEqual(sorted(memberRows), sorted([[adbk._resourceID, personObject._resourceID], [adbk._resourceID, groupObject._resourceID]]))
- foreignMemberRows = yield Select([aboForeignMembers.GROUP_ID, aboForeignMembers.MEMBER_ADDRESS], From=aboForeignMembers).on(txn)
+ foreignMemberRows = yield Select([aboForeignMembers.GROUP_ID, aboForeignMembers.MEMBER_ADDRESS], From=aboForeignMembers,
+ #Where=(aboForeignMembers.GROUP_ID == groupObject._resourceID),
+ ).on(txn)
self.assertEqual(foreignMemberRows, [[groupObject._resourceID, "urn:uuid:uid3"]])
yield home.removeAddressBookWithName("addressbook")
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/file.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/file.py 2012-11-02 20:50:49 UTC (rev 10001)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/file.py 2012-11-03 16:05:43 UTC (rev 10002)
@@ -1079,8 +1079,23 @@
self._transaction.postCommit(notifier.notify)
self._transaction.notificationAddedForObject(self)
+ @inlineCallbacks
+ def asInvited(self):
+ """
+ Stub for interface-compliance tests.
+ """
+ yield None
+ returnValue([])
+ @inlineCallbacks
+ def asShared(self):
+ """
+ Stub for interface-compliance tests.
+ """
+ yield None
+ returnValue([])
+
class CommonObjectResource(FileMetaDataMixin, LoggingMixIn, FancyEqMixin):
"""
@ivar _path: The path of the file on disk
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py 2012-11-02 20:50:49 UTC (rev 10001)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py 2012-11-03 16:05:43 UTC (rev 10002)
@@ -2036,163 +2036,27 @@
Maybe notify changed. (Overridden in NotificationCollection.)
"""
-
-
-class CommonHomeChild(LoggingMixIn, FancyEqMixin, _SharedSyncLogic, HomeChildBase):
+class SharingMixIn(object):
"""
- Common ancestor class of AddressBooks and Calendars.
+ Common class for CommonHomeChild and AddressBookObject
"""
-
- compareAttributes = (
- "_name",
- "_home",
- "_resourceID",
- )
-
- _objectResourceClass = None
-
- _bindSchema = None
- _homeSchema = None
- _homeChildSchema = None
- _homeChildMetaDataSchema = None
- _revisionsSchema = None
- _objectSchema = None
-
- _bindTable = None
- _homeChildTable = None
- _homeChildBindTable = None
- _revisionsTable = None
- _revisionsBindTable = None
- _objectTable = None
-
-
- def __init__(self, home, name, resourceID, mode, status, message=None, ownerHome=None):
-
- if home._notifiers:
- childID = "%s/%s" % (home.uid(), name)
- notifiers = [notifier.clone(label="collection", id=childID)
- for notifier in home._notifiers]
- else:
- notifiers = None
-
- self._home = home
- self._name = name
- self._resourceID = resourceID
- self._bindMode = mode
- self._bindStatus = status
- self._bindMessage = message
- self._ownerHome = home if ownerHome is None else ownerHome
- self._created = None
- self._modified = None
- self._objects = {}
- self._objectNames = None
- self._syncTokenRevision = None
- self._notifiers = notifiers
- self._index = None # Derived classes need to set this
-
-
@classproperty
- def _childNamesForHomeID(cls): #@NoSelf
- bind = cls._bindSchema
- return Select([bind.RESOURCE_NAME], From=bind,
- Where=(bind.HOME_RESOURCE_ID ==
- Parameter("homeID")).And
- (bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
-
-
- @classmethod
- def metadataColumns(cls):
+ def _bindInsertQuery(cls, **kw): #@NoSelf
"""
- Return a list of column name for retrieval of metadata. This allows
- different child classes to have their own type specific data, but still make use of the
- common base logic.
+ DAL statement to create a bind entry that connects a collection to its
+ home.
"""
-
- # Common behavior is to have created and modified
-
- return (
- cls._homeChildMetaDataSchema.CREATED,
- cls._homeChildMetaDataSchema.MODIFIED,
- )
-
-
- @classmethod
- def metadataAttributes(cls):
- """
- Return a list of attribute names for retrieval of metadata. This allows
- different child classes to have their own type specific data, but still make use of the
- common base logic.
- """
-
- # Common behavior is to have created and modified
-
- return (
- "_created",
- "_modified",
- )
-
-
- @classmethod
- @inlineCallbacks
- def listObjects(cls, home):
- """
- Retrieve the names of the children that exist in the given home.
-
- @return: an iterable of C{str}s.
- """
- # FIXME: tests don't cover this as directly as they should.
- rows = yield cls._childNamesForHomeID.on(
- home._txn, homeID=home._resourceID)
- names = [row[0] for row in rows]
- returnValue(names)
-
-
- @classproperty
- def _invitedBindForHomeID(cls): #@NoSelf
bind = cls._bindSchema
- return cls._bindFor((bind.HOME_RESOURCE_ID == Parameter("homeID"))
- .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED))
+ return Insert({
+ bind.HOME_RESOURCE_ID: Parameter("homeID"),
+ bind.RESOURCE_ID: Parameter("resourceID"),
+ bind.RESOURCE_NAME: Parameter("name"),
+ bind.BIND_MODE: Parameter("mode"),
+ bind.BIND_STATUS: Parameter("bindStatus"),
+ bind.MESSAGE: Parameter("message"),
+ })
-
@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())
- return Select(columns,
- From=child.join(
- bind, child.RESOURCE_ID == bind.RESOURCE_ID,
- 'left outer').join(
- childMetaData, childMetaData.RESOURCE_ID == bind.RESOURCE_ID,
- 'left outer'),
- Where=(bind.HOME_RESOURCE_ID == Parameter("homeID")
- ).And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
-
-
- @classmethod
def _updateBindColumnsQuery(cls, columnMap): #@NoSelf
bind = cls._bindSchema
return Update(columnMap,
@@ -2384,61 +2248,7 @@
returnValue(resourceName)
- def shareMode(self):
- """
- @see: L{ICalendar.shareMode}
- """
- return self._bindMode
-
- def owned(self):
- """
- @see: L{ICalendar.owned}
- """
- return self._bindMode == _BIND_MODE_OWN
-
-
- def shareStatus(self):
- """
- @see: L{ICalendar.shareStatus}
- """
- return self._bindStatus
-
-
- def shareMessage(self):
- """
- @see: L{ICalendar.shareMessage}
- """
- return self._bindMessage
-
-
- def shareUID(self):
- """
- @see: L{ICalendar.shareUID}
- """
- return self.name()
-
-
- @inlineCallbacks
- def unshare(self, homeType):
- """
- Unshares a collection, regardless of which "direction" it was shared.
-
- @param homeType: a valid store type (ECALENDARTYPE or EADDRESSBOOKTYPE)
- """
- if self.owned():
- # This collection may be shared to others
- for sharedToHome in [x.viewerHome() for x in (yield self.asShared())]:
- (yield self.unshareWith(sharedToHome))
- else:
- # This collection is shared to me
- sharerHomeID = (yield self.sharerHomeID())
- sharerHome = (yield self._txn.homeWithResourceID(homeType,
- sharerHomeID))
- sharerCollection = (yield sharerHome.childWithID(self._resourceID))
- (yield sharerCollection.unshareWith(self._home))
-
-
@classmethod
def _bindFor(cls, condition): #@NoSelf
bind = cls._bindSchema
@@ -2483,7 +2293,7 @@
self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
)
- cls = self.__class__ # for ease of grepping...
+ cls = self._home._childClass # for ease of grepping...
result = []
for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in acceptedRows: #@UnusedVariable
assert bindStatus == _BIND_STATUS_ACCEPTED
@@ -2526,7 +2336,7 @@
rows = yield self._invitedBindForResourceID.on(
self._txn, resourceID=self._resourceID, homeID=self._home._resourceID,
)
- cls = self.__class__ # for ease of grepping...
+ cls = self._home._childClass # for ease of grepping...
result = []
for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in rows: #@UnusedVariable
@@ -2540,11 +2350,224 @@
)
yield new.initFromStore()
result.append(new)
+
returnValue(result)
+
+
+
+class CommonHomeChild(LoggingMixIn, FancyEqMixin, _SharedSyncLogic, HomeChildBase, SharingMixIn):
+ """
+ Common ancestor class of AddressBooks and Calendars.
+ """
+
+ compareAttributes = (
+ "_name",
+ "_home",
+ "_resourceID",
+ )
+
+ _objectResourceClass = None
+
+ _bindSchema = None
+ _homeSchema = None
+ _homeChildSchema = None
+ _homeChildMetaDataSchema = None
+ _revisionsSchema = None
+ _objectSchema = None
+
+ _bindTable = None
+ _homeChildTable = None
+ _homeChildBindTable = None
+ _revisionsTable = None
+ _revisionsBindTable = None
+ _objectTable = None
+
+
+ def __init__(self, home, name, resourceID, mode, status, message=None, ownerHome=None):
+
+ if home._notifiers:
+ childID = "%s/%s" % (home.uid(), name)
+ notifiers = [notifier.clone(label="collection", id=childID)
+ for notifier in home._notifiers]
+ else:
+ notifiers = None
+
+ self._home = home
+ self._name = name
+ self._resourceID = resourceID
+ self._bindMode = mode
+ self._bindStatus = status
+ self._bindMessage = message
+ self._ownerHome = home if ownerHome is None else ownerHome
+ self._created = None
+ self._modified = None
+ self._objects = {}
+ self._objectNames = None
+ self._syncTokenRevision = None
+ self._notifiers = notifiers
+ self._index = None # Derived classes need to set this
+
+
+ @classproperty
+ def _childNamesForHomeID(cls): #@NoSelf
+ bind = cls._bindSchema
+ return Select([bind.RESOURCE_NAME], From=bind,
+ Where=(bind.HOME_RESOURCE_ID ==
+ Parameter("homeID")).And
+ (bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
+
+
@classmethod
+ def metadataColumns(cls):
+ """
+ Return a list of column name for retrieval of metadata. This allows
+ different child classes to have their own type specific data, but still make use of the
+ common base logic.
+ """
+
+ # Common behavior is to have created and modified
+
+ return (
+ cls._homeChildMetaDataSchema.CREATED,
+ cls._homeChildMetaDataSchema.MODIFIED,
+ )
+
+
+ @classmethod
+ def metadataAttributes(cls):
+ """
+ Return a list of attribute names for retrieval of metadata. This allows
+ different child classes to have their own type specific data, but still make use of the
+ common base logic.
+ """
+
+ # Common behavior is to have created and modified
+
+ return (
+ "_created",
+ "_modified",
+ )
+
+
+ @classmethod
@inlineCallbacks
+ def listObjects(cls, home):
+ """
+ Retrieve the names of the children that exist in the given home.
+
+ @return: an iterable of C{str}s.
+ """
+ # FIXME: tests don't cover this as directly as they should.
+ rows = yield cls._childNamesForHomeID.on(
+ home._txn, homeID=home._resourceID)
+ names = [row[0] for row in rows]
+ returnValue(names)
+
+
+ @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())
+ return Select(columns,
+ From=child.join(
+ bind, child.RESOURCE_ID == bind.RESOURCE_ID,
+ 'left outer').join(
+ childMetaData, childMetaData.RESOURCE_ID == bind.RESOURCE_ID,
+ 'left outer'),
+ Where=(bind.HOME_RESOURCE_ID == Parameter("homeID")
+ ).And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED))
+
+
+ def shareMode(self):
+ """
+ @see: L{ICalendar.shareMode}
+ """
+ return self._bindMode
+
+
+ def owned(self):
+ """
+ @see: L{ICalendar.owned}
+ """
+ return self._bindMode == _BIND_MODE_OWN
+
+
+ def shareStatus(self):
+ """
+ @see: L{ICalendar.shareStatus}
+ """
+ return self._bindStatus
+
+
+ def shareMessage(self):
+ """
+ @see: L{ICalendar.shareMessage}
+ """
+ return self._bindMessage
+
+
+ def shareUID(self):
+ """
+ @see: L{ICalendar.shareUID}
+ """
+ return self.name()
+
+
+ @inlineCallbacks
+ def unshare(self, homeType):
+ """
+ Unshares a collection, regardless of which "direction" it was shared.
+
+ @param homeType: a valid store type (ECALENDARTYPE or EADDRESSBOOKTYPE)
+ """
+ if self.owned():
+ # This collection may be shared to others
+ for sharedToHome in [x.viewerHome() for x in (yield self.asShared())]:
+ (yield self.unshareWith(sharedToHome))
+ else:
+ # This collection is shared to me
+ sharerHomeID = (yield self.sharerHomeID())
+ sharerHome = (yield self._txn.homeWithResourceID(homeType,
+ sharerHomeID))
+ sharerCollection = (yield sharerHome.childWithID(self._resourceID))
+ (yield sharerCollection.unshareWith(self._home))
+
+
+ @classmethod
+ @inlineCallbacks
def loadAllObjects(cls, home):
"""
Load all L{CommonHomeChild} instances which are children of a given
@@ -2587,8 +2610,7 @@
ownerHome = home
else:
#TODO: get all ownerHomeIDs at once
- ownerHomeID = (yield cls._ownerHomeWithResourceID.on(
- home._txn, resourceID=resourceID))[0][0]
+ ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
child = cls(
@@ -2622,6 +2644,23 @@
@classmethod
@inlineCallbacks
+ def ownerHomeID(cls, txn, resourceID):
+
+ ownerHomeRows = yield cls._ownerHomeWithResourceID.on(txn, resourceID=resourceID)
+
+ if not ownerHomeRows:
+ # no owner, so shared item must be group
+ abo = schema.ADDRESSBOOK_OBJECT
+ groupAddressBookRows = yield Select([abo.ADDRESSBOOK_RESOURCE_ID],
+ From=abo,
+ Where=(abo.RESOURCE_ID == Parameter("resourceID"))).on(txn, resourceID=resourceID)
+ groupAddressBookID = groupAddressBookRows[0][0]
+ ownerHomeRows = yield cls._ownerHomeWithResourceID.on(txn, resourceID=groupAddressBookID)
+
+ returnValue(ownerHomeRows[0][0])
+
+ @classmethod
+ @inlineCallbacks
def invitedObjectWithName(cls, home, name):
"""
Retrieve the child with the given C{name} contained in the given
@@ -2643,12 +2682,10 @@
bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
- #TODO: combine with _invitedBindForNameAndHomeID and sort results
- ownerHomeID = (yield cls._ownerHomeWithResourceID.on(
- home._txn, resourceID=resourceID))[0][0]
+ ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
- child = cls(
+ child = ownerHome._childClass(
home=home,
name=resourceName, resourceID=resourceID,
mode=bindMode, status=bindStatus,
@@ -2700,8 +2737,7 @@
if bindMode == _BIND_MODE_OWN:
ownerHomeID = homeID
else:
- ownerHomeID = (yield cls._ownerHomeWithResourceID.on(
- home._txn, resourceID=resourceID))[0][0]
+ ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
rows[0].append(ownerHomeID)
if rows and queryCacher:
@@ -2762,8 +2798,7 @@
if bindMode == _BIND_MODE_OWN:
ownerHome = home
else:
- ownerHomeID = (yield cls._ownerHomeWithResourceID.on(
- home._txn, resourceID=resourceID))[0][0]
+ ownerHomeID = yield cls.ownerHomeID(home._txn, resourceID)
ownerHome = yield home._txn.homeWithResourceID(home._homeType, ownerHomeID)
child = cls(
home=home,
@@ -2775,22 +2810,6 @@
returnValue(child)
- @classproperty
- def _bindInsertQuery(cls, **kw): #@NoSelf
- """
- DAL statement to create a bind entry that connects a collection to its
- home.
- """
- bind = cls._bindSchema
- return Insert({
- bind.HOME_RESOURCE_ID: Parameter("homeID"),
- bind.RESOURCE_ID: Parameter("resourceID"),
- bind.RESOURCE_NAME: Parameter("name"),
- bind.BIND_MODE: Parameter("mode"),
- bind.BIND_STATUS: Parameter("bindStatus"),
- bind.MESSAGE: Parameter("message"),
- })
-
@classmethod
@inlineCallbacks
def create(cls, home, name):
@@ -3016,9 +3035,8 @@
# we already know who the owner is.
returnValue(self._home._resourceID)
else:
- rid = (yield self._ownerHomeWithResourceID.on(
- self._txn, resourceID=self._resourceID))[0][0]
- returnValue(rid)
+ ownerHomeID = yield self.ownerHomeID(self._txn, self._resourceID)
+ returnValue(ownerHomeID)
@inlineCallbacks
@@ -3047,6 +3065,7 @@
returnValue(results)
+ # TODO: move to Calendar
@classproperty
def _objectResourceNamesQuery(cls): #@NoSelf
"""
@@ -3057,6 +3076,7 @@
Where=obj.PARENT_RESOURCE_ID == Parameter('resourceID'))
+ # TODO: Make abstract here, and and move to Calendar
@inlineCallbacks
def listObjectResources(self):
if self._objectNames is None:
@@ -3066,6 +3086,7 @@
returnValue(self._objectNames)
+ # TODO: move to Calendar
@classproperty
def _objectCountQuery(cls): #@NoSelf
"""
@@ -3076,6 +3097,7 @@
Where=obj.PARENT_RESOURCE_ID == Parameter('resourceID'))
+ # TODO: Make abstract here, and and move to Calendar
@inlineCallbacks
def countObjectResources(self):
if self._objectNames is None:
@@ -3476,13 +3498,21 @@
self._locked = False
+ #TODO: move to CalendarObject
@classproperty
- def _allColumnsWithParent(cls): #@NoSelf
+ def _allColumnsWithParentQuery(cls): #@NoSelf
obj = cls._objectSchema
return Select(cls._allColumns, From=obj,
Where=obj.PARENT_RESOURCE_ID == Parameter("parentID"))
+ # TODO: Make abstract here, and and move to CalendarObject
+ @classmethod
+ @inlineCallbacks
+ def _allColumnsWithParent(cls, parent):
+ returnValue((yield cls._allColumnsWithParentQuery.on(
+ parent._txn, parentID=parent._resourceID)))
+
@classmethod
@inlineCallbacks
def loadAllObjects(cls, parent):
@@ -3496,8 +3526,7 @@
results = []
# Load from the main table first
- dataRows = yield cls._allColumnsWithParent.on(
- parent._txn, parentID=parent._resourceID)
+ dataRows = yield cls._allColumnsWithParent(parent)
if dataRows:
# Get property stores for all these child resources (if any found)
@@ -3525,14 +3554,6 @@
@classmethod
- def _allColumnsWithParentAndNames(cls, names): #@NoSelf
- obj = cls._objectSchema
- return Select(cls._allColumns, From=obj,
- Where=(obj.PARENT_RESOURCE_ID == Parameter("parentID")).And(
- obj.RESOURCE_NAME.In(Parameter("names", len(names)))))
-
-
- @classmethod
@inlineCallbacks
def loadAllObjectsWithNames(cls, parent, names):
"""
@@ -3548,8 +3569,24 @@
returnValue(results)
+ #TODO: move to CalendarObject
@classmethod
+ def _allColumnsWithParentAndNamesQuery(cls, names): #@NoSelf
+ obj = cls._objectSchema
+ return Select(cls._allColumns, From=obj,
+ Where=(obj.PARENT_RESOURCE_ID == Parameter("parentID")).And(
+ obj.RESOURCE_NAME.In(Parameter("names", len(names)))))
+
+
+ # TODO: Make abstract here, and and move to CalendarObject
+ @classmethod
@inlineCallbacks
+ def _allColumnsWithParentAndNames(cls, parent, names):
+ returnValue((yield cls._allColumnsWithParentAndNamesQuery(names).on(
+ parent._txn, parentID=parent._resourceID, names=names)))
+
+ @classmethod
+ @inlineCallbacks
def _loadAllObjectsWithNames(cls, parent, names):
"""
Load all child objects with the specified names. This must create the
@@ -3566,8 +3603,7 @@
results = []
# Load from the main table first
- dataRows = yield cls._allColumnsWithParentAndNames(names).on(
- parent._txn, parentID=parent._resourceID, names=names)
+ dataRows = yield cls._allColumnsWithParentAndNames(parent, names)
if dataRows:
# Get property stores for all these child resources
@@ -3754,6 +3790,9 @@
def _txn(self):
return self._parentCollection._txn
+ @property
+ def _home(self):
+ return self._parentCollection._home
def transaction(self):
return self._parentCollection._txn
@@ -4256,7 +4295,6 @@
Where=(obj.NOTIFICATION_HOME_RESOURCE_ID == Parameter(
"homeID")))
-
@classmethod
@inlineCallbacks
def loadAllObjects(cls, parent):
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 2012-11-02 20:50:49 UTC (rev 10001)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql 2012-11-03 16:05:43 UTC (rev 10002)
@@ -341,7 +341,7 @@
create table ADDRESSBOOK_OBJECT (
RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
- ADDRESSBOOK_RESOURCE_ID integer references ADDRESSBOOK_OBJECT on delete cascade, -- ### could add non-null, but ab woul reference itself
+ ADDRESSBOOK_RESOURCE_ID integer references ADDRESSBOOK_OBJECT on delete cascade, -- ### could add non-null, but ab would reference itself
RESOURCE_NAME varchar(255) not null,
VCARD_TEXT text not null,
VCARD_UID varchar(255) not null,
@@ -373,7 +373,7 @@
---------------------------------
create table ABO_MEMBERS (
- GROUP_ID integer not null references ADDRESSBOOK_OBJECT, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ GROUP_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
ADDRESSBOOK_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- only used on insert and whole address book delete
MEMBER_ID integer not null references ADDRESSBOOK_OBJECT, -- member AddressBook Object's RESOURCE_ID
primary key(GROUP_ID, MEMBER_ID) -- implicit index
@@ -384,7 +384,7 @@
------------------------------------------
create table ABO_FOREIGN_MEMBERS (
- GROUP_ID integer not null references ADDRESSBOOK_OBJECT, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ GROUP_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
ADDRESSBOOK_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- only used on insert and whole address book delete
MEMBER_ADDRESS varchar(255) not null, -- member AddressBook Object's 'calendar' address
primary key(GROUP_ID, MEMBER_ADDRESS) -- implicit index
Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/upgrade/test/test_migrate.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/upgrade/test/test_migrate.py 2012-11-02 20:50:49 UTC (rev 10001)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/upgrade/test/test_migrate.py 2012-11-03 16:05:43 UTC (rev 10002)
@@ -404,8 +404,9 @@
"""
Create an upgrade service.
"""
+ #FIXME: not parallel
return UpgradeToDatabaseService(
self.fileStore, self.sqlStore, self.stubService,
- parallel=2, spawner=StubSpawner()
+ parallel=0, spawner=StubSpawner()
)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20121103/76f3b41e/attachment-0001.html>
More information about the calendarserver-changes
mailing list