[CalendarServer-changes] [14468] CalendarServer/branches/users/sagen/trashcan-4/txdav
source_changes at macosforge.org
source_changes at macosforge.org
Mon Feb 23 13:25:17 PST 2015
Revision: 14468
http://trac.calendarserver.org//changeset/14468
Author: sagen at apple.com
Date: 2015-02-23 13:25:17 -0800 (Mon, 23 Feb 2015)
Log Message:
-----------
Objects in trash were still appearing in original collection via listObjectResources()
Modified Paths:
--------------
CalendarServer/branches/users/sagen/trashcan-4/txdav/caldav/datastore/sql.py
CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/sql.py
CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/sql_schema/current.sql
CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/test/test_sql.py
Modified: CalendarServer/branches/users/sagen/trashcan-4/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/sagen/trashcan-4/txdav/caldav/datastore/sql.py 2015-02-23 18:03:06 UTC (rev 14467)
+++ CalendarServer/branches/users/sagen/trashcan-4/txdav/caldav/datastore/sql.py 2015-02-23 21:25:17 UTC (rev 14468)
@@ -2361,6 +2361,8 @@
obj.CREATED,
obj.MODIFIED,
obj.DATAVERSION,
+ obj.TRASHED,
+ obj.IS_TRASH,
]
@@ -2382,6 +2384,8 @@
"_created",
"_modified",
"_dataversion",
+ "_trashed",
+ "_is_trash",
)
Modified: CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/sql.py 2015-02-23 18:03:06 UTC (rev 14467)
+++ CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/sql.py 2015-02-23 21:25:17 UTC (rev 14468)
@@ -7015,7 +7015,7 @@
rows = yield Select(
[obj.RESOURCE_NAME],
From=obj,
- Where=obj.PARENT_RESOURCE_ID == Parameter('parentID')
+ Where=(obj.PARENT_RESOURCE_ID == Parameter('parentID')).And(obj.IS_TRASH == False)
).on(parent._txn, parentID=parent.id())
returnValue(sorted([row[0] for row in rows]))
@@ -7498,7 +7498,7 @@
def _updateIsTrashQuery(cls):
obj = cls._objectSchema
return Update(
- {obj.IS_TRASH: Parameter("isTrash")},
+ {obj.IS_TRASH: Parameter("isTrash"), obj.TRASHED: Parameter("trashed")},
Where=obj.RESOURCE_ID == Parameter("resourceID"),
)
@@ -7506,7 +7506,7 @@
@inlineCallbacks
def toTrash(self):
yield self._updateIsTrashQuery.on(
- self._txn, isTrash=True, resourceID=self._resourceID
+ self._txn, isTrash=True, trashed=datetime.datetime.utcnow(), resourceID=self._resourceID
)
yield self._parentCollection.removedObjectResource(self)
yield self._parentCollection._deleteRevision(self.name())
@@ -7526,7 +7526,7 @@
trash = self._parentCollection
self._parentCollection = yield trash.originalParentForResource(self)
yield self._updateIsTrashQuery.on(
- self._txn, isTrash=False, resourceID=self._resourceID
+ self._txn, isTrash=False, trashed=None, resourceID=self._resourceID
)
yield trash._deleteRevision(
trash.nameForResource(
@@ -7544,7 +7544,7 @@
@classproperty
def _selectIsTrashQuery(cls):
obj = cls._objectSchema
- return Select((obj.IS_TRASH,), From=obj, Where=obj.RESOURCE_ID == Parameter("resourceID"))
+ return Select((obj.IS_TRASH, obj.TRASHED), From=obj, Where=obj.RESOURCE_ID == Parameter("resourceID"))
@inlineCallbacks
@@ -7557,7 +7557,17 @@
)[0][0]
)
+ @inlineCallbacks
+ def whenTrashed(self):
+ returnValue(
+ (
+ yield self._selectIsTrashQuery.on(
+ self._txn, resourceID=self._resourceID
+ )
+ )[0][1]
+ )
+
def removeNotifyCategory(self):
"""
Indicates what category to use when determining the priority of push
Modified: CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/sql_schema/current.sql 2015-02-23 18:03:06 UTC (rev 14467)
+++ CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/sql_schema/current.sql 2015-02-23 21:25:17 UTC (rev 14468)
@@ -133,7 +133,8 @@
CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
CHILD_TYPE varchar(10) default null, -- None, inbox, trash (FIXME: convert this to enumeration)
- IS_TRASH boolean default false not null -- collection is in the trash
+ TRASHED timestamp default null,
+ IS_TRASH boolean default false not null -- collection is in the trash
);
@@ -261,6 +262,7 @@
CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
DATAVERSION integer default 0 not null,
+ TRASHED timestamp default null,
IS_TRASH boolean default false not null, -- entire resource is in the trash
unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
@@ -482,6 +484,7 @@
CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
DATAVERSION integer default 0 not null,
+ TRASHED timestamp default null,
IS_TRASH boolean default false not null,
unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
Modified: CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/test/test_sql.py
===================================================================
--- CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/test/test_sql.py 2015-02-23 18:03:06 UTC (rev 14467)
+++ CalendarServer/branches/users/sagen/trashcan-4/txdav/common/datastore/test/test_sql.py 2015-02-23 21:25:17 UTC (rev 14468)
@@ -633,37 +633,59 @@
# Verify it's not in the trash
self.assertFalse((yield resource.isTrash()))
+ trashed = yield resource.whenTrashed()
+ self.assertTrue(trashed is None)
# Move object to trash
yield resource.toTrash()
+ yield txn.commit()
+ yield JobItem.waitEmpty(self.store.newTransaction, reactor, 60)
+
+ txn = self.store.newTransaction()
+
# Verify it's in the trash
+ resource = yield self._getResource(txn, "user01", "trash", "")
self.assertTrue((yield resource.isTrash()))
+ trashed = yield resource.whenTrashed()
+ self.assertFalse(trashed is None)
# No objects in collection
- objects = yield collection.listObjectResources()
- self.assertEquals(len(objects), 0)
+ resourceNames = yield self._getResourceNames(txn, "user01", "calendar")
+ self.assertEqual(len(resourceNames), 0)
# One object in trash
- objects = yield trash.listObjectResources()
- self.assertEquals(len(objects), 1)
+ resourceNames = yield self._getResourceNames(txn, "user01", "trash")
+ self.assertEqual(len(resourceNames), 1)
# Put back from trash
- resource = yield self._getResource(txn, "user01", "trash", objects[0])
yield resource.fromTrash()
+ yield txn.commit()
+ yield JobItem.waitEmpty(self.store.newTransaction, reactor, 60)
+
+ txn = self.store.newTransaction()
+
# Not in trash
- self.assertFalse((yield resource.isTrash()))
+ resource = yield self._getResource(txn, "user01", "trash", "")
+ self.assertTrue(resource is None)
+
# One object in collection
- objects = yield collection.listObjectResources()
- self.assertEquals(len(objects), 1)
+ resourceNames = yield self._getResourceNames(txn, "user01", "calendar")
+ self.assertEqual(len(resourceNames), 1)
+ resource = yield self._getResource(txn, "user01", "calendar", "test.ics")
+ self.assertFalse((yield resource.isTrash()))
+ trashed = yield resource.whenTrashed()
+ self.assertTrue(trashed is None)
# No objects in trash
- objects = yield trash.listObjectResources()
- self.assertEquals(len(objects), 0)
+ resourceNames = yield self._getResourceNames(txn, "user01", "trash")
+ self.assertEqual(len(resourceNames), 0)
+ yield txn.commit()
+
# Not implemented
# #
# # Now with addressbook
@@ -809,6 +831,8 @@
txn = self.store.newTransaction()
resourceNames = yield self._getResourceNames(txn, "user01", "inbox")
self.assertEqual(len(resourceNames), 1)
+ resource = yield self._getResource(txn, "user01", "inbox", "")
+ yield resource.remove()
# user01's copy has SCHEDULE-STATUS update
data = yield self._getResourceData(txn, "user01", "calendar", "test.ics")
@@ -829,6 +853,10 @@
# user01's copy is in the trash, still with user02 accepted
txn = self.store.newTransaction()
+ resource = yield self._getResource(txn, "user01", "trash", "")
+ self.assertTrue((yield resource.isTrash()))
+ trashed = yield resource.whenTrashed()
+ self.assertFalse(trashed is None)
data = yield self._getResourceData(txn, "user01", "trash", "")
self.assertTrue("PARTSTAT=ACCEPTED" in data)
yield txn.commit()
@@ -859,6 +887,10 @@
txn = self.store.newTransaction()
# user01's copy should be back on their calendar
+ resource = yield self._getResource(txn, "user01", "calendar", "test.ics")
+ self.assertFalse((yield resource.isTrash()))
+ trashed = yield resource.whenTrashed()
+ self.assertTrue(trashed is None)
data = yield self._getResourceData(txn, "user01", "calendar", "test.ics")
self.assertTrue("PARTSTAT=NEEDS-ACTION" in data)
@@ -871,6 +903,138 @@
@inlineCallbacks
+ def test_trashScheduledFullyInFutureAttendeeRemove(self):
+
+ from twistedcaldav.stdconfig import config
+ self.patch(config, "EnableTrashCollection", True)
+
+ # A month in the future
+ start = DateTime.getNowUTC()
+ start.setHHMMSS(0, 0, 0)
+ start.offsetMonth(1)
+ end = DateTime.getNowUTC()
+ end.setHHMMSS(1, 0, 0)
+ end.offsetMonth(1)
+ subs = {
+ "start": start,
+ "end": end,
+ }
+
+ data1 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-attendee-reply
+DTSTART;TZID=America/Los_Angeles:%(start)s
+DTEND;TZID=America/Los_Angeles:%(end)s
+DTSTAMP:20150204T192546Z
+SUMMARY:Scheduled
+ORGANIZER;CN="User 01":mailto:user01 at example.com
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE:mailto:user02 at example.com
+END:VEVENT
+END:VCALENDAR
+""" % subs
+
+ data2 = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-attendee-reply
+DTSTART;TZID=America/Los_Angeles:%(start)s
+DTEND;TZID=America/Los_Angeles:%(end)s
+DTSTAMP:20150204T192546Z
+SUMMARY:Scheduled
+ORGANIZER;CN="User 01":mailto:user01 at example.com
+ATTENDEE:mailto:user01 at example.com
+ATTENDEE;PARTSTAT=ACCEPTED:mailto:user02 at example.com
+END:VEVENT
+END:VCALENDAR
+""" % subs
+
+ # user01 invites user02
+ txn = self.store.newTransaction()
+ yield self._createResource(
+ txn, "user01", "calendar", "test.ics", data1
+ )
+ yield txn.commit()
+
+ yield JobItem.waitEmpty(self.store.newTransaction, reactor, 60)
+
+ # user01's copy has SCHEDULE-STATUS update
+ txn = self.store.newTransaction()
+ data = yield self._getResourceData(txn, "user01", "calendar", "test.ics")
+ self.assertTrue("SCHEDULE-STATUS=1.2" in data)
+
+ # user02 has an inbox item
+ resourceNames = yield self._getResourceNames(txn, "user02", "inbox")
+ self.assertEqual(len(resourceNames), 1)
+
+ # user02 accepts
+ yield self._updateResource(txn, "user02", "calendar", "", data2)
+ yield txn.commit()
+
+ yield JobItem.waitEmpty(self.store.newTransaction, reactor, 60)
+
+ # user01 has an inbox item
+ txn = self.store.newTransaction()
+ resourceNames = yield self._getResourceNames(txn, "user01", "inbox")
+ self.assertEqual(len(resourceNames), 1)
+ resource = yield self._getResource(txn, "user01", "inbox", "")
+ yield resource.remove()
+
+ # user01's copy has SCHEDULE-STATUS update
+ data = yield self._getResourceData(txn, "user01", "calendar", "test.ics")
+ self.assertTrue("SCHEDULE-STATUS=2.0" in data)
+ self.assertTrue("PARTSTAT=ACCEPTED" in data)
+
+ resource = yield self._getResource(txn, "user02", "inbox", "")
+ yield resource.remove()
+
+ yield txn.commit()
+
+ # user02 trashes event
+ txn = self.store.newTransaction()
+ resource = yield self._getResource(txn, "user02", "calendar", "")
+ yield resource.remove()
+
+ yield txn.commit()
+
+ yield JobItem.waitEmpty(self.store.newTransaction, reactor, 60)
+
+ # user01's calendar copy shows user02 declined
+ txn = self.store.newTransaction()
+
+ data = yield self._getResourceData(txn, "user01", "calendar", "test.ics")
+ self.assertTrue("PARTSTAT=DECLINED" in data)
+
+ # user01's inbox copy also shows user02 declined
+ data = yield self._getResourceData(txn, "user01", "inbox", "")
+ self.assertTrue("PARTSTAT=DECLINED" in data)
+ resource = yield self._getResource(txn, "user01", "inbox", "")
+ yield resource.remove()
+
+ # result = yield txn.execSQL("select * from calendar_object", [])
+ # for row in result:
+ # print("ROW", row)
+
+ # user02's copy is in the trash only, and still has ACCEPTED
+ resourceNames = yield self._getResourceNames(txn, "user02", "trash")
+ self.assertEqual(len(resourceNames), 1)
+
+ resourceNames = yield self._getResourceNames(txn, "user02", "calendar")
+ self.assertEqual(len(resourceNames), 0)
+
+ resourceNames = yield self._getResourceNames(txn, "user02", "inbox")
+ self.assertEqual(len(resourceNames), 0)
+
+ data = yield self._getResourceData(txn, "user02", "trash", "")
+ self.assertTrue("PARTSTAT=ACCEPTED" in data)
+
+ yield txn.commit()
+
+
+ @inlineCallbacks
def test_trashScheduledFullyInPast(self):
from twistedcaldav.stdconfig import config
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20150223/dd1dfb5c/attachment-0001.html>
More information about the calendarserver-changes
mailing list