[CalendarServer-changes] [9383] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Mon Jun 25 09:27:34 PDT 2012
Revision: 9383
http://trac.macosforge.org/projects/calendarserver/changeset/9383
Author: cdaboo at apple.com
Date: 2012-06-25 09:27:34 -0700 (Mon, 25 Jun 2012)
Log Message:
-----------
Remove COUNT=400 truncation behavior. Added upper/lower time range limits. Fix all tests to use current time-relative
iCalendar data.
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/tools/calverify.py
CalendarServer/trunk/calendarserver/tools/test/test_calverify.py
CalendarServer/trunk/calendarserver/tools/test/test_purge_old_events.py
CalendarServer/trunk/calendarserver/tools/validcalendardata.py
CalendarServer/trunk/conf/caldavd-apple.plist
CalendarServer/trunk/conf/caldavd-test.plist
CalendarServer/trunk/conf/caldavd.plist
CalendarServer/trunk/twistedcaldav/ical.py
CalendarServer/trunk/twistedcaldav/instance.py
CalendarServer/trunk/twistedcaldav/method/put_common.py
CalendarServer/trunk/twistedcaldav/method/report_calendar_query.py
CalendarServer/trunk/twistedcaldav/method/report_common.py
CalendarServer/trunk/twistedcaldav/method/report_freebusy.py
CalendarServer/trunk/twistedcaldav/query/calendarqueryfilter.py
CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
CalendarServer/trunk/twistedcaldav/scheduling/scheduler.py
CalendarServer/trunk/twistedcaldav/stdconfig.py
CalendarServer/trunk/twistedcaldav/test/test_calendarquery.py
CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
CalendarServer/trunk/txdav/caldav/datastore/sql.py
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/1.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/2.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/3.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/4.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/24204e8682b99527cbda64d7423acda7.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/61038c41bd02ae5daf9f7fe9d54199fd.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/84be58ced1f1bb34057e1bd7e602c9c8.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/acc1015b7dc300c1b5665f6833960994.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b0d5785f275c064117ffd1fc20f4ed40.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b495c5dd5aa53392078eb43b1f906a80.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b88dd50941e4a31520ee396fd7894c96.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/1.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/2.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/3.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_bad/1.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_bad/2.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/1.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/2.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/3.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/1.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/2.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/3.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics
CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics
CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py
CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
CalendarServer/trunk/txdav/caldav/icalendarstore.py
CalendarServer/trunk/txdav/common/datastore/sql.py
CalendarServer/trunk/txdav/common/datastore/sql_legacy.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/test/test_sql_tables.py
CalendarServer/trunk/txdav/common/datastore/test/util.py
Added Paths:
-----------
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v9.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v9.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_9_to_10.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_9_to_10.sql
Modified: CalendarServer/trunk/calendarserver/tools/calverify.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/calverify.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/calendarserver/tools/calverify.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -719,7 +719,7 @@
returnValue((True, "Nothing to scan"))
component = Component(None, pycalendar=caldata)
- if self.config.MaxInstancesForRRULE:
+ if getattr(self.config, "MaxInstancesForRRULE", 0):
component.truncateRecurrence(self.config.MaxInstancesForRRULE)
result = True
message = ""
Modified: CalendarServer/trunk/calendarserver/tools/test/test_calverify.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_calverify.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/calendarserver/tools/test/test_calverify.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -963,6 +963,7 @@
(yield self.calendarUnderTest(home_name, calendar_name, txn)).calendarObjectWithName(name))
)
+now = PyCalendarDateTime.getToday().getYear()
class CalVerifyMismatchTestsNonRecurring(CalVerifyMismatchTestsBase):
"""
@@ -977,10 +978,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISSING_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -989,7 +990,7 @@
ATTENDEE:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
# Attendees have event, organizer does not
MISSING_ORGANIZER_2_ICS = """BEGIN:VCALENDAR
@@ -999,10 +1000,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISSING_ORGANIZER_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1011,7 +1012,7 @@
ATTENDEE:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISSING_ORGANIZER_3_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1020,10 +1021,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISSING_ORGANIZER_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1032,7 +1033,7 @@
ATTENDEE:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
# Attendee partstat mismatch
MISMATCH_ATTENDEE_1_ICS = """BEGIN:VCALENDAR
@@ -1042,10 +1043,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1054,7 +1055,7 @@
ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH_ATTENDEE_2_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1063,10 +1064,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1075,7 +1076,7 @@
ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH_ATTENDEE_3_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1084,10 +1085,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1096,7 +1097,7 @@
ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
# Attendee events outside time range
MISMATCH2_ATTENDEE_1_ICS = """BEGIN:VCALENDAR
@@ -1106,10 +1107,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH2_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1118,7 +1119,7 @@
ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH2_ATTENDEE_2_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1127,10 +1128,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH2_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:19990307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1139,7 +1140,7 @@
ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH2_ATTENDEE_3_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1148,10 +1149,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH2_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:19990307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1160,7 +1161,7 @@
ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
# Organizer event outside time range
MISMATCH_ORGANIZER_1_ICS = """BEGIN:VCALENDAR
@@ -1170,10 +1171,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH_ORGANIZER_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:19990307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1182,7 +1183,7 @@
ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now-2}
MISMATCH_ORGANIZER_2_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1191,10 +1192,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH_ORGANIZER_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1203,7 +1204,7 @@
ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
# Attendee uuid3 has event with different organizer
MISMATCH3_ATTENDEE_1_ICS = """BEGIN:VCALENDAR
@@ -1213,10 +1214,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH3_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1225,7 +1226,7 @@
ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH3_ATTENDEE_2_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1234,10 +1235,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH3_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1245,7 +1246,7 @@
ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:47B16BB4-DB5F-4BF6-85FE-A7DA54230F92
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH3_ATTENDEE_3_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1254,17 +1255,17 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH3_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:47B16BB4-DB5F-4BF6-85FE-A7DA54230F92
ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:47B16BB4-DB5F-4BF6-85FE-A7DA54230F92
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH_ORGANIZER_3_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1273,10 +1274,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH_ORGANIZER_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1285,7 +1286,7 @@
ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
# Attendee uuid3 has event they are not invited to
MISMATCH2_ORGANIZER_1_ICS = """BEGIN:VCALENDAR
@@ -1295,10 +1296,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH2_ORGANIZER_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1306,7 +1307,7 @@
ATTENDEE;PARTSTAT=DECLINED:urn:uuid:47B16BB4-DB5F-4BF6-85FE-A7DA54230F92
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH2_ORGANIZER_2_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1315,10 +1316,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH2_ORGANIZER_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1326,7 +1327,7 @@
ATTENDEE;PARTSTAT=DECLINED:urn:uuid:47B16BB4-DB5F-4BF6-85FE-A7DA54230F92
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH2_ORGANIZER_3_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1335,10 +1336,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH2_ORGANIZER_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1347,7 +1348,7 @@
ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
requirements = {
@@ -1413,9 +1414,9 @@
}
output = StringIO()
calverify = CalVerifyService(self._sqlCalendarStore, options, output, reactor, config)
- yield calverify.doScan(False, True, False, start=PyCalendarDateTime(2010, 1, 1, 0, 0, 0))
+ yield calverify.doScan(False, True, False, start=PyCalendarDateTime(now, 1, 1, 0, 0, 0))
- self.assertEqual(calverify.results["Number of events to process"], 15)
+ self.assertEqual(calverify.results["Number of events to process"], 17)
self.assertEqual(calverify.results["Missing Attendee"], set((
("MISSING_ATTENDEE_ICS", self.uuid1, self.uuid2,),
("MISSING_ATTENDEE_ICS", self.uuid1, self.uuid3,),
@@ -1478,9 +1479,9 @@
}
output = StringIO()
calverify = CalVerifyService(self._sqlCalendarStore, options, output, reactor, config)
- yield calverify.doScan(False, True, True, start=PyCalendarDateTime(2010, 1, 1, 0, 0, 0))
+ yield calverify.doScan(False, True, True, start=PyCalendarDateTime(now, 1, 1, 0, 0, 0))
- self.assertEqual(calverify.results["Number of events to process"], 15)
+ self.assertEqual(calverify.results["Number of events to process"], 17)
self.assertEqual(calverify.results["Missing Attendee"], set((
("MISSING_ATTENDEE_ICS", self.uuid1, self.uuid2,),
("MISSING_ATTENDEE_ICS", self.uuid1, self.uuid3,),
@@ -1554,7 +1555,7 @@
# Re-scan after changes to make sure there are no errors
self.commit()
calverify = CalVerifyService(self._sqlCalendarStore, options, output, reactor, config)
- yield calverify.doScan(False, True, False, start=PyCalendarDateTime(2010, 1, 1, 0, 0, 0))
+ yield calverify.doScan(False, True, False, start=PyCalendarDateTime(now, 1, 1, 0, 0, 0))
self.assertEqual(calverify.results["Number of events to process"], 14)
self.assertTrue("Missing Attendee" not in calverify.results)
@@ -1580,10 +1581,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISSING_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1591,7 +1592,7 @@
ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
# Attendee partstat mismatch
MISMATCH_ATTENDEE_1_ICS = """BEGIN:VCALENDAR
@@ -1601,10 +1602,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1612,7 +1613,7 @@
ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
MISMATCH_ATTENDEE_L1_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -1621,10 +1622,10 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:MISMATCH_ATTENDEE_ICS
-DTEND:20100307T151500Z
+DTEND:%(year)s0307T151500Z
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART:20100307T111500Z
+DTSTART:%(year)s0307T111500Z
DTSTAMP:20100303T181220Z
SEQUENCE:2
ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1632,7 +1633,7 @@
ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
requirements = {
@@ -1683,7 +1684,7 @@
}
output = StringIO()
calverify = CalVerifyService(self._sqlCalendarStore, options, output, reactor, config)
- yield calverify.doScan(False, True, False, start=PyCalendarDateTime(2010, 1, 1, 0, 0, 0))
+ yield calverify.doScan(False, True, False, start=PyCalendarDateTime(now, 1, 1, 0, 0, 0))
self.assertEqual(calverify.results["Number of events to process"], 3)
self.assertEqual(calverify.results["Missing Attendee"], set((
@@ -1732,7 +1733,7 @@
}
output = StringIO()
calverify = CalVerifyService(self._sqlCalendarStore, options, output, reactor, config)
- yield calverify.doScan(False, True, True, start=PyCalendarDateTime(2010, 1, 1, 0, 0, 0))
+ yield calverify.doScan(False, True, True, start=PyCalendarDateTime(now, 1, 1, 0, 0, 0))
self.assertEqual(calverify.results["Number of events to process"], 3)
self.assertEqual(calverify.results["Missing Attendee"], set((
@@ -1763,9 +1764,9 @@
testResults = sorted(calverify.results["Fixed Auto-Accepts"], key=lambda x:x["uid"])
self.assertEqual(testResults[0]["path"], "/calendars/__uids__/%s/calendar/mismatched_attendee.ics" % self.uuidl1)
self.assertEqual(testResults[0]["uid"], "MISMATCH_ATTENDEE_ICS")
- self.assertEqual(testResults[0]["start"].getText(), "20100307T031500")
+ self.assertEqual(testResults[0]["start"].getText(), "%s0307T031500" % (now,))
self.assertEqual(testResults[1]["uid"], "MISSING_ATTENDEE_ICS")
- self.assertEqual(testResults[1]["start"].getText(), "20100307T031500")
+ self.assertEqual(testResults[1]["start"].getText(), "%s0307T031500" % (now,))
sync_token_new1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
@@ -1775,7 +1776,7 @@
# Re-scan after changes to make sure there are no errors
self.commit()
calverify = CalVerifyService(self._sqlCalendarStore, options, output, reactor, config)
- yield calverify.doScan(False, True, False, start=PyCalendarDateTime(2010, 1, 1, 0, 0, 0))
+ yield calverify.doScan(False, True, False, start=PyCalendarDateTime(now, 1, 1, 0, 0, 0))
self.assertEqual(calverify.results["Number of events to process"], 4)
self.assertTrue("Missing Attendee" not in calverify.results)
Modified: CalendarServer/trunk/calendarserver/tools/test/test_purge_old_events.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/test/test_purge_old_events.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/calendarserver/tools/test/test_purge_old_events.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -36,6 +36,7 @@
import os
+now = PyCalendarDateTime.getToday().getYear()
OLD_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -75,15 +76,15 @@
BEGIN:VEVENT
CREATED:20100303T181216Z
UID:685BC3A1-195A-49B3-926D-388DDACA78A6
-DTEND;TZID=US/Pacific:20000307T151500
+DTEND;TZID=US/Pacific:%(year)s0307T151500
TRANSP:OPAQUE
SUMMARY:Ancient event
-DTSTART;TZID=US/Pacific:20000307T111500
+DTSTART;TZID=US/Pacific:%(year)s0307T111500
DTSTAMP:20100303T181220Z
SEQUENCE:2
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now-5}
OLD_ATTACHMENT_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -125,15 +126,15 @@
UID:57A5D1F6-9A57-4F74-9520-25C617F54B88
TRANSP:OPAQUE
SUMMARY:Ancient event with attachment
-DTSTART;TZID=US/Pacific:20000308T111500
-DTEND;TZID=US/Pacific:20000308T151500
+DTSTART;TZID=US/Pacific:%(year)s0308T111500
+DTEND;TZID=US/Pacific:%(year)s0308T151500
DTSTAMP:20100303T181220Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/57A5D1F6-9A57-4F74-95
20-25C617F54B88.dropbox
SEQUENCE:2
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now-5}
ENDLESS_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -173,16 +174,16 @@
BEGIN:VEVENT
CREATED:20100303T194654Z
UID:9FDE0E4C-1495-4CAF-863B-F7F0FB15FE8C
-DTEND;TZID=US/Pacific:20000308T151500
+DTEND;TZID=US/Pacific:%(year)s0308T151500
RRULE:FREQ=YEARLY;INTERVAL=1
TRANSP:OPAQUE
SUMMARY:Ancient Repeating Endless
-DTSTART;TZID=US/Pacific:20000308T111500
+DTSTART;TZID=US/Pacific:%(year)s0308T111500
DTSTAMP:20100303T194710Z
SEQUENCE:4
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now-5}
REPEATING_AWHILE_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -222,16 +223,16 @@
BEGIN:VEVENT
CREATED:20100303T194716Z
UID:76236B32-2BC4-4D78-956B-8D42D4086200
-DTEND;TZID=US/Pacific:20000309T151500
+DTEND;TZID=US/Pacific:%(year)s0309T151500
RRULE:FREQ=YEARLY;INTERVAL=1;COUNT=3
TRANSP:OPAQUE
SUMMARY:Ancient Repeat Awhile
-DTSTART;TZID=US/Pacific:20000309T111500
+DTSTART;TZID=US/Pacific:%(year)s0309T111500
DTSTAMP:20100303T194747Z
SEQUENCE:6
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now-5}
STRADDLING_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -257,16 +258,16 @@
BEGIN:VEVENT
CREATED:20100303T213643Z
UID:1C219DAD-D374-4822-8C98-ADBA85E253AB
-DTEND;TZID=US/Pacific:20090508T121500
-RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=20100509T065959Z
+DTEND;TZID=US/Pacific:%(year)s0508T121500
+RRULE:FREQ=MONTHLY;INTERVAL=1;UNTIL=%(until)s0509T065959Z
TRANSP:OPAQUE
SUMMARY:Straddling cut-off
-DTSTART;TZID=US/Pacific:20090508T111500
+DTSTART;TZID=US/Pacific:%(year)s0508T111500
DTSTAMP:20100303T213704Z
SEQUENCE:5
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now-2, "until":now+1}
RECENT_ICS = """BEGIN:VCALENDAR
VERSION:2.0
@@ -292,15 +293,15 @@
BEGIN:VEVENT
CREATED:20100303T195159Z
UID:F2F14D94-B944-43D9-8F6F-97F95B2764CA
-DTEND;TZID=US/Pacific:20100304T141500
+DTEND;TZID=US/Pacific:%(year)s0304T141500
TRANSP:OPAQUE
SUMMARY:Recent
-DTSTART;TZID=US/Pacific:20100304T120000
+DTSTART;TZID=US/Pacific:%(year)s0304T120000
DTSTAMP:20100303T195203Z
SEQUENCE:2
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % {"year":now}
VCARD_1 = """BEGIN:VCARD
@@ -347,6 +348,9 @@
@inlineCallbacks
def setUp(self):
+ # Turn off delayed indexing option so we can have some useful tests
+ self.patch(config, "FreeBusyIndexDelayedExpand", False)
+
yield super(PurgeOldEventsTests, self).setUp()
self._sqlCalendarStore = yield buildStore(self, self.notifierFactory)
yield self.populate()
@@ -380,45 +384,44 @@
@inlineCallbacks
def test_eventsOlderThan(self):
- cutoff = PyCalendarDateTime(2010, 4, 1, 0, 0, 0)
+ cutoff = PyCalendarDateTime(now, 4, 1, 0, 0, 0)
txn = self._sqlCalendarStore.newTransaction()
# Query for all old events
results = (yield txn.eventsOlderThan(cutoff))
- self.assertEquals(results,
- [
- ['home1', 'calendar1', 'old.ics', '2000-03-07 23:15:00'],
- ['home1', 'calendar1', 'oldattachment.ics', '2000-03-08 23:15:00'],
- ['home2', 'calendar3', 'repeating_awhile.ics', '2002-03-09 23:15:00'],
- ['home2', 'calendar2', 'recent.ics', '2010-03-04 22:15:00'],
- ]
+ self.assertEquals(sorted(results),
+ sorted([
+ ['home1', 'calendar1', 'old.ics', '1901-01-01 01:00:00'],
+ ['home1', 'calendar1', 'oldattachment.ics', '1901-01-01 01:00:00'],
+ ['home2', 'calendar3', 'repeating_awhile.ics', '1901-01-01 01:00:00'],
+ ['home2', 'calendar2', 'recent.ics', '%s-03-04 22:15:00' % (now,)],
+ ])
)
# Query for oldest event
results = (yield txn.eventsOlderThan(cutoff, batchSize=1))
self.assertEquals(results,
[
- ['home1', 'calendar1', 'old.ics', '2000-03-07 23:15:00'],
+ ['home1', 'calendar1', 'old.ics', '1901-01-01 01:00:00'],
]
)
-
- test_eventsOlderThan.todo = "New lazy indexing broke this"
+
@inlineCallbacks
def test_removeOldEvents(self):
- cutoff = PyCalendarDateTime(2010, 4, 1, 0, 0, 0)
+ cutoff = PyCalendarDateTime(now, 4, 1, 0, 0, 0)
txn = self._sqlCalendarStore.newTransaction()
# Remove oldest event
count = (yield txn.removeOldEvents(cutoff, batchSize=1))
self.assertEquals(count, 1)
results = (yield txn.eventsOlderThan(cutoff))
- self.assertEquals(results,
- [
- ['home1', 'calendar1', 'oldattachment.ics', '2000-03-08 23:15:00'],
- ['home2', 'calendar3', 'repeating_awhile.ics', '2002-03-09 23:15:00'],
- ['home2', 'calendar2', 'recent.ics', '2010-03-04 22:15:00'],
- ]
+ self.assertEquals(sorted(results),
+ sorted([
+ ['home1', 'calendar1', 'oldattachment.ics', '1901-01-01 01:00:00'],
+ ['home2', 'calendar3', 'repeating_awhile.ics', '1901-01-01 01:00:00'],
+ ['home2', 'calendar2', 'recent.ics', '%s-03-04 22:15:00' % (now,)],
+ ])
)
# Remove remaining oldest events
@@ -430,8 +433,6 @@
# Remove oldest events (none left)
count = (yield txn.removeOldEvents(cutoff))
self.assertEquals(count, 0)
-
- test_removeOldEvents.todo = "New lazy indexing broke this"
@inlineCallbacks
@@ -452,6 +453,7 @@
returnValue(attachment)
+
@inlineCallbacks
def test_removeOrphanedAttachments(self):
attachment = (yield self._addAttachment())
@@ -469,7 +471,7 @@
self.assertTrue(os.path.exists(attachmentPath))
# Delete all old events (including the event containing the attachment)
- cutoff = PyCalendarDateTime(2010, 4, 1, 0, 0, 0)
+ cutoff = PyCalendarDateTime(now, 4, 1, 0, 0, 0)
count = (yield txn.removeOldEvents(cutoff))
# Just look for orphaned attachments but don't delete
@@ -490,26 +492,26 @@
# Verify the file itself is gone
self.assertFalse(os.path.exists(attachmentPath))
+
@inlineCallbacks
def test_purgeOldEvents(self):
# Dry run
total = (yield purgeOldEvents(self._sqlCalendarStore, self.directory,
- self.rootResource, PyCalendarDateTime(2010, 4, 1, 0, 0, 0), 2, dryrun=True,
+ self.rootResource, PyCalendarDateTime(now, 4, 1, 0, 0, 0), 2, dryrun=True,
verbose=False))
self.assertEquals(total, 4)
# Actually remove
total = (yield purgeOldEvents(self._sqlCalendarStore, self.directory,
- self.rootResource, PyCalendarDateTime(2010, 4, 1, 0, 0, 0), 2, verbose=False))
+ self.rootResource, PyCalendarDateTime(now, 4, 1, 0, 0, 0), 2, verbose=False))
self.assertEquals(total, 4)
# There should be no more left
total = (yield purgeOldEvents(self._sqlCalendarStore, self.directory,
- self.rootResource, PyCalendarDateTime(2010, 4, 1, 0, 0, 0), 2, verbose=False))
+ self.rootResource, PyCalendarDateTime(now, 4, 1, 0, 0, 0), 2, verbose=False))
self.assertEquals(total, 0)
- test_purgeOldEvents.todo = "New lazy indexing broke this"
@inlineCallbacks
def test_purgeUID(self):
@@ -533,7 +535,7 @@
# Purge home1
total, ignored = (yield purgeUID(self._sqlCalendarStore, "home1", self.directory,
self.rootResource, verbose=False, proxies=False,
- when=PyCalendarDateTime(2010, 4, 1, 12, 0, 0, 0, PyCalendarTimezone(utc=True))))
+ when=PyCalendarDateTime(now, 4, 1, 12, 0, 0, 0, PyCalendarTimezone(utc=True))))
# 2 items deleted: 1 event and 1 vcard
self.assertEquals(total, 2)
@@ -589,7 +591,7 @@
# Remove old events first
total = (yield purgeOldEvents(self._sqlCalendarStore, self.directory,
- self.rootResource, PyCalendarDateTime(2010, 4, 1, 0, 0, 0), 2, verbose=False))
+ self.rootResource, PyCalendarDateTime(now, 4, 1, 0, 0, 0), 2, verbose=False))
self.assertEquals(total, 4)
# Dry run
@@ -607,4 +609,3 @@
dryrun=False, verbose=False))
self.assertEquals(total, 0)
- test_purgeOrphanedAttachments.todo = "New lazy indexing broke this"
Modified: CalendarServer/trunk/calendarserver/tools/validcalendardata.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/validcalendardata.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/calendarserver/tools/validcalendardata.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -155,7 +155,7 @@
truncated = False
try:
component = Component.fromString(self.input.read())
- if config.MaxInstancesForRRULE != 0:
+ if getattr(self.config, "MaxInstancesForRRULE", 0) != 0:
truncated = component.truncateRecurrence(config.MaxInstancesForRRULE)
component.validCalendarData(doFix=False, validateRecurrences=True)
component.validCalendarForCalDAV(methodAllowed=True)
Modified: CalendarServer/trunk/conf/caldavd-apple.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-apple.plist 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/conf/caldavd-apple.plist 2012-06-25 16:27:34 UTC (rev 9383)
@@ -161,12 +161,7 @@
<key>MaxAllowedInstances</key>
<integer>3000</integer>
- <!-- Maximum number of instances allowed for a single RRULE -->
- <!-- 0 for no limit -->
- <key>MaxInstancesForRRULE</key>
- <integer>400</integer>
-
<!--
Directory service
Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/conf/caldavd-test.plist 2012-06-25 16:27:34 UTC (rev 9383)
@@ -167,11 +167,6 @@
<key>MaxAllowedInstances</key>
<integer>3000</integer>
- <!-- Maximum number of instances allowed for a single RRULE -->
- <!-- 0 for no limit -->
- <key>MaxInstancesForRRULE</key>
- <integer>400</integer>
-
<!--
Directory service
Modified: CalendarServer/trunk/conf/caldavd.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd.plist 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/conf/caldavd.plist 2012-06-25 16:27:34 UTC (rev 9383)
@@ -149,12 +149,7 @@
<key>MaxAllowedInstances</key>
<integer>3000</integer>
- <!-- Maximum number of instances allowed for a single RRULE -->
- <!-- 0 for no limit -->
- <key>MaxInstancesForRRULE</key>
- <integer>400</integer>
-
<!--
Directory service
Modified: CalendarServer/trunk/twistedcaldav/ical.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/ical.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/ical.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -978,7 +978,7 @@
# so that all-day date/times remain that way. However, when doing the timeRangesOverlap test below, we
# Need to convert the all-days to floating (T000000) so that the timezone overlap calculation can be done
# properly.
- instances = self.expandTimeRanges(end, normalizeFunction=normalizeForExpand)
+ instances = self.expandTimeRanges(end, lowerLimit=start, normalizeFunction=normalizeForExpand)
first = True
for key in instances:
instance = instances[key]
@@ -1051,7 +1051,7 @@
)
return self.cachedInstances
- def expandTimeRanges(self, limit, ignoreInvalidInstances=False, normalizeFunction=normalizeForIndex):
+ def expandTimeRanges(self, limit, lowerLimit=None, ignoreInvalidInstances=False, normalizeFunction=normalizeForIndex):
"""
Expand the set of recurrence instances for the components
contained within this VCALENDAR component. We will assume
@@ -1063,9 +1063,9 @@
"""
componentSet = self.subcomponents()
- return self.expandSetTimeRanges(componentSet, limit, ignoreInvalidInstances, normalizeFunction=normalizeFunction)
+ return self.expandSetTimeRanges(componentSet, limit, lowerLimit=lowerLimit, ignoreInvalidInstances=ignoreInvalidInstances, normalizeFunction=normalizeFunction)
- def expandSetTimeRanges(self, componentSet, limit, ignoreInvalidInstances=False, normalizeFunction=normalizeForIndex):
+ def expandSetTimeRanges(self, componentSet, limit, lowerLimit=None, ignoreInvalidInstances=False, normalizeFunction=normalizeForIndex):
"""
Expand the set of recurrence instances up to the specified date limit.
What we do is first expand the master instance into the set of generate
@@ -1092,7 +1092,7 @@
# Set of instances to return
instances = InstanceList(ignoreInvalidInstances=ignoreInvalidInstances, normalizeFunction=normalizeFunction)
- instances.expandTimeRanges(componentSet, limit)
+ instances.expandTimeRanges(componentSet, limit, lowerLimit=lowerLimit)
return instances
def getComponentInstances(self):
Modified: CalendarServer/trunk/twistedcaldav/instance.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/instance.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/instance.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -88,6 +88,7 @@
def __init__(self, ignoreInvalidInstances=False, normalizeFunction=normalizeForIndex):
self.instances = {}
self.limit = None
+ self.lowerLimit = None
self.ignoreInvalidInstances = ignoreInvalidInstances
self.normalizeFunction = normalizeFunction
@@ -99,7 +100,7 @@
def __getitem__(self, key):
return self.instances[key]
- def expandTimeRanges(self, componentSet, limit):
+ def expandTimeRanges(self, componentSet, limit, lowerLimit=None):
"""
Expand the set of recurrence instances up to the specified date limit.
What we do is first expand the master instance into the set of generate
@@ -119,40 +120,40 @@
if component.hasProperty("RECURRENCE-ID"):
overrides.append(component)
else:
- self._addMasterEventComponent(component, limit)
+ self._addMasterEventComponent(component, lowerLimit, limit)
got_master = True
elif component.name() == "VTODO":
if component.hasProperty("RECURRENCE-ID"):
overrides.append(component)
else:
- self._addMasterToDoComponent(component, limit)
+ self._addMasterToDoComponent(component, lowerLimit, limit)
got_master = True
elif component.name() == "VJOURNAL":
#TODO: VJOURNAL
raise NotImplementedError("VJOURNAL recurrence expansion not supported yet")
elif component.name() == "VFREEBUSY":
- self._addFreeBusyComponent(component, limit)
+ self._addFreeBusyComponent(component, lowerLimit, limit)
elif component.name() == "VAVAILABILITY":
- self._addAvailabilityComponent(component, limit)
+ self._addAvailabilityComponent(component, lowerLimit, limit)
elif component.name() == "AVAILABLE":
if component.hasProperty("RECURRENCE-ID"):
overrides.append(component)
else:
# AVAILABLE components are just like VEVENT components
- self._addMasterEventComponent(component, limit)
+ self._addMasterEventComponent(component, lowerLimit, limit)
got_master = True
for component in overrides:
if component.name() == "VEVENT":
- self._addOverrideEventComponent(component, limit, got_master)
+ self._addOverrideEventComponent(component, lowerLimit, limit, got_master)
elif component.name() == "VTODO":
- self._addOverrideToDoComponent(component, limit, got_master)
+ self._addOverrideToDoComponent(component, lowerLimit, limit, got_master)
elif component.name() == "VJOURNAL":
#TODO: VJOURNAL
raise NotImplementedError("VJOURNAL recurrence expansion not supported yet")
elif component.name() == "AVAILABLE":
# AVAILABLE components are just like VEVENT components
- self._addOverrideEventComponent(component, limit, got_master)
+ self._addOverrideEventComponent(component, lowerLimit, limit, got_master)
def addInstance(self, instance):
"""
@@ -191,7 +192,7 @@
return (rulestart, start, end, duration,)
- def _addMasterEventComponent(self, component, limit):
+ def _addMasterEventComponent(self, component, lowerLimit, upperlimit):
"""
Add the specified master VEVENT Component to the instance list, expanding it
within the supplied time range.
@@ -204,9 +205,9 @@
return
rulestart, start, end, duration = details
- self._addMasterComponent(component, limit, rulestart, start, end, duration)
+ self._addMasterComponent(component, lowerLimit, upperlimit, rulestart, start, end, duration)
- def _addOverrideEventComponent(self, component, limit, got_master):
+ def _addOverrideEventComponent(self, component, lowerLimit, upperlimit, got_master):
"""
Add the specified overridden VEVENT Component to the instance list, replacing
the one generated by the master component.
@@ -221,7 +222,7 @@
return
_ignore_rulestart, start, end, _ignore_duration = details
- self._addOverrideComponent(component, limit, start, end, got_master)
+ self._addOverrideComponent(component, lowerLimit, upperlimit, start, end, got_master)
def _getMasterToDoDetails(self, component):
"""
@@ -268,7 +269,7 @@
return (rulestart, start, end, duration,)
- def _addMasterToDoComponent(self, component, limit):
+ def _addMasterToDoComponent(self, component, lowerLimit, upperlimit):
"""
Add the specified master VTODO Component to the instance list, expanding it
within the supplied time range.
@@ -280,9 +281,9 @@
return
rulestart, start, end, duration = details
- self._addMasterComponent(component, limit, rulestart, start, end, duration)
+ self._addMasterComponent(component, lowerLimit, upperlimit, rulestart, start, end, duration)
- def _addOverrideToDoComponent(self, component, limit, got_master):
+ def _addOverrideToDoComponent(self, component, lowerLimit, upperlimit, got_master):
"""
Add the specified overridden VTODO Component to the instance list, replacing
the one generated by the master component.
@@ -297,9 +298,9 @@
return
_ignore_rulestart, start, end, _ignore_duration = details
- self._addOverrideComponent(component, limit, start, end, got_master)
+ self._addOverrideComponent(component, lowerLimit, upperlimit, start, end, got_master)
- def _addMasterComponent(self, component, limit, rulestart, start, end, duration):
+ def _addMasterComponent(self, component, lowerLimit, upperlimit, rulestart, start, end, duration):
rrules = component.getRecurrenceSet()
if rrules is not None and rulestart is not None:
@@ -309,23 +310,29 @@
# than the master DTSTART, and if we exclude those, the associated
# overridden instances will cause an InvalidOverriddenInstance.
limited = rrules.expand(rulestart,
- PyCalendarPeriod(PyCalendarDateTime(1900,1,1), limit), expanded)
+ PyCalendarPeriod(PyCalendarDateTime(1900,1,1), upperlimit), expanded)
for startDate in expanded:
startDate = self.normalizeFunction(startDate)
endDate = startDate + duration
- self.addInstance(Instance(component, startDate, endDate))
+ if lowerLimit is None or endDate >= lowerLimit:
+ self.addInstance(Instance(component, startDate, endDate))
+ else:
+ self.lowerLimit = lowerLimit
if limited:
- self.limit = limit
+ self.limit = upperlimit
else:
# Always add main instance if included in range.
- if start < limit:
- start = self.normalizeFunction(start)
- end = self.normalizeFunction(end)
- self.addInstance(Instance(component, start, end))
+ if start < upperlimit:
+ if lowerLimit is None or end >= lowerLimit:
+ start = self.normalizeFunction(start)
+ end = self.normalizeFunction(end)
+ self.addInstance(Instance(component, start, end))
+ else:
+ self.lowerLimit = lowerLimit
else:
- self.limit = limit
+ self.limit = upperlimit
- def _addOverrideComponent(self, component, limit, start, end, got_master):
+ def _addOverrideComponent(self, component, lowerLimit, upperlimit, start, end, got_master):
# Get the recurrence override info
rid = component.getRecurrenceIDUTC()
@@ -337,12 +344,14 @@
rid = self.normalizeFunction(rid)
# Make sure start is within the limit
- if start > limit and rid > limit:
+ if start > upperlimit and rid > upperlimit:
return
+ if lowerLimit is not None and end < lowerLimit and rid < lowerLimit:
+ return
# Make sure override RECURRENCE-ID is a valid instance of the master
if got_master:
- if str(rid) not in self.instances and rid < limit:
+ if str(rid) not in self.instances and rid < upperlimit:
if self.ignoreInvalidInstances:
return
else:
@@ -382,7 +391,7 @@
# Now replacing existing entry with the new one
self.addInstance(Instance(component, start, end, originalStart, False, False))
- def _addFreeBusyComponent(self, component, limit):
+ def _addFreeBusyComponent(self, component, lowerLimit, upperlimit):
"""
Add the specified master VFREEBUSY Component to the instance list, expanding it
within the supplied time range.
@@ -391,14 +400,18 @@
"""
start = component.getStartDateUTC()
- if start is not None and start >= limit:
- # If the free busy is beyond the end of the range we want, ignore it
- return
-
end = component.getEndDateUTC()
if end is None and start is not None:
raise ValueError("VFREEBUSY component must have both DTSTART and DTEND: %r" % (component, ))
+ # If the free busy is beyond the end of the range we want, ignore it
+ if start is not None and start >= upperlimit:
+ return
+
+ # If the free busy is before the start of the range we want, ignore it
+ if lowerLimit is not None and end is not None and end < lowerLimit:
+ return
+
# Now look at each FREEBUSY property
for fb in component.properties("FREEBUSY"):
# Look at each period in the property
@@ -406,13 +419,13 @@
for period in fb.value():
# Ignore if period starts after limit
period = period.getValue()
- if period.getStart() >= limit:
+ if period.getStart() >= upperlimit:
continue
start = self.normalizeFunction(period.getStart())
end = self.normalizeFunction(period.getEnd())
self.addInstance(Instance(component, start, end))
- def _addAvailabilityComponent(self, component, limit):
+ def _addAvailabilityComponent(self, component, lowerLimit, upperlimit):
"""
Add the specified master VAVAILABILITY Component to the instance list, expanding it
within the supplied time range. VAVAILABILITY components are not recurring, they have an
@@ -424,14 +437,17 @@
"""
start = component.getStartDateUTC()
- if start is not None and start >= limit:
- # If the free busy is beyond the end of the range we want, ignore it
+ if start is not None and start >= upperlimit:
+ # If the availability is beyond the end of the range we want, ignore it
return
if start is None:
start = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
start = self.normalizeFunction(start)
end = component.getEndDateUTC()
+ if lowerLimit is not None and end is not None and end < lowerLimit:
+ # If the availability is before the start of the range we want, ignore it
+ return
if end is None:
end = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
end = self.normalizeFunction(end)
Modified: CalendarServer/trunk/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/put_common.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/method/put_common.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -650,24 +650,6 @@
return succeed(None)
- def truncateRecurrence(self):
-
- if config.MaxInstancesForRRULE != 0:
- try:
- result = self.calendar.truncateRecurrence(config.MaxInstancesForRRULE)
- except (ValueError, TypeError), ex:
- log.err("Cannot truncate calendar resource: %s" % (ex,))
- raise HTTPError(ErrorResponse(
- responsecode.FORBIDDEN,
- (caldav_namespace, "valid-calendar-data"),
- "Cannot truncate recurrences",
- ))
- if result:
- self.calendardata = None
- return result
- else:
- return False
-
@inlineCallbacks
def preservePrivateComments(self):
# Check for private comments on the old resource and the new resource and re-insert
@@ -1198,9 +1180,6 @@
))
- # Handle RRULE truncation
- rruleChanged = self.truncateRecurrence()
-
# Preserve private comments
yield self.preservePrivateComments()
@@ -1255,7 +1234,7 @@
response = (yield self.doStore(data_changed))
# Must not set ETag in response if data changed
- if did_implicit_action or rruleChanged or dropboxChanged or alarmChanged:
+ if did_implicit_action or dropboxChanged or alarmChanged:
def _removeEtag(request, response):
response.headers.removeHeader('etag')
return response
Modified: CalendarServer/trunk/twistedcaldav/method/report_calendar_query.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/report_calendar_query.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/method/report_calendar_query.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,18 +20,18 @@
__all__ = ["report_urn_ietf_params_xml_ns_caldav_calendar_query"]
-from twext.python.log import Logger
-from twext.web2.dav.http import ErrorResponse
-
from twisted.internet.defer import inlineCallbacks, returnValue,\
maybeDeferred
+
+from twext.python.log import Logger
from twext.web2 import responsecode
-from txdav.xml import element as davxml
from twext.web2.dav.http import MultiStatusResponse
+from twext.web2.dav.http import ErrorResponse
from twext.web2.dav.method.report import NumberOfMatchesWithinLimits
from twext.web2.dav.util import joinURL
from twext.web2.http import HTTPError, StatusResponse
+from twistedcaldav import caldavxml
from twistedcaldav.caldavxml import caldav_namespace, MaxInstances
from twistedcaldav.config import config
from txdav.common.icommondatastore import IndexedSearchException,\
@@ -40,6 +40,9 @@
from twistedcaldav.method import report_common
from twistedcaldav.query import calendarqueryfilter
+from txdav.caldav.icalendarstore import TimeRangeLowerLimit, TimeRangeUpperLimit
+from txdav.xml import element as davxml
+
log = Logger()
@inlineCallbacks
@@ -260,6 +263,18 @@
davxml.NumberOfMatchesWithinLimits(),
"Too many components",
))
+ except TimeRangeLowerLimit, e:
+ raise HTTPError(ErrorResponse(
+ responsecode.FORBIDDEN,
+ caldavxml.MinDateTime(),
+ "Time-range value too far in the past. Must be on or after %s." % (str(e.limit),)
+ ))
+ except TimeRangeUpperLimit, e:
+ raise HTTPError(ErrorResponse(
+ responsecode.FORBIDDEN,
+ caldavxml.MaxDateTime(),
+ "Time-range value too far in the future. Must be on or before %s." % (str(e.limit),)
+ ))
if not hasattr(request, "extendedLogItems"):
request.extendedLogItems = {}
Modified: CalendarServer/trunk/twistedcaldav/method/report_common.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/report_common.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/method/report_common.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -665,7 +665,7 @@
"""
# Expand out the set of instances for the event with in the required range
- instances = calendar.expandTimeRanges(timerange.end, ignoreInvalidInstances=True)
+ instances = calendar.expandTimeRanges(timerange.end, lowerLimit=timerange.start, ignoreInvalidInstances=True)
# Can only do timed events
for key in instances:
Modified: CalendarServer/trunk/twistedcaldav/method/report_freebusy.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/method/report_freebusy.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/method/report_freebusy.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,12 +20,11 @@
__all__ = ["report_urn_ietf_params_xml_ns_caldav_free_busy_query"]
+from twisted.internet.defer import inlineCallbacks, returnValue
+
from twext.python.log import Logger
+from twext.web2 import responsecode
from twext.web2.dav.http import ErrorResponse
-
-from twisted.internet.defer import inlineCallbacks, returnValue
-from twext.web2 import responsecode
-from txdav.xml import element as davxml
from twext.web2.dav.method.report import NumberOfMatchesWithinLimits
from twext.web2.http import HTTPError, Response, StatusResponse
from twext.web2.http_headers import MimeType
@@ -34,6 +33,9 @@
from twistedcaldav import caldavxml
from twistedcaldav.method import report_common
+from txdav.caldav.icalendarstore import TimeRangeLowerLimit, TimeRangeUpperLimit
+from txdav.xml import element as davxml
+
log = Logger()
@inlineCallbacks
@@ -85,6 +87,18 @@
davxml.NumberOfMatchesWithinLimits(),
"Too many components"
))
+ except TimeRangeLowerLimit, e:
+ raise HTTPError(ErrorResponse(
+ responsecode.FORBIDDEN,
+ caldavxml.MinDateTime(),
+ "Time-range value too far in the past. Must be on or after %s." % (str(e.limit),)
+ ))
+ except TimeRangeUpperLimit, e:
+ raise HTTPError(ErrorResponse(
+ responsecode.FORBIDDEN,
+ caldavxml.MaxDateTime(),
+ "Time-range value too far in the future. Must be on or before %s." % (str(e.limit),)
+ ))
# Now build a new calendar object with the free busy info we have
fbcalendar = report_common.buildFreeBusyResult(fbinfo, timerange)
Modified: CalendarServer/trunk/twistedcaldav/query/calendarqueryfilter.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/query/calendarqueryfilter.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/query/calendarqueryfilter.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+# Copyright (c) 2009-2012 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
log = Logger()
+
class FilterBase(object):
"""
Determines which matching components are returned.
@@ -47,6 +48,7 @@
def valid(self, level=0):
raise NotImplementedError
+
class Filter(FilterBase):
"""
Determines which matching components are returned.
@@ -59,7 +61,7 @@
# One comp-filter element must be present
if len(xml_element.children) != 1 or xml_element.children[0].qname() != (caldav_namespace, "comp-filter"):
raise ValueError("Invalid CALDAV:filter element: %s" % (xml_element,))
-
+
self.child = ComponentFilter(xml_element.children[0])
def match(self, component, access=None):
@@ -67,7 +69,7 @@
Returns True if the given calendar component matches this filter, False
otherwise.
"""
-
+
# We only care about certain access restrictions.
if access not in (Component.ACCESS_CONFIDENTIAL, Component.ACCESS_RESTRICTED):
access = None
@@ -97,10 +99,10 @@
"""
Indicate whether this filter element's structure is valid wrt iCalendar
data object model.
-
+
@return: True if valid, False otherwise
"""
-
+
# Must have one child element for VCALENDAR
return self.child.valid(0)
@@ -132,9 +134,18 @@
"""
Get the date farthest into the future in any time-range elements
"""
-
+
return self.child.getmaxtimerange(None, False)
+ def getmintimerange(self):
+ """
+ Get the date farthest into the past in any time-range elements. That is either
+ the start date, or if start is not present, the end date.
+ """
+
+ return self.child.getmintimerange(None, False)
+
+
class FilterChildBase(FilterBase):
"""
CalDAV filter element.
@@ -149,7 +160,7 @@
for child in xml_element.children:
qname = child.qname()
-
+
if qname in (
(caldav_namespace, "is-not-defined"),
(caldav_namespace, "time-range"),
@@ -157,7 +168,7 @@
):
if qualifier is not None:
raise ValueError("Only one of CalDAV:time-range, CalDAV:text-match allowed")
-
+
if qname == (caldav_namespace, "is-not-defined"):
qualifier = IsNotDefined(child)
elif qname == (caldav_namespace, "time-range"):
@@ -176,7 +187,7 @@
if qualifier and isinstance(qualifier, IsNotDefined) and (len(filters) != 0):
raise ValueError("No other tests allowed when CalDAV:is-not-defined is present")
-
+
self.qualifier = qualifier
self.filters = filters
self.filter_name = xml_element.attributes["name"]
@@ -194,7 +205,7 @@
Returns True if the given calendar item (either a component, property or parameter value)
matches this filter, False otherwise.
"""
-
+
# Always return True for the is-not-defined case as the result of this will
# be negated by the caller
if not self.defined: return True
@@ -210,6 +221,7 @@
else:
return True
+
class ComponentFilter (FilterChildBase):
"""
Limits a search to only the chosen component types.
@@ -245,7 +257,7 @@
# In particular do not match VALARM.
if access and subcomponent.name() not in ("VEVENT", "VTODO", "VJOURNAL", "VFREEBUSY", "VTIMEZONE",):
continue
-
+
# Try to match the component name
if isinstance(self.filter_name, str):
if subcomponent.name() != self.filter_name: continue
@@ -255,7 +267,7 @@
else:
return not self.defined
return self.defined
-
+
def setInstances(self, instances):
"""
Give the list of instances to each comp-filter element.
@@ -264,7 +276,7 @@
self.instances = instances
for compfilter in [x for x in self.filters if isinstance(x, ComponentFilter)]:
compfilter.setInstances(instances)
-
+
def valid(self, level):
"""
Indicate whether this filter element's structure is valid wrt iCalendar
@@ -273,7 +285,7 @@
@param level: the nesting level of this filter element, 0 being the top comp-filter.
@return: True if valid, False otherwise
"""
-
+
# Check for time-range
timerange = self.qualifier and isinstance(self.qualifier, TimeRange)
@@ -287,7 +299,7 @@
if self.filter_name in ("VCALENDAR", "VALARM", "STANDARD", "DAYLIGHT", "AVAILABLE"):
log.msg("comp-filter wrong component type: %s" % (self.filter_name,))
return False
-
+
# time-range only on VEVENT, VTODO, VJOURNAL, VFREEBUSY, VAVAILABILITY
if timerange and self.filter_name not in ("VEVENT", "VTODO", "VJOURNAL", "VFREEBUSY", "VAVAILABILITY"):
log.msg("time-range cannot be used with component %s" % (self.filter_name,))
@@ -297,7 +309,7 @@
if (self.filter_name in ("VCALENDAR", "VTIMEZONE", "VEVENT", "VTODO", "VJOURNAL", "VFREEBUSY", "VAVAILABILITY")):
log.msg("comp-filter wrong sub-component type: %s" % (self.filter_name,))
return False
-
+
# time-range only on VALARM, AVAILABLE
if timerange and self.filter_name not in ("VALARM", "AVAILABLE",):
log.msg("time-range cannot be used with sub-component %s" % (self.filter_name,))
@@ -307,7 +319,7 @@
if (self.filter_name in ("VCALENDAR", "VTIMEZONE", "VEVENT", "VTODO", "VJOURNAL", "VFREEBUSY", "VALARM", "STANDARD", "DAYLIGHT", "AVAILABLE")) or timerange:
log.msg("comp-filter wrong standard component type: %s" % (self.filter_name,))
return False
-
+
# Test each property
for propfilter in [x for x in self.filters if isinstance(x, PropertyFilter)]:
if not propfilter.valid():
@@ -330,11 +342,11 @@
Set the default timezone to use with this query.
@param tzinfo: a L{PyCalendarTimezone} to use.
"""
-
+
# Give tzinfo to any TimeRange we have
if isinstance(self.qualifier, TimeRange):
self.qualifier.settzinfo(tzinfo)
-
+
# Pass down to sub components/properties
for x in self.filters:
x.settzinfo(tzinfo)
@@ -346,7 +358,7 @@
@param currentMaximum: current future value to compare with
@type currentMaximum: L{PyCalendarDateTime}
"""
-
+
# Give tzinfo to any TimeRange we have
isStartTime = False
if isinstance(self.qualifier, TimeRange):
@@ -355,13 +367,35 @@
if currentMaximum is None or currentMaximum < compareWith:
currentMaximum = compareWith
currentIsStartTime = isStartTime
-
+
# Pass down to sub components/properties
for x in self.filters:
currentMaximum, currentIsStartTime = x.getmaxtimerange(currentMaximum, currentIsStartTime)
return currentMaximum, currentIsStartTime
+ def getmintimerange(self, currentMinimum, currentIsEndTime):
+ """
+ Get the date farthest into the past in any time-range elements. That is either
+ the start date, or if start is not present, the end date.
+ """
+
+ # Give tzinfo to any TimeRange we have
+ isEndTime = False
+ if isinstance(self.qualifier, TimeRange):
+ isEndTime = self.qualifier.start is None
+ compareWith = self.qualifier.end if isEndTime else self.qualifier.start
+ if currentMinimum is None or currentMinimum > compareWith:
+ currentMinimum = compareWith
+ currentIsEndTime = isEndTime
+
+ # Pass down to sub components/properties
+ for x in self.filters:
+ currentMinimum, currentIsEndTime = x.getmintimerange(currentMinimum, currentIsEndTime)
+
+ return currentMinimum, currentIsEndTime
+
+
class PropertyFilter (FilterChildBase):
"""
Limits a search to specific properties.
@@ -394,10 +428,10 @@
@return: True if valid, False otherwise
"""
-
+
# Check for time-range
timerange = self.qualifier and isinstance(self.qualifier, TimeRange)
-
+
# time-range only on COMPLETED, CREATED, DTSTAMP, LAST-MODIFIED
if timerange and self.filter_name.upper() not in ("COMPLETED", "CREATED", "DTSTAMP", "LAST-MODIFIED"):
log.msg("time-range cannot be used with property %s" % (self.filter_name,))
@@ -416,7 +450,7 @@
Set the default timezone to use with this query.
@param tzinfo: a L{PyCalendarTimezone} to use.
"""
-
+
# Give tzinfo to any TimeRange we have
if isinstance(self.qualifier, TimeRange):
self.qualifier.settzinfo(tzinfo)
@@ -428,7 +462,7 @@
@param currentMaximum: current future value to compare with
@type currentMaximum: L{PyCalendarDateTime}
"""
-
+
# Give tzinfo to any TimeRange we have
isStartTime = False
if isinstance(self.qualifier, TimeRange):
@@ -440,6 +474,24 @@
return currentMaximum, currentIsStartTime
+ def getmintimerange(self, currentMinimum, currentIsEndTime):
+ """
+ Get the date farthest into the past in any time-range elements. That is either
+ the start date, or if start is not present, the end date.
+ """
+
+ # Give tzinfo to any TimeRange we have
+ isEndTime = False
+ if isinstance(self.qualifier, TimeRange):
+ isEndTime = self.qualifier.start is None
+ compareWith = self.qualifier.end if isEndTime else self.qualifier.start
+ if currentMinimum is None or currentMinimum > compareWith:
+ currentMinimum = compareWith
+ currentIsEndTime = isEndTime
+
+ return currentMinimum, currentIsEndTime
+
+
class ParameterFilter (FilterChildBase):
"""
Limits a search to specific parameters.
@@ -456,6 +508,7 @@
return result
+
class IsNotDefined (FilterBase):
"""
Specifies that the named iCalendar item does not exist.
@@ -468,6 +521,7 @@
# is-not-defined option.
return True
+
class TextMatch (FilterBase):
"""
Specifies a substring match on a property or parameter value.
@@ -532,7 +586,7 @@
if self.match_type == "equals":
return s == test
elif self.match_type == "contains":
- return s.find(test) != -1
+ return s.find(test) != -1
elif self.match_type == "starts-with":
return s.startswith(test)
elif self.match_type == "ends-with":
@@ -550,9 +604,10 @@
else:
if _textCompare(unicode(value, "utf-8")):
return not self.negate
-
+
return self.negate
+
class TimeRange (FilterBase):
"""
Specifies a time for testing components against.
@@ -565,7 +620,7 @@
# One of start or end must be present
if "start" not in xml_element.attributes and "end" not in xml_element.attributes:
raise ValueError("One of 'start' or 'end' must be present in CALDAV:time-range")
-
+
self.start = PyCalendarDateTime.parseText(xml_element.attributes["start"]) if "start" in xml_element.attributes else None
self.end = PyCalendarDateTime.parseText(xml_element.attributes["end"]) if "end" in xml_element.attributes else None
self.tzinfo = None
@@ -575,7 +630,7 @@
Set the default timezone to use with this query.
@param tzinfo: a L{PyCalendarTimezone} to use.
"""
-
+
# Give tzinfo to any TimeRange we have
self.tzinfo = tzinfo
@@ -585,7 +640,7 @@
@return: True if valid, False otherwise
"""
-
+
if self.start is not None and self.start.isDateOnly():
log.msg("start attribute in <time-range> is not a date-time: %s" % (self.start,))
return False
@@ -621,9 +676,9 @@
"""
if component is None:
return False
-
+
assert instances is not None or self.end is None, "Failure to expand instance for time-range filter: %r" % (self,)
-
+
# Special case open-ended unbounded
if instances is None:
if component.getRecurrenceIDUTC() is None:
@@ -642,10 +697,10 @@
testcomponent = component._parent
else:
testcomponent = component
-
+
for key in instances:
instance = instances[key]
-
+
# First make sure components match
if not testcomponent.same(instance.component):
continue
Modified: CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/scheduling/icaldiff.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -16,7 +16,6 @@
from twext.python.log import Logger
-from twistedcaldav.config import config
from twistedcaldav.ical import Component, Property
from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
from twistedcaldav.scheduling.itip import iTipGenerator
@@ -248,12 +247,6 @@
self.attendee = normalizeCUAddr(attendee)
- if config.MaxInstancesForRRULE != 0:
- try:
- self.oldcalendar.truncateRecurrence(config.MaxInstancesForRRULE)
- except (ValueError, TypeError), ex:
- log.err("Cannot truncate calendar resource: %s" % (ex,))
-
returnCalendar = self.oldcalendar.duplicate()
returnMaster = returnCalendar.masterComponent()
Modified: CalendarServer/trunk/twistedcaldav/scheduling/scheduler.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/scheduling/scheduler.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/scheduling/scheduler.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -908,20 +908,12 @@
For data coming in from outside we need to normalize the calendar user addresses so that later iTIP
processing will match calendar users against those in stored calendar data. Only do that for invites
not freebusy.
-
- We also need to apply recurrence truncation here so the incoming iTIP's RRULE matches the truncated
- version in any attendee calendar. This avoids a problem where the iTIP message appears to represent
- a significant change as reported in schedule-changes property.
"""
if not self.checkForFreeBusy():
self.calendar.normalizeCalendarUserAddresses(normalizationLookup,
self.resource.principalForCalendarUserAddress)
- # Apply recurrence truncation at this point
- if config.MaxInstancesForRRULE != 0:
- self.calendar.truncateRecurrence(config.MaxInstancesForRRULE)
-
def checkAuthorization(self):
# Must have an unauthenticated user
if self.resource.currentPrincipal(self.request) != davxml.Principal(davxml.Unauthenticated()):
Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -328,7 +328,6 @@
"MaxResourceSize" : 1048576, # Maximum resource size (in bytes)
"MaxAttendeesPerInstance" : 100, # Maximum number of unique attendees
"MaxAllowedInstances" : 3000, # Maximum number of instances the server will index
- "MaxInstancesForRRULE" : 400, # Maximum number of instances for an RRULE
# Set to URL path of wiki authentication service, e.g. "/auth", in order
# to use javascript authentication dialog. Empty string indicates standard
@@ -922,6 +921,7 @@
"FreeBusyCacheDaysBack": 7,
"FreeBusyCacheDaysForward": 12 * 7,
+ "FreeBusyIndexLowerLimitDays": 365,
"FreeBusyIndexExpandAheadDays": 365,
"FreeBusyIndexExpandMaxDays": 5 * 365,
"FreeBusyIndexDelayedExpand": True,
Modified: CalendarServer/trunk/twistedcaldav/test/test_calendarquery.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_calendarquery.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/test/test_calendarquery.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -1,5 +1,5 @@
##
-# Copyright (c) 2005-2010 Apple Inc. All rights reserved.
+# Copyright (c) 2005-2012 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -36,7 +36,9 @@
from twisted.internet.defer import inlineCallbacks, returnValue
from txdav.common.datastore.test.util import buildStore, StubNotifierFactory
+from pycalendar.datetime import PyCalendarDateTime
+
@inlineCallbacks
def addEventsDir(testCase, eventsDir, uri):
"""
@@ -109,8 +111,8 @@
)
query_timerange = caldavxml.TimeRange(
- start="20021001T000000Z",
- end="20021101T000000Z",
+ start="%04d1001T000000Z" % (PyCalendarDateTime.getToday().getYear(),),
+ end="%04d1101T000000Z" % (PyCalendarDateTime.getToday().getYear(),),
)
query = caldavxml.CalendarQuery(
Modified: CalendarServer/trunk/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/twistedcaldav/test/test_icalendar.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -2434,9 +2434,9 @@
for description, original, ignoreInvalidInstances, results in data:
component = Component.fromString(original)
if results is None:
- self.assertRaises(InvalidOverriddenInstanceError, component.expandTimeRanges, PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances)
+ self.assertRaises(InvalidOverriddenInstanceError, component.expandTimeRanges, PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances)
else:
- instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances)
+ instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances)
self.assertTrue(len(instances.instances) == len(results), "%s: wrong number of instances" % (description,))
periods = tuple([(instance.start, instance.end) for instance in sorted(instances.instances.values(), key=lambda x:x.start)])
self.assertEqual(periods, results)
@@ -2776,9 +2776,9 @@
for description, original, ignoreInvalidInstances, results in data:
component = Component.fromString(original)
if results is None:
- self.assertRaises(InvalidOverriddenInstanceError, component.expandTimeRanges, PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances)
+ self.assertRaises(InvalidOverriddenInstanceError, component.expandTimeRanges, PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances)
else:
- instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances, normalizeFunction=normalizeForExpand)
+ instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1), ignoreInvalidInstances=ignoreInvalidInstances, normalizeFunction=normalizeForExpand)
self.assertTrue(len(instances.instances) == len(results), "%s: wrong number of instances" % (description,))
periods = tuple([(instance.start, instance.end) for instance in sorted(instances.instances.values(), key=lambda x:x.start)])
self.assertEqual(periods, results)
@@ -2786,6 +2786,361 @@
self.assertEqual(start.isDateOnly(), results[0][0].isDateOnly(), "%s: %s wrong date/time start state" % (description, start,))
self.assertEqual(end.isDateOnly(), results[0][1].isDateOnly(), "%s: %s wrong date/time end state" % (description, end,))
+ def test_expand_instances_lowerlimit(self):
+
+ data = (
+ (
+ "Non recurring - no limit",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+END:VCALENDAR
+""",
+ None,
+ (
+ (
+ PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ ),
+ None,
+ ),
+ (
+ "Non recurring - limit not effective",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+END:VCALENDAR
+""",
+ PyCalendarDateTime(2007, 1, 1),
+ (
+ (
+ PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ ),
+ None,
+ ),
+ (
+ "Non recurring - limit effective",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+END:VCALENDAR
+""",
+ PyCalendarDateTime(2010, 1, 1),
+ (),
+ PyCalendarDateTime(2010, 1, 1),
+ ),
+ (
+ "Simple recurring - no limit",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+RRULE:FREQ=YEARLY;COUNT=4
+END:VEVENT
+END:VCALENDAR
+""",
+ None,
+ (
+ (
+ PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2008, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2009, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2009, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2010, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2010, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ ),
+ None,
+ ),
+ (
+ "Simple recurring - limit not effective",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+RRULE:FREQ=YEARLY;COUNT=4
+END:VEVENT
+END:VCALENDAR
+""",
+ PyCalendarDateTime(2007, 1, 1),
+ (
+ (
+ PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2008, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2008, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2009, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2009, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2010, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2010, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ ),
+ None,
+ ),
+ (
+ "Simple recurring - limit effective partial",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+RRULE:FREQ=YEARLY;COUNT=4
+END:VEVENT
+END:VCALENDAR
+""",
+ PyCalendarDateTime(2010, 1, 1),
+ (
+ (
+ PyCalendarDateTime(2010, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2010, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ ),
+ PyCalendarDateTime(2010, 1, 1),
+ ),
+ (
+ "Simple recurring - limit effective full",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+RRULE:FREQ=YEARLY;COUNT=4
+END:VEVENT
+END:VCALENDAR
+""",
+ PyCalendarDateTime(2012, 1, 1),
+ (),
+ PyCalendarDateTime(2012, 1, 1),
+ ),
+ (
+ "Complex recurring - no limit",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+RRULE:FREQ=YEARLY;COUNT=4
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20081114T000000Z
+DTSTART:20081115T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20101114T000000Z
+DTSTART:20101115T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+END:VCALENDAR
+""",
+ None,
+ (
+ (
+ PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2008, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2008, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2009, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2009, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2010, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2010, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ ),
+ None,
+ ),
+ (
+ "Complex recurring - limit not effective",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+RRULE:FREQ=YEARLY;COUNT=4
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20081114T000000Z
+DTSTART:20081115T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20101114T000000Z
+DTSTART:20101115T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+END:VCALENDAR
+""",
+ PyCalendarDateTime(2007, 1, 1),
+ (
+ (
+ PyCalendarDateTime(2007, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2007, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2008, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2008, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2009, 11, 14, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2009, 11, 14, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ (
+ PyCalendarDateTime(2010, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2010, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ ),
+ None,
+ ),
+ (
+ "Complex recurring - limit effective partial",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+RRULE:FREQ=YEARLY;COUNT=4
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20081114T000000Z
+DTSTART:20081115T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20101114T000000Z
+DTSTART:20101115T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+END:VCALENDAR
+""",
+ PyCalendarDateTime(2010, 1, 1),
+ (
+ (
+ PyCalendarDateTime(2010, 11, 15, 0, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ PyCalendarDateTime(2010, 11, 15, 1, 0, 0, tzid=PyCalendarTimezone(utc=True)),
+ ),
+ ),
+ PyCalendarDateTime(2010, 1, 1),
+ ),
+ (
+ "Complex recurring - limit effective full",
+ """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-1
+DTSTART:20071114T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+RRULE:FREQ=YEARLY;COUNT=4
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20081114T000000Z
+DTSTART:20081115T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+BEGIN:VEVENT
+UID:12345-67890-1
+RECURRENCE-ID:20101114T000000Z
+DTSTART:20101115T000000Z
+DTSTAMP:20080601T120000Z
+DURATION:PT1H
+END:VEVENT
+END:VCALENDAR
+""",
+ PyCalendarDateTime(2012, 1, 1),
+ (),
+ PyCalendarDateTime(2012, 1, 1),
+ ),
+ )
+
+ for description, original, lowerLimit, results, limited in data:
+ component = Component.fromString(original)
+ instances = component.expandTimeRanges(PyCalendarDateTime(2100, 1, 1), lowerLimit=lowerLimit)
+ self.assertTrue(len(instances.instances) == len(results), "%s: wrong number of instances" % (description,))
+ periods = tuple([(instance.start, instance.end) for instance in sorted(instances.instances.values(), key=lambda x:x.start)])
+ self.assertEqual(periods, results)
+ for start, end in periods:
+ self.assertEqual(start.isDateOnly(), results[0][0].isDateOnly(), "%s: %s wrong date/time start state" % (description, start,))
+ self.assertEqual(end.isDateOnly(), results[0][1].isDateOnly(), "%s: %s wrong date/time end state" % (description, end,))
+ self.assertEqual(instances.lowerLimit, limited)
+
def test_has_property_in_any_component(self):
data = (
Modified: CalendarServer/trunk/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/sql.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/sql.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -858,6 +858,7 @@
instanceIndexingRequired = not hasattr(component, "noInstanceIndexing") or inserting or reCreate
if instanceIndexingRequired:
+
# Decide how far to expand based on the component. doInstanceIndexing will indicate whether we
# store expanded instance data immediately, or wait until a re-expand is triggered by some later
# operation.
@@ -901,25 +902,34 @@
PyCalendarDuration(days=config.FreeBusyIndexExpandMaxDays)):
raise IndexedSearchException
+ if config.FreeBusyIndexLowerLimitDays:
+ truncateLowerLimit = PyCalendarDateTime.getToday()
+ truncateLowerLimit.offsetDay(-config.FreeBusyIndexLowerLimitDays)
+ else:
+ truncateLowerLimit = None
+
# Always do recurrence expansion even if we do not intend to index - we need this to double-check the
# validity of the iCalendar recurrence data.
try:
- instances = component.expandTimeRanges(expand, ignoreInvalidInstances=reCreate)
+ instances = component.expandTimeRanges(expand, lowerLimit=truncateLowerLimit, ignoreInvalidInstances=reCreate)
recurrenceLimit = instances.limit
+ recurrenceLowerLimit = instances.lowerLimit
except InvalidOverriddenInstanceError, e:
self.log_error("Invalid instance %s when indexing %s in %s" %
(e.rid, self._name, self._calendar,))
if txn._migrating:
# TODO: fix the data here by re-writing component then re-index
- instances = component.expandTimeRanges(expand, ignoreInvalidInstances=True)
+ instances = component.expandTimeRanges(expand, lowerLimit=truncateLowerLimit, ignoreInvalidInstances=True)
recurrenceLimit = instances.limit
+ recurrenceLowerLimit = instances.lowerLimit
else:
raise
# Now coerce indexing to off if needed
if not doInstanceIndexing:
instances = None
+ recurrenceLowerLimit = None
recurrenceLimit = PyCalendarDateTime(1900, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
co = schema.CALENDAR_OBJECT
@@ -977,6 +987,7 @@
# Only needed if indexing being changed
if instanceIndexingRequired:
+ values[co.RECURRANCE_MIN] = pyCalendarTodatetime(normalizeForIndex(recurrenceLowerLimit)) if recurrenceLowerLimit else None
values[co.RECURRANCE_MAX] = pyCalendarTodatetime(normalizeForIndex(recurrenceLimit)) if recurrenceLimit else None
if inserting:
@@ -1003,8 +1014,8 @@
).on(txn)
else:
values = {
- co.RECURRANCE_MAX :
- pyCalendarTodatetime(normalizeForIndex(recurrenceLimit)) if recurrenceLimit else None,
+ co.RECURRANCE_MIN : pyCalendarTodatetime(normalizeForIndex(recurrenceLowerLimit)) if recurrenceLowerLimit else None,
+ co.RECURRANCE_MAX : pyCalendarTodatetime(normalizeForIndex(recurrenceLimit)) if recurrenceLimit else None,
}
yield Update(
@@ -1019,11 +1030,11 @@
).on(txn)
if instanceIndexingRequired and doInstanceIndexing:
- yield self._addInstances(component, instances, txn)
+ yield self._addInstances(component, instances, truncateLowerLimit, txn)
@inlineCallbacks
- def _addInstances(self, component, instances, txn):
+ def _addInstances(self, component, instances, truncateLowerLimit, txn):
"""
Add the set of supplied instances to the store.
@@ -1031,69 +1042,73 @@
@type component: L{Component}
@param instances: the set of instances to add
@type instances: L{InstanceList}
+ @param truncateLowerLimit: the lower limit for instances
+ @type truncateLowerLimit: L{PyCalendarDateTime}
@param txn: transaction to use
@type txn: L{Transaction}
"""
- tr = schema.TIME_RANGE
- tpy = schema.TRANSPARENCY
-
# TIME_RANGE table update
+ lowerLimitApplied = False
for key in instances:
instance = instances[key]
start = instance.start
end = instance.end
float = instance.start.floating()
+ transp = instance.component.propertyValue("TRANSP") == "TRANSPARENT"
+ fbtype = instance.component.getFBType()
start.setTimezoneUTC(True)
end.setTimezoneUTC(True)
- transp = instance.component.propertyValue("TRANSP") == "TRANSPARENT"
- instanceid = (yield Insert({
- tr.CALENDAR_RESOURCE_ID : self._calendar._resourceID,
- tr.CALENDAR_OBJECT_RESOURCE_ID : self._resourceID,
- tr.FLOATING : float,
- tr.START_DATE : pyCalendarTodatetime(start),
- tr.END_DATE : pyCalendarTodatetime(end),
- tr.FBTYPE :
- icalfbtype_to_indexfbtype.get(
- instance.component.getFBType(),
- icalfbtype_to_indexfbtype["FREE"]),
- tr.TRANSPARENT : transp,
- }, Return=tr.INSTANCE_ID).on(txn))[0][0]
- peruserdata = component.perUserTransparency(instance.rid)
- for useruid, transp in peruserdata:
- (yield Insert({
- tpy.TIME_RANGE_INSTANCE_ID : instanceid,
- tpy.USER_ID : useruid,
- tpy.TRANSPARENT : transp,
- }).on(txn))
+ # Ignore if below the lower limit
+ if truncateLowerLimit and end < truncateLowerLimit:
+ lowerLimitApplied = True
+ continue
+
+ yield self._addInstanceDetails(component, instance.rid, start, end, float, transp, fbtype, txn)
+
+ # For truncated items we insert a tomb stone lower bound so that a time-range
+ # query with just an end bound will match
+ if lowerLimitApplied or instances.lowerLimit and len(instances.instances) == 0:
+ start = PyCalendarDateTime(1901, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
+ end = PyCalendarDateTime(1901, 1, 1, 1, 0, 0, tzid=PyCalendarTimezone(utc=True))
+ yield self._addInstanceDetails(component, None, start, end, False, True, "UNKNOWN", txn)
+
# Special - for unbounded recurrence we insert a value for "infinity"
# that will allow an open-ended time-range to always match it.
- if component.isRecurringUnbounded():
+ # We also need to add the "infinity" value if the event was bounded but
+ # starts after the future expansion cut-off limit.
+ if component.isRecurringUnbounded() or instances.limit and len(instances.instances) == 0:
start = PyCalendarDateTime(2100, 1, 1, 0, 0, 0, tzid=PyCalendarTimezone(utc=True))
end = PyCalendarDateTime(2100, 1, 1, 1, 0, 0, tzid=PyCalendarTimezone(utc=True))
- float = False
- transp = True
- instanceid = (yield Insert({
- tr.CALENDAR_RESOURCE_ID : self._calendar._resourceID,
- tr.CALENDAR_OBJECT_RESOURCE_ID : self._resourceID,
- tr.FLOATING : float,
- tr.START_DATE : pyCalendarTodatetime(start),
- tr.END_DATE : pyCalendarTodatetime(end),
- tr.FBTYPE :
- icalfbtype_to_indexfbtype["UNKNOWN"],
- tr.TRANSPARENT : transp,
- }, Return=tr.INSTANCE_ID).on(txn))[0][0]
- peruserdata = component.perUserTransparency(None)
- for useruid, transp in peruserdata:
- (yield Insert({
- tpy.TIME_RANGE_INSTANCE_ID : instanceid,
- tpy.USER_ID : useruid,
- tpy.TRANSPARENT : transp,
- }).on(txn))
+ yield self._addInstanceDetails(component, None, start, end, False, True, "UNKNOWN", txn)
@inlineCallbacks
+ def _addInstanceDetails(self, component, rid, start, end, float, transp, fbtype, txn):
+
+ tr = schema.TIME_RANGE
+ tpy = schema.TRANSPARENCY
+
+ instanceid = (yield Insert({
+ tr.CALENDAR_RESOURCE_ID : self._calendar._resourceID,
+ tr.CALENDAR_OBJECT_RESOURCE_ID : self._resourceID,
+ tr.FLOATING : float,
+ tr.START_DATE : pyCalendarTodatetime(start),
+ tr.END_DATE : pyCalendarTodatetime(end),
+ tr.FBTYPE : icalfbtype_to_indexfbtype.get(fbtype, icalfbtype_to_indexfbtype["FREE"]),
+ tr.TRANSPARENT : transp,
+ }, Return=tr.INSTANCE_ID).on(txn))[0][0]
+ peruserdata = component.perUserTransparency(rid)
+ for useruid, transp in peruserdata:
+ (yield Insert({
+ tpy.TIME_RANGE_INSTANCE_ID : instanceid,
+ tpy.USER_ID : useruid,
+ tpy.TRANSPARENT : transp,
+ }).on(txn))
+
+
+ @inlineCallbacks
def component(self):
"""
Read calendar data and validate/fix it. Do not raise a store error here
@@ -1128,19 +1143,22 @@
@classproperty
- def _recurrenceMaxByIDQuery(cls): #@NoSelf
+ def _recurrenceMinMaxByIDQuery(cls): #@NoSelf
"""
- DAL query to load RECURRANCE_MAX via an object's resource ID.
+ DAL query to load RECURRANCE_MIN, RECURRANCE_MAX via an object's resource ID.
"""
co = schema.CALENDAR_OBJECT
- return Select([co.RECURRANCE_MAX], From=co,
- Where=co.RESOURCE_ID == Parameter("resourceID"))
+ return Select(
+ [co.RECURRANCE_MIN, co.RECURRANCE_MAX,],
+ From=co,
+ Where=co.RESOURCE_ID == Parameter("resourceID"),
+ )
@inlineCallbacks
- def recurrenceMax(self, txn=None):
+ def recurrenceMinMax(self, txn=None):
"""
- Get the RECURRANCE_MAX value from the database. Occasionally we might need to do an
+ Get the RECURRANCE_MIN, RECURRANCE_MAX value from the database. Occasionally we might need to do an
update to time-range data via a separate transaction, so we allow that to be passed in.
@return: L{PyCalendarDateTime} result
@@ -1148,11 +1166,14 @@
# Setup appropriate txn
txn = txn if txn is not None else self._txn
- rMax = (
- yield self._recurrenceMaxByIDQuery.on(txn,
+ rMin, rMax = (
+ yield self._recurrenceMinMaxByIDQuery.on(txn,
resourceID=self._resourceID)
- )[0][0]
- returnValue(parseSQLDateToPyCalendar(rMax) if rMax is not None else None)
+ )[0]
+ returnValue((
+ parseSQLDateToPyCalendar(rMin) if rMin is not None else None,
+ parseSQLDateToPyCalendar(rMax) if rMax is not None else None,
+ ))
@classproperty
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/1.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/1.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/1.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -24,7 +24,7 @@
o:wsanchez at example.com
ATTENDEE;CN="Cyrus Daboo";CUTYPE=INDIVIDUAL;PARTSTAT=ACCEPTED:mailto:cda
boo at example.com
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
TRANSP:OPAQUE
ORGANIZER;CN="Wilfredo Sanchez":mailto:wsanchez at example.com
UID:uid1
@@ -35,11 +35,11 @@
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/FE5CDC6F-7776-4607-83
A9-B90FF7ACC8D0.dropbox
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
BEGIN:VALARM
X-WR-ALARMUID:DB39AB67-449C-441C-89D2-D740B5F41A73
-TRIGGER;VALUE=DATE-TIME:20090324T180009Z
+TRIGGER;VALUE=DATE-TIME:%(now)s0324T180009Z
ACTION:AUDIO
END:VALARM
END:VEVENT
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/2.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/2.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/2.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -22,22 +22,22 @@
END:VTIMEZONE
BEGIN:VEVENT
UID:uid2
-DTSTART;TZID=US/Eastern:20060102T140000
+DTSTART;TZID=US/Eastern:%(now)s0102T140000
DURATION:PT1H
CREATED:20060102T190000Z
DTSTAMP:20051222T210507Z
RRULE:FREQ=DAILY;COUNT=5
-SUMMARY:event 6-%ctr
+SUMMARY:event 6-ctr
END:VEVENT
BEGIN:VEVENT
UID:uid2
-RECURRENCE-ID;TZID=US/Eastern:20060104T140000
-DTSTART;TZID=US/Eastern:20060104T160000
+RECURRENCE-ID;TZID=US/Eastern:%(now)s0104T140000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
-SUMMARY:event 6-%ctr changed again
+SUMMARY:event 6-ctr changed again
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/3.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/3.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/3.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -22,12 +22,12 @@
END:VTIMEZONE
BEGIN:VEVENT
UID:uid3
-DTSTART;TZID=US/Pacific:20060101T130000
+DTSTART;TZID=US/Pacific:%(now)s0101T130000
DURATION:PT1H
CREATED:20060101T210000Z
DTSTAMP:20051222T210146Z
LAST-MODIFIED:20051222T210203Z
SEQUENCE:1
-SUMMARY:event 3-%ctr
+SUMMARY:event 3-ctr
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/4.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/4.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_1/4.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -4,7 +4,7 @@
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:uid4
-DTSTART;VALUE=DATE:20060201
+DTSTART;VALUE=DATE:%(now)s0201
DURATION:P1D
CREATED:20060101T210000Z
DTSTAMP:20051222T210146Z
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/24204e8682b99527cbda64d7423acda7.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/24204e8682b99527cbda64d7423acda7.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/24204e8682b99527cbda64d7423acda7.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -21,12 +21,12 @@
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
-UID:9A6519F71822CD45840C3440-%ctr at ninevah.local
-DTSTART;TZID=US/Mountain:20060101T110000
+UID:9A6519F71822CD45840C3440-ctr at ninevah.local
+DTSTART;TZID=US/Mountain:%(now)s0101T110000
DURATION:PT1H
CREATED:20060101T160000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210052Z
-SUMMARY:event 2-%ctr
+SUMMARY:event 2-ctr
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/61038c41bd02ae5daf9f7fe9d54199fd.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/61038c41bd02ae5daf9f7fe9d54199fd.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/61038c41bd02ae5daf9f7fe9d54199fd.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -21,11 +21,11 @@
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
-UID:54E181BC7CCC373042B28842-%ctr at ninevah.local
-DTSTART;TZID=US/Eastern:20060101T100000
+UID:54E181BC7CCC373042B28842-ctr at ninevah.local
+DTSTART;TZID=US/Eastern:%(now)s0101T100000
DURATION:PT1H
CREATED:20060101T150000Z
DTSTAMP:20051222T205953Z
-SUMMARY:event 1-%ctr
+SUMMARY:event 1-ctr
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/84be58ced1f1bb34057e1bd7e602c9c8.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/84be58ced1f1bb34057e1bd7e602c9c8.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/84be58ced1f1bb34057e1bd7e602c9c8.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -21,11 +21,11 @@
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
-UID:54E181BC7CCC373042B28842-8-%ctr at ninevah.local
-DTSTART;TZID=US/Eastern:20060107T100000
+UID:54E181BC7CCC373042B28842-8-ctr at ninevah.local
+DTSTART;TZID=US/Eastern:%(now)s0107T100000
DURATION:PT1H
CREATED:20060101T150000Z
DTSTAMP:20051222T205953Z
-SUMMARY:event 8-%ctr
+SUMMARY:event 8-ctr
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/acc1015b7dc300c1b5665f6833960994.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/acc1015b7dc300c1b5665f6833960994.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/acc1015b7dc300c1b5665f6833960994.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -21,11 +21,11 @@
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
-UID:54E181BC7CCC373042B28842-9-%ctr at ninevah.local
-DTSTART;TZID=US/Eastern:20060107T103000
+UID:54E181BC7CCC373042B28842-9-ctr at ninevah.local
+DTSTART;TZID=US/Eastern:%(now)s0107T103000
DURATION:PT1H
CREATED:20060101T150000Z
DTSTAMP:20051222T205953Z
-SUMMARY:event 9-%ctr
+SUMMARY:event 9-ctr
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b0d5785f275c064117ffd1fc20f4ed40.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b0d5785f275c064117ffd1fc20f4ed40.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b0d5785f275c064117ffd1fc20f4ed40.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -21,12 +21,12 @@
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
-UID:A3217B429B4D2FF2DC2EEE66-%ctr at ninevah.local
-DTSTART;TZID=US/Eastern:20060101T180000
+UID:A3217B429B4D2FF2DC2EEE66-ctr at ninevah.local
+DTSTART;TZID=US/Eastern:%(now)s0101T180000
DURATION:PT1H
CREATED:20060101T230000Z
DTSTAMP:20051222T210310Z
-SUMMARY:event 4-%ctr
+SUMMARY:event 4-ctr
BEGIN:VALARM
ACTION:AUDIO
DURATION:PT10M
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b495c5dd5aa53392078eb43b1f906a80.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b495c5dd5aa53392078eb43b1f906a80.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b495c5dd5aa53392078eb43b1f906a80.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -21,13 +21,13 @@
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
-UID:945113826375CBB89184DC36-%ctr at ninevah.local
-DTSTART;TZID=US/Eastern:20060102T100000
+UID:945113826375CBB89184DC36-ctr at ninevah.local
+DTSTART;TZID=US/Eastern:%(now)s0102T100000
DURATION:PT1H
CREATED:20060102T150000Z
DTSTAMP:20051222T210412Z
RRULE:FREQ=DAILY;COUNT=5
-SUMMARY:event 5-%ctr
+SUMMARY:event 5-ctr
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b88dd50941e4a31520ee396fd7894c96.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b88dd50941e4a31520ee396fd7894c96.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home1/calendar_2/b88dd50941e4a31520ee396fd7894c96.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -21,11 +21,11 @@
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
-UID:54E181BC7CCC373042B28842-10-%ctr at ninevah.local
-DTSTART;TZID=US/Eastern:20060108T100000
+UID:54E181BC7CCC373042B28842-10-ctr at ninevah.local
+DTSTART;TZID=US/Eastern:%(now)s0108T100000
DURATION:PT1H
CREATED:20060101T150000Z
DTSTAMP:20051222T205953Z
-SUMMARY:event 10-%ctr
+SUMMARY:event 10-ctr
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/1.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/1.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/1.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid1
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid1.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid1.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/2.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/2.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/2.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid2
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/3.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/3.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_attachments/calendar_1/3.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid3
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_bad/1.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_bad/1.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_bad/1.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -26,6 +26,6 @@
SUMMARY:Busted
DTSTART;TZID=US/Pacific:20000324T121500
CREATED:20090326T145440Z
-RRULE:FREQ=DAILY
+RRULE:FREQ=HOURLY
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_bad/2.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_bad/2.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_bad/2.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -22,22 +22,22 @@
END:VTIMEZONE
BEGIN:VEVENT
UID:uid2
-DTSTART;TZID=US/Eastern:20060102T140000
+DTSTART;TZID=US/Eastern:%(now)s0102T140000
DURATION:PT1H
CREATED:20060102T190000Z
DTSTAMP:20051222T210507Z
RRULE:FREQ=DAILY;COUNT=5
-SUMMARY:event 6-%ctr
+SUMMARY:event 6-ctr
END:VEVENT
BEGIN:VEVENT
UID:uid2
-RECURRENCE-ID;TZID=US/Eastern:20060104T140000
-DTSTART;TZID=US/Eastern:20060104T160000
+RECURRENCE-ID;TZID=US/Eastern:%(now)s0104T140000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
-SUMMARY:event 6-%ctr changed again
+SUMMARY:event 6-ctr changed again
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/1.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/1.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/1.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -22,22 +22,22 @@
END:VTIMEZONE
BEGIN:VEVENT
UID:uid2
-DTSTART;TZID=US/Eastern:20060102T140000
+DTSTART;TZID=US/Eastern:%(now)s0102T140000
DURATION:PT1H
CREATED:20060102T190000Z
DTSTAMP:20051222T210507Z
RRULE:FREQ=DAILY;COUNT=5
-SUMMARY:event 6-%ctr
+SUMMARY:event 6-ctr
END:VEVENT
BEGIN:VEVENT
UID:uid2
-RECURRENCE-ID;TZID=US/Eastern:20060104T160000
-DTSTART;TZID=US/Eastern:20060104T160000
+RECURRENCE-ID;TZID=US/Eastern:%(now)s0104T160000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
-SUMMARY:event 6-%ctr changed again
+SUMMARY:event 6-ctr changed again
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/2.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/2.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/2.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -22,24 +22,24 @@
END:VTIMEZONE
BEGIN:VEVENT
UID:uid3
-DTSTART;TZID=US/Eastern:20060102T140000
+DTSTART;TZID=US/Eastern:%(now)s0102T140000
DURATION:PT1H
CREATED:20060102T190000Z
DTSTAMP:20051222T210507Z
RRULE:FREQ=DAILY;COUNT=5
-SUMMARY:event 6-%ctr
+SUMMARY:event 6-ctr
ORGANIZER:urn:uuid:home_bad
ATTENDEE:urn:uuid:home_bad
END:VEVENT
BEGIN:VEVENT
UID:uid3
-RECURRENCE-ID;TZID=US/Eastern:20060104T140000
-DTSTART;TZID=US/Eastern:20060104T160000
+RECURRENCE-ID;TZID=US/Eastern:%(now)s0104T140000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
-SUMMARY:event 6-%ctr changed again
+SUMMARY:event 6-ctr changed again
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/3.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/3.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_bad/calendar_fix_recurrence/3.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -22,21 +22,21 @@
END:VTIMEZONE
BEGIN:VEVENT
UID:uid4
-DTSTART;TZID=US/Eastern:20060104T160000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
-SUMMARY:event 6-%ctr changed again
+SUMMARY:event 6-ctr changed again
END:VEVENT
BEGIN:VEVENT
UID:uid4
-RECURRENCE-ID;TZID=US/Eastern:20060104T160000
-DTSTART;TZID=US/Eastern:20060104T160000
+RECURRENCE-ID;TZID=US/Eastern:%(now)s0104T160000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
-SUMMARY:event 6-%ctr changed again
+SUMMARY:event 6-ctr changed again
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/1.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/1.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/1.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid1
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid1.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid1.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/2.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/2.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/2.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid2
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/3.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/3.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_no_splits/calendar_1/3.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid3
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/1.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid1
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid1.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid1.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/2.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid2
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_1/3.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid3
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/1.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid2-1
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid1.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid1.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/2.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,13 +20,13 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20090324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid2-2
DTSTAMP:20090326T145447Z
X-APPLE-DROPBOX:/calendars/__uids__/user01/dropbox/uid2.dropbox
ATTACH;VALUE=URI:/calendars/__uids__/user01/dropbox/uid2.dropbox/test.txt
SUMMARY:CalDAV protocol updates
-DTSTART;TZID=US/Pacific:20090324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/3.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -23,7 +23,7 @@
UID:uid2-3
DTSTAMP:20090326T145447Z
SUMMARY:Do something...
-DUE;TZID=US/Pacific:20110324T121500
+DUE;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VTODO
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/4.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -20,11 +20,11 @@
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
-DTEND;TZID=US/Pacific:20100324T124500
+DTEND;TZID=US/Pacific:%(now)s0324T124500
UID:uid4-2
DTSTAMP:20090326T145447Z
SUMMARY:CalDAV protocol updates 2010
-DTSTART;TZID=US/Pacific:20100324T121500
+DTSTART;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VEVENT
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/calendar_store/ho/me/home_splits/calendar_2/5.ics 2012-06-25 16:27:34 UTC (rev 9383)
@@ -23,7 +23,7 @@
UID:uid2-5
DTSTAMP:20090326T145447Z
SUMMARY:Do something...2012
-DUE;TZID=US/Pacific:20120324T121500
+DUE;TZID=US/Pacific:%(now)s0324T121500
CREATED:20090326T145440Z
END:VTODO
END:VCALENDAR
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_file.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -42,6 +42,8 @@
from txdav.caldav.datastore.test.common import (
CommonTests, test_event_text, event1modified_text)
+from pycalendar.datetime import PyCalendarDateTime
+
storePath = FilePath(__file__).parent().child("calendar_store")
def _todo(f, why):
@@ -65,6 +67,16 @@
calendarPath.parent().makedirs()
storePath.copyTo(calendarPath)
+ # Set year values to current year
+ nowYear = PyCalendarDateTime.getToday().getYear()
+ for home in calendarPath.child("ho").child("me").children():
+ if not home.basename().startswith("."):
+ for calendar in home.children():
+ if not calendar.basename().startswith("."):
+ for resource in calendar.children():
+ if resource.basename().endswith(".ics"):
+ resource.setContent(resource.getContent() % {"now":nowYear})
+
testID = test.id()
test.calendarStore = CalendarStore(storeRootPath, test.notifierFactory,
quota=deriveQuota(test))
Modified: CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/datastore/test/test_sql.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -49,6 +49,7 @@
from twistedcaldav.sharing import SharedCollectionRecord
import datetime
+from pycalendar.datetime import PyCalendarDateTime
class CalendarSQLStorageTests(CalendarCommonTests, unittest.TestCase):
"""
@@ -61,6 +62,7 @@
self._sqlCalendarStore = yield buildStore(self, self.notifierFactory)
yield self.populate()
+ self.nowYear = {"now":PyCalendarDateTime.getToday().getYear()}
@inlineCallbacks
def populate(self):
@@ -226,30 +228,30 @@
END:VTIMEZONE
BEGIN:VEVENT
UID:uid2
-DTSTART;TZID=US/Eastern:20060102T140000
+DTSTART;TZID=US/Eastern:%(now)s0102T140000
DURATION:PT1H
CREATED:20060102T190000Z
DTSTAMP:20051222T210507Z
-RDATE;TZID=US/Eastern:20060104T160000
+RDATE;TZID=US/Eastern:%(now)s0104T160000
RRULE:FREQ=DAILY;COUNT=5
-SUMMARY:event 6-%ctr
+SUMMARY:event 6-ctr
END:VEVENT
BEGIN:VEVENT
UID:uid2
-RECURRENCE-ID;TZID=US/Eastern:20060104T160000
-DTSTART;TZID=US/Eastern:20060104T160000
+RECURRENCE-ID;TZID=US/Eastern:%(now)s0104T160000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
-SUMMARY:event 6-%ctr changed again
+SUMMARY:event 6-ctr changed again
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
END:VALARM
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n"))
+""".replace("\n", "\r\n") % self.nowYear)
toResource = yield toCalendar.calendarObjectWithName("2.ics")
caldata = yield toResource.component()
@@ -277,32 +279,32 @@
END:VTIMEZONE
BEGIN:VEVENT
UID:uid3
-DTSTART;TZID=US/Eastern:20060102T140000
+DTSTART;TZID=US/Eastern:%(now)s0102T140000
DURATION:PT1H
ATTENDEE:urn:uuid:home_bad
CREATED:20060102T190000Z
DTSTAMP:20051222T210507Z
ORGANIZER:urn:uuid:home_bad
RRULE:FREQ=DAILY;COUNT=5
-SUMMARY:event 6-%ctr
+SUMMARY:event 6-ctr
END:VEVENT
BEGIN:VEVENT
UID:uid3
-RECURRENCE-ID;TZID=US/Eastern:20060104T140000
-DTSTART;TZID=US/Eastern:20060104T160000
+RECURRENCE-ID;TZID=US/Eastern:%(now)s0104T140000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
ORGANIZER:urn:uuid:home_bad
-SUMMARY:event 6-%ctr changed again
+SUMMARY:event 6-ctr changed again
BEGIN:VALARM
ACTION:AUDIO
TRIGGER;RELATED=START:-PT10M
END:VALARM
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n"))
+""".replace("\n", "\r\n") % self.nowYear)
toResource = yield toCalendar.calendarObjectWithName("3.ics")
caldata = yield toResource.component()
@@ -330,26 +332,26 @@
END:VTIMEZONE
BEGIN:VEVENT
UID:uid4
-DTSTART;TZID=US/Eastern:20060104T160000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
-RDATE;TZID=US/Eastern:20060104T160000
-SUMMARY:event 6-%ctr changed again
+RDATE;TZID=US/Eastern:%(now)s0104T160000
+SUMMARY:event 6-ctr changed again
END:VEVENT
BEGIN:VEVENT
UID:uid4
-RECURRENCE-ID;TZID=US/Eastern:20060104T160000
-DTSTART;TZID=US/Eastern:20060104T160000
+RECURRENCE-ID;TZID=US/Eastern:%(now)s0104T160000
+DTSTART;TZID=US/Eastern:%(now)s0104T160000
DURATION:PT1H
CREATED:20060102T190000Z
DESCRIPTION:Some notes
DTSTAMP:20051222T210507Z
-SUMMARY:event 6-%ctr changed again
+SUMMARY:event 6-ctr changed again
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n"))
+""".replace("\n", "\r\n") % self.nowYear)
@inlineCallbacks
def test_migrateDuplicateAttachmentsCalendarFromFile(self):
@@ -385,7 +387,7 @@
filter = caldavxml.Filter(
caldavxml.ComponentFilter(
caldavxml.ComponentFilter(
- caldavxml.TimeRange(start="20060201T000000Z", end="20060202T000000Z"),
+ caldavxml.TimeRange(start="%(now)s0201T000000Z" % self.nowYear, end="%(now)s0202T000000Z" % self.nowYear),
name=("VEVENT", "VFREEBUSY", "VAVAILABILITY"),
),
name="VCALENDAR",
@@ -613,44 +615,45 @@
@inlineCallbacks
def _defer1():
yield cal1.createObjectResourceWithName("1.ics", VComponent.fromString(
- "BEGIN:VCALENDAR\r\n"
- "VERSION:2.0\r\n"
- "PRODID:-//Apple Inc.//iCal 4.0.1//EN\r\n"
- "CALSCALE:GREGORIAN\r\n"
- "BEGIN:VTIMEZONE\r\n"
- "TZID:US/Pacific\r\n"
- "BEGIN:DAYLIGHT\r\n"
- "TZOFFSETFROM:-0800\r\n"
- "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\n"
- "DTSTART:20070311T020000\r\n"
- "TZNAME:PDT\r\n"
- "TZOFFSETTO:-0700\r\n"
- "END:DAYLIGHT\r\n"
- "BEGIN:STANDARD\r\n"
- "TZOFFSETFROM:-0700\r\n"
- "RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\n"
- "DTSTART:20071104T020000\r\n"
- "TZNAME:PST\r\n"
- "TZOFFSETTO:-0800\r\n"
- "END:STANDARD\r\n"
- "END:VTIMEZONE\r\n"
- "BEGIN:VEVENT\r\n"
- "CREATED:20100203T013849Z\r\n"
- "UID:uid1\r\n"
- "DTEND;TZID=US/Pacific:20100207T173000\r\n"
- "TRANSP:OPAQUE\r\n"
- "SUMMARY:New Event\r\n"
- "DTSTART;TZID=US/Pacific:20100207T170000\r\n"
- "DTSTAMP:20100203T013909Z\r\n"
- "SEQUENCE:3\r\n"
- "BEGIN:VALARM\r\n"
- "X-WR-ALARMUID:1377CCC7-F85C-4610-8583-9513D4B364E1\r\n"
- "TRIGGER:-PT20M\r\n"
- "ATTACH;VALUE=URI:Basso\r\n"
- "ACTION:AUDIO\r\n"
- "END:VALARM\r\n"
- "END:VEVENT\r\n"
- "END:VCALENDAR\r\n"
+"""BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid1
+DTEND;TZID=US/Pacific:%(now)s0207T173000
+TRANSP:OPAQUE
+SUMMARY:New Event
+DTSTART;TZID=US/Pacific:%(now)s0207T170000
+DTSTAMP:20100203T013909Z
+SEQUENCE:3
+BEGIN:VALARM
+X-WR-ALARMUID:1377CCC7-F85C-4610-8583-9513D4B364E1
+TRIGGER:-PT20M
+ATTACH;VALUE=URI:Basso
+ACTION:AUDIO
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % self.nowYear
))
yield txn1.commit()
d1 = _defer1()
@@ -658,44 +661,45 @@
@inlineCallbacks
def _defer2():
yield cal2.createObjectResourceWithName("2.ics", VComponent.fromString(
- "BEGIN:VCALENDAR\r\n"
- "VERSION:2.0\r\n"
- "PRODID:-//Apple Inc.//iCal 4.0.1//EN\r\n"
- "CALSCALE:GREGORIAN\r\n"
- "BEGIN:VTIMEZONE\r\n"
- "TZID:US/Pacific\r\n"
- "BEGIN:DAYLIGHT\r\n"
- "TZOFFSETFROM:-0800\r\n"
- "RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\n"
- "DTSTART:20070311T020000\r\n"
- "TZNAME:PDT\r\n"
- "TZOFFSETTO:-0700\r\n"
- "END:DAYLIGHT\r\n"
- "BEGIN:STANDARD\r\n"
- "TZOFFSETFROM:-0700\r\n"
- "RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\n"
- "DTSTART:20071104T020000\r\n"
- "TZNAME:PST\r\n"
- "TZOFFSETTO:-0800\r\n"
- "END:STANDARD\r\n"
- "END:VTIMEZONE\r\n"
- "BEGIN:VEVENT\r\n"
- "CREATED:20100203T013849Z\r\n"
- "UID:uid2\r\n"
- "DTEND;TZID=US/Pacific:20100207T173000\r\n"
- "TRANSP:OPAQUE\r\n"
- "SUMMARY:New Event\r\n"
- "DTSTART;TZID=US/Pacific:20100207T170000\r\n"
- "DTSTAMP:20100203T013909Z\r\n"
- "SEQUENCE:3\r\n"
- "BEGIN:VALARM\r\n"
- "X-WR-ALARMUID:1377CCC7-F85C-4610-8583-9513D4B364E1\r\n"
- "TRIGGER:-PT20M\r\n"
- "ATTACH;VALUE=URI:Basso\r\n"
- "ACTION:AUDIO\r\n"
- "END:VALARM\r\n"
- "END:VEVENT\r\n"
- "END:VCALENDAR\r\n"
+"""BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//Apple Inc.//iCal 4.0.1//EN
+CALSCALE:GREGORIAN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+DTSTART:20070311T020000
+TZNAME:PDT
+TZOFFSETTO:-0700
+END:DAYLIGHT
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+DTSTART:20071104T020000
+TZNAME:PST
+TZOFFSETTO:-0800
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+CREATED:20100203T013849Z
+UID:uid2
+DTEND;TZID=US/Pacific:%(now)s0207T173000
+TRANSP:OPAQUE
+SUMMARY:New Event
+DTSTART;TZID=US/Pacific:%(now)s0207T170000
+DTSTAMP:20100203T013909Z
+SEQUENCE:3
+BEGIN:VALARM
+X-WR-ALARMUID:1377CCC7-F85C-4610-8583-9513D4B364E1
+TRIGGER:-PT20M
+ATTACH;VALUE=URI:Basso
+ACTION:AUDIO
+END:VALARM
+END:VEVENT
+END:VCALENDAR
+""".replace("\n", "\r\n") % self.nowYear
))
yield txn2.commit()
d2 = _defer2()
@@ -1171,16 +1175,17 @@
@inlineCallbacks
- def test_recurrenceMax(self):
+ def test_recurrenceMinMax(self):
"""
- Test CalendarObjectResource.recurrenceMax to make sure it handles a None value.
+ Test CalendarObjectResource.recurrenceMinMax to make sure it handles a None value.
"""
# Valid object
resource = yield self.calendarObjectUnderTest()
# Valid lock
- rMax = yield resource.recurrenceMax()
+ rMin, rMax = yield resource.recurrenceMinMax()
+ self.assertEqual(rMin, None)
self.assertEqual(rMax, None)
@inlineCallbacks
@@ -1196,7 +1201,7 @@
PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
BEGIN:VEVENT
UID:instance
-DTSTART:20060102T140000Z
+DTSTART:%(now)s0102T140000Z
DURATION:PT1H
CREATED:20060102T190000Z
DTSTAMP:20051222T210507Z
@@ -1204,7 +1209,7 @@
SUMMARY:instance
END:VEVENT
END:VCALENDAR
-""".replace("\n", "\r\n")
+""".replace("\n", "\r\n") % self.nowYear
self.patch(config, "FreeBusyIndexDelayedExpand", False)
@@ -1212,7 +1217,8 @@
calendar = yield self.calendarUnderTest()
component = Component.fromString(caldata)
calendarObject = yield calendar.createCalendarObjectWithName("indexing.ics", component)
- rmax = yield calendarObject.recurrenceMax()
+ rmin, rmax = yield calendarObject.recurrenceMinMax()
+ self.assertEqual(rmin, None)
self.assertNotEqual(rmax.getYear(), 1900)
instances = yield calendarObject.instances()
self.assertNotEqual(len(instances), 0)
Modified: CalendarServer/trunk/txdav/caldav/icalendarstore.py
===================================================================
--- CalendarServer/trunk/txdav/caldav/icalendarstore.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/caldav/icalendarstore.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -44,6 +44,8 @@
# Exceptions
"QuotaExceeded",
+ "TimeRangeLowerLimit",
+ "TimeRangeUpperLimit",
# Enumerations
"BIND_OWN",
@@ -61,6 +63,24 @@
+class TimeRangeLowerLimit(Exception):
+ """
+ A request for time-range information too far in the past cannot be satisfied.
+ """
+
+ def __init__(self, lowerLimit):
+ self.limit = lowerLimit
+
+
+class TimeRangeUpperLimit(Exception):
+ """
+ A request for time-range information too far in the future cannot be satisfied.
+ """
+
+ def __init__(self, upperLimit):
+ self.limit = upperLimit
+
+
class ICalendarTransaction(ICommonTransaction):
"""
Transaction functionality required to be implemented by calendar stores.
Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -72,6 +72,8 @@
Delete, utcNowSQL, Union, Insert, Len, Max, Parameter, SavepointAction, \
Select, Update, ColumnSyntax, TableSyntax, Upper
+from twistedcaldav.config import config
+
from txdav.base.propertystore.base import PropertyName
from txdav.base.propertystore.none import PropertyStore as NonePropertyStore
from txdav.base.propertystore.sql import PropertyStore
@@ -84,6 +86,8 @@
from txdav.base.datastore.util import normalizeUUIDOrNot
+from pycalendar.datetime import PyCalendarDateTime
+
from cStringIO import StringIO
from sqlparse import parse
import collections
@@ -770,6 +774,14 @@
Returns a deferred to a list of (uid, calendarName, eventName, maxDate)
tuples.
"""
+
+ # Make sure cut off is after any lower limit truncation in the DB
+ if config.FreeBusyIndexLowerLimitDays:
+ truncateLowerLimit = PyCalendarDateTime.getToday()
+ truncateLowerLimit.offsetDay(-config.FreeBusyIndexLowerLimitDays)
+ if cutoff < truncateLowerLimit:
+ raise ValueError("Cannot query events older than %s" % (truncateLowerLimit.getText(),))
+
kwds = { "CutOff" : pyCalendarTodatetime(cutoff) }
if batchSize is not None:
kwds["batchSize"] = batchSize
@@ -786,6 +798,13 @@
many were removed.
"""
+ # Make sure cut off is after any lower limit truncation in the DB
+ if config.FreeBusyIndexLowerLimitDays:
+ truncateLowerLimit = PyCalendarDateTime.getToday()
+ truncateLowerLimit.offsetDay(-config.FreeBusyIndexLowerLimitDays)
+ if cutoff < truncateLowerLimit:
+ raise ValueError("Cannot query events older than %s" % (truncateLowerLimit.getText(),))
+
results = (yield self.eventsOlderThan(cutoff, batchSize=batchSize))
count = 0
for uid, calendarName, eventName, _ignore_maxDate in results:
Modified: CalendarServer/trunk/txdav/common/datastore/sql_legacy.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_legacy.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/common/datastore/sql_legacy.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -22,39 +22,36 @@
import StringIO
-from twistedcaldav.sharing import SharedCollectionRecord
from twisted.python import hashlib
from twisted.internet.defer import succeed, inlineCallbacks, returnValue
-from twext.python.clsprop import classproperty
-from twext.python.log import Logger, LoggingMixIn
-
from twistedcaldav.config import config
from twistedcaldav.dateops import normalizeForIndex, pyCalendarTodatetime
from twistedcaldav.memcachepool import CachePoolUserMixIn
from twistedcaldav.notifications import NotificationRecord
-from twistedcaldav.query import (
- calendarqueryfilter, calendarquery, addressbookquery, expression,
- addressbookqueryfilter)
+from twistedcaldav.query import \
+ calendarqueryfilter, calendarquery, addressbookquery, expression, \
+ addressbookqueryfilter
from twistedcaldav.query.sqlgenerator import sqlgenerator
from twistedcaldav.sharing import Invite
+from twistedcaldav.sharing import SharedCollectionRecord
-from txdav.common.icommondatastore import (
- IndexedSearchException, ReservationError, NoSuchObjectResourceError)
+from txdav.caldav.icalendarstore import TimeRangeLowerLimit, TimeRangeUpperLimit
+from txdav.common.icommondatastore import IndexedSearchException, \
+ ReservationError, NoSuchObjectResourceError
-from twext.enterprise.dal.syntax import Update, SavepointAction
-from twext.enterprise.dal.syntax import Insert
-from twext.enterprise.dal.syntax import Select
-from twext.enterprise.dal.syntax import Delete
-from twext.enterprise.dal.syntax import Parameter
from txdav.common.datastore.sql_tables import (
_BIND_MODE_OWN, _BIND_MODE_READ, _BIND_MODE_WRITE, _BIND_MODE_DIRECT,
_BIND_STATUS_INVITED, _BIND_STATUS_ACCEPTED, _BIND_STATUS_DECLINED,
_BIND_STATUS_INVALID, CALENDAR_BIND_TABLE, CALENDAR_HOME_TABLE,
ADDRESSBOOK_HOME_TABLE, ADDRESSBOOK_BIND_TABLE, schema)
+from twext.enterprise.dal.syntax import Delete, Insert, Parameter, \
+ SavepointAction, Select, Update
+from twext.python.clsprop import classproperty
+from twext.python.log import Logger, LoggingMixIn
-
+from pycalendar.datetime import PyCalendarDateTime
from pycalendar.duration import PyCalendarDuration
log = Logger()
@@ -1126,31 +1123,37 @@
@classproperty
- def _notExpandedBeyondQuery(cls): #@NoSelf
+ def _notExpandedWithinQuery(cls): #@NoSelf
"""
DAL query to satisfy L{PostgresLegacyIndexEmulator.notExpandedBeyond}.
"""
co = schema.CALENDAR_OBJECT
- return Select([co.RESOURCE_NAME], From=co,
- Where=(co.RECURRANCE_MAX < Parameter("minDate"))
- .And(co.CALENDAR_RESOURCE_ID == Parameter("resourceID")))
+ return Select(
+ [co.RESOURCE_NAME],
+ From=co,
+ Where=((co.RECURRANCE_MIN < Parameter("minDate"))
+ .Or(co.RECURRANCE_MAX < Parameter("maxDate")))
+ .And(co.CALENDAR_RESOURCE_ID == Parameter("resourceID"))
+ )
@inlineCallbacks
- def notExpandedBeyond(self, minDate):
+ def notExpandedWithin(self, minDate, maxDate):
"""
Gives all resources which have not been expanded beyond a given date
in the database. (Unused; see above L{postgresqlgenerator}.
"""
returnValue([row[0] for row in (
- yield self._notExpandedBeyondQuery.on(
- self._txn, minDate=pyCalendarTodatetime(normalizeForIndex(minDate)),
+ yield self._notExpandedWithinQuery.on(
+ self._txn,
+ minDate=pyCalendarTodatetime(normalizeForIndex(minDate)) if minDate is not None else None,
+ maxDate=pyCalendarTodatetime(normalizeForIndex(maxDate)),
resourceID=self.calendar._resourceID))]
)
@inlineCallbacks
- def reExpandResource(self, name, expand_until):
+ def reExpandResource(self, name, expand_start, expand_end):
"""
Given a resource name, remove it from the database and re-add it
with a longer expansion.
@@ -1172,15 +1175,25 @@
# Now do the re-expand using the appropriate transaction
try:
+ doExpand = False
if newTxn is None:
- rmax = None
+ doExpand = True
else:
- rmax = (yield obj.recurrenceMax(txn=newTxn))
+ # We repeat this check because the resource may have been re-expanded by someone else
+ rmin, rmax = (yield obj.recurrenceMinMax(txn=newTxn))
+
+ # If the resource is not fully expanded, see if within the required range or not.
+ # Note that expand_start could be None if no lower limit is applied, but expand_end will
+ # never be None
+ if rmax is not None and rmax < expand_end:
+ doExpand = True
+ if rmin is not None and expand_start is not None and rmin > expand_start:
+ doExpand = True
- if rmax is None or rmax < expand_until:
+ if doExpand:
yield obj.updateDatabase(
(yield obj.component()),
- expand_until=expand_until,
+ expand_until=expand_end,
reCreate=True,
txn=newTxn,
)
@@ -1190,15 +1203,15 @@
@inlineCallbacks
- def testAndUpdateIndex(self, minDate):
+ def testAndUpdateIndex(self, minDate, maxDate):
# Find out if the index is expanded far enough
- names = yield self.notExpandedBeyond(minDate)
+ names = yield self.notExpandedWithin(minDate, maxDate)
# Actually expand recurrence max
for name in names:
- self.log_info("Search falls outside range of index for %s %s" %
- (name, minDate))
- yield self.reExpandResource(name, minDate)
+ self.log_info("Search falls outside range of index for %s %s to %s" %
+ (name, minDate, maxDate))
+ yield self.reExpandResource(name, minDate, maxDate)
@inlineCallbacks
@@ -1230,6 +1243,9 @@
generator=generator
)
if qualifiers is not None:
+
+ today = PyCalendarDateTime.getToday()
+
# Determine how far we need to extend the current expansion of
# events. If we have an open-ended time-range we will expand
# one year past the start. That should catch bounded
@@ -1239,11 +1255,29 @@
if maxDate:
maxDate = maxDate.duplicate()
maxDate.setDateOnly(True)
+ upperLimit = today + PyCalendarDuration(days=config.FreeBusyIndexExpandMaxDays)
+ if maxDate > upperLimit:
+ raise TimeRangeUpperLimit(upperLimit)
if isStartDate:
maxDate += PyCalendarDuration(days=365)
- yield self.testAndUpdateIndex(maxDate)
+
+ # Determine if the start date is too early for the restricted range we
+ # are applying. If it is today or later we don't need to worry about truncation
+ # in the past.
+ minDate, _ignore_isEndDate = filter.getmintimerange()
+ if minDate >= today:
+ minDate = None
+ if minDate is not None and config.FreeBusyIndexLowerLimitDays:
+ truncateLowerLimit = today - PyCalendarDuration(days=config.FreeBusyIndexLowerLimitDays)
+ if minDate < truncateLowerLimit:
+ raise TimeRangeLowerLimit(truncateLowerLimit)
+
+
+ if maxDate is not None or minDate is not None:
+ yield self.testAndUpdateIndex(minDate, maxDate)
+
else:
- # We cannot handler this filter in an indexed search
+ # We cannot handle this filter in an indexed search
raise IndexedSearchException()
else:
qualifiers = None
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2012-06-25 16:27:34 UTC (rev 9383)
@@ -92,6 +92,7 @@
"DROPBOX_ID" nvarchar2(255),
"ORGANIZER" nvarchar2(255),
"ORGANIZER_OBJECT" integer references CALENDAR_OBJECT,
+ "RECURRANCE_MIN" date,
"RECURRANCE_MAX" date,
"ACCESS" integer default 0 not null,
"SCHEDULE_OBJECT" integer default 0,
@@ -257,7 +258,7 @@
"VALUE" nvarchar2(255)
);
-insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '9');
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '10');
insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '2');
insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '1');
create index INVITE_INVITE_UID_9b0902ff on INVITE (
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql 2012-06-25 16:27:34 UTC (rev 9383)
@@ -174,6 +174,7 @@
DROPBOX_ID varchar(255),
ORGANIZER varchar(255),
ORGANIZER_OBJECT integer references CALENDAR_OBJECT,
+ RECURRANCE_MIN date, -- minimum date that recurrences have been expanded to.
RECURRANCE_MAX date, -- maximum date that recurrences have been expanded to.
ACCESS integer default 0 not null,
SCHEDULE_OBJECT boolean default false,
@@ -494,6 +495,6 @@
VALUE varchar(255)
);
-insert into CALENDARSERVER values ('VERSION', '9');
+insert into CALENDARSERVER values ('VERSION', '10');
insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '3');
insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '1');
Added: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v9.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v9.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v9.sql 2012-06-25 16:27:34 UTC (rev 9383)
@@ -0,0 +1,359 @@
+create sequence RESOURCE_ID_SEQ;
+create sequence INSTANCE_ID_SEQ;
+create sequence REVISION_SEQ;
+create table CALENDAR_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table CALENDAR_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR (
+ "RESOURCE_ID" integer primary key
+);
+
+create table CALENDAR_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR on delete cascade,
+ "SUPPORTED_COMPONENTS" nvarchar2(255) default null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table INVITE (
+ "INVITE_UID" nvarchar2(255),
+ "NAME" nvarchar2(255),
+ "RECIPIENT_ADDRESS" nvarchar2(255),
+ "HOME_RESOURCE_ID" integer not null,
+ "RESOURCE_ID" integer not null
+);
+
+create table NOTIFICATION_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique
+);
+
+create table NOTIFICATION (
+ "RESOURCE_ID" integer primary key,
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME,
+ "NOTIFICATION_UID" nvarchar2(255),
+ "XML_TYPE" nvarchar2(255),
+ "XML_DATA" nclob,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique("NOTIFICATION_UID", "NOTIFICATION_HOME_RESOURCE_ID")
+);
+
+create table CALENDAR_BIND (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "CALENDAR_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "SEEN_BY_OWNER" integer not null,
+ "SEEN_BY_SHAREE" integer not null,
+ "MESSAGE" nclob,
+ primary key("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_ID"),
+ unique("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_NAME")
+);
+
+create table CALENDAR_BIND_MODE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
+create table CALENDAR_BIND_STATUS (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
+create table CALENDAR_OBJECT (
+ "RESOURCE_ID" integer primary key,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob,
+ "ICALENDAR_UID" nvarchar2(255),
+ "ICALENDAR_TYPE" nvarchar2(255),
+ "ATTACHMENTS_MODE" integer default 0 not null,
+ "DROPBOX_ID" nvarchar2(255),
+ "ORGANIZER" nvarchar2(255),
+ "ORGANIZER_OBJECT" integer references CALENDAR_OBJECT,
+ "RECURRANCE_MAX" date,
+ "ACCESS" integer default 0 not null,
+ "SCHEDULE_OBJECT" integer default 0,
+ "SCHEDULE_TAG" nvarchar2(36) default null,
+ "SCHEDULE_ETAGS" nclob default null,
+ "PRIVATE_COMMENTS" integer default 0 not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique("CALENDAR_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MO (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('none', 0);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_OBJECT_ATTACHMENTS_MO (DESCRIPTION, ID) values ('write', 2);
+create table CALENDAR_ACCESS_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(32) unique
+);
+
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
+create table TIME_RANGE (
+ "INSTANCE_ID" integer primary key,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "FLOATING" integer not null,
+ "START_DATE" timestamp not null,
+ "END_DATE" timestamp not null,
+ "FBTYPE" integer not null,
+ "TRANSPARENT" integer not null
+);
+
+create table FREE_BUSY_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
+create table TRANSPARENCY (
+ "TIME_RANGE_INSTANCE_ID" integer not null references TIME_RANGE on delete cascade,
+ "USER_ID" nvarchar2(255),
+ "TRANSPARENT" integer not null
+);
+
+create table ATTACHMENT (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "DROPBOX_ID" nvarchar2(255),
+ "CONTENT_TYPE" nvarchar2(255),
+ "SIZE" integer not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "PATH" nvarchar2(1024),
+ primary key("DROPBOX_ID", "PATH")
+);
+
+create table RESOURCE_PROPERTY (
+ "RESOURCE_ID" integer not null,
+ "NAME" nvarchar2(255),
+ "VALUE" nclob,
+ "VIEWER_UID" nvarchar2(255),
+ primary key("RESOURCE_ID", "NAME", "VIEWER_UID")
+);
+
+create table ADDRESSBOOK_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table ADDRESSBOOK_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references ADDRESSBOOK_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table ADDRESSBOOK (
+ "RESOURCE_ID" integer primary key
+);
+
+create table ADDRESSBOOK_METADATA (
+ "RESOURCE_ID" integer primary key references ADDRESSBOOK on delete cascade,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table ADDRESSBOOK_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
+ "ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "SEEN_BY_OWNER" integer not null,
+ "SEEN_BY_SHAREE" integer not null,
+ "MESSAGE" nclob,
+ primary key("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_ID"),
+ unique("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_NAME")
+);
+
+create table ADDRESSBOOK_OBJECT (
+ "RESOURCE_ID" integer primary key,
+ "ADDRESSBOOK_RESOURCE_ID" integer not null references ADDRESSBOOK on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "VCARD_TEXT" nclob,
+ "VCARD_UID" nvarchar2(255),
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique("ADDRESSBOOK_RESOURCE_ID", "RESOURCE_NAME"),
+ unique("ADDRESSBOOK_RESOURCE_ID", "VCARD_UID")
+);
+
+create table CALENDAR_OBJECT_REVISIONS (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer references CALENDAR,
+ "CALENDAR_NAME" nvarchar2(255) default null,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null
+);
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "ADDRESSBOOK_RESOURCE_ID" integer references ADDRESSBOOK,
+ "ADDRESSBOOK_NAME" nvarchar2(255) default null,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null
+);
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null,
+ unique("NOTIFICATION_HOME_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table APN_SUBSCRIPTIONS (
+ "TOKEN" nvarchar2(255),
+ "RESOURCE_KEY" nvarchar2(255),
+ "MODIFIED" integer not null,
+ "SUBSCRIBER_GUID" nvarchar2(255),
+ primary key("TOKEN", "RESOURCE_KEY")
+);
+
+create table CALENDARSERVER (
+ "NAME" nvarchar2(255) primary key,
+ "VALUE" nvarchar2(255)
+);
+
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '9');
+insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '2');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '1');
+create index INVITE_INVITE_UID_9b0902ff on INVITE (
+ INVITE_UID
+);
+
+create index INVITE_RESOURCE_ID_b36ddc23 on INVITE (
+ RESOURCE_ID
+);
+
+create index INVITE_HOME_RESOURCE__e9bdf77e on INVITE (
+ HOME_RESOURCE_ID
+);
+
+create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
+ NOTIFICATION_HOME_RESOURCE_ID
+);
+
+create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ RECURRANCE_MAX
+);
+
+create index CALENDAR_OBJECT_ORGAN_7ce24750 on CALENDAR_OBJECT (
+ ORGANIZER_OBJECT
+);
+
+create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
+ DROPBOX_ID
+);
+
+create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
+ CALENDAR_RESOURCE_ID
+);
+
+create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
+ CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index TRANSPARENCY_TIME_RAN_5f34467f on TRANSPARENCY (
+ TIME_RANGE_INSTANCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
+ CALENDAR_HOME_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_BIND_RESO_205aa75c on ADDRESSBOOK_BIND (
+ ADDRESSBOOK_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID,
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_2643d556 on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ RESOURCE_NAME
+);
+
+create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_f460d62d on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID,
+ ADDRESSBOOK_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_OBJECT_RE_9a848f39 on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_RESOURCE_ID,
+ RESOURCE_NAME
+);
+
+create index ADDRESSBOOK_OBJECT_RE_cb101e6b on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_RESOURCE_ID,
+ REVISION
+);
+
+create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID,
+ REVISION
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
+ RESOURCE_KEY
+);
+
Added: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v9.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v9.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v9.sql 2012-06-25 16:27:34 UTC (rev 9383)
@@ -0,0 +1,499 @@
+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2012 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ DATAVERSION integer default 0 not null
+);
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+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,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+
+-----------------------
+-- Calendar Metadata --
+-----------------------
+
+create table CALENDAR_METADATA (
+ 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)
+);
+
+
+------------------------
+-- Sharing Invitation --
+------------------------
+
+create table INVITE (
+ INVITE_UID varchar(255) not null,
+ NAME varchar(255) not null,
+ RECIPIENT_ADDRESS varchar(255) not null,
+ HOME_RESOURCE_ID integer not null,
+ RESOURCE_ID integer not null
+
+ -- Need primary key on (INVITE_UID, NAME, RECIPIENT_ADDRESS)?
+);
+
+create index INVITE_INVITE_UID on INVITE(INVITE_UID);
+create index INVITE_RESOURCE_ID on INVITE(RESOURCE_ID);
+create index INVITE_HOME_RESOURCE_ID on INVITE(HOME_RESOURCE_ID);
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique -- implicit index
+);
+
+create table NOTIFICATION (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME,
+ NOTIFICATION_UID varchar(255) not null,
+ 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),
+
+ unique(NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+ NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+
+ -- An invitation which hasn't been accepted yet will not yet have a resource
+ -- name, so this field may be null.
+
+ CALENDAR_RESOURCE_NAME varchar(255),
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ SEEN_BY_OWNER boolean not null,
+ SEEN_BY_SHAREE boolean not null,
+ MESSAGE text,
+
+ primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+ unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME) -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own' );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+
+
+---------------------
+-- Calendar Object --
+---------------------
+
+create table CALENDAR_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ ICALENDAR_TEXT text not null,
+ ICALENDAR_UID varchar(255) not null,
+ ICALENDAR_TYPE varchar(255) not null,
+ ATTACHMENTS_MODE integer default 0 not null, -- enum CALENDAR_OBJECT_ATTACHMENTS_MODE
+ DROPBOX_ID varchar(255),
+ ORGANIZER varchar(255),
+ ORGANIZER_OBJECT integer references CALENDAR_OBJECT,
+ RECURRANCE_MAX date, -- maximum date that recurrences have been expanded to.
+ ACCESS integer default 0 not null,
+ SCHEDULE_OBJECT boolean default false,
+ SCHEDULE_TAG varchar(36) default null,
+ SCHEDULE_ETAGS text default null,
+ PRIVATE_COMMENTS boolean default false not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique(CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+ -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+ -- calendar objects, this constraint has to be selectively enforced by the
+ -- application layer.
+
+ -- unique(CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ORGANIZER_OBJECT on
+ CALENDAR_OBJECT(ORGANIZER_OBJECT);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+ CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJECT_ATTACHMENTS_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJECT_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, '' );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public' );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private' );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted' );
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+ INSTANCE_ID integer primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ FLOATING boolean not null,
+ START_DATE timestamp not null,
+ END_DATE timestamp not null,
+ FBTYPE integer not null,
+ TRANSPARENT boolean not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown' );
+insert into FREE_BUSY_TYPE values (1, 'free' );
+insert into FREE_BUSY_TYPE values (2, 'busy' );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative' );
+
+
+------------------
+-- Transparency --
+------------------
+
+create table TRANSPARENCY (
+ TIME_RANGE_INSTANCE_ID integer not null references TIME_RANGE on delete cascade,
+ USER_ID varchar(255) not null,
+ TRANSPARENT boolean not null
+);
+
+create index TRANSPARENCY_TIME_RANGE_INSTANCE_ID on
+ TRANSPARENCY(TIME_RANGE_INSTANCE_ID);
+
+----------------
+-- Attachment --
+----------------
+
+create table ATTACHMENT (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ DROPBOX_ID varchar(255) not null,
+ CONTENT_TYPE varchar(255) not null,
+ SIZE integer not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ PATH varchar(1024) not null,
+
+ primary key(DROPBOX_ID, PATH) --implicit index
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+ ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+ RESOURCE_ID integer not null, -- foreign key: *.RESOURCE_ID
+ NAME varchar(255) not null,
+ VALUE text not null, -- FIXME: xml?
+ VIEWER_UID varchar(255),
+
+ primary key(RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ DATAVERSION integer default 0 not null
+);
+
+-------------------------------
+-- AddressBook Home Metadata --
+-------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+ RESOURCE_ID integer primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+-----------------
+-- AddressBook --
+-----------------
+
+create table ADDRESSBOOK (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+
+--------------------------
+-- AddressBook Metadata --
+--------------------------
+
+create table ADDRESSBOOK_METADATA (
+ RESOURCE_ID integer primary key references ADDRESSBOOK on delete cascade, -- implicit index
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+----------------------
+-- AddressBook Bind --
+----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK
+
+create table ADDRESSBOOK_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
+
+ -- An invitation which hasn't been accepted yet will not yet have a resource
+ -- name, so this field may be null.
+
+ ADDRESSBOOK_RESOURCE_NAME varchar(255),
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ SEEN_BY_OWNER boolean not null,
+ SEEN_BY_SHAREE boolean not null,
+ MESSAGE text, -- FIXME: xml?
+
+ primary key(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID), -- implicit index
+ unique(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME) -- implicit index
+);
+
+create index ADDRESSBOOK_BIND_RESOURCE_ID on
+ ADDRESSBOOK_BIND(ADDRESSBOOK_RESOURCE_ID);
+
+create table ADDRESSBOOK_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ ADDRESSBOOK_RESOURCE_ID integer not null references ADDRESSBOOK on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ VCARD_TEXT text not null,
+ VCARD_UID varchar(255) not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+ unique(ADDRESSBOOK_RESOURCE_ID, VCARD_UID) -- implicit index
+);
+
+---------------
+-- Revisions --
+---------------
+
+create sequence REVISION_SEQ;
+
+
+---------------
+-- Revisions --
+---------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer references CALENDAR,
+ CALENDAR_NAME varchar(255) default null,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
+
+-------------------------------
+-- AddressBook Object Revisions --
+-------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ ADDRESSBOOK_RESOURCE_ID integer references ADDRESSBOOK,
+ ADDRESSBOOK_NAME varchar(255) default null,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_ADDRESSBOOK_RESOURCE_ID
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, RESOURCE_NAME);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_RESOURCE_ID, REVISION);
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME on delete cascade,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null,
+
+ unique(NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+ TOKEN varchar(255) not null,
+ RESOURCE_KEY varchar(255) not null,
+ MODIFIED integer not null,
+ SUBSCRIBER_GUID varchar(255) not null,
+
+ primary key(TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+ on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+ NAME varchar(255) primary key, -- implicit index
+ VALUE varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '9');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '3');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '1');
Added: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_9_to_10.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_9_to_10.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_9_to_10.sql 2012-06-25 16:27:34 UTC (rev 9383)
@@ -0,0 +1,27 @@
+----
+-- Copyright (c) 2012 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+--------------------------------------------------
+-- Upgrade database schema from VERSION 9 to 10 --
+--------------------------------------------------
+
+ -- Just need to modify one column
+alter table CALENDAR_OBJECT
+ add ("RECURRANCE_MIN" date);
+
+-- Now update the version
+-- No data upgrades
+update CALENDARSERVER set VALUE = '10' where NAME = 'VERSION';
Added: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_9_to_10.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_9_to_10.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_9_to_10.sql 2012-06-25 16:27:34 UTC (rev 9383)
@@ -0,0 +1,27 @@
+----
+-- Copyright (c) 2012 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+--------------------------------------------------
+-- Upgrade database schema from VERSION 9 to 10 --
+--------------------------------------------------
+
+-- Just need to add one column
+alter table CALENDAR_OBJECT
+ add column RECURRANCE_MIN date;
+
+-- Now update the version
+-- No data upgrades
+update CALENDARSERVER set VALUE = '10' where NAME = 'VERSION';
Modified: CalendarServer/trunk/txdav/common/datastore/test/test_sql_tables.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/test/test_sql_tables.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/common/datastore/test/test_sql_tables.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -1,6 +1,6 @@
# -*- test-case-name: txdav.caldav.datastore.test.test_sql -*-
##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
+# Copyright (c) 2010-2012 Apple Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -85,7 +85,7 @@
)
schema = pathObj.getContent()
pos = schema.find("('VERSION', '")
- version = int(schema[pos+13])
+ version = int(schema[pos+13:pos+15])
self.assertIn("insert into CALENDARSERVER (NAME, VALUE) "
"values ('VERSION', '%s');" % version,
self.translated())
Modified: CalendarServer/trunk/txdav/common/datastore/test/util.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/test/util.py 2012-06-25 16:10:40 UTC (rev 9382)
+++ CalendarServer/trunk/txdav/common/datastore/test/util.py 2012-06-25 16:27:34 UTC (rev 9383)
@@ -49,6 +49,8 @@
from twext.enterprise.ienterprise import AlreadyFinishedError
from twistedcaldav.vcard import Component as ABComponent
+from pycalendar.datetime import PyCalendarDateTime
+
md5key = PropertyName.fromElement(TwistedGETContentMD5)
def allInstancesOf(cls):
@@ -373,12 +375,19 @@
objData, metadata = calendarObjNames[objectName]
yield calendar.createCalendarObjectWithName(
objectName,
- VComponent.fromString(objData),
+ VComponent.fromString(updateToCurrentYear(objData)),
metadata = metadata,
)
yield populateTxn.commit()
+def updateToCurrentYear(data):
+ """
+ Update the supplied iCalendar data so that all dates are updated to the current year.
+ """
+
+ nowYear = PyCalendarDateTime.getToday().getYear()
+ return data % {"now":nowYear}
@inlineCallbacks
def resetCalendarMD5s(md5s, store):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120625/ace38744/attachment-0001.html>
More information about the calendarserver-changes
mailing list