[CalendarServer-changes] [6152] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Fri Aug 20 09:22:29 PDT 2010
Revision: 6152
http://trac.macosforge.org/projects/calendarserver/changeset/6152
Author: cdaboo at apple.com
Date: 2010-08-20 09:22:29 -0700 (Fri, 20 Aug 2010)
Log Message:
-----------
Fix webdav sync report with postgres. This includes a minor tweak to bring it into line with the
current spec.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/index.py
CalendarServer/trunk/twistedcaldav/method/copymove_contact.py
CalendarServer/trunk/twistedcaldav/resource.py
CalendarServer/trunk/twistedcaldav/sql.py
CalendarServer/trunk/twistedcaldav/storebridge.py
CalendarServer/trunk/twistedcaldav/test/test_index.py
CalendarServer/trunk/twistedcaldav/test/test_vcardindex.py
CalendarServer/trunk/twistedcaldav/vcardindex.py
CalendarServer/trunk/txcaldav/calendarstore/file.py
CalendarServer/trunk/txcaldav/calendarstore/postgres.py
CalendarServer/trunk/txcaldav/calendarstore/postgres_schema_v1.sql
CalendarServer/trunk/txcaldav/calendarstore/util.py
CalendarServer/trunk/txcarddav/addressbookstore/file.py
CalendarServer/trunk/txdav/common/datastore/file.py
Modified: CalendarServer/trunk/twistedcaldav/index.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/index.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/twistedcaldav/index.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -183,7 +183,7 @@
if name is not None and self.resource.getChild(name_utf8) is None:
# Clean up
log.err("Stale resource record found for child %s with UID %s in %s" % (name, uid, self.resource))
- self._delete_from_db(name, uid, None)
+ self._delete_from_db(name, uid, False)
self._db_commit()
else:
resources.append(name_utf8)
@@ -215,7 +215,7 @@
return uid
- def addResource(self, name, calendar, revision, fast=False, reCreate=False):
+ def addResource(self, name, calendar, fast=False, reCreate=False):
"""
Adding or updating an existing resource.
To check for an update we attempt to get an existing UID
@@ -228,12 +228,12 @@
"""
oldUID = self.resourceUIDForName(name)
if oldUID is not None:
- self._delete_from_db(name, oldUID, None)
- self._add_to_db(name, calendar, revision, reCreate=reCreate)
+ self._delete_from_db(name, oldUID, False)
+ self._add_to_db(name, calendar, reCreate=reCreate)
if not fast:
self._db_commit()
- def deleteResource(self, name, revision):
+ def deleteResource(self, name):
"""
Remove this resource from the index.
@param name: the name of the resource to add.
@@ -241,7 +241,7 @@
"""
uid = self.resourceUIDForName(name)
if uid is not None:
- self._delete_from_db(name, uid, revision)
+ self._delete_from_db(name, uid)
self._db_commit()
def resourceExists(self, name):
@@ -279,16 +279,15 @@
def whatchanged(self, revision):
- results = [(name.encode("utf-8"), created, wasdeleted) for name, created, wasdeleted in self._db_execute("select NAME, CREATEDREVISION, WASDELETED from REVISIONS where REVISION > :1", revision)]
+ results = [(name.encode("utf-8"), deleted) for name, deleted in self._db_execute("select NAME, DELETED from REVISIONS where REVISION > :1", revision)]
results.sort(key=lambda x:x[1])
changed = []
deleted = []
- for name, created, wasdeleted in results:
+ for name, wasdeleted in results:
if name:
if wasdeleted == 'Y':
- # Don't report items that were created/deleted since the requested revision
- if created <= revision:
+ if revision:
deleted.append(name)
else:
changed.append(name)
@@ -297,6 +296,24 @@
return changed, deleted,
+ def lastRevision(self):
+ return self._db_value_for_sql(
+ "select REVISION from REVISION_SEQUENCE"
+ )
+
+ def bumpRevision(self, fast=False):
+ self._db_execute(
+ """
+ update REVISION_SEQUENCE set REVISION = REVISION + 1
+ """,
+ )
+ self._db_commit()
+ return self._db_value_for_sql(
+ """
+ select REVISION from REVISION_SEQUENCE
+ """,
+ )
+
def indexedSearch(self, filter, useruid="", fbtype=False):
"""
Finds resources matching the given qualifiers.
@@ -400,7 +417,7 @@
"""
return schema_version
- def _add_to_db(self, name, calendar, revision, cursor=None, expand_until=None, reCreate=False):
+ def _add_to_db(self, name, calendar, cursor=None, expand_until=None, reCreate=False):
"""
Records the given calendar resource in the index with the given name.
Resource names and UIDs must both be unique; only one resource name may
@@ -413,7 +430,7 @@
"""
raise NotImplementedError
- def _delete_from_db(self, name, uid, revision):
+ def _delete_from_db(self, name, uid, dorevision=True):
"""
Deletes the specified entry from all dbs.
@param name: the name of the resource to delete.
@@ -535,11 +552,22 @@
#
q.execute(
"""
+ create table REVISION_SEQUENCE (
+ REVISION integer
+ )
+ """
+ )
+ q.execute(
+ """
+ insert into REVISION_SEQUENCE (REVISION) values (0)
+ """
+ )
+ q.execute(
+ """
create table REVISIONS (
NAME text unique,
REVISION integer,
- CREATEDREVISION integer,
- WASDELETED text(1)
+ DELETED text(1)
)
"""
)
@@ -613,10 +641,10 @@
with a longer expansion.
"""
calendar = self.resource.getChild(name).iCalendar()
- self._add_to_db(name, calendar, None, expand_until=expand_until, reCreate=True)
+ self._add_to_db(name, calendar, expand_until=expand_until, reCreate=True)
self._db_commit()
- def _add_to_db(self, name, calendar, revision, cursor = None, expand_until=None, reCreate=False):
+ def _add_to_db(self, name, calendar, cursor = None, expand_until=None, reCreate=False):
"""
Records the given calendar resource in the index with the given name.
Resource names and UIDs must both be unique; only one resource name may
@@ -654,7 +682,7 @@
log.err("Invalid instance %s when indexing %s in %s" % (e.rid, name, self.resource,))
raise
- self._delete_from_db(name, uid, None)
+ self._delete_from_db(name, uid, False)
# Add RESOURCE item
self._db_execute(
@@ -738,30 +766,26 @@
""", peruserid, instanceid, 'T' if transp else 'F'
)
- if revision is not None:
- created = self._db_value_for_sql("select CREATEDREVISION from REVISIONS where NAME = :1", name)
- if created is None:
- created = revision
- self._db_execute(
- """
- insert or replace into REVISIONS (NAME, REVISION, CREATEDREVISION, WASDELETED)
- values (:1, :2, :3, :4)
- """, name, revision, revision, 'N',
- )
+ self._db_execute(
+ """
+ insert or replace into REVISIONS (NAME, REVISION, DELETED)
+ values (:1, :2, :3)
+ """, name, self.bumpRevision(fast=True), 'N',
+ )
- def _delete_from_db(self, name, uid, revision):
+ def _delete_from_db(self, name, uid, dorevision=True):
"""
Deletes the specified entry from all dbs.
@param name: the name of the resource to delete.
@param uid: the uid of the resource to delete.
"""
self._db_execute("delete from RESOURCE where NAME = :1", name)
- if revision is not None:
+ if dorevision:
self._db_execute(
"""
- update REVISIONS SET REVISION = :1, WASDELETED = :2
+ update REVISIONS SET REVISION = :1, DELETED = :2
where NAME = :3
- """, revision, 'Y', name
+ """, self.bumpRevision(fast=True), 'Y', name
)
@@ -1019,16 +1043,13 @@
log.err("Non-calendar resource: %s" % (name,))
else:
#log.msg("Indexing resource: %s" % (name,))
- self.addResource(name, calendar, 0, True, reCreate=True)
+ self.addResource(name, calendar, True, reCreate=True)
finally:
stream.close()
# Do commit outside of the loop for better performance
if do_commit:
self._db_commit()
-
- # Need new sync-token
- self.resource.initSyncToken()
class IndexSchedule (CalendarIndex):
"""
@@ -1126,13 +1147,10 @@
log.err("Non-calendar resource: %s" % (name,))
else:
#log.msg("Indexing resource: %s" % (name,))
- self.addResource(name, calendar, 0, True, reCreate=True)
+ self.addResource(name, calendar, True, reCreate=True)
finally:
stream.close()
# Do commit outside of the loop for better performance
if do_commit:
self._db_commit()
-
- # Need new sync-token
- self.resource.initSyncToken()
Modified: CalendarServer/trunk/twistedcaldav/method/copymove_contact.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/copymove_contact.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/twistedcaldav/method/copymove_contact.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -119,10 +119,6 @@
result, sourceadbk, sourceparent, destination_uri, destination, destinationadbk, destinationparent = (yield checkForAddressBookAction(self, request))
if not result or not destinationadbk:
- # assume it will work and dirty caches
- if isAddressBookCollectionResource(self):
- yield self.updateCTag()
-
# Do default WebDAV action
returnValue(KEEP_GOING)
Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/twistedcaldav/resource.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -354,6 +354,7 @@
baseProperties += (
caldavxml.SupportedCalendarComponentSet.qname(),
caldavxml.SupportedCalendarData.qname(),
+ customxml.GETCTag.qname(),
)
if self.isCalendarCollection():
@@ -366,6 +367,7 @@
baseProperties += (
davxml.ResourceID.qname(),
carddavxml.SupportedAddressData.qname(),
+ customxml.GETCTag.qname(),
customxml.PubSubXMPPPushKeyProperty.qname(),
)
@@ -532,6 +534,11 @@
elif qname == davxml.ResourceID.qname():
returnValue(davxml.ResourceID(davxml.HRef.fromString(self.resourceID())))
+ elif qname == customxml.GETCTag.qname() and (
+ self.isPseudoCalendarCollection() or self.isAddressBookCollection()
+ ):
+ returnValue(customxml.GETCTag.fromString(self.getSyncToken()))
+
elif qname == davxml.SyncToken.qname() and config.EnableSyncReport and (
self.isPseudoCalendarCollection() or self.isAddressBookCollection()
):
@@ -1305,7 +1312,7 @@
def whatchanged(self, client_token):
- current_token = str(self.readDeadProperty(customxml.GETCTag))
+ current_token = self.getSyncToken()
current_uuid, current_revision = current_token.split("#", 1)
current_revision = int(current_revision)
@@ -1331,76 +1338,12 @@
return changed, removed, current_token
- @inlineCallbacks
- def bumpSyncToken(self):
- """
- Increment the sync-token which is also the ctag.
-
- return: a deferred that returns the new revision number
- """
- assert self.isCollection()
-
- # Need to lock
- lock = MemcacheLock("ResourceLock", self.resourceID(), timeout=60.0)
- try:
- try:
- yield lock.acquire()
- except MemcacheLockTimeoutError:
- raise HTTPError(StatusResponse(responsecode.CONFLICT, "Resource: %s currently in use on the server." % (self.uri,)))
-
- try:
- token = str(self.readDeadProperty(customxml.GETCTag))
- caluuid, revision = token.split("#", 1)
- revision = int(revision) + 1
- token = "%s#%d" % (caluuid, revision,)
-
- except (HTTPError, ValueError):
- # Initialise it
- caluuid = uuid4()
- revision = 1
- token = "%s#%d" % (caluuid, revision,)
-
- yield self.updateCTag(token)
- returnValue(revision)
- finally:
- yield lock.clean()
-
- def initSyncToken(self):
- """
- Create a new sync-token which is also the ctag.
- """
- # FIXME: new implementation is in txcaldav.file, this should be
- # deleted.
- assert self.isCollection()
- # Initialise it
- caluuid = uuid4()
- revision = 1
- token = "%s#%d" % (caluuid, revision,)
- try:
- self.writeDeadProperty(customxml.GETCTag(token))
- except:
- return fail(Failure())
-
def getSyncToken(self):
"""
Return current sync-token value.
"""
- assert self.isCollection()
-
- return str(self.readDeadProperty(customxml.GETCTag))
+ raise NotImplementedError
- def updateCTag(self, token=None):
- assert self.isCollection()
-
- if not token:
- token = str(datetime.datetime.now())
- try:
- self.writeDeadProperty(customxml.GETCTag(token))
- except:
- return fail(Failure())
-
- return succeed(True)
-
#
# Stuff from CalDAVFile
#
Modified: CalendarServer/trunk/twistedcaldav/sql.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/sql.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/twistedcaldav/sql.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -190,7 +190,10 @@
self._db_init_data_tables(q)
self._db_recreate(False)
- q.execute("commit")
+ try:
+ q.execute("commit")
+ except DatabaseError:
+ pass
self._db_connection.isolation_level = old_isolation
Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -310,6 +310,22 @@
)
+ def name(self):
+ return self._newStoreCalendar.name()
+
+ def etag(self):
+ return ETag(self._newStoreCalendar.md5())
+
+ def lastModified(self):
+ return self._newStoreCalendar.modified()
+
+ def creationDate(self):
+ return self._newStoreCalendar.created()
+
+ def getSyncToken(self):
+ return self._newStoreCalendar.syncToken()
+
+
def provisionFile(self):
pass
@@ -678,6 +694,9 @@
def creationDate(self):
return self._newStoreCalendar.created()
+ def getSyncToken(self):
+ return self._newStoreCalendar.syncToken()
+
def isCollection(self):
return True
@@ -1312,6 +1331,9 @@
def creationDate(self):
return self._newStoreAddressBook.created()
+ def getSyncToken(self):
+ return self._newStoreAddressBook.syncToken()
+
def isCollection(self):
return True
Modified: CalendarServer/trunk/twistedcaldav/test/test_index.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_index.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/twistedcaldav/test/test_index.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -254,19 +254,17 @@
),
)
- revision = 0
for description, name, calendar_txt, reCreate, ok in data:
- revision += 1
calendar = Component.fromString(calendar_txt)
if ok:
f = open(os.path.join(self.indexDirPath.path, name), "w")
f.write(calendar_txt)
del f
- self.db.addResource(name, calendar, revision, reCreate=reCreate)
+ self.db.addResource(name, calendar, reCreate=reCreate)
self.assertTrue(self.db.resourceExists(name), msg=description)
else:
- self.assertRaises(InvalidOverriddenInstanceError, self.db.addResource, name, calendar, revision)
+ self.assertRaises(InvalidOverriddenInstanceError, self.db.addResource, name, calendar)
self.assertFalse(self.db.resourceExists(name), msg=description)
self.db._db_recreate()
@@ -428,16 +426,14 @@
),
)
- revision = 0
for description, name, calendar_txt, trstart, trend, organizer, instances in data:
- revision += 1
calendar = Component.fromString(calendar_txt)
f = open(os.path.join(self.indexDirPath.path, name), "w")
f.write(calendar_txt)
del f
- self.db.addResource(name, calendar, revision)
+ self.db.addResource(name, calendar)
self.assertTrue(self.db.resourceExists(name), msg=description)
# Create fake filter element to match time-range
@@ -827,16 +823,14 @@
),
)
- revision = 0
for description, name, calendar_txt, trstart, trend, organizer, peruserinstances in data:
- revision += 1
calendar = Component.fromString(calendar_txt)
f = open(os.path.join(self.indexDirPath.path, name), "w")
f.write(calendar_txt)
del f
- self.db.addResource(name, calendar, revision)
+ self.db.addResource(name, calendar)
self.assertTrue(self.db.resourceExists(name), msg=description)
# Create fake filter element to match time-range
@@ -863,8 +857,7 @@
self.assertEqual(set(instances), index_results, msg="%s, user:%s" % (description, useruid,))
- revision += 1
- self.db.deleteResource(name, revision)
+ self.db.deleteResource(name)
def test_index_revisions(self):
data1 = """BEGIN:VCALENDAR
@@ -910,17 +903,17 @@
"""
calendar = Component.fromString(data1)
- self.db.addResource("data1.ics", calendar, 1)
+ self.db.addResource("data1.ics", calendar)
calendar = Component.fromString(data2)
- self.db.addResource("data2.ics", calendar, 2)
+ self.db.addResource("data2.ics", calendar)
calendar = Component.fromString(data3)
- self.db.addResource("data3.ics", calendar, 3)
- self.db.deleteResource("data3.ics", 4)
+ self.db.addResource("data3.ics", calendar)
+ self.db.deleteResource("data3.ics")
tests = (
(0, (["data1.ics", "data2.ics",], [],)),
- (1, (["data2.ics",], [],)),
- (2, ([], [],)),
+ (1, (["data2.ics",], ["data3.ics",],)),
+ (2, ([], ["data3.ics",],)),
(3, ([], ["data3.ics",],)),
(4, ([], [],)),
(5, ([], [],)),
Modified: CalendarServer/trunk/twistedcaldav/test/test_vcardindex.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_vcardindex.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/twistedcaldav/test/test_vcardindex.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -134,15 +134,13 @@
),
)
- revision = 0
for description, name, vcard_txt in data:
- revision += 1
calendar = Component.fromString(vcard_txt)
f = open(os.path.join(self.site.resource.fp.path, name), "w")
f.write(vcard_txt)
del f
- self.db.addResource(name, calendar, revision)
+ self.db.addResource(name, calendar)
self.assertTrue(self.db.resourceExists(name), msg=description)
self.db._db_recreate()
@@ -179,17 +177,17 @@
"""
vcard = Component.fromString(data1)
- self.db.addResource("data1.vcf", vcard, 1)
+ self.db.addResource("data1.vcf", vcard)
vcard = Component.fromString(data2)
- self.db.addResource("data2.vcf", vcard, 2)
+ self.db.addResource("data2.vcf", vcard)
vcard = Component.fromString(data3)
- self.db.addResource("data3.vcf", vcard, 3)
- self.db.deleteResource("data3.vcf", 4)
+ self.db.addResource("data3.vcf", vcard)
+ self.db.deleteResource("data3.vcf")
tests = (
(0, (["data1.vcf", "data2.vcf",], [],)),
- (1, (["data2.vcf",], [],)),
- (2, ([], [],)),
+ (1, (["data2.vcf",], ["data3.vcf",],)),
+ (2, ([], ["data3.vcf",],)),
(3, ([], ["data3.vcf",],)),
(4, ([], [],)),
(5, ([], [],)),
Modified: CalendarServer/trunk/twistedcaldav/vcardindex.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/vcardindex.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/twistedcaldav/vcardindex.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -300,7 +300,7 @@
if name is not None and self.resource.getChild(name_utf8) is None:
# Clean up
log.err("Stale resource record found for child %s with UID %s in %s" % (name, uid, self.resource))
- self._delete_from_db(name, uid, None)
+ self._delete_from_db(name, uid, False)
self._db_commit()
else:
resources.append(name_utf8)
@@ -332,7 +332,7 @@
return uid
- def addResource(self, name, vcard, revision, fast=False):
+ def addResource(self, name, vcard, fast=False):
"""
Adding or updating an existing resource.
To check for an update we attempt to get an existing UID
@@ -345,12 +345,12 @@
"""
oldUID = self.resourceUIDForName(name)
if oldUID is not None:
- self._delete_from_db(name, oldUID, None)
- self._add_to_db(name, vcard, revision)
+ self._delete_from_db(name, oldUID, False)
+ self._add_to_db(name, vcard)
if not fast:
self._db_commit()
- def deleteResource(self, name, revision):
+ def deleteResource(self, name):
"""
Remove this resource from the index.
@param name: the name of the resource to add.
@@ -358,7 +358,7 @@
"""
uid = self.resourceUIDForName(name)
if uid is not None:
- self._delete_from_db(name, uid, revision)
+ self._delete_from_db(name, uid)
self._db_commit()
def resourceExists(self, name):
@@ -387,16 +387,15 @@
def whatchanged(self, revision):
- results = [(name.encode("utf-8"), created, wasdeleted) for name, created, wasdeleted in self._db_execute("select NAME, CREATEDREVISION, WASDELETED from REVISIONS where REVISION > :1", revision)]
+ results = [(name.encode("utf-8"), deleted) for name, deleted in self._db_execute("select NAME, DELETED from REVISIONS where REVISION > :1", revision)]
results.sort(key=lambda x:x[1])
changed = []
deleted = []
- for name, created, wasdeleted in results:
+ for name, wasdeleted in results:
if name:
if wasdeleted == 'Y':
- # Don't report items that were created/deleted since the requested revision
- if created <= revision:
+ if revision:
deleted.append(name)
else:
changed.append(name)
@@ -405,6 +404,25 @@
return changed, deleted,
+ def lastRevision(self):
+ return self._db_value_for_sql(
+ "select REVISION from REVISION_SEQUENCE"
+ )
+
+ def bumpRevision(self, fast=False):
+ self._db_execute(
+ """
+ update REVISION_SEQUENCE set REVISION = REVISION + 1
+ """,
+ )
+ if not fast:
+ self._db_commit()
+ return self._db_value_for_sql(
+ """
+ select REVISION from REVISION_SEQUENCE
+ """,
+ )
+
def searchValid(self, filter):
if isinstance(filter, carddavxml.Filter):
qualifiers = addressbookquery.sqladdressbookquery(filter)
@@ -512,11 +530,22 @@
#
q.execute(
"""
+ create table REVISION_SEQUENCE (
+ REVISION integer
+ )
+ """
+ )
+ q.execute(
+ """
+ insert into REVISION_SEQUENCE (REVISION) values (0)
+ """
+ )
+ q.execute(
+ """
create table REVISIONS (
NAME text unique,
REVISION integer default 0,
- CREATEDREVISION integer default 0,
- WASDELETED text(1) default "N"
+ DELETED text(1) default "N"
)
"""
)
@@ -570,7 +599,7 @@
log.err("Non-addressbook resource: %s" % (name,))
else:
#log.msg("Indexing resource: %s" % (name,))
- self.addResource(name, vcard, 0, True)
+ self.addResource(name, vcard, True)
finally:
stream.close()
@@ -578,9 +607,6 @@
if do_commit:
self._db_commit()
- # Need sync-token
- self.resource.initSyncToken()
-
def _db_can_upgrade(self, old_version):
"""
Can we do an in-place upgrade
@@ -598,6 +624,18 @@
if old_version < 2:
q.execute(
"""
+ create table REVISION_SEQUENCE (
+ REVISION integer
+ )
+ """
+ )
+ q.execute(
+ """
+ insert into REVISION_SEQUENCE (REVISION) values (0)
+ """
+ )
+ q.execute(
+ """
create table REVISIONS (
NAME text unique,
REVISION integer default 0,
@@ -620,7 +658,7 @@
)
- def _add_to_db(self, name, vcard, revision, cursor = None):
+ def _add_to_db(self, name, vcard, cursor = None):
"""
Records the given address book resource in the index with the given name.
Resource names and UIDs must both be unique; only one resource name may
@@ -640,28 +678,24 @@
""", name, uid,
)
- if revision is not None:
- created = self._db_value_for_sql("select CREATEDREVISION from REVISIONS where NAME = :1", name)
- if created is None:
- created = revision
- self._db_execute(
- """
- insert or replace into REVISIONS (NAME, REVISION, CREATEDREVISION, WASDELETED)
- values (:1, :2, :3, :4)
- """, name, revision, revision, 'N',
- )
+ self._db_execute(
+ """
+ insert or replace into REVISIONS (NAME, REVISION, DELETED)
+ values (:1, :2, :3)
+ """, name, self.bumpRevision(fast=True), 'N',
+ )
- def _delete_from_db(self, name, uid, revision):
+ def _delete_from_db(self, name, uid, dorevision=True):
"""
Deletes the specified entry from all dbs.
@param name: the name of the resource to delete.
@param uid: the uid of the resource to delete.
"""
self._db_execute("delete from RESOURCE where NAME = :1", name)
- if revision is not None:
+ if dorevision:
self._db_execute(
"""
- update REVISIONS SET REVISION = :1, WASDELETED = :2
+ update REVISIONS SET REVISION = :1, DELETED = :2
where NAME = :3
- """, revision, 'Y', name
+ """, self.bumpRevision(fast=True), 'Y', name
)
Modified: CalendarServer/trunk/txcaldav/calendarstore/file.py
===================================================================
--- CalendarServer/trunk/txcaldav/calendarstore/file.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/txcaldav/calendarstore/file.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -58,7 +58,7 @@
from txdav.common.datastore.file import (
CommonDataStore, CommonStoreTransaction, CommonHome, CommonHomeChild,
CommonObjectResource
-)
+, CommonStubResource)
from txdav.common.icommondatastore import (NoSuchObjectResourceError,
InternalDataStoreError)
@@ -230,9 +230,8 @@
def setComponent(self, component):
validateCalendarComponent(self, self._calendar, component)
- newRevision = self._calendar._updateSyncToken() # FIXME: test
self._calendar.retrieveOldIndex().addResource(
- self.name(), component, newRevision
+ self.name(), component
)
self._component = component
@@ -480,26 +479,17 @@
-class CalendarStubResource(object):
+class CalendarStubResource(CommonStubResource):
"""
Just enough resource to keep the calendar's sql DB classes going.
"""
- def __init__(self, calendar):
- self.calendar = calendar
-
-
- @property
- def fp(self):
- return self.calendar._path
-
-
def isCalendarCollection(self):
return True
def getChild(self, name):
- calendarObject = self.calendar.calendarObjectWithName(name)
+ calendarObject = self.resource.calendarObjectWithName(name)
if calendarObject:
class ChildResource(object):
def __init__(self, calendarObject):
@@ -513,17 +503,7 @@
return None
- def bumpSyncToken(self, reset=False):
- # FIXME: needs direct tests
- return self.calendar._updateSyncToken(reset)
-
- def initSyncToken(self):
- # FIXME: needs direct tests
- self.bumpSyncToken(True)
-
-
-
class Index(object):
#
# OK, here's where we get ugly.
Modified: CalendarServer/trunk/txcaldav/calendarstore/postgres.py
===================================================================
--- CalendarServer/trunk/txcaldav/calendarstore/postgres.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/txcaldav/calendarstore/postgres.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -55,7 +55,8 @@
ObjectResourceNameAlreadyExistsError, HomeChildNameAlreadyExistsError,
NoSuchHomeChildError, NoSuchObjectResourceError)
from txcaldav.calendarstore.util import (validateCalendarComponent,
- validateAddressBookComponent, dropboxIDFromCalendarObject, SyncTokenHelper)
+ validateAddressBookComponent, dropboxIDFromCalendarObject, CalendarSyncTokenHelper,
+ AddressbookSyncTokenHelper)
from txdav.datastore.file import cached
from txcaldav.icalendarstore import (ICalendarTransaction, ICalendarHome,
@@ -75,7 +76,8 @@
from twistedcaldav.config import config
from twistedcaldav.customxml import NotificationType
from twistedcaldav.dateops import normalizeForIndex
-from twistedcaldav.index import IndexedSearchException, ReservationError
+from twistedcaldav.index import IndexedSearchException, ReservationError,\
+ SyncTokenValidException
from twistedcaldav.instance import InvalidOverriddenInstanceError
from twistedcaldav.memcachepool import CachePoolUserMixIn
from twistedcaldav.notifications import NotificationRecord
@@ -324,9 +326,8 @@
validateCalendarComponent(self, self._calendar, component)
self.updateDatabase(component)
+ self._calendar._updateRevision(self._name)
- self._calendar._updateSyncToken()
-
if self._calendar._notifier:
self._calendar._home._txn.postCommit(self._calendar._notifier.notify)
@@ -1267,6 +1268,33 @@
self.log_info("Search falls outside range of index for %s %s" % (name, minDate))
self.reExpandResource(name, minDate)
+ def whatchanged(self, revision):
+
+ results = [
+ (name.encode("utf-8"), deleted)
+ for name, deleted in
+ self._txn.execSQL(
+ """select RESOURCE_NAME, DELETED from CALENDAR_OBJECT_REVISIONS
+ where REVISION > %s and CALENDAR_RESOURCE_ID = %s""",
+ [revision, self.calendar._resourceID],
+ )
+ ]
+ results.sort(key=lambda x:x[1])
+
+ changed = []
+ deleted = []
+ for name, wasdeleted in results:
+ if name:
+ if wasdeleted:
+ if revision:
+ deleted.append(name)
+ else:
+ changed.append(name)
+ else:
+ raise SyncTokenValidException
+
+ return changed, deleted,
+
def indexedSearch(self, filter, useruid='', fbtype=False):
"""
Finds resources matching the given qualifiers.
@@ -1358,7 +1386,7 @@
-class PostgresCalendar(SyncTokenHelper):
+class PostgresCalendar(CalendarSyncTokenHelper):
implements(ICalendar)
@@ -1409,6 +1437,7 @@
# update memos
del self._home._calendars[oldName]
self._home._calendars[name] = self
+ self._updateSyncToken()
def ownerCalendarHome(self):
@@ -1472,9 +1501,8 @@
validateCalendarComponent(calendarObject, self, component)
calendarObject.updateDatabase(component, inserting=True)
+ self._insertRevision(name)
- self._updateSyncToken()
-
if self._notifier:
self._home._txn.postCommit(self._notifier.notify)
@@ -1488,9 +1516,8 @@
if self._txn._cursor.rowcount == 0:
raise NoSuchObjectResourceError()
self._objects.pop(name, None)
+ self._deleteRevision(name)
- self._updateSyncToken()
-
if self._notifier:
self._txn.postCommit(self._notifier.notify)
@@ -1511,18 +1538,12 @@
)
self._objects.pop(name, None)
self._objects.pop(uid, None)
- self._updateSyncToken()
+ self._deleteRevision(name)
if self._notifier:
self._home._txn.postCommit(self._notifier.notify)
- def syncToken(self):
- return self._txn.execSQL(
- "select SYNC_TOKEN from CALENDAR where RESOURCE_ID = %s",
- [self._resourceID])[0][0]
-
-
def calendarObjectsInTimeRange(self, start, end, timeZone):
raise NotImplementedError()
@@ -1684,9 +1705,9 @@
rows = self._txn.execSQL("select nextval('RESOURCE_ID_SEQ')")
resourceID = rows[0][0]
self._txn.execSQL(
- "insert into CALENDAR (SYNC_TOKEN, RESOURCE_ID) values "
- "(%s, %s)",
- ['uninitialized', resourceID])
+ "insert into CALENDAR (RESOURCE_ID) values "
+ "(%s)",
+ [resourceID])
self._txn.execSQL("""
insert into CALENDAR_BIND (
@@ -1703,7 +1724,7 @@
newCalendar = self.calendarWithName(name)
newCalendar.properties()[
PropertyName.fromElement(ResourceType)] = calendarType
- newCalendar._updateSyncToken(True)
+ newCalendar._updateSyncToken()
if self._notifier:
self._txn.postCommit(self._notifier.notify)
@@ -2196,9 +2217,8 @@
validateAddressBookComponent(self, self._addressbook, component)
self.updateDatabase(component)
+ self._addressbook._updateRevision(self._name)
- self._addressbook._updateSyncToken()
-
if self._addressbook._notifier:
self._addressbook._home._txn.postCommit(self._addressbook._notifier.notify)
@@ -2411,6 +2431,33 @@
return obj.name()
+ def whatchanged(self, revision):
+
+ results = [
+ (name.encode("utf-8"), deleted)
+ for name, deleted in
+ self._txn.execSQL(
+ """select RESOURCE_NAME, DELETED from ADDRESSBOOK_OBJECT_REVISIONS
+ where REVISION > %s and ADDRESSBOOK_RESOURCE_ID = %s""",
+ [revision, self.addressbook._resourceID],
+ )
+ ]
+ results.sort(key=lambda x:x[1])
+
+ changed = []
+ deleted = []
+ for name, wasdeleted in results:
+ if name:
+ if wasdeleted:
+ if revision:
+ deleted.append(name)
+ else:
+ changed.append(name)
+ else:
+ raise SyncTokenValidException
+
+ return changed, deleted,
+
def searchValid(self, filter):
if isinstance(filter, carddavxml.Filter):
qualifiers = addressbookquery.sqladdressbookquery(filter)
@@ -2481,7 +2528,7 @@
-class PostgresAddressBook(SyncTokenHelper):
+class PostgresAddressBook(AddressbookSyncTokenHelper):
implements(IAddressBook)
@@ -2532,6 +2579,7 @@
# update memos
del self._home._addressbooks[oldName]
self._home._addressbooks[name] = self
+ self._updateSyncToken()
def ownerAddressBookHome(self):
@@ -2595,9 +2643,8 @@
validateAddressBookComponent(addressbookObject, self, component)
addressbookObject.updateDatabase(component, inserting=True)
+ self._insertRevision(name)
- self._updateSyncToken()
-
if self._notifier:
self._home._txn.postCommit(self._notifier.notify)
@@ -2611,9 +2658,8 @@
if self._txn._cursor.rowcount == 0:
raise NoSuchObjectResourceError()
self._objects.pop(name, None)
+ self._deleteRevision(name)
- self._updateSyncToken()
-
if self._notifier:
self._txn.postCommit(self._notifier.notify)
@@ -2634,18 +2680,12 @@
)
self._objects.pop(name, None)
self._objects.pop(uid, None)
- self._updateSyncToken()
+ self._deleteRevision(name)
if self._notifier:
self._home._txn.postCommit(self._notifier.notify)
- def syncToken(self):
- return self._txn.execSQL(
- "select SYNC_TOKEN from ADDRESSBOOK where RESOURCE_ID = %s",
- [self._resourceID])[0][0]
-
-
def addressbookObjectsSinceToken(self, token):
raise NotImplementedError()
@@ -2793,9 +2833,9 @@
rows = self._txn.execSQL("select nextval('RESOURCE_ID_SEQ')")
resourceID = rows[0][0]
self._txn.execSQL(
- "insert into ADDRESSBOOK (SYNC_TOKEN, RESOURCE_ID) values "
- "(%s, %s)",
- ['uninitialized', resourceID])
+ "insert into ADDRESSBOOK (RESOURCE_ID) values "
+ "(%s)",
+ [resourceID])
self._txn.execSQL("""
insert into ADDRESSBOOK_BIND (
@@ -2812,7 +2852,7 @@
newAddressbook = self.addressbookWithName(name)
newAddressbook.properties()[
PropertyName.fromElement(ResourceType)] = addressbookType
- newAddressbook._updateSyncToken(True)
+ newAddressbook._updateSyncToken()
if self._notifier:
self._txn.postCommit(self._notifier.notify)
Modified: CalendarServer/trunk/txcaldav/calendarstore/postgres_schema_v1.sql
===================================================================
--- CalendarServer/trunk/txcaldav/calendarstore/postgres_schema_v1.sql 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/txcaldav/calendarstore/postgres_schema_v1.sql 2010-08-20 16:22:29 UTC (rev 6152)
@@ -20,8 +20,8 @@
--------------
create table CALENDAR (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'),
- SYNC_TOKEN varchar(255),
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'),
+ REVISION integer default 0,
CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
);
@@ -211,6 +211,27 @@
);
+------------------------------
+-- 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 --
------------------
@@ -253,10 +274,10 @@
-----------------
create table ADDRESSBOOK (
- RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'),
- SYNC_TOKEN varchar(255),
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'),
+ REVISION integer default 0,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
);
@@ -293,3 +314,25 @@
unique(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME),
unique(ADDRESSBOOK_RESOURCE_ID, VCARD_UID)
);
+
+------------------------------
+-- AddressBook Object Revision --
+------------------------------
+
+create sequence ADDRESSBOOK_OBJECT_REVISION_SEQ;
+
+
+-------------------------------
+-- 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,
+
+ unique(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME)
+);
+
+
Modified: CalendarServer/trunk/txcaldav/calendarstore/util.py
===================================================================
--- CalendarServer/trunk/txcaldav/calendarstore/util.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/txcaldav/calendarstore/util.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -24,9 +24,6 @@
from txdav.common.icommondatastore import InvalidObjectResourceError,\
NoSuchObjectResourceError
-from twistedcaldav.customxml import GETCTag
-from uuid import uuid4
-from txdav.propertystore.base import PropertyName
def validateCalendarComponent(calendarObject, calendar, component):
@@ -126,30 +123,183 @@
-class SyncTokenHelper(object):
+class CalendarSyncTokenHelper(object):
"""
- Implement a basic _updateSyncToken in terms of an object with a property
- store. This is a mixin for use by data store implementations.
+ This is a mixin for use by data store implementations.
"""
- def _updateSyncToken(self, reset=False):
- # FIXME: add locking a-la CalDAVResource.bumpSyncToken
- # FIXME: tests for desired concurrency properties
- ctag = PropertyName.fromString(GETCTag.sname())
- props = self.properties()
- token = props.get(ctag)
- if token is None or reset:
- tokenuuid = uuid4()
- revision = 1
- else:
- # FIXME: no direct tests for update
- token = str(token)
- tokenuuid, revision = token.split("#", 1)
- revision = int(revision) + 1
- token = "%s#%d" % (tokenuuid, revision)
- props[ctag] = GETCTag(token)
- # FIXME: no direct tests for commit
- return revision
+ def syncToken(self):
+ revision = self._txn.execSQL(
+ "select REVISION from CALENDAR where RESOURCE_ID = %s",
+ [self._resourceID])[0][0]
+ return "%s#%s" % (self._resourceID, revision,)
+ def _updateSyncToken(self):
+
+ self._txn.execSQL("""
+ update CALENDAR
+ set (REVISION)
+ = (nextval('CALENDAR_OBJECT_REVISION_SEQ'))
+ where RESOURCE_ID = %s
+ """,
+ [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('CALENDAR_OBJECT_REVISION_SEQ')
+ """
+ )
+
+ if action == "delete":
+ self._txn.execSQL("""
+ update CALENDAR_OBJECT_REVISIONS
+ set (REVISION, DELETED) = (%s, TRUE)
+ where CALENDAR_RESOURCE_ID = %s and RESOURCE_NAME = %s
+ """,
+ [nextrevision, self._resourceID, name]
+ )
+ self._txn.execSQL("""
+ update CALENDAR
+ set (REVISION) = (%s)
+ where RESOURCE_ID = %s
+ """,
+ [nextrevision, self._resourceID]
+ )
+ elif action == "update":
+ self._txn.execSQL("""
+ update CALENDAR_OBJECT_REVISIONS
+ set (REVISION) = (%s)
+ where CALENDAR_RESOURCE_ID = %s and RESOURCE_NAME = %s
+ """,
+ [nextrevision, self._resourceID, name]
+ )
+ self._txn.execSQL("""
+ update CALENDAR
+ set (REVISION) = (%s)
+ where RESOURCE_ID = %s
+ """,
+ [nextrevision, self._resourceID]
+ )
+ elif action == "insert":
+ self._txn.execSQL("""
+ delete from CALENDAR_OBJECT_REVISIONS
+ where CALENDAR_RESOURCE_ID = %s and RESOURCE_NAME = %s
+ """,
+ [self._resourceID, name,]
+ )
+ self._txn.execSQL("""
+ insert into CALENDAR_OBJECT_REVISIONS
+ (CALENDAR_RESOURCE_ID, RESOURCE_NAME, REVISION, DELETED)
+ values (%s, %s, %s, FALSE)
+ """,
+ [self._resourceID, name, nextrevision]
+ )
+ self._txn.execSQL("""
+ update CALENDAR
+ set (REVISION) = (%s)
+ where RESOURCE_ID = %s
+ """,
+ [nextrevision, self._resourceID]
+ )
+
+class AddressbookSyncTokenHelper(object):
+ """
+ This is a mixin for use by data store implementations.
+ """
+
+ def syncToken(self):
+ revision = self._txn.execSQL(
+ "select REVISION from ADDRESSBOOK where RESOURCE_ID = %s",
+ [self._resourceID])[0][0]
+ return "%s#%s" % (self._resourceID, revision,)
+
+ def _updateSyncToken(self):
+
+ self._txn.execSQL("""
+ update ADDRESSBOOK
+ set (REVISION)
+ = (nextval('ADDRESSBOOK_OBJECT_REVISION_SEQ'))
+ where RESOURCE_ID = %s
+ """,
+ [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('ADDRESSBOOK_OBJECT_REVISION_SEQ')
+ """
+ )
+
+ if action == "delete":
+ self._txn.execSQL("""
+ update ADDRESSBOOK_OBJECT_REVISIONS
+ set (REVISION, DELETED) = (%s, TRUE)
+ where ADDRESSBOOK_RESOURCE_ID = %s and RESOURCE_NAME = %s
+ """,
+ [nextrevision, self._resourceID, name]
+ )
+ self._txn.execSQL("""
+ update ADDRESSBOOK
+ set (REVISION) = (%s)
+ where RESOURCE_ID = %s
+ """,
+ [nextrevision, self._resourceID]
+ )
+ elif action == "update":
+ self._txn.execSQL("""
+ update ADDRESSBOOK_OBJECT_REVISIONS
+ set (REVISION) = (%s)
+ where ADDRESSBOOK_RESOURCE_ID = %s and RESOURCE_NAME = %s
+ """,
+ [nextrevision, self._resourceID, name]
+ )
+ self._txn.execSQL("""
+ update ADDRESSBOOK
+ set (REVISION) = (%s)
+ where RESOURCE_ID = %s
+ """,
+ [nextrevision, self._resourceID]
+ )
+ elif action == "insert":
+ self._txn.execSQL("""
+ delete from ADDRESSBOOK_OBJECT_REVISIONS
+ where ADDRESSBOOK_RESOURCE_ID = %s and RESOURCE_NAME = %s
+ """,
+ [self._resourceID, name,]
+ )
+ self._txn.execSQL("""
+ insert into ADDRESSBOOK_OBJECT_REVISIONS
+ (ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME, REVISION, DELETED)
+ values (%s, %s, %s, FALSE)
+ """,
+ [self._resourceID, name, nextrevision]
+ )
+ self._txn.execSQL("""
+ update ADDRESSBOOK
+ set (REVISION) = (%s)
+ where RESOURCE_ID = %s
+ """,
+ [nextrevision, self._resourceID]
+ )
+
\ No newline at end of file
Modified: CalendarServer/trunk/txcarddav/addressbookstore/file.py
===================================================================
--- CalendarServer/trunk/txcarddav/addressbookstore/file.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/txcarddav/addressbookstore/file.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -177,9 +177,8 @@
except InvalidVCardDataError, e:
raise InvalidObjectResourceError(e)
- newRevision = self._addressbook._updateSyncToken() # FIXME: test
self._addressbook.retrieveOldIndex().addResource(
- self.name(), component, newRevision
+ self.name(), component
)
self._component = component
Modified: CalendarServer/trunk/txdav/common/datastore/file.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/file.py 2010-08-20 16:16:22 UTC (rev 6151)
+++ CalendarServer/trunk/txdav/common/datastore/file.py 2010-08-20 16:22:29 UTC (rev 6152)
@@ -20,7 +20,8 @@
"""
from twext.python.log import LoggingMixIn
-from twext.web2.dav.element.rfc2518 import ResourceType, GETContentType
+from twext.web2.dav.element.rfc2518 import ResourceType, GETContentType, HRef
+from twext.web2.dav.element.rfc5842 import ResourceID
from twext.web2.http_headers import generateContentType, MimeType
from twisted.python.util import FancyEqMixin
@@ -43,11 +44,11 @@
from txdav.propertystore.base import PropertyName
from txdav.propertystore.xattr import PropertyStore
-from txcaldav.calendarstore.util import SyncTokenHelper
-
from errno import EEXIST, ENOENT
from zope.interface import implements, directlyProvides
+import uuid
+
ECALENDARTYPE = 0
EADDRESSBOOKTYPE = 1
TOPPATHS = (
@@ -295,11 +296,9 @@
return self._uid
- def _updateSyncToken(self, reset=False):
- "Stub for updating sync token."
- # FIXME: actually update something
+ def transaction(self):
+ return self._transaction
-
def retrieveOldShares(self):
"""
Retrieve the old Index object.
@@ -471,8 +470,7 @@
return None
-class CommonHomeChild(FileMetaDataMixin, LoggingMixIn, FancyEqMixin,
- SyncTokenHelper):
+class CommonHomeChild(FileMetaDataMixin, LoggingMixIn, FancyEqMixin):
"""
Common ancestor class of AddressBooks and Calendars.
"""
@@ -543,7 +541,6 @@
@writeOperation
def rename(self, name):
- self._updateSyncToken()
oldName = self.name()
self._renamedName = name
self._home._newChildren[name] = self
@@ -554,6 +551,8 @@
self._transaction.addOperation(doIt, "rename home child %r -> %r" %
(oldName, name))
+ self.retrieveOldIndex().bumpRevision()
+
if self._notifier:
self._transaction.postCommit(self._notifier.notify)
@@ -648,8 +647,7 @@
if name.startswith("."):
raise NoSuchObjectResourceError(name)
- newRevision = self._updateSyncToken() # FIXME: Test
- self.retrieveOldIndex().deleteResource(name, newRevision)
+ self.retrieveOldIndex().deleteResource(name)
objectResourcePath = self._path.child(name)
if objectResourcePath.isfile():
@@ -673,7 +671,13 @@
def syncToken(self):
- raise NotImplementedError()
+
+ try:
+ urnuuid = str(self.properties()[PropertyName.fromElement(ResourceID)].children[0])
+ except KeyError:
+ urnuuid = uuid.uuid4().urn
+ self.properties()[PropertyName(*ResourceID.qname())] = ResourceID(HRef.fromString(urnuuid))
+ return "%s#%s" % (urnuuid[9:], self.retrieveOldIndex().lastRevision())
def objectResourcesSinceToken(self, token):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20100820/6e7e8a31/attachment-0001.html>
More information about the calendarserver-changes
mailing list