[CalendarServer-changes] [11159] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Thu May 9 12:07:38 PDT 2013
Revision: 11159
http://trac.calendarserver.org//changeset/11159
Author: cdaboo at apple.com
Date: 2013-05-09 12:07:38 -0700 (Thu, 09 May 2013)
Log Message:
-----------
Move default alarm properties into DB columns.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/resource.py
CalendarServer/trunk/twistedcaldav/sharing.py
CalendarServer/trunk/twistedcaldav/storebridge.py
CalendarServer/trunk/txdav/caldav/datastore/sql.py
CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py
CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py
Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/twistedcaldav/resource.py 2013-05-09 19:07:38 UTC (rev 11159)
@@ -530,21 +530,6 @@
returnValue(res)
- def _hasSharedProperty(self, qname, request):
-
- # Always have default alarms on shared calendars
- if qname in (
- caldavxml.DefaultAlarmVEventDateTime.qname(),
- caldavxml.DefaultAlarmVEventDate.qname(),
- caldavxml.DefaultAlarmVToDoDateTime.qname(),
- caldavxml.DefaultAlarmVToDoDate.qname(),
- ) and self.isCalendarCollection():
- return True
-
- p = self.deadProperties().contains(qname)
- return p
-
-
def _hasGlobalProperty(self, property, request):
"""
Need to special case schedule-calendar-transp for backwards compatability.
@@ -715,6 +700,8 @@
"%r is not a WebDAVElement instance" % (property,)
)
+ self._preProcessWriteProperty(property, request)
+
res = (yield self._writeGlobalProperty(property, request))
returnValue(res)
@@ -781,8 +768,6 @@
@inlineCallbacks
def _writeGlobalProperty(self, property, request):
- self._preProcessWriteProperty(property, request)
-
if property.qname() == caldavxml.ScheduleCalendarTransp.qname():
yield self._newStoreObject.setUsedForFreeBusy(property == caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()))
returnValue(None)
@@ -1962,35 +1947,70 @@
the default alarm properties in a more useful way that using readProperty.
In particular it will handle inheritance of the property from the home if a
calendar does not explicitly have the property.
+
+ Important: we need to distinguish between the property not being present, or
+ present but empty, however the store by default is unable to distinguish between
+ None and and empty C{str}. So what we do is use the value "empty" to represent
+ a present but empty property.
"""
- def getDefaultAlarm(self, vevent, timed):
+ ALARM_PROPERTIES = {
+ caldavxml.DefaultAlarmVEventDateTime.qname(): (True, True,),
+ caldavxml.DefaultAlarmVEventDate.qname(): (True, False,),
+ caldavxml.DefaultAlarmVToDoDateTime.qname(): (False, True,),
+ caldavxml.DefaultAlarmVToDoDate.qname(): (False, False,),
+ }
- if vevent:
- propname = caldavxml.DefaultAlarmVEventDateTime if timed else caldavxml.DefaultAlarmVEventDate
- else:
- propname = caldavxml.DefaultAlarmVToDoDateTime if timed else caldavxml.DefaultAlarmVToDoDate
+ ALARM_PROPERTY_CLASSES = {
+ caldavxml.DefaultAlarmVEventDateTime.qname(): caldavxml.DefaultAlarmVEventDateTime,
+ caldavxml.DefaultAlarmVEventDate.qname(): caldavxml.DefaultAlarmVEventDate,
+ caldavxml.DefaultAlarmVToDoDateTime.qname(): caldavxml.DefaultAlarmVToDoDateTime,
+ caldavxml.DefaultAlarmVToDoDate.qname(): caldavxml.DefaultAlarmVToDoDate,
+ }
+ def getDefaultAlarmProperty(self, propname):
+
+ vevent, timed = DefaultAlarmPropertyMixin.ALARM_PROPERTIES[propname]
+
if self.isCalendarCollection():
# Get from calendar or inherit from home
- try:
- prop = self.deadProperties().get(propname.qname())
- except HTTPError:
- prop = None
- if prop is None:
- prop = self.parentResource().getDefaultAlarm(vevent, timed)
+ alarm = self._newStoreObject.getDefaultAlarm(vevent, timed)
+ if alarm is None:
+ return self.parentResource().getDefaultAlarmProperty(propname)
+ elif alarm == "empty":
+ return DefaultAlarmPropertyMixin.ALARM_PROPERTY_CLASSES[propname]()
else:
# Just return whatever is on the home
- try:
- prop = self.deadProperties().get(propname.qname())
- except HTTPError:
- prop = None
+ alarm = self._newStoreHome.getDefaultAlarm(vevent, timed)
- return str(prop) if prop is not None else None
+ return DefaultAlarmPropertyMixin.ALARM_PROPERTY_CLASSES[propname](alarm) if alarm else None
+ @inlineCallbacks
+ def setDefaultAlarmProperty(self, prop):
+ vevent, timed = DefaultAlarmPropertyMixin.ALARM_PROPERTIES[prop.qname()]
+ alarm = str(prop)
+
+ if self.isCalendarCollection():
+ yield self._newStoreObject.setDefaultAlarm(alarm if alarm else "empty", vevent, timed)
+ else:
+ yield self._newStoreHome.setDefaultAlarm(alarm if alarm else "empty", vevent, timed)
+
+
+ @inlineCallbacks
+ def removeDefaultAlarmProperty(self, propname):
+
+ vevent, timed = DefaultAlarmPropertyMixin.ALARM_PROPERTIES[propname]
+
+ if self.isCalendarCollection():
+ yield self._newStoreObject.setDefaultAlarm(None, vevent, timed)
+ else:
+ yield self._newStoreHome.setDefaultAlarm(None, vevent, timed)
+
+
+
class CommonHomeResource(PropfindCacheMixin, SharedHomeMixin, CalDAVResource):
"""
Logic common to Calendar and Addressbook home resources.
@@ -2416,6 +2436,24 @@
return existing
+ def _hasGlobalProperty(self, property, request):
+ """
+ Need to special case schedule-calendar-transp for backwards compatability.
+ """
+
+ if type(property) is tuple:
+ qname = property
+ else:
+ qname = property.qname()
+
+ # Force calendar collections to always appear to have the property
+ if qname in DefaultAlarmPropertyMixin.ALARM_PROPERTIES:
+ return succeed(self.getDefaultAlarmProperty(qname) is not None)
+
+ else:
+ return super(CalendarHomeResource, self)._hasGlobalProperty(property, request)
+
+
@inlineCallbacks
def readProperty(self, property, request):
if type(property) is tuple:
@@ -2449,10 +2487,39 @@
else:
returnValue(None)
+ elif qname in DefaultAlarmPropertyMixin.ALARM_PROPERTIES:
+ returnValue(self.getDefaultAlarmProperty(qname))
+
result = (yield super(CalendarHomeResource, self).readProperty(property, request))
returnValue(result)
+ @inlineCallbacks
+ def _writeGlobalProperty(self, property, request):
+
+ if property.qname() in DefaultAlarmPropertyMixin.ALARM_PROPERTIES:
+ yield self.setDefaultAlarmProperty(property)
+ returnValue(None)
+
+ result = (yield super(CalendarHomeResource, self)._writeGlobalProperty(property, request))
+ returnValue(result)
+
+
+ @inlineCallbacks
+ def removeProperty(self, property, request):
+ if type(property) is tuple:
+ qname = property
+ else:
+ qname = property.qname()
+
+ if qname in DefaultAlarmPropertyMixin.ALARM_PROPERTIES:
+ result = (yield self.removeDefaultAlarmProperty(qname))
+ returnValue(result)
+
+ result = (yield super(CalendarHomeResource, self).removeProperty(property, request))
+ returnValue(result)
+
+
def _setupProvisions(self):
# Cache children which must be of a specific type
Modified: CalendarServer/trunk/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/sharing.py 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/twistedcaldav/sharing.py 2013-05-09 19:07:38 UTC (rev 11159)
@@ -1202,10 +1202,10 @@
# Calendars always start out transparent and with empty default alarms
if isNewShare and shareeCollection.isCalendarCollection():
yield shareeCollection._newStoreObject.setUsedForFreeBusy(False)
- yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDateTime.fromString(""), request)
- yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDate.fromString(""), request)
- yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVToDoDateTime.fromString(""), request)
- yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVToDoDate.fromString(""), request)
+ yield shareeCollection._newStoreObject.setDefaultAlarm("empty", True, True)
+ yield shareeCollection._newStoreObject.setDefaultAlarm("empty", True, False)
+ yield shareeCollection._newStoreObject.setDefaultAlarm("empty", False, True)
+ yield shareeCollection._newStoreObject.setDefaultAlarm("empty", False, False)
# Notify client of changes
yield self.notifyChanged()
Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py 2013-05-09 19:07:38 UTC (rev 11159)
@@ -1214,7 +1214,65 @@
return caldavxml.CalendarData
+ def _hasGlobalProperty(self, property, request):
+ """
+ Need to special case schedule-calendar-transp for backwards compatability.
+ """
+
+ if type(property) is tuple:
+ qname = property
+ else:
+ qname = property.qname()
+
+ # Force calendar collections to always appear to have the property
+ if qname in DefaultAlarmPropertyMixin.ALARM_PROPERTIES:
+ return succeed(self.getDefaultAlarmProperty(qname) is not None)
+
+ else:
+ return super(CalendarCollectionResource, self)._hasGlobalProperty(property, request)
+
+
@inlineCallbacks
+ def readProperty(self, property, request):
+ if type(property) is tuple:
+ qname = property
+ else:
+ qname = property.qname()
+
+ if qname in DefaultAlarmPropertyMixin.ALARM_PROPERTIES:
+ returnValue(self.getDefaultAlarmProperty(qname))
+
+ result = (yield super(CalendarCollectionResource, self).readProperty(property, request))
+ returnValue(result)
+
+
+ @inlineCallbacks
+ def _writeGlobalProperty(self, property, request):
+
+ if property.qname() in DefaultAlarmPropertyMixin.ALARM_PROPERTIES:
+ yield self.setDefaultAlarmProperty(property)
+ returnValue(None)
+
+ result = (yield super(CalendarCollectionResource, self)._writeGlobalProperty(property, request))
+ returnValue(result)
+
+
+ @inlineCallbacks
+ def removeProperty(self, property, request):
+ if type(property) is tuple:
+ qname = property
+ else:
+ qname = property.qname()
+
+ if qname in DefaultAlarmPropertyMixin.ALARM_PROPERTIES:
+ result = (yield self.removeDefaultAlarmProperty(qname))
+ returnValue(result)
+
+ result = (yield super(CalendarCollectionResource, self).removeProperty(property, request))
+ returnValue(result)
+
+
+ @inlineCallbacks
def storeResourceData(self, newchild, component, returnChangedData=False):
yield newchild.storeComponent(component)
Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py 2013-05-09 19:07:38 UTC (rev 11159)
@@ -358,6 +358,10 @@
return (
cls._homeMetaDataSchema.DEFAULT_EVENTS,
cls._homeMetaDataSchema.DEFAULT_TASKS,
+ cls._homeMetaDataSchema.ALARM_VEVENT_TIMED,
+ cls._homeMetaDataSchema.ALARM_VEVENT_ALLDAY,
+ cls._homeMetaDataSchema.ALARM_VTODO_TIMED,
+ cls._homeMetaDataSchema.ALARM_VTODO_ALLDAY,
cls._homeMetaDataSchema.CREATED,
cls._homeMetaDataSchema.MODIFIED,
)
@@ -376,6 +380,10 @@
return (
"_default_events",
"_default_tasks",
+ "_alarm_vevent_timed",
+ "_alarm_vevent_allday",
+ "_alarm_vtodo_timed",
+ "_alarm_vtodo_allday",
"_created",
"_modified",
)
@@ -784,6 +792,12 @@
# Not allowed to delete the default calendar
return calendar._resourceID in (self._default_events, self._default_tasks)
+ ALARM_DETAILS = {
+ (True, True): (_homeMetaDataSchema.ALARM_VEVENT_TIMED, "_alarm_vevent_timed"),
+ (True, False): (_homeMetaDataSchema.ALARM_VEVENT_ALLDAY, "_alarm_vevent_allday"),
+ (False, True): (_homeMetaDataSchema.ALARM_VTODO_TIMED, "_alarm_vtodo_timed"),
+ (False, False): (_homeMetaDataSchema.ALARM_VTODO_ALLDAY, "_alarm_vtodo_allday"),
+ }
def getDefaultAlarm(self, vevent, timed):
"""
@@ -793,20 +807,14 @@
@type vevent: C{bool}
@param timed: timed ({C{True}) or all-day ({C{False})
@type timed: C{bool}
+
@return: the alarm (text)
@rtype: C{str}
"""
- if vevent:
- propname = caldavxml.DefaultAlarmVEventDateTime if timed else caldavxml.DefaultAlarmVEventDate
- else:
- propname = caldavxml.DefaultAlarmVToDoDateTime if timed else caldavxml.DefaultAlarmVToDoDate
+ return getattr(self, self.ALARM_DETAILS[(vevent, timed)][1])
- prop = self.properties().get(PropertyName.fromElement(propname))
- return str(prop) if prop is not None else None
-
-
@inlineCallbacks
def setDefaultAlarm(self, alarm, vevent, timed):
"""
@@ -820,12 +828,16 @@
@type timed: C{bool}
"""
- if vevent:
- prop = caldavxml.DefaultAlarmVEventDateTime if timed else caldavxml.DefaultAlarmVEventDate
- else:
- prop = caldavxml.DefaultAlarmVToDoDateTime if timed else caldavxml.DefaultAlarmVToDoDate
+ colname, attr_alarm = self.ALARM_DETAILS[(vevent, timed)]
- self.properties()[PropertyName.fromElement(prop)] = prop.fromString(alarm)
+ setattr(self, attr_alarm, alarm)
+
+ chm = self._homeMetaDataSchema
+ yield Update(
+ {colname: alarm},
+ Where=chm.RESOURCE_ID == self._resourceID,
+ ).on(self._txn)
+ yield self.invalidateQueryCache()
yield self.notifyChanged()
@@ -914,6 +926,10 @@
return (
cls._bindSchema.TRANSP,
+ cls._bindSchema.ALARM_VEVENT_TIMED,
+ cls._bindSchema.ALARM_VEVENT_ALLDAY,
+ cls._bindSchema.ALARM_VTODO_TIMED,
+ cls._bindSchema.ALARM_VTODO_ALLDAY,
)
@@ -927,6 +943,10 @@
return (
"_transp",
+ "_alarm_vevent_timed",
+ "_alarm_vevent_allday",
+ "_alarm_vtodo_timed",
+ "_alarm_vtodo_allday",
)
@@ -1009,6 +1029,12 @@
else:
return True
+ ALARM_DETAILS = {
+ (True, True): (_bindSchema.ALARM_VEVENT_TIMED, "_alarm_vevent_timed"),
+ (True, False): (_bindSchema.ALARM_VEVENT_ALLDAY, "_alarm_vevent_allday"),
+ (False, True): (_bindSchema.ALARM_VTODO_TIMED, "_alarm_vtodo_timed"),
+ (False, False): (_bindSchema.ALARM_VTODO_ALLDAY, "_alarm_vtodo_allday"),
+ }
def getDefaultAlarm(self, vevent, timed):
"""
@@ -1022,19 +1048,9 @@
@rtype: C{str}
"""
- if vevent:
- propname = caldavxml.DefaultAlarmVEventDateTime if timed else caldavxml.DefaultAlarmVEventDate
- else:
- propname = caldavxml.DefaultAlarmVToDoDateTime if timed else caldavxml.DefaultAlarmVToDoDate
+ return getattr(self, self.ALARM_DETAILS[(vevent, timed)][1])
- prop = self.properties().get(PropertyName.fromElement(propname))
- if prop is None:
- return self.viewerHome().getDefaultAlarm(vevent, timed)
- else:
- return str(prop)
-
-
@inlineCallbacks
def setDefaultAlarm(self, alarm, vevent, timed):
"""
@@ -1048,12 +1064,16 @@
@type timed: C{bool}
"""
- if vevent:
- prop = caldavxml.DefaultAlarmVEventDateTime if timed else caldavxml.DefaultAlarmVEventDate
- else:
- prop = caldavxml.DefaultAlarmVToDoDateTime if timed else caldavxml.DefaultAlarmVToDoDate
+ colname, attr_alarm = self.ALARM_DETAILS[(vevent, timed)]
- self.properties()[PropertyName.fromElement(prop)] = prop.fromString(alarm)
+ setattr(self, attr_alarm, alarm)
+
+ cal = self._bindSchema
+ yield Update(
+ {colname: alarm},
+ Where=(cal.CALENDAR_HOME_RESOURCE_ID == self.viewerHome()._resourceID).And(cal.CALENDAR_RESOURCE_ID == self._resourceID)
+ ).on(self._txn)
+ yield self.invalidateQueryCache()
yield self.notifyChanged()
@@ -1080,9 +1100,7 @@
self._transp = _TRANSP_OPAQUE if use_it else _TRANSP_TRANSPARENT
cal = self._bindSchema
yield Update(
- {
- cal.TRANSP : self._transp
- },
+ {cal.TRANSP : self._transp},
Where=(cal.CALENDAR_HOME_RESOURCE_ID == self.viewerHome()._resourceID).And(cal.CALENDAR_RESOURCE_ID == self._resourceID)
).on(self._txn)
yield self.invalidateQueryCache()
@@ -1806,7 +1824,9 @@
# See if default exists and add using appropriate logic
alarm = self.calendar().getDefaultAlarm(vevent, timed)
- if alarm and component.addAlarms(alarm):
+ if alarm is None:
+ alarm = self.calendar().viewerHome().getDefaultAlarm(vevent, timed)
+ if alarm and alarm != "empty" and component.addAlarms(alarm):
self._componentChanged = True
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2013-05-09 19:07:38 UTC (rev 11159)
@@ -1566,3 +1566,129 @@
obj = (yield self.calendarObjectUnderTest())
calendarObject = (yield home.objectResourceWithID(obj._resourceID))
self.assertNotEquals(calendarObject, None)
+
+
+ @inlineCallbacks
+ def test_defaultAlarms(self):
+ """
+ L{ICalendarHome.objectResourceWithID} will return the calendar object..
+ """
+
+ alarmhome1 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT1M
+END:VALARM
+"""
+
+ alarmhome2 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT2M
+END:VALARM
+"""
+
+ alarmhome3 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT3M
+END:VALARM
+"""
+
+ alarmhome4 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT4M
+END:VALARM
+"""
+
+ alarmcalendar1 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT1M
+END:VALARM
+"""
+
+ alarmcalendar2 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT2M
+END:VALARM
+"""
+
+ alarmcalendar3 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT3M
+END:VALARM
+"""
+
+ alarmcalendar4 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT4M
+END:VALARM
+"""
+
+ detailshome = (
+ (True, True, alarmhome1,),
+ (True, False, alarmhome2,),
+ (False, True, alarmhome3,),
+ (False, False, alarmhome4,),
+ )
+
+ home = yield self.homeUnderTest()
+ for vevent, timed, _ignore_alarm in detailshome:
+ alarm_result = (yield home.getDefaultAlarm(vevent, timed))
+ self.assertEquals(alarm_result, None)
+
+ for vevent, timed, alarm in detailshome:
+ yield home.setDefaultAlarm(alarm, vevent, timed)
+
+ yield self.commit()
+
+ home = yield self.homeUnderTest()
+ for vevent, timed, alarm in detailshome:
+ alarm_result = (yield home.getDefaultAlarm(vevent, timed))
+ self.assertEquals(alarm_result, alarm)
+
+ for vevent, timed, alarm in detailshome:
+ yield home.setDefaultAlarm(None, vevent, timed)
+
+ yield self.commit()
+
+ home = yield self.homeUnderTest()
+ for vevent, timed, _ignore_alarm in detailshome:
+ alarm_result = (yield home.getDefaultAlarm(vevent, timed))
+ self.assertEquals(alarm_result, None)
+
+ yield self.commit()
+
+ detailscalendar = (
+ (True, True, alarmcalendar1,),
+ (True, False, alarmcalendar2,),
+ (False, True, alarmcalendar3,),
+ (False, False, alarmcalendar4,),
+ )
+
+ calendar = yield self.calendarUnderTest()
+ for vevent, timed, _ignore_alarm in detailscalendar:
+ alarm_result = (yield calendar.getDefaultAlarm(vevent, timed))
+ self.assertEquals(alarm_result, None)
+
+ for vevent, timed, alarm in detailscalendar:
+ yield calendar.setDefaultAlarm(alarm, vevent, timed)
+
+ yield self.commit()
+
+ calendar = yield self.calendarUnderTest()
+ for vevent, timed, alarm in detailscalendar:
+ alarm_result = (yield calendar.getDefaultAlarm(vevent, timed))
+ self.assertEquals(alarm_result, alarm)
+
+ yield self.commit()
+
+ calendar = yield self.calendarUnderTest()
+ for vevent, timed, alarm in detailscalendar:
+ yield calendar.setDefaultAlarm(None, vevent, timed)
+
+ yield self.commit()
+
+ calendar = yield self.calendarUnderTest()
+ for vevent, timed, _ignore_alarm in detailscalendar:
+ alarm_result = (yield calendar.getDefaultAlarm(vevent, timed))
+ self.assertEquals(alarm_result, None)
+
+ yield self.commit()
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2013-05-09 19:07:38 UTC (rev 11159)
@@ -30,6 +30,10 @@
"QUOTA_USED_BYTES" integer default 0 not null,
"DEFAULT_EVENTS" integer default null references CALENDAR on delete set null,
"DEFAULT_TASKS" integer default null references CALENDAR on delete set null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null,
"CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
"MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
);
@@ -65,7 +69,11 @@
"BIND_MODE" integer not null,
"BIND_STATUS" integer not null,
"MESSAGE" nclob,
- "TRANSP" integer default 0 not null,
+ "TRANSP" integer default 0 not null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null,
primary key("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_ID"),
unique("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_NAME")
);
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql 2013-05-09 19:07:38 UTC (rev 11159)
@@ -31,9 +31,9 @@
-- Note that this must match the node info schema in twext.enterprise.queue.
create table NODE_INFO (
HOSTNAME varchar(255) not null,
- PID integer not null,
- PORT integer not null,
- TIME timestamp not null default timezone('UTC', CURRENT_TIMESTAMP),
+ PID integer not null,
+ PORT integer not null,
+ TIME timestamp not null default timezone('UTC', CURRENT_TIMESTAMP),
primary key (HOSTNAME, PORT)
);
@@ -68,12 +68,16 @@
----------------------------
create table CALENDAR_HOME_METADATA (
- RESOURCE_ID integer primary key references CALENDAR_HOME on delete cascade, -- implicit index
- QUOTA_USED_BYTES integer default 0 not null,
- DEFAULT_EVENTS integer default null references CALENDAR on delete set null,
- DEFAULT_TASKS integer default null references CALENDAR on delete set null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+ RESOURCE_ID integer primary key references CALENDAR_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ DEFAULT_EVENTS integer default null references CALENDAR on delete set null,
+ DEFAULT_TASKS integer default null references CALENDAR on delete set null,
+ ALARM_VEVENT_TIMED text default null,
+ ALARM_VEVENT_ALLDAY text default null,
+ ALARM_VTODO_TIMED text default null,
+ ALARM_VTODO_ALLDAY text default null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
);
@@ -82,10 +86,10 @@
-----------------------
create table CALENDAR_METADATA (
- RESOURCE_ID integer primary key references CALENDAR on delete cascade, -- implicit index
+ RESOURCE_ID integer primary key references CALENDAR on delete cascade, -- implicit index
SUPPORTED_COMPONENTS varchar(255) default null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
);
@@ -105,8 +109,8 @@
XML_TYPE varchar(255) not null,
XML_DATA text not null,
MD5 char(32) not null,
- CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
- MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
);
@@ -127,7 +131,11 @@
BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
MESSAGE text,
- TRANSP integer default 0 not null, -- enum CALENDAR_TRANSP
+ TRANSP integer default 0 not null, -- enum CALENDAR_TRANSP
+ ALARM_VEVENT_TIMED text default null,
+ ALARM_VEVENT_ALLDAY text default null,
+ ALARM_VTODO_TIMED text default null,
+ ALARM_VTODO_ALLDAY text default null,
primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME) -- implicit index
@@ -494,7 +502,7 @@
create table APN_SUBSCRIPTIONS (
TOKEN varchar(255) not null,
RESOURCE_KEY varchar(255) not null,
- MODIFIED integer not null,
+ MODIFIED integer not null,
SUBSCRIBER_GUID varchar(255) not null,
USER_AGENT varchar(255) default null,
IP_ADDR varchar(255) default null,
@@ -514,7 +522,7 @@
ORGANIZER varchar(255) not null,
ATTENDEE varchar(255) not null,
ICALUID varchar(255) not null,
- ACCESSED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ ACCESSED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
);
@@ -533,7 +541,7 @@
---------------------------
create table IMIP_INVITATION_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
FROM_ADDR varchar(255) not null,
TO_ADDR varchar(255) not null,
@@ -545,7 +553,7 @@
-----------------------
create table IMIP_POLLING_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP)
);
@@ -554,7 +562,7 @@
---------------------
create table IMIP_REPLY_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
ORGANIZER varchar(255) not null,
ATTENDEE varchar(255) not null,
@@ -566,7 +574,7 @@
------------------------
create table PUSH_NOTIFICATION_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP),
PUSH_ID varchar(255) not null
);
@@ -576,7 +584,7 @@
-----------------
create table GROUP_CACHER_POLLING_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null,
NOT_BEFORE timestamp default timezone('UTC', CURRENT_TIMESTAMP)
);
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql 2013-05-09 19:07:38 UTC (rev 11159)
@@ -22,13 +22,21 @@
alter table ATTACHMENT
add ("DEFAULT_EVENTS" integer default null references CALENDAR on delete set null,
- "DEFAULT_TASKS" integer default null references CALENDAR on delete set null);
+ "DEFAULT_TASKS" integer default null references CALENDAR on delete set null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null);
-- Calendar bind related updates
alter table CALENDAR_BIND
- add ("TRANSP" integer default 0 not null);
+ add ("TRANSP" integer default 0 not null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null);
create table CALENDAR_TRANSP (
"ID" integer primary key,
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql 2013-05-09 19:07:38 UTC (rev 11159)
@@ -22,14 +22,22 @@
-- Calendar home related updates
alter table CALENDAR_HOME_METADATA
- add column DEFAULT_EVENTS integer default null references CALENDAR on delete set null,
- add column DEFAULT_TASKS integer default null references CALENDAR on delete set null;
+ add column DEFAULT_EVENTS integer default null references CALENDAR on delete set null,
+ add column DEFAULT_TASKS integer default null references CALENDAR on delete set null,
+ add column ALARM_VEVENT_TIMED text default null,
+ add column ALARM_VEVENT_ALLDAY text default null,
+ add column ALARM_VTODO_TIMED text default null,
+ add column ALARM_VTODO_ALLDAY text default null;
-- Calendar bind related updates
alter table CALENDAR_BIND
- add column TRANSP integer default 0 not null;
+ add column TRANSP integer default 0 not null,
+ add column ALARM_VEVENT_TIMED text default null,
+ add column ALARM_VEVENT_ALLDAY text default null,
+ add column ALARM_VTODO_TIMED text default null,
+ add column ALARM_VTODO_ALLDAY text default null;
create table CALENDAR_TRANSP (
ID integer primary key,
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py 2013-05-09 19:07:38 UTC (rev 11159)
@@ -20,8 +20,10 @@
from txdav.xml.element import HRef
from twext.enterprise.dal.syntax import Update
from txdav.common.datastore.upgrade.sql.upgrades.upgrade_from_3_to_4 import moveDefaultCalendarProperties, \
- moveCalendarTranspProperties, removeResourceType
+ moveCalendarTranspProperties, removeResourceType, moveDefaultAlarmProperties
from txdav.xml import element
+from twistedcaldav import caldavxml
+from txdav.common.datastore.sql_tables import _BIND_MODE_WRITE
"""
Tests for L{txdav.common.datastore.upgrade.sql.upgrade}.
@@ -38,16 +40,17 @@
def test_defaultCalendarUpgrade(self):
# Set dead property on inbox
- inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
- inbox.properties()[PropertyName.fromElement(ScheduleDefaultCalendarURL)] = ScheduleDefaultCalendarURL(HRef.fromString("/calendars/__uids__/user01/calendar_1"))
+ for user in ("user01", "user02",):
+ inbox = (yield self.calendarUnderTest(name="inbox", home=user))
+ inbox.properties()[PropertyName.fromElement(ScheduleDefaultCalendarURL)] = ScheduleDefaultCalendarURL(HRef.fromString("/calendars/__uids__/%s/calendar_1" % (user,)))
- # Force current default to null
- home = (yield self.homeUnderTest(name="user01"))
- chm = home._homeMetaDataSchema
- yield Update(
- {chm.DEFAULT_EVENTS: None},
- Where=chm.RESOURCE_ID == home._resourceID,
- ).on(self.transactionUnderTest())
+ # Force current default to null
+ home = (yield self.homeUnderTest(name=user))
+ chm = home._homeMetaDataSchema
+ yield Update(
+ {chm.DEFAULT_EVENTS: None},
+ Where=chm.RESOURCE_ID == home._resourceID,
+ ).on(self.transactionUnderTest())
# Force data version to previous
ch = home._homeSchema
@@ -62,68 +65,206 @@
yield moveDefaultCalendarProperties(self._sqlCalendarStore)
# Test results
- home = (yield self.homeUnderTest(name="user01"))
- calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
- self.assertTrue(home.isDefaultCalendar(calendar))
- inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
- self.assertTrue(PropertyName.fromElement(ScheduleDefaultCalendarURL) not in inbox.properties())
+ for user in ("user01", "user02",):
+ home = (yield self.homeUnderTest(name=user))
+ calendar = (yield self.calendarUnderTest(name="calendar_1", home=user))
+ self.assertTrue(home.isDefaultCalendar(calendar))
+ inbox = (yield self.calendarUnderTest(name="inbox", home=user))
+ self.assertTrue(PropertyName.fromElement(ScheduleDefaultCalendarURL) not in inbox.properties())
@inlineCallbacks
def test_calendarTranspUpgrade(self):
# Set dead property on inbox
- inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
- inbox.properties()[PropertyName.fromElement(CalendarFreeBusySet)] = CalendarFreeBusySet(HRef.fromString("/calendars/__uids__/user01/calendar_1"))
+ for user in ("user01", "user02",):
+ inbox = (yield self.calendarUnderTest(name="inbox", home=user))
+ inbox.properties()[PropertyName.fromElement(CalendarFreeBusySet)] = CalendarFreeBusySet(HRef.fromString("/calendars/__uids__/%s/calendar_1" % (user,)))
- # Force current to transparent
- calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
- yield calendar.setUsedForFreeBusy(False)
- calendar.properties()[PropertyName.fromElement(ScheduleCalendarTransp)] = ScheduleCalendarTransp(Opaque())
+ # Force current to transparent
+ calendar = (yield self.calendarUnderTest(name="calendar_1", home=user))
+ yield calendar.setUsedForFreeBusy(False)
+ calendar.properties()[PropertyName.fromElement(ScheduleCalendarTransp)] = ScheduleCalendarTransp(Opaque())
- # Force data version to previous
- home = (yield self.homeUnderTest(name="user01"))
- ch = home._homeSchema
- yield Update(
- {ch.DATAVERSION: 3},
- Where=ch.RESOURCE_ID == home._resourceID,
- ).on(self.transactionUnderTest())
+ # Force data version to previous
+ home = (yield self.homeUnderTest(name=user))
+ ch = home._homeSchema
+ yield Update(
+ {ch.DATAVERSION: 3},
+ Where=ch.RESOURCE_ID == home._resourceID,
+ ).on(self.transactionUnderTest())
yield self.commit()
- calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
- self.assertFalse(calendar.isUsedForFreeBusy())
- self.assertTrue(PropertyName.fromElement(ScheduleCalendarTransp) in calendar.properties())
- inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
- self.assertTrue(PropertyName.fromElement(CalendarFreeBusySet) in inbox.properties())
+ for user in ("user01", "user02",):
+ calendar = (yield self.calendarUnderTest(name="calendar_1", home=user))
+ self.assertFalse(calendar.isUsedForFreeBusy())
+ self.assertTrue(PropertyName.fromElement(ScheduleCalendarTransp) in calendar.properties())
+ inbox = (yield self.calendarUnderTest(name="inbox", home=user))
+ self.assertTrue(PropertyName.fromElement(CalendarFreeBusySet) in inbox.properties())
yield self.commit()
# Trigger upgrade
yield moveCalendarTranspProperties(self._sqlCalendarStore)
# Test results
- home = (yield self.homeUnderTest(name="user01"))
- calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
- self.assertTrue(calendar.isUsedForFreeBusy())
- inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
- self.assertTrue(PropertyName.fromElement(CalendarFreeBusySet) not in inbox.properties())
+ for user in ("user01", "user02",):
+ home = (yield self.homeUnderTest(name=user))
+ calendar = (yield self.calendarUnderTest(name="calendar_1", home=user))
+ self.assertTrue(calendar.isUsedForFreeBusy())
+ inbox = (yield self.calendarUnderTest(name="inbox", home=user))
+ self.assertTrue(PropertyName.fromElement(CalendarFreeBusySet) not in inbox.properties())
@inlineCallbacks
+ def test_defaultAlarmUpgrade(self):
+
+ alarmhome1 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT1M
+END:VALARM
+"""
+
+ alarmhome2 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT2M
+END:VALARM
+"""
+
+ alarmhome3 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT3M
+END:VALARM
+"""
+
+ alarmhome4 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT4M
+END:VALARM
+"""
+
+ alarmcalendar1 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT1M
+END:VALARM
+"""
+
+ alarmcalendar2 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT2M
+END:VALARM
+"""
+
+ alarmcalendar3 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT3M
+END:VALARM
+"""
+
+ alarmcalendar4 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT4M
+END:VALARM
+"""
+
+ alarmshared1 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT1M
+END:VALARM
+"""
+
+ alarmshared2 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT2M
+END:VALARM
+"""
+
+ alarmshared3 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT3M
+END:VALARM
+"""
+
+ alarmshared4 = """BEGIN:VALARM
+ACTION:AUDIO
+TRIGGER;RELATED=START:-PT4M
+END:VALARM
+"""
+
+ # Setup old properties
+ detailshome = (
+ (True, True, alarmhome1, caldavxml.DefaultAlarmVEventDateTime,),
+ (True, False, alarmhome2, caldavxml.DefaultAlarmVEventDate,),
+ (False, True, alarmhome3, caldavxml.DefaultAlarmVToDoDateTime,),
+ (False, False, alarmhome4, caldavxml.DefaultAlarmVToDoDate,),
+ )
+ detailscalendar = (
+ (True, True, alarmcalendar1, caldavxml.DefaultAlarmVEventDateTime,),
+ (True, False, alarmcalendar2, caldavxml.DefaultAlarmVEventDate,),
+ (False, True, alarmcalendar3, caldavxml.DefaultAlarmVToDoDateTime,),
+ (False, False, alarmcalendar4, caldavxml.DefaultAlarmVToDoDate,),
+ )
+ detailsshared = (
+ (True, True, alarmshared1, caldavxml.DefaultAlarmVEventDateTime,),
+ (True, False, alarmshared2, caldavxml.DefaultAlarmVEventDate,),
+ (False, True, alarmshared3, caldavxml.DefaultAlarmVToDoDateTime,),
+ (False, False, alarmshared4, caldavxml.DefaultAlarmVToDoDate,),
+ )
+
+ home = yield self.homeUnderTest(name="user01")
+ for _ignore_vevent, _ignore_timed, alarm, prop in detailshome:
+ home.properties()[PropertyName.fromElement(prop)] = prop(alarm)
+ calendar = yield self.calendarUnderTest(name="calendar_1", home="user01")
+ for _ignore_vevent, _ignore_timed, alarm, prop in detailscalendar:
+ calendar.properties()[PropertyName.fromElement(prop)] = prop(alarm)
+ home2 = yield self.homeUnderTest(name="user02")
+ shared_name = yield calendar.shareWith(home2, _BIND_MODE_WRITE)
+ shared = yield self.calendarUnderTest(name=shared_name, home="user02")
+ for _ignore_vevent, _ignore_timed, alarm, prop in detailsshared:
+ shared.properties()[PropertyName.fromElement(prop)] = prop(alarm)
+ yield self.commit()
+
+ # Trigger upgrade
+ yield moveDefaultAlarmProperties(self._sqlCalendarStore)
+
+ # Check each type of collection
+ home = yield self.homeUnderTest(name="user01")
+ for vevent, timed, alarm, prop in detailshome:
+ alarm_result = (yield home.getDefaultAlarm(vevent, timed))
+ self.assertEquals(alarm_result, alarm)
+ self.assertTrue(PropertyName.fromElement(prop) not in home.properties())
+
+ calendar = yield self.calendarUnderTest(name="calendar_1", home="user01")
+ for vevent, timed, alarm, prop in detailscalendar:
+ alarm_result = (yield calendar.getDefaultAlarm(vevent, timed))
+ self.assertEquals(alarm_result, alarm)
+ self.assertTrue(PropertyName.fromElement(prop) not in home.properties())
+
+ shared = yield self.calendarUnderTest(name=shared_name, home="user02")
+ for vevent, timed, alarm, prop in detailsshared:
+ alarm_result = (yield shared.getDefaultAlarm(vevent, timed))
+ self.assertEquals(alarm_result, alarm)
+ self.assertTrue(PropertyName.fromElement(prop) not in home.properties())
+
+
+ @inlineCallbacks
def test_resourceTypeUpgrade(self):
# Set dead property on calendar
- calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
- calendar.properties()[PropertyName.fromElement(element.ResourceType)] = element.ResourceType(element.Collection())
+ for user in ("user01", "user02",):
+ calendar = (yield self.calendarUnderTest(name="calendar_1", home=user))
+ calendar.properties()[PropertyName.fromElement(element.ResourceType)] = element.ResourceType(element.Collection())
yield self.commit()
- calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
- self.assertTrue(PropertyName.fromElement(element.ResourceType) in calendar.properties())
+ for user in ("user01", "user02",):
+ calendar = (yield self.calendarUnderTest(name="calendar_1", home=user))
+ self.assertTrue(PropertyName.fromElement(element.ResourceType) in calendar.properties())
yield self.commit()
# Trigger upgrade
yield removeResourceType(self._sqlCalendarStore)
# Test results
- calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
- self.assertTrue(PropertyName.fromElement(element.ResourceType) not in calendar.properties())
+ for user in ("user01", "user02",):
+ calendar = (yield self.calendarUnderTest(name="calendar_1", home=user))
+ self.assertTrue(PropertyName.fromElement(element.ResourceType) not in calendar.properties())
Modified: CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py 2013-05-09 19:03:32 UTC (rev 11158)
+++ CalendarServer/trunk/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py 2013-05-09 19:07:38 UTC (rev 11159)
@@ -27,6 +27,7 @@
updateAllCalendarHomeDataVersions, removeProperty, cleanPropertyStore
from txdav.xml.parser import WebDAVDocument
from txdav.xml import element
+from twisted.python.failure import Failure
"""
Data upgrade from database version 3 to 4
@@ -42,6 +43,7 @@
"""
yield moveDefaultCalendarProperties(sqlStore)
yield moveCalendarTranspProperties(sqlStore)
+ yield moveDefaultAlarmProperties(sqlStore)
yield removeResourceType(sqlStore)
# Always bump the DB value
@@ -59,13 +61,13 @@
"""
meta = schema.CALENDAR_HOME_METADATA
- yield _processProperty(sqlStore, caldavxml.ScheduleDefaultCalendarURL, meta.DEFAULT_EVENTS)
- yield _processProperty(sqlStore, customxml.ScheduleDefaultTasksURL, meta.DEFAULT_TASKS)
+ yield _processDefaultCalendarProperty(sqlStore, caldavxml.ScheduleDefaultCalendarURL, meta.DEFAULT_EVENTS)
+ yield _processDefaultCalendarProperty(sqlStore, customxml.ScheduleDefaultTasksURL, meta.DEFAULT_TASKS)
@inlineCallbacks
-def _processProperty(sqlStore, propname, colname):
+def _processDefaultCalendarProperty(sqlStore, propname, colname):
"""
Move the specified property value to the matching CALENDAR_HOME_METADATA table column.
@@ -121,8 +123,9 @@
yield cleanPropertyStore()
except RuntimeError:
+ f = Failure()
yield sqlTxn.abort()
- raise
+ f.raiseException()
@@ -186,12 +189,130 @@
yield cleanPropertyStore()
except RuntimeError:
+ f = Failure()
yield sqlTxn.abort()
- raise
+ f.raiseException()
@inlineCallbacks
+def moveDefaultAlarmProperties(sqlStore):
+ """
+ Need to move all the CalDAV:default-calendar and CS:default-tasks properties in the
+ RESOURCE_PROPERTY table to the new CALENDAR_HOME_METADATA table columns, extracting
+ the new value from the XML property.
+ """
+
+ yield _processDefaultAlarmProperty(
+ sqlStore,
+ caldavxml.DefaultAlarmVEventDateTime,
+ True,
+ True,
+ )
+ yield _processDefaultAlarmProperty(
+ sqlStore,
+ caldavxml.DefaultAlarmVEventDate,
+ True,
+ False,
+ )
+ yield _processDefaultAlarmProperty(
+ sqlStore,
+ caldavxml.DefaultAlarmVToDoDateTime,
+ False,
+ True,
+ )
+ yield _processDefaultAlarmProperty(
+ sqlStore,
+ caldavxml.DefaultAlarmVToDoDate,
+ False,
+ False,
+ )
+
+
+
+ at inlineCallbacks
+def _processDefaultAlarmProperty(sqlStore, propname, vevent, timed):
+ """
+ Move the specified property value to the matching CALENDAR_HOME_METADATA or CALENDAR_BIND table column.
+
+ Since the number of properties may well be large, we need to do this in batches.
+ """
+
+ hm = schema.CALENDAR_HOME_METADATA
+ cb = schema.CALENDAR_BIND
+ rp = schema.RESOURCE_PROPERTY
+
+ try:
+ calendars_for_id = {}
+ while True:
+ sqlTxn = sqlStore.newTransaction()
+ rows = (yield rowsForProperty(sqlTxn, propname, with_uid=True, batch=BATCH_SIZE))
+ if len(rows) == 0:
+ yield sqlTxn.commit()
+ break
+ delete_ids = []
+ for rid, value, viewer in rows:
+ delete_ids.append(rid)
+
+ prop = WebDAVDocument.fromString(value).root_element
+ alarm = str(prop.children[0]) if prop.children else None
+
+ # First check if the rid is a home - this is the most common case
+ ids = yield Select(
+ [hm.RESOURCE_ID, ],
+ From=hm,
+ Where=hm.RESOURCE_ID == rid,
+ ).on(sqlTxn)
+
+ if len(ids) > 0:
+ # Home object
+ calendarHome = (yield sqlTxn.calendarHomeWithResourceID(ids[0][0]))
+ if calendarHome is not None:
+ yield calendarHome.setDefaultAlarm(alarm, vevent, timed)
+ else:
+ # rid is a calendar - we need to find the per-user calendar for the resource viewer
+ if rid not in calendars_for_id:
+ ids = yield Select(
+ [cb.CALENDAR_HOME_RESOURCE_ID, cb.BIND_MODE, ],
+ From=cb,
+ Where=cb.CALENDAR_RESOURCE_ID == rid,
+ ).on(sqlTxn)
+ calendars_for_id[rid] = ids
+
+ if viewer:
+ calendarHome = (yield sqlTxn.calendarHomeWithUID(viewer))
+ else:
+ calendarHome = None
+ for row in calendars_for_id[rid]:
+ home_id, bind_mode = row
+ if bind_mode == _BIND_MODE_OWN:
+ calendarHome = (yield sqlTxn.calendarHomeWithResourceID(home_id))
+ break
+
+ if calendarHome is not None:
+ calendar = yield calendarHome.childWithID(rid)
+ if calendar is not None:
+ yield calendar.setDefaultAlarm(alarm, vevent, timed)
+
+ # Always delete the row so that batch processing works correctly
+ yield Delete(
+ From=rp,
+ Where=(rp.RESOURCE_ID.In(Parameter("ids", len(delete_ids)))).And
+ (rp.NAME == PropertyName.fromElement(propname).toString()),
+ ).on(sqlTxn, ids=delete_ids)
+
+ yield sqlTxn.commit()
+
+ yield cleanPropertyStore()
+
+ except RuntimeError:
+ f = Failure()
+ yield sqlTxn.abort()
+ f.raiseException()
+
+
+
+ at inlineCallbacks
def removeResourceType(sqlStore):
sqlTxn = sqlStore.newTransaction()
yield removeProperty(sqlTxn, PropertyName.fromElement(element.ResourceType))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130509/85e88214/attachment-0001.html>
More information about the calendarserver-changes
mailing list