[CalendarServer-changes] [10006] CalendarServer/branches/users/gaya/sharedgroups

source_changes at macosforge.org source_changes at macosforge.org
Tue Nov 6 20:09:23 PST 2012


Revision: 10006
          http://trac.calendarserver.org//changeset/10006
Author:   gaya at apple.com
Date:     2012-11-06 20:09:23 -0800 (Tue, 06 Nov 2012)
Log Message:
-----------
checkpoint changes

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

Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py	2012-11-06 22:01:57 UTC (rev 10005)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/sharing.py	2012-11-07 04:09:23 UTC (rev 10006)
@@ -906,27 +906,20 @@
 
     def isGroup(self):
         try:
-            kind = self._newStoreObject._kind
+            return self._newStoreObject._kind == _ABO_KIND_GROUP
         except AttributeError:
-            pass
-        else:
-            if kind == _ABO_KIND_GROUP:
-                self.log_info("isGroup():self=%s returning True" % (self,))
-                return True
+            return False
 
-        self.log_info("isGroup():self=%s returning False" % (self,))
-        return False
 
-
     def POST_handler_content_type(self, request, contentType):
         if self.isCollection() or self.isGroup():
             if contentType:
                 if contentType in self._postHandlers:
                     return self._postHandlers[contentType](self, request)
                 else:
-                    self.log_info("Get a POST of an unsupported content type on a collection type: %s" % (contentType,))
+                    self.log_info("Got a POST on collection or group with an unsupported content type: %s" % (contentType,))
             else:
-                self.log_info("Get a POST with no content type on a collection")
+                self.log_info("Got a POST on collection or group with no content type")
         return succeed(responsecode.FORBIDDEN)
 
     _postHandlers = {

Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/vcard.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/vcard.py	2012-11-06 22:01:57 UTC (rev 10005)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/vcard.py	2012-11-07 04:09:23 UTC (rev 10006)
@@ -431,11 +431,8 @@
         """
         assert self.name() == "VCARD", "Not a vcard: %r" % (self,)
 
-        if not hasattr(self, "_resource_members"):
-            self._resource_members = [prop.value() for prop in list(self.properties("X-ADDRESSBOOKSERVER-MEMBER"))]
+        return [prop.value() for prop in list(self.properties("X-ADDRESSBOOKSERVER-MEMBER"))]
 
-        return self._resource_members
-
     def validVCardData(self, doFix=True, doRaise=True):
         """
         @return: tuple of fixed, unfixed issues

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2012-11-06 22:01:57 UTC (rev 10005)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/carddav/datastore/sql.py	2012-11-07 04:09:23 UTC (rev 10006)
@@ -37,7 +37,7 @@
 from twistedcaldav import carddavxml, customxml
 from twistedcaldav.memcacher import Memcacher
 from twistedcaldav.vcard import Component as VCard, InvalidVCardDataError, \
-    vCardProductID
+    vCardProductID, Property
 
 from txdav.base.propertystore.base import PropertyName
 from txdav.carddav.datastore.util import validateAddressBookComponent
@@ -364,11 +364,25 @@
         aboForeignMembers = schema.ABO_FOREIGN_MEMBERS
         aboMembers = schema.ABO_MEMBERS
 
+        print("remove:%s, name=%s" % (self, self._name))
+
         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"
+                ownerGroupComponent = yield ownerGroup.component()
+                member = "urn:uuid:" + self._uid
+                if member in ownerGroupComponent.resourceMembers():
+                    ownerGroupComponent.removeProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", member))
+                    ownerGroup.updateDatabase(ownerGroupComponent)
 
+        elif self._kind == _ABO_KIND_GROUP:
+            # need to invalidate queryCacher
+            queryCacher = self._txn._queryCacher
+            if queryCacher:
+                for shareeAddressBook in (yield self.asShared()):
+                    cacheKey = queryCacher.keyForObjectWithName(shareeAddressBook._home._resourceID, shareeAddressBook._name)
+                    yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+
         # delete members table row for this object
         groupIDs = yield Delete(
             aboMembers,
@@ -393,7 +407,72 @@
         self._kind = None
         self._ownerAddressBookResourceID = None
 
+    @classmethod
+    def _allWithResourceIDAnd(cls, resourceIDs, column, paramName):
+        """
+        DAL query for all columns where PARENT_RESOURCE_ID matches a parentID
+        parameter and a given instance column matches a given parameter name.
+        """
+        obj = cls._objectSchema
+        return Select(
+            cls._allColumns, From=obj,
+            Where=(column == Parameter(paramName)).And(
+                obj.RESOURCE_ID.In(Parameter("resourceIDs", len(resourceIDs))))
+        )
+
+
+    @classmethod
+    def _allWithResourceIDAndName(cls, resourceIDs): #@NoSelf
+        return cls._allWithResourceIDAnd(resourceIDs, cls._objectSchema.RESOURCE_NAME, "name")
+
+
+    @classmethod
+    def _allWithResourceIDAndUID(cls, resourceIDs): #@NoSelf
+        return cls._allWithResourceIDAnd(resourceIDs, cls._objectSchema.UID, "uid")
+
+
     @classproperty
+    def _allWithResourceID(cls): #@NoSelf
+        obj = cls._objectSchema
+        return Select(
+            cls._allColumns, From=obj,
+            Where=(obj.RESOURCE_ID == Parameter("resourceID")))
+
+
+    @inlineCallbacks
+    def initFromStore(self):
+        """
+        Initialise this object from the store. We read in and cache all the
+        extra metadata from the DB to avoid having to do DB queries for those
+        individually later. Either the name or uid is present, so we have to
+        tweak the query accordingly.
+
+        @return: L{self} if object exists in the DB, else C{None}
+        """
+        memberIDs = yield self._addressbook._addressBookObjectIDs()
+        if self._name:
+            rows = (yield self._allWithResourceIDAndName(memberIDs).on(
+                self._txn, name=self._name,
+                resourceIDs=memberIDs,)) if memberIDs else []
+        elif self._uid:
+            rows = (yield self._allWithResourceIDAndUID(memberIDs).on(
+                self._txn, uid=self._uid,
+                resourceIDs=memberIDs,)) if memberIDs else []
+        elif self._resourceID:
+            rows = (yield self._allWithResourceID(memberIDs).on(
+                self._txn, resourceID=self._resourceID,)) if self._resourceID in memberIDs else []
+        print("initFromStore:self=%s, self._name=%s, self._uid=%s, self._resourceID=%s, self._parentCollection._resourceID=%s rows=%s" %
+              (self, self._name, self._uid, self._resourceID, self._parentCollection._resourceID, rows))
+
+        if rows:
+            self._initFromRow(tuple(rows[0]))
+            yield self._loadPropertyStore()
+            returnValue(self)
+        else:
+            returnValue(None)
+
+
+    @classproperty
     def _allColumns(cls): #@NoSelf
         """
         Full set of columns in the object table that need to be loaded to
@@ -540,6 +619,12 @@
         assert inserting or self._kind == kind  # can't change kind. Should be checked in upper layers
         self._kind = kind
 
+        ''' FIXME: 
+            SECURITY HOLE on 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.)
+            Fixes: just prevent it, but may make some clients fail when sharee adds groups + members to shared group.
+        '''
+
         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:
@@ -560,17 +645,21 @@
                     ))[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)
+                ownerGroupComponent = yield ownerGroup.component()
+                member = "urn:uuid:" + self._uid
+                if not member in ownerGroupComponent.resourceMembers():
+                    ownerGroupComponent.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", member))
+                    ownerGroup.updateDatabase(ownerGroupComponent)
 
+            # 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(
@@ -624,6 +713,7 @@
 
             memberIDsToDelete = set(currentMemberIDs) - set(memberIDs)
             memberIDsToAdd = set(memberIDs) - set(currentMemberIDs)
+            print("updateDatabase3:self=%s component.resourceMembers()=%s, currentMemberIDs:%s,  memberIDsToAdd:%s, memberIDsToDelete:%s" % (self, component.resourceMembers(), currentMemberIDs, memberIDsToAdd, memberIDsToDelete,))
 
             for memberIDToDelete in memberIDsToDelete:
                 yield Delete(
@@ -632,7 +722,7 @@
                 ).on(self._txn)
 
             for memberIDToAdd in memberIDsToAdd:
-                print("updateDatabase3:self=%s Insert(aboMembers.GROUP_ID:%s,  aboMembers.ADDRESSBOOK_ID:%s, aboMembers.MEMBER_ID:%s" % (
+                print("updateDatabase3.1: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,

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-06 22:01:57 UTC (rev 10005)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/common/datastore/sql_schema/current.sql	2012-11-07 04:09:23 UTC (rev 10006)
@@ -441,7 +441,7 @@
 
 create table ADDRESSBOOK_OBJECT_REVISIONS (
   ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
-  ADDRESSBOOK_RESOURCE_ID      integer      references ADDRESSBOOK_OBJECT,
+  ADDRESSBOOK_RESOURCE_ID      integer      references ADDRESSBOOK_OBJECT on delete cascade,
   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/20121106/062587c1/attachment-0001.html>


More information about the calendarserver-changes mailing list