[CalendarServer-changes] [11176] CalendarServer/branches/users/gaya/sharedgroups-3

source_changes at macosforge.org source_changes at macosforge.org
Mon May 13 18:50:25 PDT 2013


Revision: 11176
          http://trac.calendarserver.org//changeset/11176
Author:   gaya at apple.com
Date:     2013-05-13 18:50:25 -0700 (Mon, 13 May 2013)
Log Message:
-----------
checkpoint: All tests work.  All Calendar CalDAVTester tests work.

Modified Paths:
--------------
    CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/storebridge.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/sql.py
    CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql.py

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/storebridge.py	2013-05-14 01:48:52 UTC (rev 11175)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/twistedcaldav/storebridge.py	2013-05-14 01:50:25 UTC (rev 11176)
@@ -460,8 +460,7 @@
         """
 
         # Check sharee collection first
-        isShareeResource = self.isShareeResource()
-        if isShareeResource:
+        if self.isShareeResource():
             log.debug("Removing shared collection %s" % (self,))
             yield self.removeShareeCollection(request)
             returnValue(NO_CONTENT)

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/sql.py	2013-05-14 01:48:52 UTC (rev 11175)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/carddav/datastore/sql.py	2013-05-14 01:50:25 UTC (rev 11176)
@@ -29,6 +29,7 @@
 
 from twext.enterprise.dal.syntax import Delete, Insert, Len, Parameter, \
     Update, Union, Max, Select, utcNowSQL
+from twext.enterprise.locking import NamedLock
 from twext.python.clsprop import classproperty
 from twext.web2.http import HTTPError
 from twext.web2.http_headers import MimeType
@@ -37,13 +38,13 @@
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twisted.python import hashlib
 from twistedcaldav import carddavxml, customxml
+from twistedcaldav.config import config
 from twistedcaldav.memcacher import Memcacher
 from twistedcaldav.vcard import Component as VCard, InvalidVCardDataError, \
     vCardProductID, Property
 
 from txdav.base.propertystore.base import PropertyName
 from txdav.base.propertystore.sql import PropertyStore
-from txdav.carddav.datastore.util import validateAddressBookComponent
 from txdav.carddav.iaddressbookstore import IAddressBookHome, IAddressBook, \
     IAddressBookObject, GroupForSharedAddressBookDeleteNotAllowedError, \
     GroupWithUnsharedAddressNotAllowedError, SharedGroupDeleteNotAllowedError
@@ -55,7 +56,10 @@
     _BIND_MODE_OWN, _BIND_MODE_WRITE, _BIND_STATUS_ACCEPTED, \
     _BIND_STATUS_DECLINED, _BIND_STATUS_INVITED
 from txdav.common.icommondatastore import InternalDataStoreError, \
+    InvalidUIDError, UIDExistsError, ObjectResourceTooBigError, \
+    InvalidObjectResourceError, InvalidComponentForStoreError, \
     AllRetriesFailed
+
 from txdav.xml.rfc2518 import ResourceType
 
 from zope.interface.declarations import implements
@@ -1586,11 +1590,81 @@
         yield addressbook.notifyChanged()
 
 
+    # Stuff from put_addressbook_common
+    def fullValidation(self, component, inserting):
+        """
+        Do full validation of source and destination calendar data.
+        """
+
+        # Basic validation
+
+        # Valid data sizes
+        if config.MaxResourceSize:
+            vcardsize = len(str(component))
+            if vcardsize > config.MaxResourceSize:
+                raise ObjectResourceTooBigError()
+
+        # Valid calendar data checks
+        self.validAddressDataCheck(component, inserting)
+
+
+    def validAddressDataCheck(self, component, inserting):  #@UnusedVariable
+        """
+        Check that the calendar data is valid iCalendar.
+        @return:         tuple: (True/False if the calendar data is valid,
+                                 log message string).
+        """
+
+        # Valid calendar data checks
+        if not isinstance(component, VCard):
+            raise InvalidObjectResourceError("Wrong type of object: %s" % (type(component),))
+
+        try:
+            component.validVCardData()
+        except InvalidVCardDataError, e:
+            raise InvalidObjectResourceError(str(e))
+        try:
+            component.validForCardDAV()
+        except InvalidVCardDataError, e:
+            raise InvalidComponentForStoreError(str(e))
+
+
     @inlineCallbacks
+    def _lockUID(self, component, inserting):
+        """
+        Create a lock on the component's UID and verify, after getting the lock, that the incoming UID
+        meets the requirements of the store.
+        """
+
+        new_uid = component.resourceUID()
+        yield NamedLock.acquire(self._txn, "vCardUIDLock:%s" % (hashlib.md5(new_uid).hexdigest(),))
+
+        # UID conflict check - note we do this after reserving the UID to avoid a race condition where two requests
+        # try to write the same calendar data to two different resource URIs.
+
+        # Cannot overwrite a resource with different UID
+        if not inserting:
+            if self._uid != new_uid:
+                raise InvalidUIDError("Cannot change the UID in an existing resource.")
+        else:
+            # New UID must be unique for the owner - no need to do this on an overwrite as we can assume
+            # the store is already consistent in this regard
+            elsewhere = (yield self.addressbook().addressbookObjectWithUID(new_uid))
+            if elsewhere is not None:
+                raise UIDExistsError("UID already exists in same addressbook.")
+
+
+    @inlineCallbacks
     def setComponent(self, component, inserting=False):
 
         self._componentChanged = False
-        validateAddressBookComponent(self, self._addressbook, component, inserting)
+
+        # Handle all validation operations here.
+        self.fullValidation(component, inserting)
+
+        # UID lock - this will remain active until the end of the current txn
+        yield self._lockUID(component, inserting)
+
         yield self.updateDatabase(component, inserting=inserting)
         yield self._changeAddressBookRevision(self._addressbook, inserting)
 
@@ -1606,8 +1680,6 @@
                 # update revisions table of shared group's containing address book
                 yield self._changeAddressBookRevision(self.ownerHome().addressbook(), inserting)
 
-        # TODO:  a better job here!
-        #self._componentChanged = (self._component != component)
         self._component = component
         returnValue(self._componentChanged)
 
@@ -1720,6 +1792,7 @@
 
             # don't store group members in object text
 
+            orginialComponent = str(component)
             # sort addresses in component text
             memberAddresses = component.resourceMemberAddresses()
             component.removeProperties("X-ADDRESSBOOKSERVER-MEMBER")
@@ -1730,6 +1803,7 @@
             componentText = str(component)
             self._md5 = hashlib.md5(componentText).hexdigest()
             self._size = len(componentText)
+            self._componentChanged = componentText != orginialComponent
 
             # remove members from component get new text
             component.removeProperties("X-ADDRESSBOOKSERVER-MEMBER")

Modified: CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql.py	2013-05-14 01:48:52 UTC (rev 11175)
+++ CalendarServer/branches/users/gaya/sharedgroups-3/txdav/common/datastore/sql.py	2013-05-14 01:50:25 UTC (rev 11176)
@@ -3048,7 +3048,17 @@
         )
 
 
+    @inlineCallbacks
+    def invalidateQueryCache(self):
+        queryCacher = self._txn._queryCacher
+        if queryCacher is not None:
+            cacheKey = queryCacher.keyForHomeChildMetaData(self._resourceID)
+            yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+            cacheKey = queryCacher.keyForObjectWithName(self._home._resourceID, self._name)
+            yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
 
+
+
 class CommonHomeChild(LoggingMixIn, FancyEqMixin, Memoizable, _SharedSyncLogic, HomeChildBase, SharingMixIn):
     """
     Common ancestor class of AddressBooks and Calendars.
@@ -3412,16 +3422,6 @@
         return "<%s: %s>" % (self.__class__.__name__, self._resourceID)
 
 
-    @inlineCallbacks
-    def invalidateQueryCache(self):
-        queryCacher = self._txn._queryCacher
-        if queryCacher is not None:
-            cacheKey = queryCacher.keyForHomeChildMetaData(self._resourceID)
-            yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
-            cacheKey = queryCacher.keyForObjectWithName(self._home._resourceID, self._name)
-            yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
-
-
     def exists(self):
         """
         An empty resource-id means this object does not yet exist in the DB.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130513/993c1bc5/attachment.html>


More information about the calendarserver-changes mailing list