[CalendarServer-changes] [10882] CalendarServer/branches/users/gaya/sharedgroups

source_changes at macosforge.org source_changes at macosforge.org
Fri Mar 8 20:49:28 PST 2013


Revision: 10882
          http://trac.calendarserver.org//changeset/10882
Author:   gaya at apple.com
Date:     2013-03-08 20:49:28 -0800 (Fri, 08 Mar 2013)
Log Message:
-----------
merge from trunk

Modified Paths:
--------------
    CalendarServer/branches/users/gaya/sharedgroups/calendarserver/push/notifier.py
    CalendarServer/branches/users/gaya/sharedgroups/calendarserver/tap/util.py
    CalendarServer/branches/users/gaya/sharedgroups/calendarserver/tools/test/test_calverify.py
    CalendarServer/branches/users/gaya/sharedgroups/conf/caldavd-apple.plist
    CalendarServer/branches/users/gaya/sharedgroups/twext/internet/decorate.py
    CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/caldavxml.py
    CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/scheduling/caldav/delivery.py
    CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/stdconfig.py
    CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py
    CalendarServer/branches/users/gaya/sharedgroups/txdav/base/datastore/subpostgres.py
    CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/file.py
    CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/sql.py

Modified: CalendarServer/branches/users/gaya/sharedgroups/calendarserver/push/notifier.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/calendarserver/push/notifier.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/calendarserver/push/notifier.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -18,14 +18,13 @@
 Notification framework for Calendar Server
 """
 
+import datetime
 from twext.python.log import LoggingMixIn, Logger
-
 from twisted.internet.defer import inlineCallbacks, succeed
 from twext.enterprise.dal.record import fromTable
 from twext.enterprise.queue import WorkItem
 from txdav.common.datastore.sql_tables import schema
-from twisted.application import service
-from twisted.python.reflect import namedClass
+from twext.enterprise.dal.syntax import Delete
 
 
 log = Logger()
@@ -33,14 +32,19 @@
 
 class PushNotificationWork(WorkItem, fromTable(schema.PUSH_NOTIFICATION_WORK)):
 
+    group = "PUSH_ID"
+
     @inlineCallbacks
     def doWork(self):
 
-        # FIXME: Coalescing goes here?
+        # Delete all other work items with the same pushID
+        yield Delete(From=self.table,
+                     Where=self.table.PUSH_ID == self.pushID 
+                    ).on(self.transaction)
 
-        pushService = self.transaction._pushService
-        if pushService is not None:
-            yield pushService.enqueue(self.pushID)
+        pushDistributor = self.transaction._pushDistributor
+        if pushDistributor is not None:
+            yield pushDistributor.enqueue(self.pushID)
 
 
 
@@ -119,9 +123,10 @@
     work queue.
     """
 
-    def __init__(self, store, hostname, reactor=None):
+    def __init__(self, store, hostname, coalesceSeconds, reactor=None):
         self.store = store
         self.hostname = hostname
+        self.coalesceSeconds = coalesceSeconds
 
         if reactor is None:
             from twisted.internet import reactor
@@ -130,7 +135,10 @@
     @inlineCallbacks
     def send(self, id):
         txn = self.store.newTransaction()
-        yield txn.enqueue(PushNotificationWork, pushID=id)
+        notBefore = datetime.datetime.utcnow() + datetime.timedelta(
+            seconds=self.coalesceSeconds)
+        yield txn.enqueue(PushNotificationWork, pushID=self.pushKeyForId(id),
+            notBefore=notBefore)
         yield txn.commit()
 
     def newNotifier(self, label="default", id=None, prefix=None):
@@ -153,22 +161,21 @@
 
 
 
-def getPubSubAPSConfiguration(id, config):
+def getPubSubAPSConfiguration(pushKey, config):
     """
-    Returns the Apple push notification settings specific to the notifier
-    ID, which includes a prefix that is either "CalDAV" or "CardDAV"
+    Returns the Apple push notification settings specific to the pushKey
     """
     try:
-        prefix, id = id.split("|", 1)
+        protocol, ignored = pushKey.split("|", 1)
     except ValueError:
-        # id has no prefix, so we can't look up APS config
+        # id has no protocol, so we can't look up APS config
         return None
 
     # If we are directly talking to apple push, advertise those settings
-    applePushSettings = config.Notifications.Services.ApplePushNotifier
+    applePushSettings = config.Notifications.Services.APNS
     if applePushSettings.Enabled:
         settings = {}
-        settings["APSBundleID"] = applePushSettings[prefix]["Topic"]
+        settings["APSBundleID"] = applePushSettings[protocol]["Topic"]
         if config.EnableSSL:
             url = "https://%s:%s/%s" % (config.ServerHostName, config.SSLPort,
                 applePushSettings.SubscriptionURL)
@@ -183,27 +190,26 @@
     return None
 
 
-class PushService(service.MultiService):
+class PushDistributor(object):
     """
-    A Service which passes along notifications to the protocol-specific subservices
+    Distributes notifications to the protocol-specific subservices
     """
 
-    @classmethod
-    def makeService(cls, settings, store):
-        multiService = cls()
-        for key, subSettings in settings.Services.iteritems():
-            if subSettings["Enabled"]:
-                subService = namedClass(subSettings["Service"]).makeService(
-                    subSettings, store)
-                subService.setServiceParent(multiService)
-                multiService.subServices.append(subService)            
-        return multiService
+    def __init__(self, observers):
+        """
+        @param observers: the list of observers to distribute pushKeys to
+        @type observers: C{list} 
+        """
+        # TODO: add an IPushObservers interface?
+        self.observers = observers 
 
-    def __init__(self):
-        service.MultiService.__init__(self)
-        self.subServices = []
+    @inlineCallbacks
+    def enqueue(self, pushKey):
+        """
+        Pass along enqueued pushKey to any observers
 
-    @inlineCallbacks
-    def enqueue(self, id):
-        for subService in self.subServices:
-            yield subService.enqueue(id)
+        @param pushKey: the push key to distribute to the observers
+        @type pushKey: C{str}
+        """
+        for observer in self.observers:
+            yield observer.enqueue(pushKey)

Modified: CalendarServer/branches/users/gaya/sharedgroups/calendarserver/tap/util.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/calendarserver/tap/util.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/calendarserver/tap/util.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -132,7 +132,9 @@
         options=config.Postgres.Options,
         uid=uid, gid=gid,
         spawnedDBUser=config.SpawnedDBUser,
-        importFileName=config.DBImportFile
+        importFileName=config.DBImportFile,
+        pgCtl=config.Postgres.Ctl,
+        initDB=config.Postgres.Init,
     )
 
 

Modified: CalendarServer/branches/users/gaya/sharedgroups/calendarserver/tools/test/test_calverify.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/calendarserver/tools/test/test_calverify.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/calendarserver/tools/test/test_calverify.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -1033,7 +1033,11 @@
             (yield self.calendarUnderTest(home_name, calendar_name, txn)).calendarObjectWithName(name))
         )
 
-now = PyCalendarDateTime.getToday().getYear()
+now = PyCalendarDateTime.getToday()
+now.setDay(1)
+now.offsetMonth(2)
+nowYear = now.getYear()
+nowMonth = now.getMonth()
 
 class CalVerifyMismatchTestsNonRecurring(CalVerifyMismatchTestsBase):
     """
@@ -1048,10 +1052,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISSING_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1060,7 +1064,7 @@
 ATTENDEE:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Attendees have event, organizer does not
     MISSING_ORGANIZER_2_ICS = """BEGIN:VCALENDAR
@@ -1070,10 +1074,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISSING_ORGANIZER_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1082,7 +1086,7 @@
 ATTENDEE:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISSING_ORGANIZER_3_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1091,10 +1095,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISSING_ORGANIZER_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1103,7 +1107,7 @@
 ATTENDEE:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Attendee partstat mismatch
     MISMATCH_ATTENDEE_1_ICS = """BEGIN:VCALENDAR
@@ -1113,10 +1117,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1125,7 +1129,7 @@
 ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH_ATTENDEE_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1134,10 +1138,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1146,7 +1150,7 @@
 ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH_ATTENDEE_3_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1155,10 +1159,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1167,7 +1171,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Attendee events outside time range
     MISMATCH2_ATTENDEE_1_ICS = """BEGIN:VCALENDAR
@@ -1177,10 +1181,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH2_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1189,7 +1193,7 @@
 ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH2_ATTENDEE_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1198,10 +1202,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH2_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1210,7 +1214,7 @@
 ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH2_ATTENDEE_3_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1219,10 +1223,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH2_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1231,7 +1235,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Organizer event outside time range
     MISMATCH_ORGANIZER_1_ICS = """BEGIN:VCALENDAR
@@ -1241,10 +1245,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ORGANIZER_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1253,7 +1257,7 @@
 ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now - 2}
+""".replace("\n", "\r\n") % {"year": nowYear - 1, "month": nowMonth}
 
     MISMATCH_ORGANIZER_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1262,10 +1266,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ORGANIZER_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1274,7 +1278,7 @@
 ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Attendee uuid3 has event with different organizer
     MISMATCH3_ATTENDEE_1_ICS = """BEGIN:VCALENDAR
@@ -1284,10 +1288,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH3_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1296,7 +1300,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH3_ATTENDEE_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1305,10 +1309,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH3_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1316,7 +1320,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:47B16BB4-DB5F-4BF6-85FE-A7DA54230F92
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH3_ATTENDEE_3_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1325,17 +1329,17 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH3_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 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") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH_ORGANIZER_3_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1344,10 +1348,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ORGANIZER_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1356,7 +1360,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Attendee uuid3 has event they are not invited to
     MISMATCH2_ORGANIZER_1_ICS = """BEGIN:VCALENDAR
@@ -1366,10 +1370,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH2_ORGANIZER_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1377,7 +1381,7 @@
 ATTENDEE;PARTSTAT=DECLINED:urn:uuid:47B16BB4-DB5F-4BF6-85FE-A7DA54230F92
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH2_ORGANIZER_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1386,10 +1390,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH2_ORGANIZER_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1397,7 +1401,7 @@
 ATTENDEE;PARTSTAT=DECLINED:urn:uuid:47B16BB4-DB5F-4BF6-85FE-A7DA54230F92
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH2_ORGANIZER_3_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1406,10 +1410,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH2_ORGANIZER_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1418,7 +1422,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:AC478592-7783-44D1-B2AE-52359B4E8415
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     requirements = {
         CalVerifyMismatchTestsBase.uuid1 : {
@@ -1481,7 +1485,7 @@
             "uid": "",
             "uuid": "",
             "tzid": "",
-            "start": PyCalendarDateTime(now, 1, 1, 0, 0, 0),
+            "start": PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
         }
         output = StringIO()
         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
@@ -1548,7 +1552,7 @@
             "uid": "",
             "uuid": "",
             "tzid": "",
-            "start": PyCalendarDateTime(now, 1, 1, 0, 0, 0),
+            "start": PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
         }
         output = StringIO()
         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
@@ -1657,10 +1661,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISSING_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1668,7 +1672,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Attendee partstat mismatch
     MISMATCH_ATTENDEE_1_ICS = """BEGIN:VCALENDAR
@@ -1678,10 +1682,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1689,7 +1693,7 @@
 ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH_ATTENDEE_L1_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1698,10 +1702,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1709,7 +1713,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     requirements = {
         CalVerifyMismatchTestsBase.uuid1 : {
@@ -1757,7 +1761,7 @@
             "uid": "",
             "uuid": "",
             "tzid": "",
-            "start": PyCalendarDateTime(now, 1, 1, 0, 0, 0),
+            "start": PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
         }
         output = StringIO()
         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
@@ -1808,7 +1812,7 @@
             "uid": "",
             "uuid": "",
             "tzid": "",
-            "start": PyCalendarDateTime(now, 1, 1, 0, 0, 0),
+            "start": PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
         }
         output = StringIO()
         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
@@ -1843,9 +1847,9 @@
         testResults = sorted(calverify.results["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(), "%s0307T031500" % (now,))
+        self.assertEqual(testResults[0]["start"].getText()[:8], "%(year)s%(month)02d07" % {"year": nowYear, "month": nowMonth})
         self.assertEqual(testResults[1]["uid"], "MISSING_ATTENDEE_ICS")
-        self.assertEqual(testResults[1]["start"].getText(), "%s0307T031500" % (now,))
+        self.assertEqual(testResults[1]["start"].getText()[:8], "%(year)s%(month)02d07" % {"year": nowYear, "month": nowMonth})
 
         sync_token_new1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
         sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
@@ -1884,10 +1888,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISSING_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1895,7 +1899,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Attendee partstat mismatch
     MISMATCH_ATTENDEE_1_ICS = """BEGIN:VCALENDAR
@@ -1905,10 +1909,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1916,7 +1920,7 @@
 ATTENDEE;PARTSTAT=NEEDS-ACTION:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     MISMATCH_ATTENDEE_L1_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -1925,10 +1929,10 @@
 BEGIN:VEVENT
 CREATED:20100303T181216Z
 UID:MISMATCH_ATTENDEE_ICS
-DTEND:%(year)s0307T151500Z
+DTEND:%(year)s%(month)02d07T151500Z
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T111500Z
+DTSTART:%(year)s%(month)02d07T111500Z
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -1936,7 +1940,7 @@
 ATTENDEE;PARTSTAT=ACCEPTED:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     requirements = {
         CalVerifyMismatchTestsBase.uuid1 : {
@@ -1984,7 +1988,7 @@
             "uid": "",
             "uuid": CalVerifyMismatchTestsBase.uuidl1,
             "tzid": "",
-            "start": PyCalendarDateTime(now, 1, 1, 0, 0, 0),
+            "start": PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
         }
         output = StringIO()
         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
@@ -2033,7 +2037,7 @@
             "uid": "",
             "uuid": CalVerifyMismatchTestsBase.uuidl1,
             "tzid": "",
-            "start": PyCalendarDateTime(now, 1, 1, 0, 0, 0),
+            "start": PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
         }
         output = StringIO()
         calverify = SchedulingMismatchService(self._sqlCalendarStore, options, output, reactor, config)
@@ -2063,7 +2067,7 @@
         testResults = sorted(calverify.results["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(), "%s0307T031500" % (now,))
+        self.assertEqual(testResults[0]["start"].getText()[:8], "%(year)s%(month)02d07" % {"year": nowYear, "month": nowMonth})
 
         sync_token_new1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
         sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
@@ -2105,7 +2109,7 @@
 UID:INVITE_NO_OVERLAP_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP_ICS
-DTSTART:%(year)s0307T100000Z
+DTSTART:%(year)s%(month)02d07T100000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2114,7 +2118,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Two overlapping
     INVITE_NO_OVERLAP1_1_ICS = """BEGIN:VCALENDAR
@@ -2126,7 +2130,7 @@
 UID:INVITE_NO_OVERLAP1_1_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP1_1_ICS
-DTSTART:%(year)s0307T110000Z
+DTSTART:%(year)s%(month)02d07T110000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2135,7 +2139,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     INVITE_NO_OVERLAP1_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -2146,7 +2150,7 @@
 UID:INVITE_NO_OVERLAP1_2_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP1_2_ICS
-DTSTART:%(year)s0307T120000Z
+DTSTART:%(year)s%(month)02d07T120000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2155,7 +2159,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Two overlapping with one transparent
     INVITE_NO_OVERLAP2_1_ICS = """BEGIN:VCALENDAR
@@ -2167,7 +2171,7 @@
 UID:INVITE_NO_OVERLAP2_1_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP2_1_ICS
-DTSTART:%(year)s0307T140000Z
+DTSTART:%(year)s%(month)02d07T140000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2176,7 +2180,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     INVITE_NO_OVERLAP2_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -2186,7 +2190,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP2_2_ICS
 SUMMARY:INVITE_NO_OVERLAP2_2_ICS
-DTSTART:%(year)s0307T150000Z
+DTSTART:%(year)s%(month)02d07T150000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2196,7 +2200,7 @@
 TRANSP:TRANSPARENT
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Two overlapping with one cancelled
     INVITE_NO_OVERLAP3_1_ICS = """BEGIN:VCALENDAR
@@ -2208,7 +2212,7 @@
 UID:INVITE_NO_OVERLAP3_1_ICS
 TRANSP:OPAQUE
 SUMMARY:Ancient event
-DTSTART:%(year)s0307T170000Z
+DTSTART:%(year)s%(month)02d07T170000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2217,7 +2221,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     INVITE_NO_OVERLAP3_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -2227,7 +2231,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP3_2_ICS
 SUMMARY:INVITE_NO_OVERLAP3_2_ICS
-DTSTART:%(year)s0307T180000Z
+DTSTART:%(year)s%(month)02d07T180000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2237,7 +2241,7 @@
 STATUS:CANCELLED
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Two overlapping recurring
     INVITE_NO_OVERLAP4_1_ICS = """BEGIN:VCALENDAR
@@ -2249,7 +2253,7 @@
 UID:INVITE_NO_OVERLAP4_1_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP4_1_ICS
-DTSTART:%(year)s0308T120000Z
+DTSTART:%(year)s%(month)02d08T120000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2259,7 +2263,7 @@
 RRULE:FREQ=DAILY;COUNT=3
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     INVITE_NO_OVERLAP4_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -2269,7 +2273,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP4_2_ICS
 SUMMARY:INVITE_NO_OVERLAP4_2_ICS
-DTSTART:%(year)s0309T120000Z
+DTSTART:%(year)s%(month)02d09T120000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2279,7 +2283,7 @@
 RRULE:FREQ=DAILY;COUNT=2
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Two overlapping on one recurrence instance
     INVITE_NO_OVERLAP5_1_ICS = """BEGIN:VCALENDAR
@@ -2291,7 +2295,7 @@
 UID:INVITE_NO_OVERLAP5_1_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP5_1_ICS
-DTSTART:%(year)s0312T120000Z
+DTSTART:%(year)s%(month)02d12T120000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2301,7 +2305,7 @@
 RRULE:FREQ=DAILY;COUNT=3
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     INVITE_NO_OVERLAP5_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -2311,7 +2315,7 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP5_2_ICS
 SUMMARY:INVITE_NO_OVERLAP5_2_ICS
-DTSTART:%(year)s0313T140000Z
+DTSTART:%(year)s%(month)02d13T140000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2324,8 +2328,8 @@
 CREATED:20100303T181216Z
 UID:INVITE_NO_OVERLAP5_2_ICS
 SUMMARY:INVITE_NO_OVERLAP5_2_ICS
-RECURRENCE-ID:%(year)s0314T140000Z
-DTSTART:%(year)s0314T130000Z
+RECURRENCE-ID:%(year)s%(month)02d14T140000Z
+DTSTART:%(year)s%(month)02d14T130000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2334,7 +2338,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Two not overlapping - one all-day
     INVITE_NO_OVERLAP6_1_ICS = """BEGIN:VCALENDAR
@@ -2363,7 +2367,7 @@
 UID:INVITE_NO_OVERLAP6_1_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP6_1_ICS
-DTSTART;TZID=America/Los_Angeles:%(year)s0320T200000
+DTSTART;TZID=America/Los_Angeles:%(year)s%(month)02d20T200000
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2372,7 +2376,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     INVITE_NO_OVERLAP6_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -2383,7 +2387,7 @@
 UID:INVITE_NO_OVERLAP6_2_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP6_2_ICS
-DTSTART;VALUE=DATE:%(year)s0321
+DTSTART;VALUE=DATE:%(year)s%(month)02d21
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
 ORGANIZER:urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0
@@ -2391,7 +2395,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     # Two overlapping - same organizer and summary
     INVITE_NO_OVERLAP7_1_ICS = """BEGIN:VCALENDAR
@@ -2403,7 +2407,7 @@
 UID:INVITE_NO_OVERLAP7_1_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP7_1_ICS
-DTSTART:%(year)s0323T110000Z
+DTSTART:%(year)s%(month)02d23T110000Z
 DURATION:PT2H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2412,7 +2416,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     INVITE_NO_OVERLAP7_2_ICS = """BEGIN:VCALENDAR
 VERSION:2.0
@@ -2423,7 +2427,7 @@
 UID:INVITE_NO_OVERLAP7_2_ICS
 TRANSP:OPAQUE
 SUMMARY:INVITE_NO_OVERLAP7_1_ICS
-DTSTART:%(year)s0323T120000Z
+DTSTART:%(year)s%(month)02d23T120000Z
 DURATION:PT1H
 DTSTAMP:20100303T181220Z
 SEQUENCE:2
@@ -2432,7 +2436,7 @@
 ATTENDEE:urn:uuid:75EA36BE-F71B-40F9-81F9-CF59BF40CA8F
 END:VEVENT
 END:VCALENDAR
-""".replace("\n", "\r\n") % {"year": now}
+""".replace("\n", "\r\n") % {"year": nowYear, "month": nowMonth}
 
     allEvents = {
         "invite1.ics"      : (INVITE_NO_OVERLAP_ICS, CalVerifyMismatchTestsBase.metadata,),
@@ -2496,7 +2500,7 @@
             "uid": "",
             "uuid": self.uuidl1,
             "tzid": "utc",
-            "start": PyCalendarDateTime(now, 1, 1, 0, 0, 0),
+            "start": PyCalendarDateTime(nowYear, 1, 1, 0, 0, 0),
         }
         output = StringIO()
         calverify = DoubleBookingService(self._sqlCalendarStore, options, output, reactor, config)
@@ -2506,10 +2510,10 @@
         self.assertEqual(
             [(sorted((i.uid1, i.uid2,)), str(i.start),) for i in calverify.results["Double-bookings"]],
             [
-                (["INVITE_NO_OVERLAP1_1_ICS", "INVITE_NO_OVERLAP1_2_ICS"], "%(year)s0307T120000Z" % {"year": now}),
-                (["INVITE_NO_OVERLAP4_1_ICS", "INVITE_NO_OVERLAP4_2_ICS"], "%(year)s0309T120000Z" % {"year": now}),
-                (["INVITE_NO_OVERLAP4_1_ICS", "INVITE_NO_OVERLAP4_2_ICS"], "%(year)s0310T120000Z" % {"year": now}),
-                (["INVITE_NO_OVERLAP5_1_ICS", "INVITE_NO_OVERLAP5_2_ICS"], "%(year)s0314T130000Z" % {"year": now}),
+                (["INVITE_NO_OVERLAP1_1_ICS", "INVITE_NO_OVERLAP1_2_ICS"], "%(year)s%(month)02d07T120000Z" % {"year": nowYear, "month": nowMonth}),
+                (["INVITE_NO_OVERLAP4_1_ICS", "INVITE_NO_OVERLAP4_2_ICS"], "%(year)s%(month)02d09T120000Z" % {"year": nowYear, "month": nowMonth}),
+                (["INVITE_NO_OVERLAP4_1_ICS", "INVITE_NO_OVERLAP4_2_ICS"], "%(year)s%(month)02d10T120000Z" % {"year": nowYear, "month": nowMonth}),
+                (["INVITE_NO_OVERLAP5_1_ICS", "INVITE_NO_OVERLAP5_2_ICS"], "%(year)s%(month)02d14T130000Z" % {"year": nowYear, "month": nowMonth}),
             ],
         )
         self.assertEqual(calverify.results["Number of double-bookings"], 4)

Modified: CalendarServer/branches/users/gaya/sharedgroups/conf/caldavd-apple.plist
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/conf/caldavd-apple.plist	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/conf/caldavd-apple.plist	2013-03-09 04:49:28 UTC (rev 10882)
@@ -101,6 +101,11 @@
     <string></string>
     <key>DBImportFile</key>
     <string>/Library/Server/Calendar and Contacts/DataDump.sql</string>
+    <key>Postgres</key>
+    <dict>
+        <key>Ctl</key>
+        <string>xpg_ctl</string>
+    </dict>
 
     <!-- Data root -->
     <key>DataRoot</key>

Modified: CalendarServer/branches/users/gaya/sharedgroups/twext/internet/decorate.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twext/internet/decorate.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/twext/internet/decorate.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -27,10 +27,29 @@
 
 from twisted.internet.defer import Deferred, succeed
 
+class Memoizable(object):
+    """
+    A class that stores itself in the memo dictionary.
+    """
 
+    def memoMe(self, key, memo):
+        """
+        Add this object to the memo dictionary in whatever fashion is appropriate.
+
+        @param key: key used for lookup
+        @type key: C{object} (typically C{str} or C{int})
+        @param memo: the dict to store to
+        @type memo: C{dict}
+        """
+        raise NotImplementedError
+
+
+
 def memoizedKey(keyArgument, memoAttribute, deferredResult=True):
     """
-    Decorator which memoizes the result of a method on that method's instance.
+    Decorator which memoizes the result of a method on that method's instance. If the instance is derived from
+    class Memoizable, then the memoMe method is used to store the result, otherwise it is stored directly in
+    the dict.
 
     @param keyArgument: The name of the "key" argument.
     @type keyArgument: C{str}
@@ -75,6 +94,7 @@
                 (argname, args, kw, argpos)
             )
 
+
     def decorate(thunk):
         # cheater move to try to get the right argspec from inlineCallbacks.
         # This could probably be more robust, but the 'cell_contents' thing
@@ -103,7 +123,9 @@
 
             if isinstance(result, Deferred):
                 def memoResult(finalResult):
-                    if finalResult is not None:
+                    if isinstance(finalResult, Memoizable):
+                        finalResult.memoMe(key, memo)
+                    elif finalResult is not None:
                         memo[key] = finalResult
                     return finalResult
                 result.addCallback(memoResult)

Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/caldavxml.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/caldavxml.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/caldavxml.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -1110,21 +1110,6 @@
 
 
 @registerElement
-class Originator (CalDAVElement):
-    """
-    A property on resources in schedule Inbox and Outbox indicating the Originator used
-    for the SCHEDULE operation.
-    (CalDAV-schedule, section x.x.x)
-    """
-    name = "originator"
-    hidden = True
-    protected = True
-
-    allowed_children = {(dav_namespace, "href"): (0, 1)} # NB Minimum is zero because this is a property name
-
-
-
- at registerElement
 class Recipient (CalDAVElement):
     """
     A property on resources in schedule Inbox indicating the Recipients targeted

Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/scheduling/caldav/delivery.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/scheduling/caldav/delivery.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/scheduling/caldav/delivery.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -197,12 +197,6 @@
                 responses.add(recipient.cuaddr, Failure(exc_value=err), reqstatus=iTIPRequestStatus.NO_AUTHORITY)
                 returnValue(False)
             else:
-                # Store CALDAV:originator property
-                child.writeDeadProperty(caldavxml.Originator(davxml.HRef(self.scheduler.originator.cuaddr)))
-
-                # Store CALDAV:recipient property
-                child.writeDeadProperty(caldavxml.Recipient(davxml.HRef(recipient.cuaddr)))
-
                 # Store CS:schedule-changes property if present
                 if changes:
                     child.writeDeadProperty(changes)

Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/stdconfig.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/stdconfig.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -908,6 +908,11 @@
         "Options": [
             "-c standard_conforming_strings=on",
         ],
+        "Ctl": "pg_ctl", # Iff the DBType is '', and we're spawning postgres
+                         # ourselves, where is the pg_ctl tool to spawn it with?
+        "Init": "initdb", # Iff the DBType is '', and we're spawning postgres
+                          # ourselves, where is the initdb tool to create its
+                          # database cluster with?
     },
 
     "QueryCaching" : {

Modified: CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/twistedcaldav/storebridge.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -42,7 +42,6 @@
 from twistedcaldav.cache import CacheStoreNotifier, ResponseCacheMixin, \
     DisabledCacheNotifier
 from twistedcaldav.caldavxml import caldav_namespace
-from twistedcaldav.carddavxml import carddav_namespace
 from twistedcaldav.config import config
 from twistedcaldav.directory.wiki import WikiDirectoryService, getWikiAccess
 from twistedcaldav.ical import Component as VCalendar, Property as VProperty, \

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/base/datastore/subpostgres.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/base/datastore/subpostgres.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/base/datastore/subpostgres.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -166,7 +166,9 @@
                  testMode=False,
                  uid=None, gid=None,
                  spawnedDBUser="caldav",
-                 importFileName=None):
+                 importFileName=None,
+                 pgCtl="pg_ctl",
+                 initDB="initdb"):
         """
         Initialize a L{PostgresService} pointed at a data store directory.
 
@@ -235,8 +237,21 @@
         self.schema = schema
         self.monitor = None
         self.openConnections = []
+        self._pgCtl = pgCtl
+        self._initdb = initDB
 
 
+    def pgCtl(self):
+        """
+        Locate the path to pg_ctl.
+        """
+        return which(self._pgCtl)[0]
+
+
+    def initdb(self):
+        return which(self._initdb)[0]
+
+
     def activateDelayedShutdown(self):
         """
         Call this when starting database initialization code to protect against
@@ -369,7 +384,7 @@
         Start the database and initialize the subservice.
         """
         monitor = _PostgresMonitor(self)
-        pg_ctl = which("pg_ctl")[0]
+        pgCtl = self.pgCtl()
         # check consistency of initdb and postgres?
 
         options = []
@@ -386,9 +401,9 @@
         options.extend(self.options)
 
         reactor.spawnProcess(
-            monitor, pg_ctl,
+            monitor, pgCtl,
             [
-                pg_ctl,
+                pgCtl,
                 "start",
                 "-l", self.logFile,
                 "-w",
@@ -422,7 +437,7 @@
         env.update(PGDATA=clusterDir.path,
                    PGHOST=self.host,
                    PGUSER=self.spawnedDBUser)
-        initdb = which("initdb")[0]
+        initdb = self.initdb()
         if self.socketDir:
             if not self.socketDir.isdir():
                 self.socketDir.createDirectory()
@@ -470,9 +485,9 @@
             # database.  (This also happens in command-line tools.)
             if self.shouldStopDatabase:
                 monitor = _PostgresMonitor()
-                pg_ctl = which("pg_ctl")[0]
-                reactor.spawnProcess(monitor, pg_ctl,
-                    [pg_ctl, '-l', 'logfile', 'stop'],
+                pgCtl = self.pgCtl()
+                reactor.spawnProcess(monitor, pgCtl,
+                    [pgCtl, '-l', 'logfile', 'stop'],
                     self.env,
                     uid=self.uid, gid=self.gid,
                 )

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/file.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/file.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/file.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -742,8 +742,6 @@
                 PropertyName.fromElement(caldavxml.ScheduleTag),
                 PropertyName.fromElement(customxml.TwistedScheduleMatchETags),
                 PropertyName.fromElement(customxml.TwistedCalendarHasPrivateCommentsProperty),
-                PropertyName.fromElement(caldavxml.Originator),
-                PropertyName.fromElement(caldavxml.Recipient),
                 PropertyName.fromElement(customxml.ScheduleChanges),
             ),
         )

Modified: CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/sql.py	2013-03-09 03:02:47 UTC (rev 10881)
+++ CalendarServer/branches/users/gaya/sharedgroups/txdav/caldav/datastore/sql.py	2013-03-09 04:49:28 UTC (rev 10882)
@@ -1211,11 +1211,11 @@
             ).on(txn)
 
         if instanceIndexingRequired and doInstanceIndexing:
-            yield self._addInstances(component, instances, truncateLowerLimit, txn)
+            yield self._addInstances(component, instances, truncateLowerLimit, isInboxItem, txn)
 
 
     @inlineCallbacks
-    def _addInstances(self, component, instances, truncateLowerLimit, txn):
+    def _addInstances(self, component, instances, truncateLowerLimit, isInboxItem, txn):
         """
         Add the set of supplied instances to the store.
 
@@ -1225,6 +1225,8 @@
         @type instances: L{InstanceList}
         @param truncateLowerLimit: the lower limit for instances
         @type truncateLowerLimit: L{PyCalendarDateTime}
+        @param isInboxItem: indicates if an inbox item
+        @type isInboxItem: C{bool}
         @param txn: transaction to use
         @type txn: L{Transaction}
         """
@@ -1246,14 +1248,14 @@
                 lowerLimitApplied = True
                 continue
 
-            yield self._addInstanceDetails(component, instance.rid, start, end, floating, transp, fbtype, txn)
+            yield self._addInstanceDetails(component, instance.rid, start, end, floating, transp, fbtype, isInboxItem, 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)
+            yield self._addInstanceDetails(component, None, start, end, False, True, "UNKNOWN", isInboxItem, txn)
 
         # Special - for unbounded recurrence we insert a value for "infinity"
         # that will allow an open-ended time-range to always match it.
@@ -1262,11 +1264,11 @@
         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))
-            yield self._addInstanceDetails(component, None, start, end, False, True, "UNKNOWN", txn)
+            yield self._addInstanceDetails(component, None, start, end, False, True, "UNKNOWN", isInboxItem, txn)
 
 
     @inlineCallbacks
-    def _addInstanceDetails(self, component, rid, start, end, floating, transp, fbtype, txn):
+    def _addInstanceDetails(self, component, rid, start, end, floating, transp, fbtype, isInboxItem, txn):
 
         tr = schema.TIME_RANGE
         tpy = schema.TRANSPARENCY
@@ -1280,16 +1282,19 @@
             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, usertransp in peruserdata:
-            if usertransp != transp:
-                (yield Insert({
-                    tpy.TIME_RANGE_INSTANCE_ID : instanceid,
-                    tpy.USER_ID                : useruid,
-                    tpy.TRANSPARENT            : usertransp,
-                }).on(txn))
 
+        # Don't do transparency for inbox items - we never do freebusy on inbox
+        if not isInboxItem:
+            peruserdata = component.perUserTransparency(rid)
+            for useruid, usertransp in peruserdata:
+                if usertransp != transp:
+                    (yield Insert({
+                        tpy.TIME_RANGE_INSTANCE_ID : instanceid,
+                        tpy.USER_ID                : useruid,
+                        tpy.TRANSPARENT            : usertransp,
+                    }).on(txn))
 
+
     @inlineCallbacks
     def component(self):
         """
@@ -1938,8 +1943,6 @@
             (
             ),
             (
-                PropertyName.fromElement(caldavxml.Originator),
-                PropertyName.fromElement(caldavxml.Recipient),
                 PropertyName.fromElement(customxml.ScheduleChanges),
             ),
         )
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130308/2bfbca68/attachment-0001.html>


More information about the calendarserver-changes mailing list