[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