[CalendarServer-changes] [10945] CalendarServer/branches/users/gaya/sharedgroups/txdav

source_changes at macosforge.org source_changes at macosforge.org
Mon Mar 18 15:33:22 PDT 2013


Revision: 10945
          http://trac.calendarserver.org//changeset/10945
Author:   gaya at apple.com
Date:     2013-03-18 15:33:22 -0700 (Mon, 18 Mar 2013)
Log Message:
-----------
fix revisions, properties bugs with shared groups in AddressBook.loadAllObjects()

Modified Paths:
--------------
    CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/tests/CardDAV/sharing-addressbooks.xml
    CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
    CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
    CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py

Modified: CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/tests/CardDAV/sharing-addressbooks.xml
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/tests/CardDAV/sharing-addressbooks.xml	2013-03-18 19:57:28 UTC (rev 10944)
+++ CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/tests/CardDAV/sharing-addressbooks.xml	2013-03-18 22:33:22 UTC (rev 10945)
@@ -837,7 +837,7 @@
 
 	<test-suite name='Share group' ignore='no'>
 		<test name='1' ignore='no'>
-			<description>Sharee create 2 persons and a group</description>
+			<description>Sharee creates 2 persons and a group</description>
 			<request print-response='no'>
 				<method>PUT</method>
 				<ruri>$addressbookpath1:/1.vcf</ruri>
@@ -984,6 +984,44 @@
 				</verify>
 			</request>
 		</test>
+		<test name='6aa'>
+			<description>Shared address book exists Depth:1</description>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+				<method>PROPFIND</method>
+				<ruri>$addressbookhome2:/</ruri>
+				<header>
+					<name>Depth</name>
+					<value>1</value>
+				</header>
+				<data>
+					<content-type>text/xml; charset=utf-8</content-type>
+					<filepath>Resource/CardDAV/sharing/addressbooks/read-write/4.xml</filepath>
+				</data>
+				<verify>
+					<callback>xmlElementMatch</callback>
+					<arg>
+						<name>parent</name>
+						<value>$multistatus-response-prefix:[^{DAV:}href=$addressbookhome2:/$userid1:/]</value>
+					</arg>
+					<arg>
+						<name>exists</name>
+						<value>$verify-response-prefix:/{DAV:}owner/{DAV:}href[=$principaluri1:]</value>
+						<value>$verify-response-prefix:/{DAV:}resourcetype/{DAV:}collection</value>
+						<value>$verify-response-prefix:/{DAV:}resourcetype/{urn:ietf:params:xml:ns:carddav}addressbook</value>
+						<value>$verify-response-prefix:/{DAV:}resourcetype/{http://calendarserver.org/ns/}shared</value>
+						<value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}read</value>
+						<value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}write</value>
+						<value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}bind</value>
+						<value>$verify-response-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}unbind</value>
+					</arg>
+					<arg>
+						<name>notexists</name>
+						<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}admin</value>
+						<value>$verify-property-prefix:/{DAV:}current-user-privilege-set/{DAV:}privilege/{DAV:}all</value>
+					</arg>
+				</verify>
+			</request>
+		</test>
 		<test name='6a' ignore='no'>
 			<description>Sharee sees shared group vcard</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>

Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py	2013-03-18 19:57:28 UTC (rev 10944)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py	2013-03-18 22:33:22 UTC (rev 10945)
@@ -1153,7 +1153,7 @@
         shareeStoreObject = yield self._newStoreHome.objectWithShareUID(shareUID)
         if shareeStoreObject:
             share = yield self._shareForStoreObject(shareeStoreObject, request)
-            if share and share.uid() == shareUID:
+            if share:
                 returnValue(share)
 
         # find direct shares

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2013-03-18 19:57:28 UTC (rev 10944)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2013-03-18 22:33:22 UTC (rev 10945)
@@ -61,6 +61,7 @@
 from zope.interface.declarations import implements
 
 
+
 class AddressBookHome(CommonHome):
 
     implements(IAddressBookHome)
@@ -336,6 +337,7 @@
 AddressBookHome._register(EADDRESSBOOKTYPE)
 
 
+
 class AddressBook(CommonHomeChild, SharingMixIn):
     """
     SQL-based implementation of L{IAddressBook}.
@@ -588,9 +590,33 @@
         else:
             returnValue((yield super(AddressBook, self).bumpModified()))
 
+    '''
+    @classproperty
+    def _revisionsForHomeID(cls): #@NoSelf
+        bind = cls._bindSchema
+        rev = cls._revisionsSchema
+        return Select(
+            [rev.RESOURCE_ID, Max(rev.REVISION)],
+            From=rev.join(bind, rev.RESOURCE_ID == bind.RESOURCE_ID, 'left'),
+            Where=(bind.HOME_RESOURCE_ID == Parameter("homeID")).
+                And((rev.RESOURCE_NAME != None).Or(rev.DELETED == False)),
+            GroupBy=rev.RESOURCE_ID
+        )
+    '''
 
 
     @classmethod
+    def _revisionsForResourceIDs(cls, resourceIDs):
+        rev = cls._revisionsSchema
+        return Select(
+            [rev.RESOURCE_ID, Max(rev.REVISION)],
+            From=rev,
+            Where=rev.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs))),
+            GroupBy=rev.RESOURCE_ID
+        )
+
+
+    @classmethod
     @inlineCallbacks
     def loadAllObjects(cls, home):
         """
@@ -601,20 +627,18 @@
         optimization for Depth:1 operations on the home.
         """
         results = [home.addressbook(), ]
-        ownerHomeIDToDataRowMap = {}
+        ownerHomeToDataRowMap = {}
 
         # Load from the main table first
         dataRows = yield cls._childrenAndMetadataForHomeID.on(
             home._txn, homeID=home._resourceID
         )
-
         # get ownerHomeIDs
         for dataRow in dataRows:
             bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = dataRow[:6] #@UnusedVariable
             assert bindStatus != _BIND_MODE_OWN
             ownerHome = yield home.ownerHomeWithChildID(resourceID)
-            ownerHomeID = ownerHome._resourceID
-            ownerHomeIDToDataRowMap[ownerHomeID] = dataRow
+            ownerHomeToDataRowMap[ownerHome] = dataRow
 
         # now get group rows:
         groupBindRows = yield AddressBookObject._childrenAndMetadataForHomeID.on(
@@ -623,37 +647,36 @@
         for groupBindRow in groupBindRows:
             bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = groupBindRow[:6] #@UnusedVariable        
             ownerAddressBookID = yield AddressBookObject.ownerAddressBookFromGroupID(home._txn, resourceID)
-            ownerHome = yield home.ownerHomeWithChildID(home._txn, ownerAddressBookID)
-            ownerHomeID = ownerHome._resourceID
-            if ownerHomeID not in ownerHomeIDToDataRowMap:
+            ownerHome = yield home.ownerHomeWithChildID(ownerAddressBookID)
+            if ownerHome not in ownerHomeToDataRowMap:
                 groupBindRow[0] = _BIND_MODE_WRITE
                 groupBindRow[3] = None # bindName
                 groupBindRow[4] = None # bindStatus
                 groupBindRow[5] = None # bindMessage
-                ownerHomeIDToDataRowMap[ownerHomeID] = groupBindRow
+                ownerHomeToDataRowMap[ownerHome] = groupBindRow
 
-        if ownerHomeIDToDataRowMap:
-
+        if ownerHomeToDataRowMap:
             # Get property stores for all these child resources (if any found)
+            #FIXME: this does not load address books that are not fully owned.
             propertyStores = (yield PropertyStore.forMultipleResources(
                 home.uid(), home._txn,
                 cls._bindSchema.RESOURCE_ID, cls._bindSchema.HOME_RESOURCE_ID,
                 home._resourceID
             ))
-            revisions = yield cls._revisionsForHomeID.on(home._txn, homeID=home._resourceID)
+
+            childResourceIDs = [ownerHome._resourceID for ownerHome in ownerHomeToDataRowMap]
+            revisions = yield cls._revisionsForResourceIDs(childResourceIDs).on(home._txn, resourceIDs=childResourceIDs)
             revisions = dict(revisions)
 
             # Create the actual objects merging in properties
-            for dataRow in ownerHomeIDToDataRowMap.values():
+            for ownerHome, dataRow in ownerHomeToDataRowMap.iteritems():
                 bindMode, homeID, resourceID, bindName, bindStatus, bindMessage = dataRow[:6] #@UnusedVariable
                 metadata = dataRow[6:]
 
-                ownerHome = yield home.ownerHomeWithChildID(resourceID)
-                ownerAddressBook = yield ownerHome.addressbook()
-
                 child = cls(
                     home=home,
-                    name=ownerAddressBook.shareeAddressBookName(), resourceID=ownerAddressBook._resourceID,
+                    name=ownerHome.shareeAddressBookName(),
+                    resourceID=ownerHome._resourceID,
                     mode=bindMode, status=bindStatus,
                     message=bindMessage, ownerHome=ownerHome,
                     bindName=bindName
@@ -661,13 +684,13 @@
 
                 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
-                propstore._setDefaultUserUID(ownerHome.uid())
-                yield child._loadPropertyStore(propstore)
+                child._syncTokenRevision = revisions[child._resourceID]
+                propstore = propertyStores.get(child._resourceID, None)
+                if propstore:
+                    # 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
+                    propstore._setDefaultUserUID(ownerHome.uid())
+                yield child._loadPropertyStore(None)
                 results.append(child)
 
         returnValue(results)
@@ -1132,19 +1155,16 @@
             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 not self.owned():
-            returnValue([])
-
-        # get all accepted shared binds
-        bindRows = yield self._sharedBindForResourceID.on(
-            self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
-        )
-
         result = []
-        for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in bindRows: #@UnusedVariable
-            home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
-            new = yield home.childWithName(self.shareeAddressBookName())
-            result.append(new)
+        if self.owned():
+            # get all accepted shared binds
+            bindRows = yield self._sharedBindForResourceID.on(
+                self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+            )
+            for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in bindRows: #@UnusedVariable
+                home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+                new = yield home.childWithName(self.shareeAddressBookName())
+                result.append(new)
 
         returnValue(result)
 
@@ -1161,18 +1181,16 @@
             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 not self.owned():
-            returnValue([])
-
-        # get all accepted shared binds
         result = []
-        bindRows = yield self._unacceptedBindForResourceID.on(
-            self._txn, resourceID=self._resourceID
-        )
-        for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in bindRows: #@UnusedVariable
-            home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
-            new = yield self.objectWithName(home, self.shareeAddressBookName(), accepted=False)
-            result.append(new)
+        if self.owned():
+            # get all accepted shared binds
+            bindRows = yield self._unacceptedBindForResourceID.on(
+                self._txn, resourceID=self._resourceID
+            )
+            for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in bindRows: #@UnusedVariable
+                home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+                new = yield self.objectWithName(home, self.shareeAddressBookName(), accepted=False)
+                result.append(new)
 
         returnValue(result)
 
@@ -1224,6 +1242,7 @@
         returnValue(deletedBindName)
 
 
+
 class AddressBookObject(CommonObjectResource, SharingMixIn):
 
     implements(IAddressBookObject)
@@ -1973,19 +1992,17 @@
             in different L{CommonHome}s
         @rtype: a L{Deferred} which fires with a L{list} of L{AddressBookObject}s.
         """
-        if not self.owned():
-            returnValue([])
-
-        # get all accepted shared binds
-        groupBindRows = yield self._sharedBindForResourceID.on(
-            self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
-        )
         result = []
-        for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
-            home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
-            addressbook = yield home.childWithName(self._home.shareeAddressBookName())
-            new = yield addressbook.objectResourceWithID(resourceID)
-            result.append(new)
+        if self.owned():
+            # get all accepted shared binds
+            groupBindRows = yield self._sharedBindForResourceID.on(
+                self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+            )
+            for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
+                home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+                addressbook = yield home.childWithName(self._home.shareeAddressBookName())
+                new = yield addressbook.objectResourceWithID(resourceID)
+                result.append(new)
 
         returnValue(result)
 
@@ -2003,22 +2020,19 @@
             in different L{CommonHome}s
         @rtype: a L{Deferred} which fires with a L{list} of L{AddressBookObject}s.
         """
-        if not self.owned():
-            returnValue([])
-
-        # get all accepted shared binds
-        groupBindRows = yield self._unacceptedBindForResourceID.on(
-            self._txn, resourceID=self._resourceID
-        )
         result = []
-        for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
-            home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
-            addressbook = yield home.childWithName(self._home.shareeAddressBookName())
-            if not addressbook:
-                #addressbook = yield self._home._childClass.objectWithName(home, self._home.shareeAddressBookName(), accepted=False)
-                addressbook = yield AddressBook.objectWithName(home, self._home.shareeAddressBookName(), accepted=False)
-            new = yield AddressBookObject.objectWithID(addressbook, resourceID) # avoids object cache
-            result.append(new)
+        if self.owned():
+            # get all accepted shared binds
+            groupBindRows = yield self._unacceptedBindForResourceID.on(
+                self._txn, resourceID=self._resourceID
+            )
+            for bindMode, homeID, resourceID, bindName, bindStatus, bindMessage in groupBindRows: #@UnusedVariable
+                home = yield self._txn.homeWithResourceID(self._home._homeType, homeID)
+                addressbook = yield home.childWithName(self._home.shareeAddressBookName())
+                if not addressbook:
+                    addressbook = yield AddressBook.objectWithName(home, self._home.shareeAddressBookName(), accepted=False)
+                new = yield AddressBookObject.objectWithID(addressbook, resourceID) # avoids object cache
+                result.append(new)
 
         returnValue(result)
 

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py	2013-03-18 19:57:28 UTC (rev 10944)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py	2013-03-18 22:33:22 UTC (rev 10945)
@@ -111,6 +111,8 @@
     EADDRESSBOOKTYPE : "CardDAV",
 }
 
+
+
 class CommonDataStore(Service, object):
     """
     Shared logic for SQL-based data stores, between calendar and addressbook
@@ -2451,6 +2453,8 @@
         Maybe notify changed.  (Overridden in NotificationCollection.)
         """
 
+
+
 class SharingMixIn(object):
     """
     Common class for CommonHomeChild and AddressBookObject
@@ -2883,6 +2887,7 @@
         )
 
 
+
 class CommonHomeChild(LoggingMixIn, FancyEqMixin, Memoizable, _SharedSyncLogic, HomeChildBase, SharingMixIn):
     """
     Common ancestor class of AddressBooks and Calendars.
@@ -5121,6 +5126,7 @@
             yield Update({column: after}, Where=where).on(txn)
 
 
+
 class _AndNothing(object):
     """
     Simple placeholder for iteratively generating a 'Where' clause; the 'And'
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130318/3f4cd6bd/attachment-0001.html>


More information about the calendarserver-changes mailing list