[CalendarServer-changes] [6854] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Feb 2 17:15:04 PST 2011


Revision: 6854
          http://trac.macosforge.org/projects/calendarserver/changeset/6854
Author:   cdaboo at apple.com
Date:     2011-02-02 17:15:04 -0800 (Wed, 02 Feb 2011)
Log Message:
-----------
No more properties on object resources in sqlstore.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/method/put_addressbook_common.py
    CalendarServer/trunk/twistedcaldav/storebridge.py
    CalendarServer/trunk/txdav/base/propertystore/sql.py
    CalendarServer/trunk/txdav/caldav/datastore/sql.py
    CalendarServer/trunk/txdav/caldav/datastore/test/common.py
    CalendarServer/trunk/txdav/caldav/datastore/util.py
    CalendarServer/trunk/txdav/carddav/datastore/test/common.py
    CalendarServer/trunk/txdav/common/datastore/file.py
    CalendarServer/trunk/txdav/common/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql
    CalendarServer/trunk/txdav/common/datastore/test/test_util.py

Modified: CalendarServer/trunk/twistedcaldav/method/put_addressbook_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/put_addressbook_common.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/twistedcaldav/method/put_addressbook_common.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -440,17 +440,6 @@
             # Do the actual put or copy
             response = (yield self.doStore())
             
-            # Remember the resource's content-type.
-            if self.destinationadbk:
-                content_type = self.request.headers.getHeader("content-type")
-                if content_type is None:
-                    content_type = MimeType("text", "vcard",
-                                            params={"charset":"utf-8"})
-                self.destination.writeDeadProperty(
-                    davxml.GETContentType.fromString(generateContentType(content_type))
-                )
-
-            # Do quota check on destination
             if reservation:
                 yield reservation.unreserve()
     

Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -63,6 +63,7 @@
 
 from txdav.base.propertystore.base import PropertyName
 from txdav.common.icommondatastore import NoSuchObjectResourceError
+from txdav.idav import PropertyChangeNotAllowedError
 
 log = Logger()
 
@@ -91,42 +92,40 @@
 
     # FIXME 'uid' here should be verifying something.
     def get(self, qname, uid=None):
-        """
-        
-        """
         try:
             return self._newPropertyStore[self._convertKey(qname)]
         except KeyError:
             raise HTTPError(StatusResponse(
-                    NOT_FOUND,
-                    "No such property: {%s}%s" % qname))
+                NOT_FOUND,
+                "No such property: {%s}%s" % qname
+            ))
 
 
     def set(self, property, uid=None):
-        """
-        
-        """
-        self._newPropertyStore[self._convertKey(property.qname())] = property
+        try:
+            self._newPropertyStore[self._convertKey(property.qname())] = property
+        except PropertyChangeNotAllowedError:
+            raise HTTPError(StatusResponse(
+                FORBIDDEN,
+                "Property cannot be changed: {%s}%s" % property.qname(),
+            ))
+            
 
 
     def delete(self, qname, uid=None):
-        """
-        
-        """
-        del self._newPropertyStore[self._convertKey(qname)]
+        try:
+            del self._newPropertyStore[self._convertKey(qname)]
+        except KeyError:
+            # RFC 2518 Section 12.13.1 says that removal of
+            # non-existing property is not an error.
+            pass
 
 
     def contains(self, qname, uid=None, cache=True):
-        """
-        
-        """
         return (self._convertKey(qname) in self._newPropertyStore)
 
 
     def list(self, uid=None, filterByUID=True, cache=True):
-        """
-        
-        """
         return [(pname.namespace, pname.name) for pname in
                 self._newPropertyStore.keys()]
 
@@ -1037,6 +1036,7 @@
         super(CalendarAttachment, self).__init__(**kw)
         self._newStoreCalendarObject = calendarObject
         self._newStoreAttachment = self._newStoreObject = attachment
+        self._dead_properties = NonePropertyStore(self)
         self.attachmentName = attachmentName
 
 
@@ -1104,19 +1104,20 @@
     http_MKCOL = None
     http_MKCALENDAR = None
 
+    def http_PROPPATCH(self, request):
+        """
+        No dead properties allowed on attachments. 
+        """
+        return FORBIDDEN
+
     def isCollection(self):
         return False
 
 
-
-
-
-
 class NoParent(CalDAVResource):
     def http_MKCALENDAR(self, request):
         return CONFLICT
 
-
     def http_PUT(self, request):
         return CONFLICT
 
@@ -1145,7 +1146,7 @@
         self._newStoreObject = storeObject
         self._dead_properties = _NewStorePropertiesWrapper(
             self._newStoreObject.properties()
-        ) if self._newStoreObject else NonePropertyStore(self)
+        ) if self._newStoreObject and self._newStoreParent.objectResourcesHaveProperties() else NonePropertyStore(self)
 
 
     def isCollection(self):
@@ -1186,6 +1187,14 @@
 
         return self.storeRemove(request, True, request.uri)
 
+    def http_PROPPATCH(self, request):
+        """
+        No dead properties allowed on object resources. 
+        """
+        if self._newStoreParent.objectResourcesHaveProperties():
+            return super(_CommonObjectResource, self).http_PROPPATCH(request)
+        else:
+            return FORBIDDEN
 
     @inlineCallbacks
     def storeStream(self, stream):
@@ -1636,11 +1645,27 @@
 
     def _initializeWithObject(self, notificationObject):
         self._newStoreObject = notificationObject
-        self._dead_properties = _NewStorePropertiesWrapper(
-            self._newStoreObject.properties()
-        ) if self._newStoreObject else NonePropertyStore(self)
+        self._dead_properties = NonePropertyStore(self)
 
 
+    def liveProperties(self):
+
+        props = super(StoreNotificationObjectFile, self).liveProperties()
+        props += (customxml.NotificationType.qname(),)
+        return props
+
+    @inlineCallbacks
+    def readProperty(self, property, request):
+        if type(property) is tuple:
+            qname = property
+        else:
+            qname = property.qname()
+
+        if qname == customxml.NotificationType.qname():
+            returnValue(self._newStoreObject.xmlType())
+
+        returnValue((yield super(StoreNotificationObjectFile, self).readProperty(property, request)))
+
     def isCollection(self):
         return False
 
@@ -1678,6 +1703,11 @@
 
         return self.storeRemove(request, request.uri)
 
+    def http_PROPPATCH(self, request):
+        """
+        No dead properties allowed on notification objects. 
+        """
+        return FORBIDDEN
 
     @inlineCallbacks
     def storeRemove(self, request, where):

Modified: CalendarServer/trunk/txdav/base/propertystore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/base/propertystore/sql.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/txdav/base/propertystore/sql.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -67,28 +67,37 @@
         rows = yield txn.execSQL(
             """
             select
+              %s,
               RESOURCE_PROPERTY.RESOURCE_ID,
               RESOURCE_PROPERTY.NAME,
               RESOURCE_PROPERTY.VIEWER_UID,
               RESOURCE_PROPERTY.VALUE
             from RESOURCE_PROPERTY
-            left join %s on (RESOURCE_PROPERTY.RESOURCE_ID = %s) 
+            right join %s on (RESOURCE_PROPERTY.RESOURCE_ID = %s) 
             where %s = %%s
-            """ % (joinTable, joinColumn, parentIDColumn),
+            """ % (joinColumn, joinTable, joinColumn, parentIDColumn),
             [parentID]
         )
         
         createdStores = {}
-        for resource_id, name, view_uid, value in rows:
-            if resource_id not in createdStores:
+        for object_resource_id, resource_id, name, view_uid, value in rows:
+            if resource_id:
+                if resource_id not in createdStores:
+                    store = cls.__new__(cls)
+                    super(PropertyStore, store).__init__(defaultuser)
+                    store._txn = txn
+                    store._resourceID = resource_id
+                    store._cached = {}
+                    createdStores[resource_id] = store
+                createdStores[resource_id]._cached[(name, view_uid)] = value
+            else:
                 store = cls.__new__(cls)
                 super(PropertyStore, store).__init__(defaultuser)
                 store._txn = txn
-                store._resourceID = resource_id
+                store._resourceID = object_resource_id
                 store._cached = {}
-                createdStores[resource_id] = store
-            createdStores[resource_id]._cached[(name, view_uid)] = value
-
+                createdStores[object_resource_id] = store
+                
         returnValue(createdStores)
 
 

Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -227,6 +227,13 @@
         raise NotImplementedError()
 
 
+    def objectResourcesHaveProperties(self):
+        """
+        inbox resources need to store Originator, Recipient etc properties.
+        Other calendars do not have object resources with properties.
+        """
+        return self._name == "inbox"
+
     def initPropertyStore(self, props):
         # Setup peruser special properties
         props.setSpecialProperties(

Modified: CalendarServer/trunk/txdav/caldav/datastore/test/common.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/common.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -1144,34 +1144,36 @@
         propertyContent.name = propertyName.name
         propertyContent.namespace = propertyName.namespace
 
-        (yield self.calendarObjectUnderTest()).properties()[
-            propertyName] = propertyContent
-        yield self.commit()
-        # Sanity check; are properties even readable in a separate transaction?
-        # Should probably be a separate test.
-        self.assertEquals(
-            (yield self.calendarObjectUnderTest()).properties()[propertyName],
-            propertyContent)
-        obj = yield self.calendarObjectUnderTest()
-        event1_text = yield obj.iCalendarText()
-        event1_text_withDifferentSubject = event1_text.replace(
-            "SUMMARY:CalDAV protocol updates",
-            "SUMMARY:Changed"
-        )
-        # Sanity check; make sure the test has the right idea of the subject.
-        self.assertNotEquals(event1_text, event1_text_withDifferentSubject)
-        newComponent = VComponent.fromString(event1_text_withDifferentSubject)
-        yield obj.setComponent(newComponent)
+        calobject = (yield self.calendarObjectUnderTest())
+        if calobject._parentCollection.objectResourcesHaveProperties():
+            (yield self.calendarObjectUnderTest()).properties()[
+                propertyName] = propertyContent
+            yield self.commit()
+            # Sanity check; are properties even readable in a separate transaction?
+            # Should probably be a separate test.
+            self.assertEquals(
+                (yield self.calendarObjectUnderTest()).properties()[propertyName],
+                propertyContent)
+            obj = yield self.calendarObjectUnderTest()
+            event1_text = yield obj.iCalendarText()
+            event1_text_withDifferentSubject = event1_text.replace(
+                "SUMMARY:CalDAV protocol updates",
+                "SUMMARY:Changed"
+            )
+            # Sanity check; make sure the test has the right idea of the subject.
+            self.assertNotEquals(event1_text, event1_text_withDifferentSubject)
+            newComponent = VComponent.fromString(event1_text_withDifferentSubject)
+            yield obj.setComponent(newComponent)
+    
+            # Putting everything into a separate transaction to account for any
+            # caching that may take place.
+            yield self.commit()
+            self.assertEquals(
+                (yield self.calendarObjectUnderTest()).properties()[propertyName],
+                propertyContent
+            )
 
-        # Putting everything into a separate transaction to account for any
-        # caching that may take place.
-        yield self.commit()
-        self.assertEquals(
-            (yield self.calendarObjectUnderTest()).properties()[propertyName],
-            propertyContent
-        )
 
-
     eventWithDropbox = "\r\n".join("""
 BEGIN:VCALENDAR
 CALSCALE:GREGORIAN

Modified: CalendarServer/trunk/txdav/caldav/datastore/util.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/util.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/txdav/caldav/datastore/util.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -133,7 +133,8 @@
             # calendar server didn't have per-user properties.
             outObject = yield outCalendar.calendarObjectWithName(
                 calendarObject.name())
-            outObject.properties().update(calendarObject.properties())
+            if outCalendar.objectResourcesHaveProperties():
+                outObject.properties().update(calendarObject.properties())
     
             # Migrate attachments.
             for attachment in (yield calendarObject.attachments()):

Modified: CalendarServer/trunk/txdav/carddav/datastore/test/common.py
===================================================================
--- CalendarServer/trunk/txdav/carddav/datastore/test/common.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/txdav/carddav/datastore/test/common.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -874,36 +874,38 @@
         propertyContent.name = propertyName.name
         propertyContent.namespace = propertyName.namespace
 
-        (yield self.addressbookObjectUnderTest()).properties()[
-            propertyName] = propertyContent
-        yield self.commit()
-        # Sanity check; are properties even readable in a separate transaction?
-        # Should probably be a separate test.
-        self.assertEquals(
+        abobject = (yield self.addressbookObjectUnderTest())
+        if abobject._parentCollection.objectResourcesHaveProperties():
             (yield self.addressbookObjectUnderTest()).properties()[
-                propertyName
-            ],
-            propertyContent)
-        obj = yield self.addressbookObjectUnderTest()
-        vcard1_text = yield obj.vCardText()
-        vcard1_text_withDifferentNote = vcard1_text.replace(
-            "NOTE:CardDAV protocol updates",
-            "NOTE:Changed"
-        )
-        # Sanity check; make sure the test has the right idea of the subject.
-        self.assertNotEquals(vcard1_text, vcard1_text_withDifferentNote)
-        newComponent = VComponent.fromString(vcard1_text_withDifferentNote)
-        yield obj.setComponent(newComponent)
+                propertyName] = propertyContent
+            yield self.commit()
+            # Sanity check; are properties even readable in a separate transaction?
+            # Should probably be a separate test.
+            self.assertEquals(
+                (yield self.addressbookObjectUnderTest()).properties()[
+                    propertyName
+                ],
+                propertyContent)
+            obj = yield self.addressbookObjectUnderTest()
+            vcard1_text = yield obj.vCardText()
+            vcard1_text_withDifferentNote = vcard1_text.replace(
+                "NOTE:CardDAV protocol updates",
+                "NOTE:Changed"
+            )
+            # Sanity check; make sure the test has the right idea of the subject.
+            self.assertNotEquals(vcard1_text, vcard1_text_withDifferentNote)
+            newComponent = VComponent.fromString(vcard1_text_withDifferentNote)
+            yield obj.setComponent(newComponent)
+    
+            # Putting everything into a separate transaction to account for any
+            # caching that may take place.
+            yield self.commit()
+            self.assertEquals(
+                (yield self.addressbookObjectUnderTest()).properties()[propertyName],
+                propertyContent
+            )
 
-        # Putting everything into a separate transaction to account for any
-        # caching that may take place.
-        yield self.commit()
-        self.assertEquals(
-            (yield self.addressbookObjectUnderTest()).properties()[propertyName],
-            propertyContent
-        )
 
-
     @inlineCallbacks
     def test_dontLeakAddressbooks(self):
         """

Modified: CalendarServer/trunk/txdav/common/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/file.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/txdav/common/datastore/file.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -49,6 +49,7 @@
 from txdav.base.datastore.util import cached
 
 from txdav.base.propertystore.base import PropertyName
+from txdav.base.propertystore.none import PropertyStore as NonePropertyStore
 from txdav.base.propertystore.xattr import PropertyStore
 
 from errno import EEXIST, ENOENT
@@ -812,6 +813,12 @@
         return succeed(self.retrieveOldIndex().whatchanged(token))
 
 
+    def objectResourcesHaveProperties(self):
+        """
+        So filestore objects do need to support properties.
+        """
+        return True
+
     # FIXME: property writes should be a write operation
     @cached
     def properties(self):
@@ -911,7 +918,7 @@
     @cached
     def properties(self):
         uid = self._parentCollection._home.uid()
-        props = PropertyStore(uid, lambda : self._path)
+        props = PropertyStore(uid, lambda : self._path) if self._parentCollection.objectResourcesHaveProperties() else NonePropertyStore(uid)
         self.initPropertyStore(props)
         self._transaction.addOperation(props.flush, "object properties flush")
         return props
@@ -1169,6 +1176,10 @@
     def uid(self):
         return self._uid
 
+    def xmlType(self):
+        # NB This is the NotificationType property element
+        return self.properties()[PropertyName.fromElement(NotificationType)]
+
     def initPropertyStore(self, props):
         # Setup peruser special properties
         props.setSpecialProperties(

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -31,6 +31,7 @@
 
 from twext.python.log import Logger, LoggingMixIn
 from twext.web2.dav.element.rfc2518 import ResourceType
+from twext.web2.dav.element.parser import WebDAVDocument
 from twext.web2.http_headers import MimeType
 
 from twisted.python import hashlib
@@ -61,8 +62,9 @@
 from twext.python.clsprop import classproperty
 from twext.enterprise.dal.syntax import Select
 
+from txdav.base.propertystore.base import PropertyName
+from txdav.base.propertystore.none import PropertyStore as NonePropertyStore
 from txdav.base.propertystore.sql import PropertyStore
-from txdav.base.propertystore.base import PropertyName
 
 from twistedcaldav.customxml import NotificationType
 from twistedcaldav.dateops import datetimeMktime
@@ -1609,6 +1611,9 @@
                     [self._home._resourceID, self._resourceID, name]
                 ))[0][0]
 
+    def objectResourcesHaveProperties(self):
+        return False
+
     @inlineCallbacks
     def _loadPropertyStore(self, props=None):
         if props is None:
@@ -1734,14 +1739,17 @@
         
         if dataRows:
             # Get property stores for all these child resources (if any found)
-            propertyStores =(yield PropertyStore.loadAll(
-                parent._home.uid(),
-                parent._txn,
-                cls._objectTable["name"],
-                "%s.%s" % (cls._objectTable["name"], cls._objectTable["column_RESOURCE_ID"],),
-                "%s.%s" % (cls._objectTable["name"], cls._objectTable["column_PARENT_RESOURCE_ID"]),
-                parent._resourceID,
-            ))
+            if parent.objectResourcesHaveProperties():
+                propertyStores =(yield PropertyStore.loadAll(
+                    parent._home.uid(),
+                    parent._txn,
+                    cls._objectTable["name"],
+                    "%s.%s" % (cls._objectTable["name"], cls._objectTable["column_RESOURCE_ID"],),
+                    "%s.%s" % (cls._objectTable["name"], cls._objectTable["column_PARENT_RESOURCE_ID"]),
+                    parent._resourceID,
+                ))
+            else:
+                propertyStores = {}
         
         # Create the actual objects merging in properties
         for row in dataRows:
@@ -1853,12 +1861,15 @@
     @inlineCallbacks
     def _loadPropertyStore(self, props=None, created=False):
         if props is None:
-            props = yield PropertyStore.load(
-                self._parentCollection.ownerHome().uid(),
-                self._txn,
-                self._resourceID,
-                created=created
-            )
+            if self._parentCollection.objectResourcesHaveProperties():
+                props = yield PropertyStore.load(
+                    self._parentCollection.ownerHome().uid(),
+                    self._txn,
+                    self._resourceID,
+                    created=created
+                )
+            else:
+                props = NonePropertyStore(self._parentCollection.ownerHome().uid())
         self.initPropertyStore(props)
         self._propertyStore = props
 
@@ -2278,6 +2289,7 @@
         self._size = None
         self._created = None
         self._modified = None
+        self._xmlType = None
         self._objectText = None
 
     def __repr__(self):
@@ -2301,6 +2313,7 @@
                 NOTIFICATION_UID,
                 MD5,
                 character_length(XML_DATA),
+                XML_TYPE,
                 CREATED,
                 MODIFIED
             from NOTIFICATION
@@ -2327,9 +2340,10 @@
              child._uid,
              child._md5,
              child._size,
+             child._xmlType,
              child._created,
              child._modified,) = tuple(row)
-            yield child._loadPropertyStore(props=propertyStores.get(child._resourceID, None))
+            child._loadPropertyStore(props=propertyStores.get(child._resourceID, None))
             results.append(child)
         
         returnValue(results)
@@ -2347,6 +2361,7 @@
                 RESOURCE_ID,
                 MD5,
                 character_length(XML_DATA),
+                XML_TYPE,
                 CREATED,
                 MODIFIED
             from NOTIFICATION
@@ -2357,23 +2372,17 @@
             (self._resourceID,
              self._md5,
              self._size,
+             self._xmlType,
              self._created,
              self._modified,) = tuple(rows[0])
-            yield self._loadPropertyStore()
+            self._loadPropertyStore()
             returnValue(self)
         else:
             returnValue(None)
 
-    @inlineCallbacks
     def _loadPropertyStore(self, props=None, created=False):
         if props is None:
-            props = yield PropertyStore.load(
-                self._home.uid(),
-                self._txn,
-                self._resourceID,
-                created=created
-            )
-        self.initPropertyStore(props)
+            props = NonePropertyStore(self._home.uid())
         self._propertyStore = props
 
 
@@ -2381,17 +2390,6 @@
         return self._propertyStore
 
 
-    def initPropertyStore(self, props):
-        # Setup peruser special properties
-        props.setSpecialProperties(
-            (
-            ),
-            (
-                PropertyName.fromElement(NotificationType),
-            ),
-        )
-
-
     @property
     def _txn(self):
         return self._home._txn
@@ -2415,7 +2413,7 @@
         Set the object resource data and update and cached metadata.
         """
 
-        xmltypeString = xmltype.toxml()
+        self._xmlType = NotificationType(xmltype)
         self._md5 = hashlib.md5(xmldata).hexdigest()
         self._size = len(xmldata)
         if inserting:
@@ -2429,10 +2427,10 @@
                   CREATED,
                   MODIFIED
                 """,
-                [self._home._resourceID, uid, xmltypeString, xmldata, self._md5]
+                [self._home._resourceID, uid, self._xmlType.toxml(), xmldata, self._md5]
             )
             self._resourceID, self._created, self._modified = rows[0]
-            yield self._loadPropertyStore()
+            self._loadPropertyStore()
         else:
             rows = yield self._txn.execSQL("""
                 update NOTIFICATION
@@ -2440,10 +2438,8 @@
                 where NOTIFICATION_HOME_RESOURCE_ID = %s and NOTIFICATION_UID = %s
                 returning MODIFIED
                 """,
-                [xmltypeString, xmldata, self._md5, self._home._resourceID, uid])
+                [self._xmlType.toxml(), xmldata, self._md5, self._home._resourceID, uid])
             self._modified = rows[0][0]
-
-        self.properties()[PropertyName.fromElement(NotificationType)] = NotificationType(xmltype)
         
         self._objectText = xmldata
 
@@ -2480,7 +2476,14 @@
     def size(self):
         return self._size
 
+    def xmlType(self):
+        # NB This is the NotificationType property element
+        if isinstance(self._xmlType, str):
+            # Convert into NotificationType property element
+            self._xmlType = WebDAVDocument.fromString(self._xmlType).root_element
 
+        return self._xmlType
+
     def created(self):
         utc = datetime.datetime.strptime(self._created, "%Y-%m-%d %H:%M:%S.%f")
         return datetimeMktime(utc)

Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql	2011-02-03 01:15:04 UTC (rev 6854)
@@ -89,8 +89,8 @@
   RESOURCE_ID                   integer      primary key default nextval('RESOURCE_ID_SEQ'),
   NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME,
   NOTIFICATION_UID              varchar(255) not null,
-  XML_TYPE                      varchar      not null,
-  XML_DATA                      varchar      not null,
+  XML_TYPE                      varchar(255) not null,
+  XML_DATA                      text         not null,
   MD5                           char(32)     not null,
   CREATED                       timestamp default timezone('UTC', CURRENT_TIMESTAMP),
   MODIFIED                      timestamp default timezone('UTC', CURRENT_TIMESTAMP),

Modified: CalendarServer/trunk/txdav/common/datastore/test/test_util.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/test/test_util.py	2011-02-03 01:14:28 UTC (rev 6853)
+++ CalendarServer/trunk/txdav/common/datastore/test/test_util.py	2011-02-03 01:15:04 UTC (rev 6854)
@@ -144,7 +144,7 @@
         transport = attachment.store(someAttachmentType)
         someAttachmentData = "Here is some data for your attachment, enjoy."
         transport.write(someAttachmentData)
-        transport.loseConnection()
+        yield transport.loseConnection()
         yield maybeCommit()
         self.topService.startService()
         yield self.subStarted
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110202/f03ec7a9/attachment-0001.html>


More information about the calendarserver-changes mailing list