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

source_changes at macosforge.org source_changes at macosforge.org
Tue Jan 15 16:03:16 PST 2013


Revision: 10307
          http://trac.calendarserver.org//changeset/10307
Author:   gaya at apple.com
Date:     2013-01-15 16:03:16 -0800 (Tue, 15 Jan 2013)
Log Message:
-----------
Checkpoint changes --- on the way to making shared groups work with the current, non-final schema

Modified Paths:
--------------
    CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
    CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
    CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2013-01-15 21:15:06 UTC (rev 10306)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2013-01-16 00:03:16 UTC (rev 10307)
@@ -27,7 +27,7 @@
 ]
 
 from twext.enterprise.dal.syntax import Delete, Insert, Len, Parameter, \
-    Update, Select, utcNowSQL
+    Update, Union, Select, utcNowSQL
 
 from twext.python.clsprop import classproperty
 from twext.web2.http_headers import MimeType
@@ -54,7 +54,9 @@
     ADDRESSBOOK_OBJECT_AND_BIND_TABLE, \
     ADDRESSBOOK_OBJECT_REVISIONS_AND_BIND_TABLE, \
     _ABO_KIND_PERSON, _ABO_KIND_GROUP, _ABO_KIND_RESOURCE, \
-    _ABO_KIND_LOCATION, schema
+    _ABO_KIND_LOCATION, schema, \
+    _BIND_MODE_OWN, _BIND_STATUS_ACCEPTED
+
 from txdav.xml.rfc2518 import ResourceType
 
 from zope.interface.declarations import implements
@@ -280,12 +282,37 @@
 
 
     @inlineCallbacks
+    def _ownerGroupAndAddressBook(self):
+        """ 
+        Find the owner shared group and owner address book.  owner shared group may be None 
+        """
+        ownerGroup = None
+        if self.owned():
+            yield None
+            ownerAddressBook = self
+        else:
+            ownerAddressBook = yield self.ownerAddressBookHome().childWithID(self._resourceID)
+            if not ownerAddressBook:
+                for addressbook in (yield self.ownerAddressBookHome().addressbooks()):
+                    ownerGroup = yield addressbook.objectResourceWithID(self._resourceID)
+                    if ownerGroup:
+                        ownerAddressBook = addressbook
+                        break
+
+        returnValue((ownerGroup, ownerAddressBook))
+
+
+    @inlineCallbacks
+    def ownerGroup(self):
+        if not hasattr(self, "_ownerGroup"):
+            self._ownerGroup, self._ownerAddressBook = yield self._ownerGroupAndAddressBook()
+        returnValue(self._ownerGroup)
+
+
+    @inlineCallbacks
     def ownerAddressBook(self):
         if not hasattr(self, "_ownerAddressBook"):
-            if self.owned():
-                self._ownerAddressBook = self
-            else:
-                self._ownerAddressBook = yield self.ownerAddressBookHome().childWithID(self._resourceID)
+            self._ownerGroup, self._ownerAddressBook = yield self._ownerGroupAndAddressBook()
         returnValue(self._ownerAddressBook)
 
 
@@ -315,7 +342,125 @@
         yield None
         returnValue(self.name())
 
+    @classmethod
+    def _bindsFor(cls, where): #@NoSelf
 
+        def columns(bind): #@NoSelf
+            return [bind.BIND_MODE,
+                    bind.HOME_RESOURCE_ID,
+                    bind.RESOURCE_ID,
+                    bind.RESOURCE_NAME,
+                    bind.BIND_STATUS,
+                    bind.MESSAGE]
+
+        addressbookBind = cls._bindSchema
+        groupBind = AddressBookObject._bindSchema
+        return Select(
+            columns(addressbookBind),
+            From=addressbookBind,
+            Where=where(addressbookBind),
+            SetExpression=Union(
+                Select(
+                    columns(groupBind),
+                    From=groupBind,
+                    Where=where(groupBind),
+                    ),
+                optype=Union.OPTYPE_ALL,
+            )
+        )
+
+
+    @classproperty
+    def _invitedBindForResourceID(cls): #@NoSelf
+        return cls._bindsFor(lambda bind: ((bind.RESOURCE_ID == Parameter("resourceID"))
+                            .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+                            ))
+
+
+    @classproperty
+    def _sharedBindForResourceID(cls): #@NoSelf
+        return cls._bindsFor(lambda bind: ((bind.RESOURCE_ID == Parameter("resourceID"))
+                            .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+                            .And(bind.BIND_MODE != _BIND_MODE_OWN)
+                            ))
+
+
+    @classproperty
+    def _invitedBindForHomeID(cls): #@NoSelf
+        return cls._bindsFor(lambda bind: ((bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                            .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+                            ))
+
+
+    @classproperty
+    def _invitedBindForNameAndHomeID(cls): #@NoSelf
+        return cls._bindsFor(lambda bind: ((bind.RESOURCE_NAME == Parameter("name"))
+                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                               .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+                               ))
+
+
+    @classproperty
+    def _childForNameAndHomeID(cls): #@NoSelf
+        return cls._bindsFor(lambda bind: ((bind.RESOURCE_NAME == Parameter("name"))
+                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                               .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+                               ))
+
+
+    @classproperty
+    def _bindForResourceIDAndHomeID(cls): #@NoSelf
+        return cls._bindsFor(lambda bind: ((bind.RESOURCE_ID == Parameter("resourceID"))
+                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                               ))
+
+
+    @classproperty
+    def _metadataByIDQuery(cls): #@NoSelf
+        """
+        DAL query to retrieve created/modified dates based on a resource ID.
+        """
+        child = cls._homeChildMetaDataSchema
+        abo = schema.ADDRESSBOOK_OBJECT
+        return Select(
+            cls.metadataColumns(),
+            From=child,
+            Where=child.RESOURCE_ID == Parameter("resourceID"),
+            SetExpression=Union(
+                Select(
+                    [abo.CREATED, abo.MODIFIED],
+                    From=abo,
+                    Where=abo.RESOURCE_ID == Parameter("resourceID"),
+                    ),
+                optype=Union.OPTYPE_ALL,
+            )
+        )
+
+
+    @classproperty
+    def _changeABForSharedGroupLastModifiedQuery(cls): #@NoSelf
+        schema = AddressBook._objectSchema
+        return Update({schema.MODIFIED: utcNowSQL},
+                      Where=schema.RESOURCE_ID == Parameter("resourceID"),
+                      Return=schema.MODIFIED)
+
+
+    @inlineCallbacks
+    def _bumpModified(self, subtxn):
+        print ("_bumpModified:self = %s" % (self,))
+
+        yield self._lockLastModifiedQuery.on(subtxn, resourceID=self._resourceID)
+
+        # can't call self.ownerGroup() on a subtranaction,
+        # So just try AB schema first, then ABOBject schema
+        result = yield self._changeLastModifiedQuery.on(subtxn, resourceID=self._resourceID)
+
+        if not result:
+            result = yield self._changeABForSharedGroupLastModifiedQuery.on(subtxn, resourceID=self._resourceID)
+
+        returnValue(result)
+
+
 class AddressBookObject(CommonObjectResource, AddressBookSharingMixIn):
 
     implements(IAddressBookObject)
@@ -377,7 +522,7 @@
         aboMembers = schema.ABO_MEMBERS
         aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
 
-        ownerGroup = yield self.ownerGroup()
+        ownerGroup = yield self._addressbook.ownerGroup()
         if ownerGroup:
             # convert delete in sharee shared group address book to remove of memberships
             # that make this object visible to the sharee
@@ -389,7 +534,7 @@
                 yield self._deleteMembersWithMemberIDAndGroupIDsQuery(self._resourceID, objectIDs).on(
                     self._txn, groupIDs=objectIDs)
 
-            ownerAddressBook = yield self.ownerAddressBook()
+            ownerAddressBook = yield self._addressbook.ownerAddressBook()
             yield self._changeAddressBookRevision(ownerAddressBook)
 
         else:
@@ -551,7 +696,7 @@
             obj.MD5,
             Len(obj.TEXT),
             obj.CREATED,
-            obj.MODIFIED
+            obj.MODIFIED,
         ]
 
 
@@ -645,43 +790,12 @@
         else:
             if self._addressbook._resourceID != self._ownerAddressBookResourceID:
                 # update revisions table of shared group's containing address book
-                ownerAddressBook = yield self.ownerAddressBook()
+                ownerAddressBook = yield self._addressbook.ownerAddressBook()
                 yield self._changeAddressBookRevision(ownerAddressBook, inserting)
 
         self._component = component
 
 
-    @inlineCallbacks
-    def _ownerGroupAndAddressBook(self):
-        """ 
-        Find the owner shared group and owner address book.  owner shared group may be None 
-        """
-        ownerGroup = None
-        ownerAddressBook = yield self._addressbook.ownerAddressBook()
-        if not ownerAddressBook:
-            for addressbook in (yield self._addressbook.ownerAddressBookHome().addressbooks()):
-                ownerGroup = yield addressbook.objectResourceWithID(self._addressbook._resourceID)
-                if ownerGroup:
-                    ownerAddressBook = addressbook
-                    break
-
-        returnValue((ownerGroup, ownerAddressBook))
-
-
-    @inlineCallbacks
-    def ownerGroup(self):
-        if not hasattr(self, "_ownerGroup"):
-            self._ownerGroup, self._ownerAddressBook = yield self._ownerGroupAndAddressBook()
-        returnValue(self._ownerGroup)
-
-
-    @inlineCallbacks
-    def ownerAddressBook(self):
-        if not hasattr(self, "_ownerAddressBook"):
-            self._ownerGroup, self._ownerAddressBook = yield self._ownerGroupAndAddressBook()
-        returnValue(self._ownerAddressBook)
-
-
     @classmethod
     def _resourceIDAndUIDForUIDsAndAddressBookResourceIDQuery(cls, uids): #@NoSelf
         abo = schema.ADDRESSBOOK_OBJECT
@@ -735,7 +849,7 @@
         # For shared groups:  Non owner may NOT add group members not currently in group!
         # (Or it would be possible to troll for unshared vCard UIDs and make them shared.)
         if not self._ownerAddressBookResourceID:
-            ownerAddressBook = yield self.ownerAddressBook()
+            ownerAddressBook = yield self._addressbook.ownerAddressBook()
             self._ownerAddressBookResourceID = ownerAddressBook._resourceID
 
         if self._kind == _ABO_KIND_GROUP:
@@ -756,7 +870,7 @@
             foreignMemberAddrs.extend(["urn:uuid:" + missingUID for missingUID in set(memberUIDs) - set(foundUIDs)])
 
             #in shared group, all members must be inside the shared group
-            ownerGroup = yield self.ownerGroup()
+            ownerGroup = yield self._addressbook.ownerGroup()
             if ownerGroup:
                 if foreignMemberAddrs or \
                     set(memberIDs) - set((yield ownerGroup._allGroupObjectIDs())):
@@ -824,9 +938,9 @@
             # groupIDs.append(self._ownerAddressBookResourceID)
 
             # add owner group if there is one
-            ownerGroup = yield self.ownerGroup()
+            ownerGroup = yield self._addressbook.ownerGroup()
             if ownerGroup:
-                groupIDs.append(self._ownerGroup._resourceID)
+                groupIDs.append(ownerGroup._resourceID)
 
             # add to member table rows
             for groupID in groupIDs:

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py	2013-01-15 21:15:06 UTC (rev 10306)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql.py	2013-01-16 00:03:16 UTC (rev 10307)
@@ -2169,7 +2169,7 @@
             L{_BIND_MODE_WRITE} or L{_BIND_MODE_DIRECT}
         @type mode: L{str}
 
-        @param status: The sharing mode; L{_BIND_STATUS_INVITED} or
+        @param status: The sharing status; L{_BIND_STATUS_INVITED} or
             L{_BIND_STATUS_ACCEPTED} or L{_BIND_STATUS_DECLINED} or
             L{_BIND_STATUS_INVALID}.
         @type mode: L{str}
@@ -2223,7 +2223,7 @@
             L{_BIND_MODE_WRITE} or None to not update
         @type mode: L{str}
 
-        @param status: The sharing mode; L{_BIND_STATUS_INVITED} or
+        @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}
@@ -2332,30 +2332,6 @@
 
 
 
-    @classmethod
-    def _bindFor(cls, condition): #@NoSelf
-        bind = cls._bindSchema
-        return Select(
-            [bind.BIND_MODE,
-             bind.HOME_RESOURCE_ID,
-             bind.RESOURCE_ID,
-             bind.RESOURCE_NAME,
-             bind.BIND_STATUS,
-             bind.MESSAGE],
-                  From=bind,
-                  Where=condition
-        )
-
-
-    @classproperty
-    def _sharedBindForResourceID(cls): #@NoSelf
-        bind = cls._bindSchema
-        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
-                            .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
-                            .And(bind.BIND_MODE != _BIND_MODE_OWN)
-                            )
-
-
     @inlineCallbacks
     def asShared(self):
         """
@@ -2392,15 +2368,6 @@
             result.append(new)
         returnValue(result)
 
-
-    @classproperty
-    def _invitedBindForResourceID(cls): #@NoSelf
-        bind = cls._bindSchema
-        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
-                            .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
-                            )
-
-
     @inlineCallbacks
     def asInvited(self):
         """
@@ -2437,9 +2404,82 @@
         returnValue(result)
 
 
+    @classmethod
+    def _bindFor(cls, condition): #@NoSelf
+        bind = cls._bindSchema
+        return Select(
+            [bind.BIND_MODE,
+             bind.HOME_RESOURCE_ID,
+             bind.RESOURCE_ID,
+             bind.RESOURCE_NAME,
+             bind.BIND_STATUS,
+             bind.MESSAGE],
+                  From=bind,
+                  Where=condition
+        )
 
 
+    @classproperty
+    def _invitedBindForResourceID(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+                            .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+                            )
 
+
+    @classproperty
+    def _sharedBindForResourceID(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+                            .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+                            .And(bind.BIND_MODE != _BIND_MODE_OWN)
+                            )
+
+
+    @classmethod
+    def _sharedBindForResourceIDRows(cls, txn, resourceID, homeID): #@NoSelf
+        return cls._sharedBindForResourceID.on(
+            txn, resourceID=resourceID, homeID=homeID
+        )
+
+
+    @classproperty
+    def _invitedBindForHomeID(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._bindFor((bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                            .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED))
+
+
+    @classproperty
+    def _invitedBindForNameAndHomeID(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
+                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                               .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
+                               )
+
+
+    @classproperty
+    def _childForNameAndHomeID(cls): #@NoSelf
+        bind = cls._bindSchema
+        return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
+                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                               .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
+                               )
+
+
+    @classproperty
+    def _bindForResourceIDAndHomeID(cls): #@NoSelf
+        """
+        DAL query that looks up home child names / bind modes by home child
+        resource ID and home resource ID.
+        """
+        bind = cls._bindSchema
+        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
+                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
+                               )
+
+
 class CommonHomeChild(LoggingMixIn, FancyEqMixin, _SharedSyncLogic, HomeChildBase, SharingMixIn):
     """
     Common ancestor class of AddressBooks and Calendars.
@@ -2549,13 +2589,7 @@
         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):
@@ -2725,13 +2759,6 @@
         returnValue(results)
 
 
-    @classproperty
-    def _invitedBindForNameAndHomeID(cls): #@NoSelf
-        bind = cls._bindSchema
-        return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
-                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
-                               .And(bind.BIND_STATUS != _BIND_STATUS_ACCEPTED)
-                               )
 
 
     @classmethod
@@ -2787,15 +2814,6 @@
         returnValue(child)
 
 
-    @classproperty
-    def _childForNameAndHomeID(cls): #@NoSelf
-        bind = cls._bindSchema
-        return cls._bindFor((bind.RESOURCE_NAME == Parameter("name"))
-                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
-                               .And(bind.BIND_STATUS == _BIND_STATUS_ACCEPTED)
-                               )
-
-
     @classmethod
     @inlineCallbacks
     def objectWithName(cls, home, name):
@@ -2856,18 +2874,6 @@
         returnValue(child)
 
 
-    @classproperty
-    def _bindForResourceIDAndHomeID(cls): #@NoSelf
-        """
-        DAL query that looks up home child names / bind modes by home child
-        resource ID and home resource ID.
-        """
-        bind = cls._bindSchema
-        return cls._bindFor((bind.RESOURCE_ID == Parameter("resourceID"))
-                               .And(bind.HOME_RESOURCE_ID == Parameter("homeID"))
-                               )
-
-
     @classmethod
     @inlineCallbacks
     def objectWithID(cls, home, resourceID):
@@ -3576,6 +3582,13 @@
 
 
     @inlineCallbacks
+    def _bumpModified(self, subtxn):
+        yield self._lockLastModifiedQuery.on(subtxn, resourceID=self._resourceID)
+        result = (yield self._changeLastModifiedQuery.on(subtxn, resourceID=self._resourceID))
+        returnValue(result)
+
+
+    @inlineCallbacks
     def bumpModified(self):
         """
         Bump the MODIFIED value. A possible deadlock could happen here if two or more
@@ -3589,14 +3602,8 @@
             returnValue(None)
         self._txn.bumpAddedForObject(self)
 
-        @inlineCallbacks
-        def _bumpModified(subtxn):
-            yield self._lockLastModifiedQuery.on(subtxn, resourceID=self._resourceID)
-            result = (yield self._changeLastModifiedQuery.on(subtxn, resourceID=self._resourceID))
-            returnValue(result)
-
         try:
-            self._modified = (yield self._txn.subtransaction(_bumpModified, retries=0, failureOK=True))[0][0]
+            self._modified = (yield self._txn.subtransaction(self._bumpModified, retries=0, failureOK=True))[0][0]
 
             queryCacher = self._txn._queryCacher
             if queryCacher is not None:

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql	2013-01-15 21:15:06 UTC (rev 10306)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql	2013-01-16 00:03:16 UTC (rev 10307)
@@ -508,7 +508,8 @@
 
 create table ADDRESSBOOK_OBJECT_REVISIONS (
   ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
-  ADDRESSBOOK_RESOURCE_ID      integer      references ADDRESSBOOK,
+  -- ADDRESSBOOK_RESOURCE_ID      integer      references ADDRESSBOOK,		-- FIXME
+  ADDRESSBOOK_RESOURCE_ID      integer,
   ADDRESSBOOK_NAME             varchar(255) default null,
   RESOURCE_NAME                varchar(255),
   REVISION                     integer      default nextval('REVISION_SEQ') not null,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130115/4e18a4f7/attachment-0001.html>


More information about the calendarserver-changes mailing list