[CalendarServer-changes] [11031] CalendarServer/branches/users/cdaboo/store-scheduling

source_changes at macosforge.org source_changes at macosforge.org
Thu Apr 11 14:14:53 PDT 2013


Revision: 11031
          http://trac.calendarserver.org//changeset/11031
Author:   cdaboo at apple.com
Date:     2013-04-11 14:14:53 -0700 (Thu, 11 Apr 2013)
Log Message:
-----------
Full hook-up of implicit scheduling for store and remove.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/calverify.py
    CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/purge.py
    CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/storebridge.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/file.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/caldav/delivery.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/implicit.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/processing.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/test/test_implicit.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/test/test_pocessing.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/utils.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/sql.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/test/test_implicit.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/icalendarstore.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/carddav/datastore/file.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/carddav/datastore/sql.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/file.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/test/util.py

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/calverify.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/calverify.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/calverify.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -824,7 +824,7 @@
             calendar = yield home.childWithID(calendarID)
             calendarObj = yield calendar.objectResourceWithID(resid)
             objname = calendarObj.name()
-            yield calendar.removeObjectResource(calendarObj)
+            yield calendarObj.remove()
             yield self.txn.commit()
             self.txn = self.store.newTransaction()
 

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/purge.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/purge.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/purge.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -977,7 +977,7 @@
                             else:
                                 print("Deleting: %s" % (uri,))
                         if not self.dryrun:
-                            (yield abColl.removeObjectResourceWithName(cardName))
+                            (yield card.remove())
                         count += 1
                     if self.verbose:
                         abName = abColl.name()

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/storebridge.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/storebridge.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -2329,9 +2329,7 @@
         # Do delete
 
         try:
-            yield self._newStoreParent.removeObjectResourceWithName(
-                self._newStoreObject.name()
-            )
+            yield self._newStoreObject.remove()
         except NoSuchObjectResourceError:
             raise HTTPError(NOT_FOUND)
 

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/file.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/file.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/file.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -271,8 +271,6 @@
     calendarObjectWithName = CommonHomeChild.objectResourceWithName
     calendarObjectWithUID = CommonHomeChild.objectResourceWithUID
     createCalendarObjectWithName = CommonHomeChild.createObjectResourceWithName
-    removeCalendarObjectWithName = CommonHomeChild.removeObjectResourceWithName
-    removeCalendarObjectWithUID = CommonHomeChild.removeObjectResourceWithUID
     calendarObjectsSinceToken = CommonHomeChild.objectResourcesSinceToken
 
 

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/caldav/delivery.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/caldav/delivery.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/caldav/delivery.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -37,6 +37,7 @@
 import hashlib
 import uuid
 from txdav.base.propertystore.base import PropertyName
+from txdav.caldav.icalendarstore import ComponentUpdateState
 
 
 """
@@ -149,7 +150,7 @@
         if store_inbox:
             # Copy calendar to inbox
             try:
-                yield recipient.inbox.createCalendarObjectWithName(name, self.scheduler.calendar)
+                yield recipient.inbox._createCalendarObjectWithNameInternal(name, self.scheduler.calendar, ComponentUpdateState.INBOX)
             except Exception as e:
                 # FIXME: Bare except
                 log.err("Could not store data in Inbox : %s %s" % (recipient.inbox, e,))

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/implicit.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/implicit.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -401,8 +401,6 @@
     def extractCalendarData(self):
 
         # Get the originator who is the owner of the calendar resource being modified
-        self.originatorPrincipal = None
-        self.originator = ""
         self.originatorPrincipal = self.calendar_home.principalForUID(self.calendar_owner)
 
         # Pick the canonical CUA:

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/processing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/processing.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/processing.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -42,6 +42,8 @@
 import collections
 import hashlib
 import uuid
+from txdav.caldav.icalendarstore import ComponentUpdateState, \
+    ComponentRemoveState
 
 """
 CalDAV implicit processing.
@@ -952,11 +954,12 @@
         """
 
         # Create a new name if one was not provided
+        internal_state = ComponentUpdateState.ORGANIZER_ITIP_UPDATE if self.isOrganizerReceivingMessage() else ComponentUpdateState.ATTENDEE_ITIP_UPDATE
         if resource is None:
             name = "%s-%s.ics" % (hashlib.md5(calendar.resourceUID()).hexdigest(), str(uuid.uuid4())[:8],)
-            newchild = (yield collection.createCalendarObjectWithName(name, calendar))
+            newchild = (yield collection._createCalendarObjectWithNameInternal(name, calendar, internal_state))
         else:
-            yield resource.setComponent(calendar)
+            yield resource._setComponentInternal(calendar, internal_state=internal_state)
             newchild = None
 
         returnValue(newchild)
@@ -975,7 +978,7 @@
         @type name: C{str}
         """
 
-        yield resource._parent.removeObjectResource(resource)
+        yield resource._removeInternal(internal_state=ComponentRemoveState.INTERNAL)
 
 
     def resetAttendeePartstat(self, component, cuas, partstat, hadRSVP=False):

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/test/test_implicit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/test/test_implicit.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/test/test_implicit.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -34,6 +34,8 @@
 from twext.python.clsprop import classproperty
 from txdav.caldav.datastore.sql import CalendarPrincipal
 import hashlib
+from txdav.caldav.icalendarstore import AttendeeAllowedError
+import sys
 
 class FakeScheduler(object):
     """
@@ -50,11 +52,19 @@
 
 
 
+class FakeCalendarHome(object):
+
+    def principalForUID(self, uid):
+        return CalendarPrincipal(uid, ("urn:uuid:%s" % (uid,), "mailto:%s at example.com" % (uid,),))
+
+
+
 class Implicit (twistedcaldav.test.util.TestCase):
     """
     iCalendar support tests
     """
 
+    @inlineCallbacks
     def test_removed_attendees(self):
 
         data = (
@@ -783,7 +793,11 @@
             scheduler.oldAttendeesByInstance = scheduler.oldcalendar.getAttendeesByInstance(True, onlyScheduleAgentServer=True)
             scheduler.oldInstances = set(scheduler.oldcalendar.getComponentInstances())
             scheduler.calendar = Component.fromString(calendar2)
-            scheduler.extractCalendarData()
+
+            scheduler.calendar_home = FakeCalendarHome()
+            scheduler.calendar_owner = "user01"
+
+            yield scheduler.extractCalendarData()
             scheduler.findRemovedAttendees()
             self.assertEqual(scheduler.cancelledAttendees, set(result), msg=description)
 
@@ -819,17 +833,18 @@
         for excludes, includes, result_count, result_set in data:
             scheduler = ImplicitScheduler()
             scheduler.resource = None
-            scheduler.request = None
             scheduler.calendar = Component.fromString(calendar)
             scheduler.state = "organizer"
             scheduler.action = "modify"
-            scheduler.calendar_owner = None
             scheduler.internal_request = True
             scheduler.except_attendees = excludes
             scheduler.only_refresh_attendees = includes
             scheduler.changed_rids = None
             scheduler.reinvites = None
 
+            scheduler.calendar_home = FakeCalendarHome()
+            scheduler.calendar_owner = "user01"
+
             # Get some useful information from the calendar
             yield scheduler.extractCalendarData()
             scheduler.organizerPrincipal = CalendarPrincipal(scheduler.organizer, scheduler.organizer)
@@ -969,7 +984,7 @@
 DTSTAMP:20080601T120000Z
 DTSTART:20080601T120000Z
 DTEND:20080601T130000Z
-ORGANIZER;CN="User 02":mailto:user02 at example.com
+ORGANIZER;CN="User 01":mailto:user01 at example.com
 ATTENDEE:mailto:user01 at example.com
 ATTENDEE:mailto:user02 at example.com
 END:VEVENT
@@ -984,7 +999,7 @@
 DTSTAMP:20080601T120000Z
 DTSTART:20080601T120000Z
 DTEND:20080601T130000Z
-ORGANIZER;CN="User 02":mailto:user02 at example.com
+ORGANIZER;CN="User 01":mailto:user01 at example.com
 ATTENDEE:mailto:user01 at example.com
 ATTENDEE:mailto:user02 at example.com
 END:VEVENT
@@ -1080,13 +1095,9 @@
 """
         calendar_collection = (yield self.calendarUnderTest(home="user01"))
         calendar = Component.fromString(data)
+        yield calendar_collection.createCalendarObjectWithName("test.ics", calendar)
+        yield self.commit()
 
-        scheduler = ImplicitScheduler()
-        doAction, isScheduleObject = (yield scheduler.testImplicitSchedulingPUT(calendar_collection, None, calendar, False))
-        self.assertEqual(doAction, True)
-        self.assertEqual(isScheduleObject, True)
-        yield scheduler.doImplicitScheduling()
-
         calendar_collection2 = (yield self.calendarUnderTest(home="user02"))
         items = (yield calendar_collection2.listCalendarObjects())
         self.assertEqual(len(items), 1)
@@ -1133,22 +1144,12 @@
 """
         calendar_collection = (yield self.calendarUnderTest(home="user01"))
         calendar = Component.fromString(data1)
-        scheduler = ImplicitScheduler()
-        doAction, isScheduleObject = (yield scheduler.testImplicitSchedulingPUT(calendar_collection, None, calendar, False))
-        self.assertEqual(doAction, True)
-        self.assertEqual(isScheduleObject, True)
-        yield scheduler.doImplicitScheduling()
         yield calendar_collection.createCalendarObjectWithName("test.ics", calendar)
         yield self.commit()
 
-        calendar_collection = (yield self.calendarUnderTest(home="user01"))
-        calendar_resource = (yield self.calendarObjectUnderTest(name="test.ics", home="user01",))
-        calendar2 = Component.fromString(data2)
-        scheduler = ImplicitScheduler()
-        doAction, isScheduleObject = (yield scheduler.testImplicitSchedulingPUT(calendar_collection, calendar_resource, calendar2, False))
-        self.assertEqual(doAction, True)
-        self.assertEqual(isScheduleObject, True)
-        yield scheduler.doImplicitScheduling()
+        calendar_resource = (yield self.calendarObjectUnderTest(name="test.ics", home="user01"))
+        calendar = Component.fromString(data2)
+        yield calendar_resource.setComponent(calendar)
         yield self.commit()
 
         calendar_collection2 = (yield self.calendarUnderTest(home="user02"))
@@ -1198,23 +1199,12 @@
 """
         calendar_collection = (yield self.calendarUnderTest(home="user01"))
         calendar = Component.fromString(data1)
-        scheduler = ImplicitScheduler()
-        doAction, isScheduleObject = (yield scheduler.testImplicitSchedulingPUT(calendar_collection, None, calendar, False))
-        self.assertEqual(doAction, True)
-        self.assertEqual(isScheduleObject, True)
-        yield scheduler.doImplicitScheduling()
         yield calendar_collection.createCalendarObjectWithName("test.ics", calendar)
         yield self.commit()
 
-        calendar_collection = (yield self.calendarUnderTest(home="user01"))
-        calendar_resource = (yield self.calendarObjectUnderTest(name="test.ics", home="user01",))
-        calendar_resource.isScheduleObject = True
-        calendar2 = Component.fromString(data2)
-        scheduler = ImplicitScheduler()
-        doAction, isScheduleObject = (yield scheduler.testImplicitSchedulingDELETE(calendar_collection, calendar_resource, calendar2, False))
-        self.assertEqual(doAction, True)
-        self.assertEqual(isScheduleObject, False)
-        yield scheduler.doImplicitScheduling()
+        calendar_resource = (yield self.calendarObjectUnderTest(name="test.ics", home="user01"))
+        calendar = Component.fromString(data2)
+        yield calendar_resource.remove()
         yield self.commit()
 
         calendar_collection2 = (yield self.calendarUnderTest(home="user02"))
@@ -1250,13 +1240,18 @@
 """
         calendar_collection = (yield self.calendarUnderTest(home="user02"))
         calendar = Component.fromString(data)
+        try:
+            yield calendar_collection.createCalendarObjectWithName("test.ics", calendar)
+        except AttendeeAllowedError:
+            pass
+        except:
+            self.fail("Wrong exception raised: %s" % (sys.exc_info()[0].__name__,))
+        else:
+            self.fail("Exception not raised")
+        yield self.commit()
 
-        scheduler = ImplicitScheduler()
-        doAction, isScheduleObject = (yield scheduler.testImplicitSchedulingPUT(calendar_collection, None, calendar, False))
-        self.assertEqual(doAction, True)
-        self.assertEqual(isScheduleObject, True)
-        result = (yield scheduler.doImplicitScheduling())
-        self.assertEqual(result, ImplicitScheduler.STATUS_ORPHANED_EVENT)
+        calendar_collection = (yield self.calendarUnderTest(home="user02"))
+        calendar = Component.fromString(data)
 
         inbox1 = (yield self.calendarUnderTest(name="inbox", home="user01"))
         items = (yield inbox1.listCalendarObjects())
@@ -1299,31 +1294,30 @@
 """
         calendar_collection = (yield self.calendarUnderTest(home="user01"))
         calendar1 = Component.fromString(data1)
-
-        scheduler = ImplicitScheduler()
-        doAction, isScheduleObject = (yield scheduler.testImplicitSchedulingPUT(calendar_collection, None, calendar1, False))
-        self.assertEqual(doAction, True)
-        self.assertEqual(isScheduleObject, True)
-        yield scheduler.doImplicitScheduling()
         yield calendar_collection.createCalendarObjectWithName("test.ics", calendar1)
         yield self.commit()
 
+        calendar_resource1 = (yield self.calendarObjectUnderTest(name="test.ics", home="user01"))
+        calendar1 = (yield calendar_resource1.component())
+        self.assertTrue("SCHEDULE-STATUS=1.2" in str(calendar1).replace("\r\n ", ""))
+
+        inbox2 = (yield self.calendarUnderTest(name="inbox", home="user02"))
+        items = (yield inbox2.listCalendarObjects())
+        self.assertEqual(len(items), 1)
+        yield self.commit()
+
         calendar_collection2 = (yield self.calendarUnderTest(home="user02"))
         items = (yield calendar_collection2.listCalendarObjects())
         calendar_resource2 = (yield self.calendarObjectUnderTest(name=items[0], home="user02",))
         calendar2 = Component.fromString(data2)
+        yield calendar_resource2.setComponent(calendar2)
+        yield self.commit()
 
-        scheduler = ImplicitScheduler()
-        doAction, isScheduleObject = (yield scheduler.testImplicitSchedulingPUT(calendar_collection2, calendar_resource2, calendar2, False))
-        self.assertEqual(doAction, True)
-        self.assertEqual(isScheduleObject, True)
-        yield scheduler.doImplicitScheduling()
-
         inbox1 = (yield self.calendarUnderTest(name="inbox", home="user01"))
         items = (yield inbox1.listCalendarObjects())
         self.assertEqual(len(items), 1)
-        yield self.commit()
 
         calendar_resource1 = (yield self.calendarObjectUnderTest(name="test.ics", home="user01"))
         calendar1 = (yield calendar_resource1.component())
-        self.assertTrue("PARTSTAT=ACCEPTED" in str(calendar1))
+        self.assertTrue("SCHEDULE-STATUS=2.0" in str(calendar1).replace("\r\n ", ""))
+        self.assertTrue("PARTSTAT=ACCEPTED" in str(calendar1).replace("\r\n ", ""))

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/test/test_pocessing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/test/test_pocessing.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/test/test_pocessing.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -14,8 +14,6 @@
 # limitations under the License.
 ##
 
-from twext.web2.test.test_server import SimpleRequest
-
 from twisted.internet.defer import inlineCallbacks
 
 from twistedcaldav.config import config
@@ -73,9 +71,8 @@
 END:VEVENT
 END:VCALENDAR
 """)
-        request = SimpleRequest(self.site, "PUT", "/calendar/1.ics")
         processor = FakeImplicitProcessor()
-        processor.request = request
+        processor.txn = ""
         processor.uid = "12345-67890"
         processor.recipient_calendar = calendar
         yield processor.queueAttendeeUpdate(("urn:uuid:user02", "urn:uuid:user01",))
@@ -101,9 +98,8 @@
 END:VEVENT
 END:VCALENDAR
 """)
-        request = SimpleRequest(self.site, "PUT", "/calendar/1.ics")
         processor = FakeImplicitProcessor()
-        processor.request = request
+        processor.txn = ""
         processor.uid = "12345-67890"
         processor.recipient_calendar = calendar
         yield processor.queueAttendeeUpdate(("urn:uuid:user02", "urn:uuid:user01",))

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/utils.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/utils.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/scheduling/utils.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -16,6 +16,7 @@
 
 from twisted.internet.defer import inlineCallbacks, returnValue
 from twext.python.log import Logger
+from txdav.caldav.icalendarstore import ComponentRemoveState
 
 log = Logger()
 
@@ -39,7 +40,7 @@
             # Delete all but the first one
             log.debug("Should only have zero or one scheduling object resource with UID '%s' in calendar home: %s" % (uid, calendar_home,))
             for resource in objectResources[1:]:
-                yield resource._parentCollection.removeObjectResource(resource)
+                yield resource._removeInternal(internal_state=ComponentRemoveState.INTERNAL)
             objectResources = objectResources[:1]
 
         returnValue(objectResources[0] if len(objectResources) == 1 else None)

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/sql.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/sql.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -71,7 +71,7 @@
     TooManyAttendeesError, InvalidComponentTypeError, InvalidCalendarAccessError, \
     InvalidUIDError, UIDExistsError, ResourceDeletedError, \
     AttendeeAllowedError, InvalidPerUserDataMerge, ComponentUpdateState, \
-    ValidOrganizerError, ShareeAllowedError
+    ValidOrganizerError, ShareeAllowedError, ComponentRemoveState
 from txdav.caldav.icalendarstore import QuotaExceeded
 from txdav.common.datastore.sql import CommonHome, CommonHomeChild, \
     CommonObjectResource, ECALENDARTYPE
@@ -940,11 +940,17 @@
     calendarObjectWithName = CommonHomeChild.objectResourceWithName
     calendarObjectWithUID = CommonHomeChild.objectResourceWithUID
     createCalendarObjectWithName = CommonHomeChild.createObjectResourceWithName
-    removeCalendarObjectWithName = CommonHomeChild.removeObjectResourceWithName
-    removeCalendarObjectWithUID = CommonHomeChild.removeObjectResourceWithUID
     calendarObjectsSinceToken = CommonHomeChild.objectResourcesSinceToken
 
 
+    def _createCalendarObjectWithNameInternal(self, name, component, internal_state, options=None):
+
+        if options is None:
+            options = {}
+        options["internal_state"] = internal_state
+        return super(Calendar, self).createObjectResourceWithName(name, component, options)
+
+
     def calendarObjectsInTimeRange(self, start, end, timeZone):
         raise NotImplementedError()
 
@@ -1296,17 +1302,17 @@
     _objectTable = CALENDAR_OBJECT_TABLE
     _objectSchema = schema.CALENDAR_OBJECT
 
-    def __init__(self, calendar, name, uid, resourceID=None, metadata=None):
+    def __init__(self, calendar, name, uid, resourceID=None, options=None):
 
         super(CalendarObject, self).__init__(calendar, name, uid, resourceID)
 
-        if metadata is None:
-            metadata = {}
-        self.accessMode = metadata.get("accessMode", "")
-        self.isScheduleObject = metadata.get("isScheduleObject", False)
-        self.scheduleTag = metadata.get("scheduleTag", "")
-        self.scheduleEtags = metadata.get("scheduleEtags", "")
-        self.hasPrivateComment = metadata.get("hasPrivateComment", False)
+        if options is None:
+            options = {}
+        self.accessMode = options.get("accessMode", "")
+        self.isScheduleObject = options.get("isScheduleObject", False)
+        self.scheduleTag = options.get("scheduleTag", "")
+        self.scheduleEtags = options.get("scheduleEtags", "")
+        self.hasPrivateComment = options.get("hasPrivateComment", False)
         self._dropboxID = None
 
         # Component caching
@@ -1363,17 +1369,17 @@
 
     # Stuff from put_common
     @inlineCallbacks
-    def fullValidation(self, component, inserting, update_state):
+    def fullValidation(self, component, inserting, internal_state):
         """
         Do full validation of source and destination calendar data.
         """
 
         # Basic validation
         #TODO: figure out what to do about etag/schedule-tag
-        self.validIfScheduleMatch(False, False, update_state)
+        self.validIfScheduleMatch(False, False, internal_state)
 
         # Do validation on external requests
-        if update_state == ComponentUpdateState.NORMAL:
+        if internal_state == ComponentUpdateState.NORMAL:
 
             # Valid data sizes - do before parsing the data
             if config.MaxResourceSize:
@@ -1386,7 +1392,7 @@
             component.stripKnownTimezones()
 
         # Do validation on external requests
-        if update_state == ComponentUpdateState.NORMAL:
+        if internal_state == ComponentUpdateState.NORMAL:
 
             # Valid calendar data checks
             yield self.validCalendarDataCheck(component, inserting)
@@ -1403,20 +1409,20 @@
             component.normalizeCalendarUserAddresses(normalizationLookup, self.calendar().viewerHome().principalForCalendarUserAddress)
 
         # Check location/resource organizer requirement
-        yield self.validLocationResourceOrganizer(component, inserting, update_state)
+        yield self.validLocationResourceOrganizer(component, inserting, internal_state)
 
         # Check access
         if config.EnablePrivateEvents:
-            yield self.validAccess(component, inserting, update_state)
+            yield self.validAccess(component, inserting, internal_state)
 
 
-    def validIfScheduleMatch(self, etag_match, schedule_tag, update_state):
+    def validIfScheduleMatch(self, etag_match, schedule_tag, internal_state):
         """
         Check for If-ScheduleTag-Match header behavior.
         """
         # Only when a direct request
         self.schedule_tag_match = False
-        if not self.calendar().isInbox() and update_state == ComponentUpdateState.NORMAL:
+        if not self.calendar().isInbox() and internal_state == ComponentUpdateState.NORMAL:
             if schedule_tag:
                 self._validIfScheduleMatch(self.request)
                 self.schedule_tag_match = True
@@ -1486,12 +1492,12 @@
 
 
     @inlineCallbacks
-    def validLocationResourceOrganizer(self, component, inserting, update_state):
+    def validLocationResourceOrganizer(self, component, inserting, internal_state):
         """
         If the calendar owner is a location or resource, check whether an ORGANIZER property is required.
         """
 
-        if update_state == ComponentUpdateState.NORMAL:
+        if internal_state == ComponentUpdateState.NORMAL:
             originatorPrincipal = (yield self.calendar().ownerHome().principal())
             cutype = originatorPrincipal.getCUType() if originatorPrincipal is not None else "INDIVIDUAL"
             organizer = component.getOrganizer()
@@ -1522,7 +1528,7 @@
                 self._componentChanged = True
 
 
-    def validAccess(self, component, inserting, update_state):
+    def validAccess(self, component, inserting, internal_state):
         """
         Make sure that the X-CALENDARSERVER-ACCESS property is properly dealt with.
         """
@@ -1535,7 +1541,7 @@
                 raise InvalidCalendarAccessError("Private event access level not allowed")
 
             # Only DAV:owner is able to set the property to other than PUBLIC
-            if update_state == ComponentUpdateState.NORMAL:
+            if internal_state == ComponentUpdateState.NORMAL:
                 if self.calendar().viewerHome().uid() != self._txn._authz_uid and access != Component.ACCESS_PUBLIC:
                     raise InvalidCalendarAccessError("Private event access level change not allowed")
 
@@ -1576,7 +1582,7 @@
 
 
     @inlineCallbacks
-    def replaceMissingToDoProperties(self, calendar, inserting, update_state):
+    def replaceMissingToDoProperties(self, calendar, inserting, internal_state):
         """
         Recover any lost ORGANIZER or ATTENDEE properties in non-recurring VTODOs.
         """
@@ -1624,7 +1630,7 @@
                             anAttendee.setParameter("PARTSTAT", "COMPLETED")
                         component.addProperty(anAttendee)
 
-            elif new_completed ^ old_completed and update_state == ComponentUpdateState.NORMAL:
+            elif new_completed ^ old_completed and internal_state == ComponentUpdateState.NORMAL:
                 # COMPLETED changed - sync up attendee state
                 # We need this because many VTODO clients are not aware of scheduling,
                 # i.e. they do not adjust any ATTENDEE PARTSTATs. We are going to impose
@@ -1753,9 +1759,9 @@
 
 
     @inlineCallbacks
-    def doImplicitScheduling(self, component, inserting, update_state):
+    def doImplicitScheduling(self, component, inserting, internal_state):
 
-        data_changed = False
+        new_component = None
         did_implicit_action = False
 
         # Do scheduling
@@ -1767,14 +1773,13 @@
                 self.calendar(),
                 None if inserting else self,
                 component,
-                internal_request=(update_state != ComponentUpdateState.NORMAL),
+                internal_request=(internal_state != ComponentUpdateState.NORMAL),
             ))
 
-            if do_implicit_action and self.allowImplicitSchedule:
+            if do_implicit_action and internal_state == ComponentUpdateState.NORMAL:
 
                 # Cannot do implicit in sharee's shared calendar
-                isShareeCollection = self.destinationparent.isShareeCollection()
-                if isShareeCollection:
+                if not self.calendar().owned():
                     scheduler.setSchedulingNotAllowed(
                         ShareeAllowedError,
                         "Sharee's cannot schedule",
@@ -1785,13 +1790,12 @@
                     if isinstance(new_calendar, int):
                         returnValue(new_calendar)
                     else:
-                        self.calendar = new_calendar
-                        data_changed = True
+                        new_component = new_calendar
                 did_implicit_action = True
         else:
             is_scheduling_resource = False
 
-        returnValue((is_scheduling_resource, data_changed, did_implicit_action,))
+        returnValue((is_scheduling_resource, new_component, did_implicit_action,))
 
 
     @inlineCallbacks
@@ -1818,7 +1822,7 @@
         returnValue(component)
 
 
-    def processScheduleTags(self, component, inserting, update_state):
+    def processScheduleTags(self, component, inserting, internal_state):
 
         # Check for scheduling object resource and write property
         if self.isScheduleObject:
@@ -1830,7 +1834,7 @@
             #    from the Organizer then the schedule tag changes.
 
             # Check what kind of processing is going on
-            change_scheduletag = update_state not in (
+            change_scheduletag = internal_state not in (
                 ComponentUpdateState.ORGANIZER_ITIP_UPDATE,
                 ComponentUpdateState.ATTENDEE_ITIP_REFRESH,
             )
@@ -1859,14 +1863,15 @@
 
 
     @inlineCallbacks
-    def _lockUID(self, component, inserting):
+    def _lockUID(self, component, inserting, internal_state):
         """
         Create a lock on the component's UID and verify, after getting the lock, that the incoming UID
         meets the requirements of the store.
         """
 
         new_uid = component.resourceUID()
-        yield NamedLock.acquire(self._txn, "ImplicitUIDLock:%s" % (hashlib.md5(new_uid).hexdigest(),))
+        if internal_state == ComponentUpdateState.NORMAL:
+            yield NamedLock.acquire(self._txn, "ImplicitUIDLock:%s" % (hashlib.md5(new_uid).hexdigest(),))
 
         # UID conflict check - note we do this after reserving the UID to avoid a race condition where two requests
         # try to write the same calendar data to two different resource URIs.
@@ -1883,17 +1888,17 @@
                     raise UIDExistsError()
 
 
-    def setComponent(self, component, inserting=False):
+    def setComponent(self, component, inserting=False, options=None):
         """
         Public api for storing a component. This will do full data validation checks on the specified component.
         Scheduling will be done automatically.
         """
 
-        return self._setComponentInternal(component, inserting, ComponentUpdateState.NORMAL)
+        return self._setComponentInternal(component, inserting, ComponentUpdateState.NORMAL if options is None else options.get("internal_state"))
 
 
     @inlineCallbacks
-    def _setComponentInternal(self, component, inserting=False, update_state=ComponentUpdateState.NORMAL):
+    def _setComponentInternal(self, component, inserting=False, internal_state=ComponentUpdateState.NORMAL):
         """
         Setting the component internally to the store itself. This will bypass a whole bunch of data consistency checks
         on the assumption that those have been done prior to the component data being provided, provided the flag is set.
@@ -1902,59 +1907,64 @@
 
         self._componentChanged = False
 
-        # Handle all validation operations here.
-        yield self.fullValidation(component, inserting, update_state)
+        if internal_state != ComponentUpdateState.RAW:
+            # Handle all validation operations here.
+            yield self.fullValidation(component, inserting, internal_state)
 
-        # UID lock - this will remain active until the end of the current txn
-        yield self._lockUID(component, inserting)
+            # UID lock - this will remain active until the end of the current txn
+            yield self._lockUID(component, inserting, internal_state)
 
-        # Preserve private comments
-        yield self.preservePrivateComments(component, inserting)
+            # Preserve private comments
+            yield self.preservePrivateComments(component, inserting)
 
-        # Fix broken VTODOs
-        yield self.replaceMissingToDoProperties(component, inserting, update_state)
+            # Fix broken VTODOs
+            yield self.replaceMissingToDoProperties(component, inserting, internal_state)
 
-        # Handle sharing dropbox normalization
-        yield self.dropboxPathNormalization(component)
+            # Handle sharing dropbox normalization
+            yield self.dropboxPathNormalization(component)
 
-        # Pre-process managed attachments
-        if update_state == ComponentUpdateState.NORMAL:
-            managed_copied, managed_removed = (yield self.updatingResourceCheckAttachments(component, inserting))
+            # Pre-process managed attachments
+            if internal_state == ComponentUpdateState.NORMAL:
+                managed_copied, managed_removed = (yield self.updatingResourceCheckAttachments(component, inserting))
 
-        # Default/duplicate alarms
-        self.processAlarms(component, inserting)
+            # Default/duplicate alarms
+            self.processAlarms(component, inserting)
 
-        # Do scheduling
-        implicit_result = (yield self.doImplicitScheduling())
-        if isinstance(implicit_result, int):
-            if implicit_result == ImplicitScheduler.STATUS_ORPHANED_CANCELLED_EVENT:
-                raise ResourceDeletedError("Resource created but immediately deleted by the server.")
+            # Do scheduling
+            implicit_result = (yield self.doImplicitScheduling(component, inserting, internal_state))
+            if isinstance(implicit_result, int):
+                if implicit_result == ImplicitScheduler.STATUS_ORPHANED_CANCELLED_EVENT:
+                    raise ResourceDeletedError("Resource created but immediately deleted by the server.")
 
-            elif implicit_result == ImplicitScheduler.STATUS_ORPHANED_EVENT:
+                elif implicit_result == ImplicitScheduler.STATUS_ORPHANED_EVENT:
 
-                # Now forcibly delete the event
-                if not inserting:
-                    yield self.storeRemove()
-                    raise ResourceDeletedError("Resource modified but immediately deleted by the server.")
+                    # Now forcibly delete the event
+                    if not inserting:
+                        yield self.storeRemove()
+                        raise ResourceDeletedError("Resource modified but immediately deleted by the server.")
+                    else:
+                        raise AttendeeAllowedError("Attendee cannot create event for Organizer: %s" % (implicit_result,))
+
                 else:
-                    raise AttendeeAllowedError("Attendee cannot create event for Organizer: %s" % (implicit_result,))
-
+                    msg = "Invalid return status code from ImplicitScheduler: %s" % (implicit_result,)
+                    log.err(msg)
+                    raise InvalidObjectResourceError(msg)
             else:
-                msg = "Invalid return status code from ImplicitScheduler: %s" % (implicit_result,)
-                log.err(msg)
-                raise InvalidObjectResourceError(msg)
-        else:
-            self.isScheduleObject, data_changed, did_implicit_action = implicit_result
+                self.isScheduleObject, new_component, did_implicit_action = implicit_result
+                if new_component is not None:
+                    component = new_component
+                if did_implicit_action:
+                    self._componentChanged = True
 
-        # Always do the per-user data merge right before we store
-        component = (yield self.mergePerUserData(component, inserting))
+            # Always do the per-user data merge right before we store
+            component = (yield self.mergePerUserData(component, inserting))
 
-        self.processScheduleTags(component, inserting, update_state)
+            self.processScheduleTags(component, inserting, internal_state)
 
         yield self.updateDatabase(component, inserting=inserting)
 
         # Post process managed attachments
-        if update_state == ComponentUpdateState.NORMAL:
+        if internal_state == ComponentUpdateState.NORMAL:
             if managed_copied:
                 yield self.copyResourceAttachments(managed_copied)
             if managed_removed:
@@ -2323,15 +2333,49 @@
         returnValue(self._cachedCommponentPerUser[user_uuid])
 
 
+    def remove(self):
+        return self._removeInternal(internal_state=ComponentRemoveState.NORMAL)
+
+
     @inlineCallbacks
-    def remove(self):
+    def _removeInternal(self, internal_state=ComponentRemoveState.NORMAL):
+
+        isinbox = self._calendar.isInbox()
+
+        # Do If-Schedule-Tag-Match behavior first
+        # Important: this should only ever be done when storeRemove is called
+        # directly as a result of an HTTP DELETE to ensure the proper If-
+        # header is used in this test.
+        if not isinbox and internal_state == ComponentRemoveState.NORMAL:
+            #TODO: figure out what to do about etag/schedule-tag
+            self.validIfScheduleMatch(False, False, internal_state)
+
+        # Pre-flight scheduling operation
+        scheduler = None
+        if not isinbox and internal_state == ComponentRemoveState.NORMAL:
+            # Get data we need for implicit scheduling
+            calendar = (yield self.componentForUser())
+            scheduler = ImplicitScheduler()
+            do_implicit_action, _ignore = (yield scheduler.testImplicitSchedulingDELETE(
+                self.calendar(),
+                self,
+                calendar,
+                internal_request=(internal_state != ComponentUpdateState.NORMAL),
+            ))
+            if do_implicit_action:
+                yield NamedLock.acquire(self._txn, "ImplicitUIDLock:%s" % (hashlib.md5(calendar.resourceUID()).hexdigest(),))
+
         # Need to also remove attachments
         if self._dropboxID:
             yield DropBoxAttachment.resourceRemoved(self._txn, self._resourceID, self._dropboxID)
         yield ManagedAttachment.resourceRemoved(self._txn, self._resourceID)
         yield super(CalendarObject, self).remove()
 
+        # Do scheduling
+        if scheduler is not None:
+            yield scheduler.doImplicitScheduling()
 
+
     @classproperty
     def _recurrenceMinMaxByIDQuery(cls): # @NoSelf
         """

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/test/test_implicit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/test/test_implicit.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/test/test_implicit.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -313,6 +313,7 @@
 END:VCALENDAR
 """
 
+        self.patch(config, "EnablePrivateEvents", True)
         calendar_collection = (yield self.calendarUnderTest(home="user01"))
         calendar = Component.fromString(data1)
         try:
@@ -345,6 +346,7 @@
 END:VCALENDAR
 """
 
+        self.patch(config, "EnablePrivateEvents", True)
         calendar_collection = (yield self.calendarUnderTest(home="user01"))
         calendar = Component.fromString(data1)
         txn = self.transactionUnderTest()
@@ -735,9 +737,6 @@
 X-APPLE-DROPBOX:https://example.com/calendars/users/user02/dropbox/123.dropbox
 ATTACH;VALUE=URI:https://example.com/calendars/users/user02/dropbox/123.dropbox/1.txt
 ATTACH;VALUE=URI:https://example.org/attachments/2.txt
-ORGANIZER;CN="User 01":mailto:user01 at example.com
-ATTENDEE:mailto:user01 at example.com
-ATTENDEE:mailto:user02 at example.com
 END:VTODO
 END:VCALENDAR
 """
@@ -1040,7 +1039,6 @@
 DTSTAMP:20080601T120000Z
 DTSTART:20080601T120000Z
 DTEND:20080601T130000Z
-X-CALENDARSERVER-PRIVATE-COMMENT:My Comment
 END:VEVENT
 END:VCALENDAR
 """
@@ -1067,7 +1065,6 @@
 """
 
         calendar_resource = (yield self.calendarObjectUnderTest(name="test.ics", home="user01",))
-        calendar_resource.isScheduleObject = True
         calendar = Component.fromString(data2)
         yield calendar_resource.setComponent(calendar)
         schedule_tag = calendar_resource.scheduleTag
@@ -1114,6 +1111,6 @@
 
         calendar_resource = (yield self.calendarObjectUnderTest(name="test.ics", home="user01",))
         calendar = Component.fromString(data4)
-        yield calendar_resource._setComponentInternal(calendar, update_state=ComponentUpdateState.ORGANIZER_ITIP_UPDATE)
+        yield calendar_resource._setComponentInternal(calendar, internal_state=ComponentUpdateState.ORGANIZER_ITIP_UPDATE)
         self.assertEqual(calendar_resource.scheduleTag, schedule_tag)
         yield self.commit()

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/icalendarstore.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/icalendarstore.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/icalendarstore.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -64,6 +64,8 @@
     NORMAL -                this is an application layer (user) generated store that should do all
                             validation and implicit scheduling operations.
 
+    INBOX  -                the store is updating an inbox item as the result of an iTIP message.
+
     ORGANIZER_ITIP_UPDATE - the store is an update to an organizer's data caused by processing an incoming
                             iTIP message. Some validation and implicit scheduling is not done. Schedule-Tag
                             is not changed.
@@ -76,20 +78,45 @@
                             iTIP message. Some validation and implicit scheduling is not done. Schedule-Tag
                             is changed.
 
+    RAW                   - store the supplied data as-is without any processing or validation. This is used
+                            for unit testing purposes only.
     """
 
     NORMAL = NamedConstant()
+    INBOX = NamedConstant()
     ORGANIZER_ITIP_UPDATE = NamedConstant()
     ATTENDEE_ITIP_UPDATE = NamedConstant()
     ATTENDEE_ITIP_REFRESH = NamedConstant()
+    RAW = NamedConstant()
 
     NORMAL.description = "normal"
+    INBOX.description = "inbox"
     ORGANIZER_ITIP_UPDATE.description = "organizer-update"
     ATTENDEE_ITIP_UPDATE.description = "attendee-update"
     ATTENDEE_ITIP_REFRESH.description = "attendee-refresh"
+    RAW.description = "raw"
 
 
 
+class ComponentRemoveState(Names):
+    """
+    These are constants that define what type of component remove operation is being done. This is used
+    in the .remove() api to determine what type of processing needs to occur.
+
+    NORMAL -                this is an application layer (user) generated remove that should do all
+                            implicit scheduling operations.
+
+    INTERNAL -              remove the resource without implicit scheduling.
+    """
+
+    NORMAL = NamedConstant()
+    INTERNAL = NamedConstant()
+
+    NORMAL.description = "normal"
+    INTERNAL.description = "internal"
+
+
+
 class InvalidComponentTypeError(CommonStoreError):
     """
     Invalid object resource component type for collection.

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/carddav/datastore/file.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/carddav/datastore/file.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/carddav/datastore/file.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -83,9 +83,12 @@
     def _addressbookStore(self):
         return self._dataStore
 
+
     def createdHome(self):
         self.createAddressBookWithName("addressbook")
 
+
+
 class AddressBook(CommonHomeChild):
     """
     File-based implementation of L{IAddressBook}.
@@ -113,10 +116,12 @@
         self._index = Index(self)
         self._objectResourceClass = AddressBookObject
 
+
     @property
     def _addressbookHome(self):
         return self._home
 
+
     def resourceType(self):
         return ResourceType.addressbook #@UndefinedVariable
 
@@ -126,8 +131,6 @@
     addressbookObjectWithName = CommonHomeChild.objectResourceWithName
     addressbookObjectWithUID = CommonHomeChild.objectResourceWithUID
     createAddressBookObjectWithName = CommonHomeChild.createObjectResourceWithName
-    removeAddressBookObjectWithName = CommonHomeChild.removeObjectResourceWithName
-    removeAddressBookObjectWithUID = CommonHomeChild.removeObjectResourceWithUID
     addressbookObjectsSinceToken = CommonHomeChild.objectResourcesSinceToken
 
 
@@ -142,12 +145,15 @@
             ),
         )
 
+
     def contentType(self):
         """
         The content type of Addresbook objects is text/vcard.
         """
         return MimeType.fromString("text/vcard; charset=utf-8")
 
+
+
 class AddressBookObject(CommonObjectResource):
     """
     """
@@ -272,11 +278,13 @@
         self._objectText = text
         return text
 
+
     def uid(self):
         if not hasattr(self, "_uid"):
             self._uid = self.component().resourceUID()
         return self._uid
 
+
     # IDataStoreObject
     def contentType(self):
         """
@@ -284,6 +292,8 @@
         """
         return MimeType.fromString("text/vcard; charset=utf-8")
 
+
+
 class AddressBookStubResource(CommonStubResource):
     """
     Just enough resource to keep the addressbook's sql DB classes going.
@@ -292,6 +302,7 @@
     def isAddressBookCollection(self):
         return True
 
+
     def getChild(self, name):
         addressbookObject = self.resource.addressbookObjectWithName(name)
         if addressbookObject:
@@ -307,6 +318,7 @@
             return None
 
 
+
 class Index(object):
     #
     # OK, here's where we get ugly.
@@ -328,5 +340,3 @@
             addressbookObject._componentType = componentType
 
             yield addressbookObject
-
-

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/carddav/datastore/sql.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/carddav/datastore/sql.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -41,20 +41,20 @@
 from txdav.common.datastore.sql_legacy import PostgresLegacyABIndexEmulator
 
 from txdav.carddav.datastore.util import validateAddressBookComponent
-from txdav.carddav.iaddressbookstore import IAddressBookHome, IAddressBook,\
+from txdav.carddav.iaddressbookstore import IAddressBookHome, IAddressBook, \
     IAddressBookObject
 
-from txdav.common.datastore.sql import CommonHome, CommonHomeChild,\
+from txdav.common.datastore.sql import CommonHome, CommonHomeChild, \
     CommonObjectResource, EADDRESSBOOKTYPE
 from twext.enterprise.dal.syntax import Delete
 from twext.enterprise.dal.syntax import Insert
 
 from twext.enterprise.dal.syntax import Update
 from twext.enterprise.dal.syntax import utcNowSQL
-from txdav.common.datastore.sql_tables import ADDRESSBOOK_TABLE,\
-    ADDRESSBOOK_BIND_TABLE, ADDRESSBOOK_OBJECT_REVISIONS_TABLE,\
-    ADDRESSBOOK_OBJECT_TABLE, ADDRESSBOOK_HOME_TABLE,\
-    ADDRESSBOOK_HOME_METADATA_TABLE, ADDRESSBOOK_AND_ADDRESSBOOK_BIND,\
+from txdav.common.datastore.sql_tables import ADDRESSBOOK_TABLE, \
+    ADDRESSBOOK_BIND_TABLE, ADDRESSBOOK_OBJECT_REVISIONS_TABLE, \
+    ADDRESSBOOK_OBJECT_TABLE, ADDRESSBOOK_HOME_TABLE, \
+    ADDRESSBOOK_HOME_METADATA_TABLE, ADDRESSBOOK_AND_ADDRESSBOOK_BIND, \
     ADDRESSBOOK_OBJECT_AND_BIND_TABLE, \
     ADDRESSBOOK_OBJECT_REVISIONS_AND_BIND_TABLE, schema
 from txdav.base.propertystore.base import PropertyName
@@ -90,7 +90,6 @@
         self._childClass = AddressBook
         super(AddressBookHome, self).__init__(transaction, ownerUID, notifiers)
 
-
     addressbooks = CommonHome.children
     listAddressbooks = CommonHome.listChildren
     loadAddressbooks = CommonHome.loadChildren
@@ -163,8 +162,8 @@
     def __init__(self, *args, **kw):
         super(AddressBook, self).__init__(*args, **kw)
         self._index = PostgresLegacyABIndexEmulator(self)
-        
 
+
     @property
     def _addressbookHome(self):
         return self._home
@@ -173,15 +172,12 @@
     def resourceType(self):
         return ResourceType.addressbook #@UndefinedVariable
 
-
     ownerAddressBookHome = CommonHomeChild.ownerHome
     addressbookObjects = CommonHomeChild.objectResources
     listAddressbookObjects = CommonHomeChild.listObjectResources
     addressbookObjectWithName = CommonHomeChild.objectResourceWithName
     addressbookObjectWithUID = CommonHomeChild.objectResourceWithUID
     createAddressBookObjectWithName = CommonHomeChild.createObjectResourceWithName
-    removeAddressBookObjectWithName = CommonHomeChild.removeObjectResourceWithName
-    removeAddressBookObjectWithUID = CommonHomeChild.removeObjectResourceWithUID
     addressbookObjectsSinceToken = CommonHomeChild.objectResourcesSinceToken
 
 
@@ -211,6 +207,7 @@
         return super(AddressBook, self).unshare(EADDRESSBOOKTYPE)
 
 
+
 class AddressBookObject(CommonObjectResource):
 
     implements(IAddressBookObject)
@@ -218,7 +215,7 @@
     _objectTable = ADDRESSBOOK_OBJECT_TABLE
     _objectSchema = schema.ADDRESSBOOK_OBJECT
 
-    def __init__(self, addressbook, name, uid, resourceID=None, metadata=None):
+    def __init__(self, addressbook, name, uid, resourceID=None, options=None):
 
         super(AddressBookObject, self).__init__(addressbook, name, uid, resourceID)
 
@@ -233,7 +230,7 @@
 
 
     @inlineCallbacks
-    def setComponent(self, component, inserting=False):
+    def setComponent(self, component, inserting=False, options=None):
 
         validateAddressBookComponent(self, self._addressbook, component, inserting)
 
@@ -247,8 +244,7 @@
 
 
     @inlineCallbacks
-    def updateDatabase(self, component, expand_until=None, reCreate=False,
-                       inserting=False):
+    def updateDatabase(self, component, expand_until=None, reCreate=False, inserting=False):
         """
         Update the database tables for the new data being written.
 
@@ -265,7 +261,7 @@
         self._md5 = hashlib.md5(componentText).hexdigest()
         self._size = len(componentText)
 
-        # Special - if migrating we need to preserve the original md5    
+        # Special - if migrating we need to preserve the original md5
         if self._txn._migrating and hasattr(component, "md5"):
             self._md5 = component.md5
 
@@ -315,7 +311,7 @@
 
         if unfixed:
             self.log_error("Address data id=%s had unfixable problems:\n  %s" % (self._resourceID, "\n  ".join(unfixed),))
-        
+
         if fixed:
             self.log_error("Address data id=%s had fixable problems:\n  %s" % (self._resourceID, "\n  ".join(fixed),))
 

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/file.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/file.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/file.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -1227,12 +1227,6 @@
             raise NoSuchObjectResourceError(name)
 
 
-    @writeOperation
-    def removeObjectResourceWithUID(self, uid):
-        self.removeObjectResourceWithName(
-            self.objectResourceWithUID(uid)._path.basename())
-
-
     def syncToken(self):
 
         try:
@@ -1383,6 +1377,10 @@
         raise NotImplementedError
 
 
+    def remove(self):
+        self._parentCollection.removeObjectResourceWithName(self._name)
+
+
     def _text(self):
         raise NotImplementedError
 
@@ -1511,7 +1509,6 @@
     notificationObjects = CommonHomeChild.objectResources
     listNotificationObjects = CommonHomeChild.listObjectResources
     notificationObjectWithName = CommonHomeChild.objectResourceWithName
-    removeNotificationObjectWithUID = CommonHomeChild.removeObjectResourceWithUID
 
     def notificationObjectWithUID(self, uid):
         name = uid + ".xml"

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -1096,6 +1096,7 @@
         many were removed.
         """
 
+        assert "This needs to be moved into txdav.caldav as it needs to call _removeInternal"
         # Make sure cut off is after any lower limit truncation in the DB
         if config.FreeBusyIndexLowerLimitDays:
             truncateLowerLimit = PyCalendarDateTime.getToday()
@@ -1108,7 +1109,8 @@
         for uid, calendarName, eventName, _ignore_maxDate in results:
             home = (yield self.calendarHomeWithUID(uid))
             calendar = (yield home.childWithName(calendarName))
-            (yield calendar.removeObjectResourceWithName(eventName))
+            resource = (yield calendar.objectResourceWithName(eventName))
+            yield resource._removeInternal()
             count += 1
         returnValue(count)
 
@@ -3690,7 +3692,7 @@
 
 
     @inlineCallbacks
-    def createObjectResourceWithName(self, name, component, metadata=None):
+    def createObjectResourceWithName(self, name, component, options=None):
         """
         Create a new resource with component data and optional metadata. We
         create the python object using the metadata then create the actual store
@@ -3708,8 +3710,7 @@
                 raise TooManyObjectResourcesError()
 
         objectResource = (
-            yield self._objectResourceClass.create(self, name, component,
-                                                   metadata)
+            yield self._objectResourceClass.create(self, name, component, options)
         )
         self._objects[objectResource.name()] = objectResource
         self._objects[objectResource.uid()] = objectResource
@@ -3720,31 +3721,10 @@
 
 
     @inlineCallbacks
-    def removeObjectResourceWithName(self, name):
-
-        child = (yield self.objectResourceWithName(name))
-        if child is None:
-            raise NoSuchObjectResourceError
-        yield self.removeObjectResource(child)
-
-
-    @inlineCallbacks
-    def removeObjectResourceWithUID(self, uid):
-
-        child = (yield self.objectResourceWithUID(uid))
-        if child is None:
-            raise NoSuchObjectResourceError
-        yield self.removeObjectResource(child)
-
-
-    @inlineCallbacks
-    def removeObjectResource(self, child):
-        name = child.name()
-        uid = child.uid()
-        yield child.remove()
-        self._objects.pop(name, None)
-        self._objects.pop(uid, None)
-        yield self._deleteRevision(name)
+    def removedObjectResource(self, child):
+        self._objects.pop(child.name(), None)
+        self._objects.pop(child.uid(), None)
+        yield self._deleteRevision(child.name())
         yield self.notifyChanged()
 
 
@@ -3996,7 +3976,7 @@
 
     BATCH_LOAD_SIZE = 50
 
-    def __init__(self, parent, name, uid, resourceID=None, metadata=None):
+    def __init__(self, parent, name, uid, resourceID=None, options=None):
         self._parentCollection = parent
         self._resourceID = resourceID
         self._name = name
@@ -4140,7 +4120,7 @@
 
     @classmethod
     @inlineCallbacks
-    def create(cls, parent, name, component, metadata):
+    def create(cls, parent, name, component, options=None):
 
         child = (yield cls.objectWithName(parent, name, None))
         if child:
@@ -4149,8 +4129,8 @@
         if name.startswith("."):
             raise ObjectResourceNameNotAllowedError(name)
 
-        objectResource = cls(parent, name, None, None, metadata=metadata)
-        yield objectResource.setComponent(component, inserting=True)
+        objectResource = cls(parent, name, None, None, options=options)
+        yield objectResource.setComponent(component, inserting=True, options=options)
         yield objectResource._loadPropertyStore(created=True)
 
         # Note: setComponent triggers a notification, so we don't need to
@@ -4324,7 +4304,7 @@
         self._locked = True
 
 
-    def setComponent(self, component, inserting=False):
+    def setComponent(self, component, inserting=False, options=None):
         raise NotImplementedError
 
 
@@ -4366,6 +4346,8 @@
                                    resourceID=self._resourceID)
         self.properties()._removeResource()
 
+        self._parentCollection.removedObjectResource(self)
+
         # Set to non-existent state
         self._resourceID = None
         self._name = None

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/test/util.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/test/util.py	2013-04-11 20:31:47 UTC (rev 11030)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/test/util.py	2013-04-11 21:14:53 UTC (rev 11031)
@@ -50,6 +50,7 @@
 from txdav.base.datastore.dbapiclient import DiagnosticConnectionWrapper
 from txdav.base.datastore.subpostgres import PostgresService
 from txdav.base.propertystore.base import PropertyName
+from txdav.caldav.icalendarstore import ComponentUpdateState
 from txdav.common.datastore.sql import CommonDataStore, current_sql_schema
 from txdav.common.datastore.sql_tables import schema
 from txdav.common.icommondatastore import NoSuchHomeChildError
@@ -415,10 +416,11 @@
                     calendar = yield home.calendarWithName(calendarName)
                     for objectName in calendarObjNames:
                         objData, metadata = calendarObjNames[objectName]
-                        yield calendar.createCalendarObjectWithName(
+                        yield calendar._createCalendarObjectWithNameInternal(
                             objectName,
                             VComponent.fromString(updateToCurrentYear(objData)),
-                            metadata=metadata,
+                            internal_state=ComponentUpdateState.RAW,
+                            options=metadata,
                         )
     yield populateTxn.commit()
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130411/8adab5fa/attachment-0001.html>


More information about the calendarserver-changes mailing list