[CalendarServer-changes] [6352] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Sep 23 08:37:08 PDT 2010


Revision: 6352
          http://trac.macosforge.org/projects/calendarserver/changeset/6352
Author:   cdaboo at apple.com
Date:     2010-09-23 08:37:06 -0700 (Thu, 23 Sep 2010)
Log Message:
-----------
Allow sync report on notification collections.

Modified Paths:
--------------
    CalendarServer/trunk/twistedcaldav/method/report_sync_collection.py
    CalendarServer/trunk/twistedcaldav/resource.py
    CalendarServer/trunk/twistedcaldav/storebridge.py
    CalendarServer/trunk/txdav/common/datastore/sql.py
    CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql
    CalendarServer/trunk/txdav/common/datastore/sql_tables.py

Modified: CalendarServer/trunk/twistedcaldav/method/report_sync_collection.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/report_sync_collection.py	2010-09-23 15:36:14 UTC (rev 6351)
+++ CalendarServer/trunk/twistedcaldav/method/report_sync_collection.py	2010-09-23 15:37:06 UTC (rev 6352)
@@ -46,8 +46,12 @@
     """
     Generate a sync-collection REPORT.
     """
-    if not self.isPseudoCalendarCollection() and not self.isAddressBookCollection() or not config.EnableSyncReport:
-        log.err("sync-collection report is only allowed on calendar/inbox/addressbook collection resources %s" % (self,))
+    if not config.EnableSyncReport or (
+        not self.isPseudoCalendarCollection() and
+        not self.isAddressBookCollection() and
+        not self.isNotificationCollection()
+    ):
+        log.err("sync-collection report is only allowed on calendar/inbox/addressbook/notification collection resources %s" % (self,))
         raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, davxml.SupportedReport()))
    
     responses = []

Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py	2010-09-23 15:36:14 UTC (rev 6351)
+++ CalendarServer/trunk/twistedcaldav/resource.py	2010-09-23 15:37:06 UTC (rev 6352)
@@ -930,6 +930,12 @@
         """
         return self.isSpecialCollection(carddavxml.AddressBook)
 
+    def isNotificationCollection(self):
+        """
+        See L{ICalDAVResource.isNotificationCollection}.
+        """
+        return self.isSpecialCollection(customxml.Notification)
+
     def isDirectoryBackedAddressBookCollection(self):       # ATM - temporary fix? (this one worked)
         return False
 
@@ -1202,8 +1208,12 @@
         if config.EnableCardDAV:
             result.append(davxml.Report(carddavxml.AddressBookQuery(),))
             result.append(davxml.Report(carddavxml.AddressBookMultiGet(),))
-        if (self.isPseudoCalendarCollection() or self.isAddressBookCollection()) and config.EnableSyncReport:
-            # Only allowed on calendar/inbox/addressbook collections
+        if (
+            self.isPseudoCalendarCollection() or
+            self.isAddressBookCollection() or
+            self.isNotificationCollection()
+        ) and config.EnableSyncReport:
+            # Only allowed on calendar/inbox/addressbook/notification collections
             result.append(davxml.Report(SyncCollection(),))
         return result
 
@@ -1332,12 +1342,15 @@
             revision = 0
 
         try:
-            changed, removed = self.index().whatchanged(revision)
+            changed, removed = self._indexWhatChanged(revision)
         except SyncTokenValidException:
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (dav_namespace, "valid-sync-token")))
 
         return changed, removed, current_token
 
+    def _indexWhatChanged(self, revision):
+        return self.index().whatchanged(revision)
+
     def getSyncToken(self):
         """
         Return current sync-token value.

Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py	2010-09-23 15:36:14 UTC (rev 6351)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py	2010-09-23 15:37:06 UTC (rev 6352)
@@ -1837,6 +1837,12 @@
     def isCollection(self):
         return True
 
+    def getSyncToken(self):
+        return self._newStoreNotifications.syncToken()
+
+    def _indexWhatChanged(self, revision):
+        return self._newStoreNotifications.resourceNamesSinceToken(revision)
+
     def addNotification(self, request, uid, xmltype, xmldata):
 
         self._newStoreNotifications.writeNotificationObject(uid, xmltype, xmldata)

Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py	2010-09-23 15:36:14 UTC (rev 6351)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py	2010-09-23 15:37:06 UTC (rev 6352)
@@ -44,7 +44,7 @@
 
 from txdav.common.datastore.sql_tables import CALENDAR_HOME_TABLE, \
     ADDRESSBOOK_HOME_TABLE, NOTIFICATION_HOME_TABLE, _BIND_MODE_OWN, \
-    _BIND_STATUS_ACCEPTED
+    _BIND_STATUS_ACCEPTED, NOTIFICATION_OBJECT_REVISIONS_TABLE
 from txdav.common.icommondatastore import HomeChildNameNotAllowedError, \
     HomeChildNameAlreadyExistsError, NoSuchHomeChildError, \
     ObjectResourceNameNotAllowedError, ObjectResourceNameAlreadyExistsError, \
@@ -242,14 +242,18 @@
         )
         if rows:
             resourceID = rows[0][0]
+            created = False
         else:
             resourceID = str(self.execSQL(
                 "insert into %(name)s (%(column_OWNER_UID)s) values (%%s) returning %(column_RESOURCE_ID)s" % NOTIFICATION_HOME_TABLE,
                 [uid]
             )[0][0])
-        return NotificationCollection(self, uid, resourceID)
+            created = True
+        collection = NotificationCollection(self, uid, resourceID)
+        if created:
+            collection._initSyncToken()
+        return collection
 
-
     def abort(self):
         if not self._completed:
             # print 'ABORTING', self._label
@@ -651,10 +655,10 @@
     def _initSyncToken(self):
         self._txn.execSQL("""
             insert into %(name)s
-            (%(column_RESOURCE_ID)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
-            values (%%s, %%s, nextval('%(sequence)s'), FALSE)
+            (%(column_HOME_RESOURCE_ID)s, %(column_RESOURCE_ID)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
+            values (%%s, %%s, %%s, nextval('%(sequence)s'), FALSE)
             """ % self._revisionsTable,
-            [self._resourceID, ""]
+            [self._home._resourceID, self._resourceID, ""]
         )
 
     def syncToken(self):
@@ -670,6 +674,30 @@
     def objectResourcesSinceToken(self, token):
         raise NotImplementedError()
 
+    def resourceNamesSinceToken(self, token):
+        results = [
+            (name.encode("utf-8"), deleted)
+            for name, deleted in
+            self._txn.execSQL("""
+                select %(column_RESOURCE_NAME)s, %(column_DELETED)s from %(name)s
+                where %(column_REVISION)s > %s and %(column_RESOURCE_ID)s = %s
+                """ % self._revisionsTable,
+                [token, self._resourceID],
+            )
+        ]
+        results.sort(key=lambda x:x[1])
+        
+        changed = []
+        deleted = []
+        for name, wasdeleted in results:
+            if name:
+                if wasdeleted:
+                    if token:
+                        deleted.append(name)
+                else:
+                    changed.append(name)
+        
+        return changed, deleted,
 
     def _updateSyncToken(self):
 
@@ -750,10 +778,10 @@
             else:
                 self._txn.execSQL("""
                     insert into %(name)s
-                    (%(column_RESOURCE_ID)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
-                    values (%%s, %%s, %%s, FALSE)
+                    (%(column_HOME_RESOURCE_ID)s, %(column_RESOURCE_ID)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
+                    values (%%s, %%s, %%s, %%s, FALSE)
                     """ % self._revisionsTable,
-                    [self._resourceID, name, nextrevision]
+                    [self._home._resourceID, self._resourceID, name, nextrevision]
                 )
             self._txn.execSQL("""
                 update %(name)s
@@ -762,6 +790,7 @@
                 """ % self._revisionsTable,
                 [nextrevision, self._resourceID, ""]
             )
+
     @cached
     def properties(self):
         props = PropertyStore(
@@ -928,10 +957,7 @@
     compareAttributes = '_uid _resourceID'.split()
 
     _objectResourceClass = None
-    _bindTable = None
-    _homeChildTable = None
-    _revisionsTable = None
-    _objectTable = None
+    _revisionsTable = NOTIFICATION_OBJECT_REVISIONS_TABLE
 
     def __init__(self, txn, uid, resourceID):
 
@@ -999,8 +1025,11 @@
             notificationObject = NotificationObject(self, None)
             inserting = True
         notificationObject.setData(uid, xmltype, xmldata, inserting=inserting)
+        if inserting:
+            self._insertRevision("%s.xml" % (uid,))
+        else:
+            self._updateRevision("%s.xml" % (uid,))
 
-
     def removeNotificationObjectWithName(self, name):
         self.removeNotificationObjectWithUID(self._nameToUID(name))
 
@@ -1012,12 +1041,32 @@
             [uid, self._resourceID]
         )
         self._notifications.pop(uid, None)
+        self._deleteRevision("%s.xml" % (uid,))
 
 
+    def _initSyncToken(self):
+        self._txn.execSQL("""
+            insert into %(name)s
+            (%(column_HOME_RESOURCE_ID)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
+            values (%%s, %%s, nextval('%(sequence)s'), FALSE)
+            """ % self._revisionsTable,
+            [self._resourceID, ""]
+        )
+
     def syncToken(self):
-        return 'dummy-sync-token'
+        revision = self._txn.execSQL(
+            """
+            select %(column_REVISION)s from %(name)s
+            where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
+            """ % self._revisionsTable,
+            [self._resourceID, ""]
+        )[0][0]
+        return "%s#%s" % (self._resourceID, revision,)
 
+    def objectResourcesSinceToken(self, token):
+        raise NotImplementedError()
 
+
     def notificationObjectsSinceToken(self, token):
         changed = []
         removed = []
@@ -1025,6 +1074,123 @@
         return (changed, removed, token)
 
 
+    def resourceNamesSinceToken(self, token):
+        results = [
+            (name.encode("utf-8"), deleted)
+            for name, deleted in
+            self._txn.execSQL("""
+                select %(column_RESOURCE_NAME)s, %(column_DELETED)s from %(name)s
+                where %(column_REVISION)s > %%s and %(column_HOME_RESOURCE_ID)s = %%s
+                """ % self._revisionsTable,
+                [token, self._resourceID],
+            )
+        ]
+        results.sort(key=lambda x:x[1])
+        
+        changed = []
+        deleted = []
+        for name, wasdeleted in results:
+            if name:
+                if wasdeleted:
+                    if token:
+                        deleted.append(name)
+                else:
+                    changed.append(name)
+        
+        return changed, deleted,
+
+    def _updateSyncToken(self):
+
+        self._txn.execSQL("""
+            update %(name)s
+            set (%(column_REVISION)s) = (nextval('%(sequence)s'))
+            where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
+            """ % self._revisionsTable,
+            [self._resourceID, ""]
+        )
+
+    def _insertRevision(self, name):
+        self._changeRevision("insert", name)
+
+    def _updateRevision(self, name):
+        self._changeRevision("update", name)
+
+    def _deleteRevision(self, name):
+        self._changeRevision("delete", name)
+
+    def _changeRevision(self, action, name):
+
+        nextrevision = self._txn.execSQL("""
+            select nextval('%(sequence)s')
+            """ % self._revisionsTable
+        )
+
+        if action == "delete":
+            self._txn.execSQL("""
+                update %(name)s
+                set (%(column_REVISION)s, %(column_DELETED)s) = (%%s, TRUE)
+                where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
+                """ % self._revisionsTable,
+                [nextrevision, self._resourceID, name]
+            )
+            self._txn.execSQL("""
+                update %(name)s
+                set (%(column_REVISION)s) = (%%s)
+                where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
+                """ % self._revisionsTable,
+                [nextrevision, self._resourceID, ""]
+            )
+        elif action == "update":
+            self._txn.execSQL("""
+                update %(name)s
+                set (%(column_REVISION)s) = (%%s)
+                where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
+                """ % self._revisionsTable,
+                [nextrevision, self._resourceID, name]
+            )
+            self._txn.execSQL("""
+                update %(name)s
+                set (%(column_REVISION)s) = (%%s)
+                where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
+                """ % self._revisionsTable,
+                [nextrevision, self._resourceID, ""]
+            )
+        elif action == "insert":
+            # Note that an "insert" may happen for a resource that previously existed and then
+            # was deleted. In that case an entry in the REVISIONS table still exists so we have to
+            # detect that and do db INSERT or UPDATE as appropriate
+
+            self._txn.execSQL("""
+                select %(column_HOME_RESOURCE_ID)s from %(name)s
+                where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
+                """ % self._revisionsTable,
+                [self._resourceID, name, ]
+            )
+            found = self._txn._cursor.rowcount != 0
+            if found:
+                self._txn.execSQL("""
+                    update %(name)s
+                    set (%(column_REVISION)s, %(column_DELETED)s) = (%%s, FALSE)
+                    where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
+                    """ % self._revisionsTable,
+                    [nextrevision, self._resourceID, name]
+                )
+            else:
+                self._txn.execSQL("""
+                    insert into %(name)s
+                    (%(column_HOME_RESOURCE_ID)s, %(column_RESOURCE_NAME)s, %(column_REVISION)s, %(column_DELETED)s)
+                    values (%%s, %%s, %%s, FALSE)
+                    """ % self._revisionsTable,
+                    [self._resourceID, name, nextrevision]
+                )
+            self._txn.execSQL("""
+                update %(name)s
+                set (%(column_REVISION)s) = (%%s)
+                where %(column_HOME_RESOURCE_ID)s = %%s and %(column_RESOURCE_NAME)s = %%s
+                """ % self._revisionsTable,
+                [nextrevision, self._resourceID, ""]
+            )
+
     @cached
     def properties(self):
         return PropertyStore(

Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql	2010-09-23 15:36:14 UTC (rev 6351)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema_v1.sql	2010-09-23 15:37:06 UTC (rev 6352)
@@ -211,27 +211,6 @@
 );
 
 
-------------------------------
--- Calendar Object Revision --
-------------------------------
-
-create sequence CALENDAR_OBJECT_REVISION_SEQ;
-
-
--------------------------------
--- Calendar Object Revisions --
--------------------------------
-
-create table CALENDAR_OBJECT_REVISIONS (
-  CALENDAR_RESOURCE_ID integer      not null references CALENDAR on delete cascade,
-  RESOURCE_NAME        varchar(255) not null,
-  REVISION             integer      not null,
-  DELETED              boolean      not null,
-
-  unique(CALENDAR_RESOURCE_ID, RESOURCE_NAME)
-);
-
-
 ------------------
 -- iTIP Message --
 ------------------
@@ -318,24 +297,54 @@
   unique(ADDRESSBOOK_RESOURCE_ID, VCARD_UID)
 );
 
-------------------------------
--- AddressBook Object Revision --
-------------------------------
+---------------
+-- Revisions --
+---------------
 
-create sequence ADDRESSBOOK_OBJECT_REVISION_SEQ;
+create sequence REVISION_SEQ;
 
 
+---------------
+-- Revisions --
+---------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+  CALENDAR_HOME_RESOURCE_ID integer      not null references CALENDAR_HOME,
+  CALENDAR_RESOURCE_ID      integer      not null references CALENDAR on delete cascade,
+  RESOURCE_NAME             varchar(255) not null,
+  REVISION                  integer      not null,
+  DELETED                   boolean      not null,
+
+  unique(CALENDAR_RESOURCE_ID, RESOURCE_NAME)
+);
+
+
 -------------------------------
 -- AddressBook Object Revisions --
 -------------------------------
 
 create table ADDRESSBOOK_OBJECT_REVISIONS (
-  ADDRESSBOOK_RESOURCE_ID integer      not null references ADDRESSBOOK on delete cascade,
-  RESOURCE_NAME           varchar(255) not null,
-  REVISION                integer      not null,
-  DELETED                 boolean      not null,
+  ADDRESSBOOK_HOME_RESOURCE_ID integer      not null references ADDRESSBOOK_HOME,
+  ADDRESSBOOK_RESOURCE_ID      integer      not null references ADDRESSBOOK on delete cascade,
+  RESOURCE_NAME                varchar(255) not null,
+  REVISION                     integer      not null,
+  DELETED                      boolean      not null,
 
   unique(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME)
 );
 
 
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+  NOTIFICATION_HOME_RESOURCE_ID integer      not null references NOTIFICATION_HOME on delete cascade,
+  RESOURCE_NAME                 varchar(255) not null,
+  REVISION                      integer      not null,
+  DELETED                       boolean      not null,
+
+  unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME)
+);
+
+

Modified: CalendarServer/trunk/txdav/common/datastore/sql_tables.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_tables.py	2010-09-23 15:36:14 UTC (rev 6351)
+++ CalendarServer/trunk/txdav/common/datastore/sql_tables.py	2010-09-23 15:37:06 UTC (rev 6352)
@@ -77,7 +77,8 @@
 
 CALENDAR_OBJECT_REVISIONS_TABLE = {
     "name"                    : "CALENDAR_OBJECT_REVISIONS",
-    "sequence"                : "CALENDAR_OBJECT_REVISION_SEQ",
+    "sequence"                : "REVISION_SEQ",
+    "column_HOME_RESOURCE_ID" : "CALENDAR_HOME_RESOURCE_ID",
     "column_RESOURCE_ID"      : "CALENDAR_RESOURCE_ID",
     "column_RESOURCE_NAME"    : "RESOURCE_NAME",
     "column_REVISION"         : "REVISION",
@@ -86,13 +87,23 @@
 
 ADDRESSBOOK_OBJECT_REVISIONS_TABLE = {
     "name"                    : "ADDRESSBOOK_OBJECT_REVISIONS",
-    "sequence"                : "ADDRESSBOOK_OBJECT_REVISION_SEQ",
+    "sequence"                : "REVISION_SEQ",
+    "column_HOME_RESOURCE_ID" : "ADDRESSBOOK_HOME_RESOURCE_ID",
     "column_RESOURCE_ID"      : "ADDRESSBOOK_RESOURCE_ID",
     "column_RESOURCE_NAME"    : "RESOURCE_NAME",
     "column_REVISION"         : "REVISION",
     "column_DELETED"          : "DELETED",
 }
 
+NOTIFICATION_OBJECT_REVISIONS_TABLE = {
+    "name"                    : "NOTIFICATION_OBJECT_REVISIONS",
+    "sequence"                : "REVISION_SEQ",
+    "column_HOME_RESOURCE_ID" : "NOTIFICATION_HOME_RESOURCE_ID",
+    "column_RESOURCE_NAME"    : "RESOURCE_NAME",
+    "column_REVISION"         : "REVISION",
+    "column_DELETED"          : "DELETED",
+}
+
 CALENDAR_OBJECT_TABLE = {
     "name"                      : "CALENDAR_OBJECT",
     "column_RESOURCE_ID"        : "RESOURCE_ID",
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100923/16725612/attachment-0001.html>


More information about the calendarserver-changes mailing list