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

source_changes at macosforge.org source_changes at macosforge.org
Tue Feb 12 19:10:21 PST 2013


Revision: 10710
          http://trac.calendarserver.org//changeset/10710
Author:   gaya at apple.com
Date:     2013-02-12 19:10:20 -0800 (Tue, 12 Feb 2013)
Log Message:
-----------
Fix multiple problems in group sharing

Modified Paths:
--------------
    CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/server/serverinfo.xml
    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/server/serverinfo.xml
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/server/serverinfo.xml	2013-02-13 01:56:19 UTC (rev 10709)
+++ CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/server/serverinfo.xml	2013-02-13 03:10:20 UTC (rev 10710)
@@ -755,7 +755,7 @@
 		<!-- group name-->
 		<substitution>
 			<key>$i18nname:</key>
-			<value>まだ</value>
+			<value>まだ</value>
 		</substitution>
 		<!-- password -->
 		<substitution>

Modified: CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/tests/CardDAV/sharing-addressbooks.xml
===================================================================
--- CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/tests/CardDAV/sharing-addressbooks.xml	2013-02-13 01:56:19 UTC (rev 10709)
+++ CalDAVTester/branches/users/gaya/sharedgroupstester/scripts/tests/CardDAV/sharing-addressbooks.xml	2013-02-13 03:10:20 UTC (rev 10710)
@@ -542,11 +542,10 @@
 				</verify>
 			</request>
 		</test>
-	</test-suite>
-	<test-suite name='Share main address book' ignore='no'>
-		<test name='1' ignore='no'>
+	</test-suite><test-suite name="Share main address book" ignore="no">
+		<test name="1" ignore="no">
 			<description>POST invitation</description>
-			<request print-response='no'>
+			<request print-response="no">
 				<method>POST</method>
 				<ruri>$addressbookpath1:/</ruri>
 				<data>
@@ -558,13 +557,13 @@
 				</verify>
 			</request>
 		</test>
-		<test name='2' ignore='no'>
+		<test name="2" ignore="no">
 			<description>Check Sharee notification collection</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>WAITCOUNT 1</method>
 				<ruri>$notificationpath2:/</ruri>
 			</request>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>GETNEW</method>
 				<ruri>$notificationpath2:/</ruri>
 				<verify>
@@ -585,12 +584,12 @@
 				</grabelement>
 			</request>
 		</test>
-		<test name='3' ignore='no'>
+		<test name="3" ignore="no">
 			<description>Sharee replies ACCEPTED</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>POST</method>
 				<ruri>$addressbookhome2:/</ruri>
-				<data substitutions='yes'>
+				<data substitutions="yes">
 					<content-type>application/xml; charset=utf-8</content-type>
 					<filepath>Resource/CardDAV/sharing/addressbooks/main/3.xml</filepath>
 				</data>
@@ -603,9 +602,9 @@
 				</grabelement>
 			</request>
 		</test>
-		<test name='4' ignore='no'>
+		<test name="4" ignore="no">
 			<description>Shared address book exists</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>PROPFIND</method>
 				<ruri>$sharedaddressbook:/</ruri>
 				<header>
@@ -635,9 +634,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='5' ignore='no'>
+		<test name="5" ignore="no">
 			<description>Sharee creates vcard</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>PUT</method>
 				<ruri>$sharedaddressbook:/1.vcf</ruri>
 				<data>
@@ -649,9 +648,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='6' ignore='no'>
+		<test name="6" ignore="no">
 			<description>Sharer sees vcard</description>
-			<request print-response='no'>
+			<request print-response="no">
 				<method>GET</method>
 				<ruri>$addressbookpath1:/1.vcf</ruri>
 				<verify>
@@ -663,9 +662,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='7' ignore='no'>
+		<test name="7" ignore="no">
 			<description>Sharer changes vcard</description>
-			<request print-response='no'>
+			<request print-response="no">
 				<method>PUT</method>
 				<ruri>$addressbookpath1:/1.vcf</ruri>
 				<data>
@@ -677,9 +676,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='8' ignore='no'>
+		<test name="8" ignore="no">
 			<description>Sharee sees changed vcard</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>GET</method>
 				<ruri>$sharedaddressbook:/1.vcf</ruri>
 				<verify>
@@ -691,9 +690,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='9' ignore='no'>
+		<test name="9" ignore="no">
 			<description>Sharer creates vcard</description>
-			<request print-response='no'>
+			<request print-response="no">
 				<method>PUT</method>
 				<ruri>$addressbookpath1:/2.vcf</ruri>
 				<data>
@@ -705,9 +704,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='10' ignore='no'>
+		<test name="10" ignore="no">
 			<description>Sharee sees new vcard</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>GET</method>
 				<ruri>$sharedaddressbook:/2.vcf</ruri>
 				<verify>
@@ -719,9 +718,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='11' ignore='no'>
+		<test name="11" ignore="no">
 			<description>Sharee changes vcard</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>PUT</method>
 				<ruri>$sharedaddressbook:/2.vcf</ruri>
 				<data>
@@ -733,9 +732,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='12' ignore='no'>
+		<test name="12" ignore="no">
 			<description>Sharer sees changed event</description>
-			<request print-response='no'>
+			<request print-response="no">
 				<method>GET</method>
 				<ruri>$addressbookpath1:/2.vcf</ruri>
 				<verify>
@@ -747,9 +746,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='12.1' ignore='no'>
+		<test name="12.1" ignore="no">
 			<description>Sharee sees group with shared address book members</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>GET</method>
 				<ruri>$sharedaddressbook:/addressbook.vcf</ruri>
 				<verify>
@@ -765,9 +764,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='12.2' ignore='no'>
+		<test name="12.2" ignore="no">
 			<description>Sharee cannot delete special group</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>DELETE</method>
 				<ruri>$sharedaddressbook:/addressbook.vcf</ruri>
 				<verify>
@@ -779,9 +778,9 @@
 				</verify>
 			</request>
 		</test>
-		<test name='13' ignore='no'>
+		<test name="13" ignore="no">
 			<description>Unshare main address book</description>
-			<request print-response='no'>
+			<request print-response="no">
 				<method>POST</method>
 				<ruri>$addressbookpath1:/</ruri>
 				<data>
@@ -797,13 +796,13 @@
 				</verify>
 			</request>
 		</test>
-		<test name='14' ignore='no'>
+		<test name="14" ignore="no">
 			<description>Check Sharee notification collection and delete invite-deleted</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>WAITCOUNT 1</method>
 				<ruri>$notificationpath2:/</ruri>
 			</request>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>GETNEW</method>
 				<ruri>$notificationpath2:/</ruri>
 				<verify>
@@ -819,14 +818,14 @@
 					</arg>
 				</verify>
 			</request>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>DELETE</method>
 				<ruri>$</ruri>
 			</request>
 		</test>
-		<test name='15' ignore='no'>
+		<test name="15" ignore="no">
 			<description>No more shared addressbook</description>
-			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response="no">
 				<method>PROPFIND</method>
 				<ruri>$sharedaddressbook:/</ruri>
 				<header>
@@ -854,8 +853,9 @@
 			</request>
 		</test>
 	</test-suite>
+	
 
-	<test-suite name='Share group' ignore='yes'>
+	<test-suite name='Share group' ignore='no'>
 		<test name='1' ignore='no'>
 			<description>Sharee create 2 persons and a group</description>
 			<request print-response='no'>
@@ -927,11 +927,11 @@
 		</test>
 		<test name='4' ignore='no'>
 			<description>Check Sharee notification collection</description>
-			<request user="$userid2:" pswd="$pswd2:" print-request='no' print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>WAITCOUNT 1</method>
 				<ruri>$notificationpath2:/</ruri>
 			</request>
-			<request user="$userid2:" pswd="$pswd2:" print-request='no' print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>GETNEW</method>
 				<ruri>$notificationpath2:/</ruri>
 				<verify>
@@ -954,7 +954,7 @@
 		</test>
 		<test name='5' ignore='no'>
 			<description>Sharee replies ACCEPTED</description>
-			<request user="$userid2:" pswd="$pswd2:" print-request='no' print-response='no'>
+			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>POST</method>
 				<ruri>$addressbookhome2:/</ruri>
 				<data substitutions='yes'>
@@ -966,15 +966,15 @@
 				</verify>
 				<grabelement>
 					<name>{DAV:}href</name>
-					<variable>$sharedaddressbook:</variable>
+					<variable>$sharedgroup:</variable>
 				</grabelement>
 			</request>
 		</test>
 		<test name='6' ignore='no'>
-			<description>Sharee sees shared group as address book</description>
+			<description>Sharee sees shared address book</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>PROPFIND</method>
-				<ruri>$sharedaddressbook:/</ruri>
+				<ruri>$addressbookhome2:/$userid1:/</ruri>
 				<header>
 					<name>Depth</name>
 					<value>0</value>
@@ -1006,7 +1006,7 @@
 			<description>Sharee sees shared group vcard</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>GET</method>
-				<ruri>$sharedaddressbook:/3.vcf</ruri>
+				<ruri>$sharedgroup:</ruri>
 				<verify>
 					<callback>addressDataMatch</callback>
 					<arg>
@@ -1016,11 +1016,11 @@
 				</verify>
 			</request>
 		</test>
-		<test name='6b' ignore='no'>
+		<test name='6b' ignore='yes'>
 			<description>Sharee cannot delete shared group vcard</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>DELETE</method>
-				<ruri>$sharedaddressbook:/3.vcf</ruri>
+				<ruri>$sharedgroup:</ruri>
 				<verify>
 					<callback>statusCode</callback>
 					<arg>
@@ -1034,7 +1034,7 @@
 			<description>Sharee creates group vcard with unknown member UID</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>PUT</method>
-				<ruri>$sharedaddressbook:/4.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/4.vcf</ruri>
 				<data>
 					<content-type>text/vcard; charset=utf-8</content-type>
 					<filepath>Resource/CardDAV/sharing/addressbooks/group/8.vcf</filepath>
@@ -1052,7 +1052,7 @@
 			<description>Sharee creates group vcard with member UID in ab but not in group</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>PUT</method>
-				<ruri>$sharedaddressbook:/4.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/4.vcf</ruri>
 				<data>
 					<content-type>text/vcard; charset=utf-8</content-type>
 					<filepath>Resource/CardDAV/sharing/addressbooks/group/9.vcf</filepath>
@@ -1070,7 +1070,7 @@
 			<description>Sharee creates vcard</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>PUT</method>
-				<ruri>$sharedaddressbook:/4.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/4.vcf</ruri>
 				<data>
 					<content-type>text/vcard; charset=utf-8</content-type>
 					<filepath>Resource/CardDAV/sharing/addressbooks/group/10.vcf</filepath>
@@ -1123,7 +1123,7 @@
 			<description>Sharee sees changed vcard</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>GET</method>
-				<ruri>$sharedaddressbook:/4.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/4.vcf</ruri>
 				<verify>
 					<callback>addressDataMatch</callback>
 					<arg>
@@ -1151,7 +1151,7 @@
 			<description>Sharee sees new vcards</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>GET</method>
-				<ruri>$sharedaddressbook:/5.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/5.vcf</ruri>
 				<verify>
 					<callback>addressDataMatch</callback>
 					<arg>
@@ -1162,7 +1162,7 @@
 			</request>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>GET</method>
-				<ruri>$sharedaddressbook:/2.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/2.vcf</ruri>
 				<verify>
 					<callback>addressDataMatch</callback>
 					<arg>
@@ -1173,7 +1173,7 @@
 			</request>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>GET</method>
-				<ruri>$sharedaddressbook:/1.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/1.vcf</ruri>
 				<verify>
 					<callback>addressDataMatch</callback>
 					<arg>
@@ -1187,7 +1187,7 @@
 			<description>Sharee removes vCard from subgroup</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>PUT</method>
-				<ruri>$sharedaddressbook:/5.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/5.vcf</ruri>
 				<data>
 					<content-type>text/vcard; charset=utf-8</content-type>
 					<filepath>Resource/CardDAV/sharing/addressbooks/group/14.vcf</filepath>
@@ -1201,7 +1201,7 @@
 			<description>Sharee cannot access removed sub group member</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>GET</method>
-				<ruri>$sharedaddressbook:/1.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/1.vcf</ruri>
 				<verify>
 					<callback>statusCode</callback>
 					<arg>
@@ -1240,7 +1240,7 @@
 			<description>Sharee deletes vCard in subgroup</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>DELETE</method>
-				<ruri>$sharedaddressbook:/2.vcf</ruri>
+				<ruri>$addressbookhome2:/$userid1:/2.vcf</ruri>
 				<verify>
 					<callback>statusCode</callback>
 				</verify>
@@ -1316,7 +1316,7 @@
 			<description>No more shared addressbook</description>
 			<request user="$userid2:" pswd="$pswd2:" print-response='no'>
 				<method>PROPFIND</method>
-				<ruri>$sharedaddressbook:/</ruri>
+				<ruri>$addressbookhome2:/$userid1:/</ruri>
 				<header>
 					<name>Depth</name>
 					<value>0</value>
@@ -1346,6 +1346,7 @@
 	<end>
 		<request user="$useradmin:" pswd="$pswdadmin:">
 			<method>DELETEALL</method>
+			<ruri>$addressbookpath1:/</ruri>
 			<ruri>$notificationpath1:/</ruri>
 			<ruri>$notificationpath2:/</ruri>
 			<ruri>$notificationpath3:/</ruri>

Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py	2013-02-13 01:56:19 UTC (rev 10709)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py	2013-02-13 03:10:20 UTC (rev 10710)
@@ -546,7 +546,7 @@
         if not self.exists():
             returnValue([])
 
-        if not hasattr(self, "_invitations"):
+        if True:#not hasattr(self, "_invitations"):
 
             acceptedHomeChildren = yield self._newStoreObject.asShared()
             # remove direct shares (it might be OK not to remove these, but that would be different from legacy code)
@@ -685,11 +685,15 @@
             pass
         '''
 
+
         # Generate invite XML
         userid = "urn:uuid:" + invitation.shareeUID()
         state = notificationState if notificationState else invitation.state()
         summary = invitation.summary() if displayName is None else displayName
 
+
+        assert state != "DECLINED"
+
         typeAttr = {'shared-type': self.sharedResourceType()}
         xmltype = customxml.InviteNotification(**typeAttr)
         xmldata = customxml.Notification(

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2013-02-13 01:56:19 UTC (rev 10709)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2013-02-13 03:10:20 UTC (rev 10710)
@@ -471,6 +471,7 @@
             if ownerHomeID not in ownerHomeIDToDataRowMap:
                 groupBindRow[0] = _BIND_MODE_WRITE
                 groupBindRow[3] = None # bindName
+                groupBindRow[4] = None # bindStatus
                 groupBindRow[5] = None # bindMessage
                 ownerHomeIDToDataRowMap[ownerHomeID] = groupBindRow
 
@@ -578,6 +579,7 @@
                         groupBindRow = groupBindRows[0]
                         groupBindRow[0] = _BIND_MODE_WRITE
                         groupBindRow[3] = None # bindName
+                        groupBindRow[4] = None # bindStatus
                         groupBindRow[5] = None # bindMessage
                         groupBindRow.append(ownerHome._resourceID)
                         rows = [groupBindRow]
@@ -663,15 +665,20 @@
                 yield child.initFromStore()
                 returnValue(child)
         else:
-
-            groupBindRows = yield AddressBookObject._bindWithHomeIDAndAddressBookID.on(
+            # TODO: do one query
+            groupBindRows = yield AddressBookObject._invitedBindWithHomeIDAndAddressBookID.on(
                     home._txn, homeID=home._resourceID, addressbookID=resourceID
             )
+            if not groupBindRows:
+                groupBindRows = yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.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[4] = None # bindStatus
                 groupBindRow[5] = None # bindMessage
                 rows = [groupBindRow]
 
@@ -735,7 +742,7 @@
 
 
     def fullyShared(self):
-        return bool(self._bindName)
+        return not self.owned() and self._bindStatus == _BIND_STATUS_ACCEPTED
 
 
     @classmethod
@@ -845,6 +852,91 @@
 
 
     @inlineCallbacks
+    def updateShare(self, shareeView, mode=None, status=None, message=None, name=None):
+        """
+        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}
+        """
+        # TODO: raise a nice exception if shareeView is not, in fact, a shared
+        # version of this same L{CommonHomeChild}
+
+        #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):
+
+            # count accepted 
+            if status is not None:
+                previouslyAcceptedBinds = 1 if shareeView.fullyShared() else 0
+                previouslyAcceptedBinds += len((yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
+                        self._txn, homeID=shareeView._home._resourceID, addressbookID=shareeView._resourceID
+                )))
+
+            #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 is not None:
+                shareeView._bindMode = columnMap[bind.BIND_MODE]
+
+            if status is not None:
+                shareeView._bindStatus = columnMap[bind.BIND_STATUS]
+                if shareeView._bindStatus == _BIND_STATUS_ACCEPTED:
+                    if 0 == previouslyAcceptedBinds:
+                        yield shareeView._initSyncToken()
+                elif shareeView._bindStatus == _BIND_STATUS_DECLINED:
+                    if 1 == previouslyAcceptedBinds:
+                        shareeView._deletedSyncToken(sharedRemoval=True)
+                        shareeView._home._children.pop(shareeView._name, None)
+
+
+            if message is not None:
+                shareeView._bindMessage = columnMap[bind.MESSAGE]
+
+            queryCacher = self._txn._queryCacher
+            if queryCacher:
+                cacheKey = queryCacher.keyForObjectWithName(shareeView._home._resourceID, shareeView._name)
+                queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
+            shareeView._name = sharedname[0][0]
+
+            # Must send notification to ensure cache invalidation occurs
+            yield self.notifyChanged()
+
+        returnValue(shareeView._name)
+
+
+    @inlineCallbacks
     def asShared(self):
         """
         Retrieve all the versions of this L{CommonHomeChild} as it is shared to
@@ -873,6 +965,7 @@
             if homeID not in homeIDToBindRowMap:
                 groupBindRow[0] = _BIND_MODE_WRITE
                 groupBindRow[3] = None # bindName
+                groupBindRow[4] = None # bindStatus
                 groupBindRow[5] = None # bindMessage
                 homeIDToBindRowMap[homeID] = groupBindRow
 
@@ -910,12 +1003,12 @@
             returnValue([])
 
         # get all accepted shared binds
-        rows = yield self._invitedBindForResourceID.on(
-            self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+        rows = yield self._unacceptedBindForResourceID.on(
+            self._txn, resourceID=self._resourceID
         )
         homeIDToBindRowMap = dict([(row[1], row) for row in rows])
 
-        groupBindRows = yield AddressBookObject._invitedBindWithAddressBookID.on(
+        groupBindRows = yield AddressBookObject._unacceptedBindWithAddressBookID.on(
                 self._txn, addressbookID=self._resourceID
         )
         for groupBindRow in groupBindRows:
@@ -923,6 +1016,7 @@
             if homeID not in homeIDToBindRowMap:
                 groupBindRow[0] = _BIND_MODE_WRITE
                 groupBindRow[3] = None # bindName
+                groupBindRow[4] = None # bindStatus
                 groupBindRow[5] = None # bindMessage
                 homeIDToBindRowMap[homeID] = groupBindRow
                 break
@@ -958,33 +1052,32 @@
 
         @return: a L{Deferred} which will fire with the previously-used name.
         """
+        resourceName = None
+
         sharedAddressBook = yield shareeHome.addressbookWithName(self.shareeABName())
-        if not sharedAddressBook:
-            returnValue(None)
+        if sharedAddressBook:
 
-        sharedRemoval = False
-        if sharedAddressBook.fullyShared():
-            groupIDs = yield sharedAddressBook.acceptedGroupIDs()
-            sharedRemoval = not bool(len(groupIDs))
-            if sharedRemoval:
-                sharedAddressBook._deletedSyncToken(sharedRemoval=True)
+            sharedRemoval = False
+            if sharedAddressBook.fullyShared():
+                acceptedGroupBinds = len((yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
+                        self._txn, homeID=sharedAddressBook._home._resourceID, addressbookID=sharedAddressBook._resourceID
+                )))
+                sharedRemoval = acceptedGroupBinds == 0
+                if sharedRemoval:
+                    sharedAddressBook._deletedSyncToken(sharedRemoval=True)
+                    shareeHome._children.pop(resourceName, None)
 
+            # Must send notification to ensure cache invalidation occurs
+            yield self.notifyChanged()
+
         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,
+        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)
 
 
@@ -1005,6 +1098,10 @@
         # super._objectText now contains the text as read of the database only,
         #     not including group member text
         self._component = None
+        self._bindMode = None
+        self._bindStatus = None
+        self._bindMessage = None
+        self._bindName = None
         super(AddressBookObject, self).__init__(addressbook, name, uid, resourceID)
 
 
@@ -1045,6 +1142,8 @@
             # sharee cannot delete group representing shared address book
             if self._resourceID == self._addressbook._resourceID:
                 raise DeleteOfGroupForSharedAddressBookNotAllowedError
+            elif self._bindName:
+                raise DeleteOfGroupForSharedAddressBookNotAllowedError
 
         aboMembers = schema.ABO_MEMBERS
         aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
@@ -1165,8 +1264,8 @@
                     self._txn, uid=self._uid,
                     resourceIDs=allowedObjectIDs,)) if allowedObjectIDs else []
             elif self._resourceID:
-                invitedGroupIDs = yield self._addressbook.invitedGroupIDs()
-                allowedObjectIDs = tuple(set(allowedObjectIDs) | set(invitedGroupIDs))
+                if self._resourceID not in allowedObjectIDs:
+                    allowedObjectIDs = yield self._addressbook.invitedGroupIDs()
                 rows = (yield self._allColumnsWithResourceID.on(
                     self._txn, resourceID=self._resourceID,)) if (self._resourceID in allowedObjectIDs) else []
 
@@ -1650,44 +1749,11 @@
         return self._addressbook.viewerHome()
 
 
-    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()
+        return self._bindName
 
 
     @classmethod
@@ -1747,8 +1813,7 @@
             will be used as the default display name.
         @type mode: L{str}
 
-        @return: the name of the shared calendar in the new calendar home.
-        @rtype: L{str}
+        @rtype: a L{Deferred} which fires with a L{ICalendar} if the sharee item
         """
 
         yield self._shareWith(shareeHome, mode, status=status, message=message)
@@ -1806,15 +1871,15 @@
             returnValue([])
 
         # get all accepted shared binds
-        groupBindRows = yield self._invitedBindForResourceID.on(
-            self._txn, resourceID=self._resourceID, homeID=self._home._resourceID
+        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.childWithID(self._addressbook._resourceID)
-            new = yield addressbook.objectResourceWithID(resourceID)
+            new = yield AddressBookObject.objectWithID(addressbook, resourceID) # avoids object cache
             result.append(new)
 
         returnValue(result)
@@ -1844,34 +1909,33 @@
         @return: a L{Deferred} which will fire with the previously-used name.
         """
 
+        resourceName = None
         sharedAddressBook = yield shareeHome.addressbookWithName(self._addressbook.shareeABName())
-        if not sharedAddressBook:
+        if sharedAddressBook:
             returnValue(None)
 
-        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)
+            sharedRemoval = False
+            if not sharedAddressBook.fullyShared():
+                acceptedGroupBinds = len((yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
+                        self._txn, homeID=sharedAddressBook._home._resourceID, addressbookID=sharedAddressBook._resourceID
+                )))
+                sharedRemoval = acceptedGroupBinds == 1
+                if sharedRemoval:
+                    sharedAddressBook._deletedSyncToken(sharedRemoval=True)
+                    shareeHome._children.pop(resourceName, None)
 
+                # Must send notification to ensure cache invalidation occurs
+                yield self._addressbook.notifyChanged()
+
         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,
+        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)
 
 
@@ -1917,6 +1981,13 @@
 
         if len(columnMap):
 
+            # count accepted 
+            if status is not None:
+                previouslyAcceptedBinds = 1 if shareeView._addressbook.fullyShared() else 0
+                previouslyAcceptedBinds += len((yield AddressBookObject._acceptedBindWithHomeIDAndAddressBookID.on(
+                        self._txn, homeID=shareeView._home._resourceID, addressbookID=shareeView._resourceID
+                )))
+
             #TODO:  with bit of parameter wrangling, call shareWith() here instead.
             sharedname = yield self._updateBindColumnsQuery(columnMap).on(
                             self._txn,
@@ -1924,20 +1995,23 @@
                         )
 
             #update affected attributes
-            if mode:
+            if mode is not None:
                 shareeView._bindMode = columnMap[bind.BIND_MODE]
 
-            if status:
+            if status is not None:
                 shareeView._bindStatus = columnMap[bind.BIND_STATUS]
                 if shareeView._bindStatus == _BIND_STATUS_ACCEPTED:
-                    yield shareeView._addressbook._initSyncToken()
+                    if 0 == previouslyAcceptedBinds:
+                        yield shareeView._addressbook._initSyncToken()
                 elif shareeView._bindStatus == _BIND_STATUS_DECLINED:
-                    shareeView._addressbook._deletedSyncToken(sharedRemoval=True)
-                    shareeView._home._children.pop(shareeView._addressbook._name, None)
+                    if 1 == previouslyAcceptedBinds:
+                        shareeView._addressbook._deletedSyncToken(sharedRemoval=True)
+                        shareeView._home._children.pop(shareeView._addressbook._name, None)
 
-            if message:
+            if message is not None:
                 shareeView._bindMessage = columnMap[bind.MESSAGE]
 
+            # safer to just invalidate in all cases rather than calculate when to invalidate
             queryCacher = self._txn._queryCacher
             if queryCacher:
                 cacheKey = queryCacher.keyForObjectWithName(shareeView._home._resourceID, shareeView._addressbook._name)
@@ -1964,13 +2038,13 @@
         )
 
     @classproperty
-    def _invitedBindWithAddressBookID(cls): #@NoSelf
+    def _unacceptedBindWithAddressBookID(cls): #@NoSelf
         bind = cls._bindSchema
         abo = cls._objectSchema
         return Select(
                   cls._bindColumns,
                   From=bind.join(abo),
-                  Where=(bind.BIND_STATUS == _BIND_STATUS_INVITED)
+                  Where=(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
                         .And(bind.RESOURCE_ID == abo.RESOURCE_ID)
                         .And(abo.ADDRESSBOOK_RESOURCE_ID == Parameter("addressbookID"))
         )

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py	2013-02-13 01:56:19 UTC (rev 10709)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py	2013-02-13 03:10:20 UTC (rev 10710)
@@ -2342,7 +2342,7 @@
 
 
     @classproperty
-    def _invitedBindForResourceID(cls): #@NoSelf
+    def _unacceptedBindForResourceID(cls): #@NoSelf
         bind = cls._bindSchema
         return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
                             .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
@@ -2443,8 +2443,7 @@
             will be used as the default display name.
         @type mode: L{str}
 
-        @return: the name of the shared home child in the new home.
-        @rtype: L{CommonHomeChild}
+        @rtype: a L{Deferred} which fires with a L{ICalendar} if the sharee item
         """
 
         yield self._shareWith(shareeHome, mode, status=status, message=message)
@@ -2510,10 +2509,10 @@
                         )
 
             #update affected attributes
-            if mode:
+            if mode is not None:
                 shareeView._bindMode = columnMap[bind.BIND_MODE]
 
-            if status:
+            if status is not None:
                 shareeView._bindStatus = columnMap[bind.BIND_STATUS]
                 if shareeView._bindStatus == _BIND_STATUS_ACCEPTED:
                     yield shareeView._initSyncToken()
@@ -2521,7 +2520,7 @@
                     shareeView._deletedSyncToken(sharedRemoval=True)
                     shareeView._home._children.pop(shareeView._name, None)
 
-            if message:
+            if message is not None:
                 shareeView._bindMessage = columnMap[bind.MESSAGE]
 
             queryCacher = self._txn._queryCacher
@@ -2562,6 +2561,8 @@
         @return: a L{Deferred} which will fire with the previously-used name.
         """
 
+        resourceName = None
+
         #remove sync tokens
         shareeChildren = yield shareeHome.children()
         for shareeChild in shareeChildren:
@@ -2573,19 +2574,18 @@
                     cacheKey = queryCacher.keyForObjectWithName(shareeHome._resourceID, shareeChild._name)
                     queryCacher.invalidateAfterCommit(self._txn, cacheKey)
 
+                resourceName = shareeChild._name
+                shareeHome._children.pop(resourceName, None)
+
+                # Must send notification to ensure cache invalidation occurs
+                yield self.notifyChanged()
+
                 break
 
-        rows = yield self._deleteBindWithResourceIDAndHomeID.on(self._txn, resourceID=self._resourceID,
+        # delete binds including invites
+        yield self._deleteBindWithResourceIDAndHomeID.on(self._txn, resourceID=self._resourceID,
              homeID=shareeHome._resourceID)
 
-        resourceName = None
-        if rows:
-            resourceName = rows[0][0]
-            shareeHome._children.pop(resourceName, None)
-
-        # Must send notification to ensure cache invalidation occurs
-        yield self.notifyChanged()
-
         returnValue(resourceName)
 
     @inlineCallbacks
@@ -2640,7 +2640,7 @@
         if not self.owned():
             returnValue([])
 
-        rows = yield self._invitedBindForResourceID.on(
+        rows = yield self._unacceptedBindForResourceID.on(
             self._txn, resourceID=self._resourceID,
         )
         cls = self._home._childClass # for ease of grepping...
@@ -3351,11 +3351,11 @@
         if resourceID in self._objects:
             return succeed(self._objects[resourceID])
         else:
-            return self._makeObjectResource(resourceID=resourceID, cache=False)
+            return self._makeObjectResource(resourceID=resourceID)
 
 
     @inlineCallbacks
-    def _makeObjectResource(self, name=None, uid=None, resourceID=None, cache=True):
+    def _makeObjectResource(self, name=None, uid=None, resourceID=None):
         """
         We create the empty object first then have it initialize itself from the
         store.
@@ -3368,7 +3368,7 @@
             objectResource = (
                 yield self._objectResourceClass.objectWithName(self, name, uid)
             )
-        if objectResource and cache:
+        if objectResource:
             self._objects[objectResource.name()] = objectResource
             self._objects[objectResource.uid()] = objectResource
             self._objects[objectResource._resourceID] = objectResource
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130212/185700b1/attachment-0001.html>


More information about the calendarserver-changes mailing list