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

source_changes at macosforge.org source_changes at macosforge.org
Wed May 1 09:33:40 PDT 2013


Revision: 11116
          http://trac.calendarserver.org//changeset/11116
Author:   cdaboo at apple.com
Date:     2013-05-01 09:33:40 -0700 (Wed, 01 May 2013)
Log Message:
-----------
Calendar transp property is now a column on the bind table.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/calverify.py
    CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/test/test_calverify.py
    CalendarServer/branches/users/cdaboo/store-scheduling/twext/enterprise/dal/syntax.py
    CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/directory/test/test_calendar.py
    CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/resource.py
    CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/scheduling_store/caldav/resource.py
    CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/scheduling_store/caldav/test/test_resource.py
    CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/sharing.py
    CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/storebridge.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/sql.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/current.sql
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_tables.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/util.py

Added Paths:
-----------
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/test/
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/test/__init__.py
    CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/calverify.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/calverify.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/calverify.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -59,7 +59,6 @@
 from twisted.python import log, usage
 from twisted.python.usage import Options
 
-from twistedcaldav import caldavxml
 from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
 from twistedcaldav.dateops import pyCalendarTodatetime
 from twistedcaldav.directory.directory import DirectoryService
@@ -69,7 +68,6 @@
 from twistedcaldav.stdconfig import DEFAULT_CONFIG_FILE
 from twistedcaldav.util import normalizationLookup
 
-from txdav.base.propertystore.base import PropertyName
 from txdav.caldav.icalendarstore import ComponentUpdateState
 from txdav.common.datastore.sql_tables import schema, _BIND_MODE_OWN
 from txdav.common.icommondatastore import InternalDataStoreError
@@ -1925,7 +1923,7 @@
                 details["rid"] = attresid
             else:
                 # Find default calendar for VEVENTs
-                defaultCalendar = (yield self.defaultCalendarForAttendee(home, inbox))
+                defaultCalendar = (yield self.defaultCalendarForAttendee(home))
                 if defaultCalendar is None:
                     raise ValueError("Cannot find suitable default calendar")
                 new_name = str(uuid.uuid4()) + ".ics"
@@ -1965,22 +1963,11 @@
 
 
     @inlineCallbacks
-    def defaultCalendarForAttendee(self, home, inbox):
+    def defaultCalendarForAttendee(self, home):
 
         # Check for property
-        default = inbox.properties().get(PropertyName.fromElement(caldavxml.ScheduleDefaultCalendarURL))
-        if default:
-            defaultName = str(default.children[0]).rstrip("/").split("/")[-1]
-            defaultCalendar = (yield home.calendarWithName(defaultName))
-            returnValue(defaultCalendar)
-        else:
-            # Iterate for the first calendar that supports VEVENTs
-            calendars = (yield home.calendars())
-            for calendar in calendars:
-                if calendar.name() != "inbox" and calendar.isSupportedComponent("VEVENT"):
-                    returnValue(calendar)
-            else:
-                returnValue(None)
+        calendar = (yield home.defaultCalendar("VEVENT"))
+        returnValue(calendar)
 
 
     def printAutoAccepts(self):

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/test/test_calverify.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/test/test_calverify.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/calendarserver/tools/test/test_calverify.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -22,16 +22,17 @@
 from calendarserver.tools.calverify import BadDataService, \
     SchedulingMismatchService, DoubleBookingService, DarkPurgeService
 
-from StringIO import StringIO
 from pycalendar.datetime import PyCalendarDateTime
+
 from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks, returnValue
-from twistedcaldav import caldavxml
+from twisted.internet.defer import inlineCallbacks
+
 from twistedcaldav.config import config
 from twistedcaldav.test.util import StoreTestCase
-from txdav.base.propertystore.base import PropertyName
+
 from txdav.common.datastore.test.util import populateCalendarsFrom
-from txdav.xml import element as davxml
+
+from StringIO import StringIO
 import os
 
 
@@ -428,7 +429,7 @@
 
     requirements = {
         "home1" : {
-            "calendar1" : {
+            "calendar_1" : {
                 "ok.ics"   : (OK_ICS, metadata,),
                 "bad1.ics" : (BAD1_ICS, metadata,),
                 "bad2.ics" : (BAD2_ICS, metadata,),
@@ -475,36 +476,6 @@
         return self._sqlCalendarStore
 
 
-    @inlineCallbacks
-    def homeUnderTest(self, txn=None):
-        """
-        Get the calendar home detailed by C{requirements['home1']}.
-        """
-        if txn is None:
-            txn = self.transactionUnderTest()
-        returnValue((yield txn.calendarHomeWithUID("home1")))
-
-
-    @inlineCallbacks
-    def calendarUnderTest(self, txn=None):
-        """
-        Get the calendar detailed by C{requirements['home1']['calendar1']}.
-        """
-        returnValue((yield
-            (yield self.homeUnderTest(txn)).calendarWithName("calendar1"))
-        )
-
-
-    @inlineCallbacks
-    def calendarObjectUnderTest(self, name, txn=None):
-        """
-        Get the calendar object detailed by C{requirements[home_name][calendar_name][name]}.
-        """
-        returnValue((yield
-            (yield self.calendarUnderTest(txn)).calendarObjectWithName(name))
-        )
-
-
     def verifyResultsByUID(self, results, expected):
         reported = set([(home, uid) for home, uid, _ignore_resid, _ignore_reason in results])
         self.assertEqual(reported, expected)
@@ -611,7 +582,7 @@
         self.assertNotEqual(sync_token_old, sync_token_new)
 
         # Make sure mailto: fix results in urn:uuid value without SCHEDULE-AGENT
-        obj = yield self.calendarObjectUnderTest("bad10.ics")
+        obj = yield self.calendarObjectUnderTest(name="bad10.ics")
         ical = yield obj.component()
         org = ical.getOrganizerProperty()
         self.assertEqual(org.value(), "urn:uuid:D46F3D71-04B7-43C2-A7B6-6F92F92E61D0")
@@ -946,17 +917,6 @@
     uuid3 = "AC478592-7783-44D1-B2AE-52359B4E8415"
     uuidl1 = "75EA36BE-F71B-40F9-81F9-CF59BF40CA8F"
 
-    @inlineCallbacks
-    def setUp(self):
-        yield super(CalVerifyMismatchTestsBase, self).setUp()
-
-        inbox = (yield self.calendarUnderTest(self.uuid3, "inbox"))
-        inbox.properties()[PropertyName.fromElement(caldavxml.ScheduleDefaultCalendarURL)] = caldavxml.ScheduleDefaultCalendarURL(
-            davxml.HRef.fromString("/calendars/__uids__/%s/calendar2/" % (self.uuid3,))
-        )
-        yield self.commit()
-
-
     def configure(self):
         super(CalVerifyMismatchTestsBase, self).configure()
         self.patch(config.DirectoryService.params, "xmlFile",
@@ -984,42 +944,6 @@
         self.notifierFactory.reset()
 
 
-    def storeUnderTest(self):
-        """
-        Create and return a L{CalendarStore} for testing.
-        """
-        return self._sqlCalendarStore
-
-
-    @inlineCallbacks
-    def homeUnderTest(self, name=None, txn=None):
-        """
-        Get the calendar home detailed by C{requirements[name]}.
-        """
-        if txn is None:
-            txn = self.transactionUnderTest()
-        returnValue((yield txn.calendarHomeWithUID(name)))
-
-
-    @inlineCallbacks
-    def calendarUnderTest(self, home_name, name="calendar", txn=None):
-        """
-        Get the calendar detailed by C{requirements[home_name][name]}.
-        """
-        returnValue((yield
-            (yield self.homeUnderTest(home_name, txn)).calendarWithName(name))
-        )
-
-
-    @inlineCallbacks
-    def calendarObjectUnderTest(self, home_name, calendar_name, name, txn=None):
-        """
-        Get the calendar object detailed by C{requirements[home_name][calendar_name][name]}.
-        """
-        returnValue((yield
-            (yield self.calendarUnderTest(home_name, calendar_name, txn)).calendarObjectWithName(name))
-        )
-
 now = PyCalendarDateTime.getToday()
 now.setDay(1)
 now.offsetMonth(2)
@@ -1450,15 +1374,25 @@
     }
 
     @inlineCallbacks
+    def setUp(self):
+        yield super(CalVerifyMismatchTestsNonRecurring, self).setUp()
+
+        home = (yield self.homeUnderTest(name=self.uuid3))
+        calendar = (yield self.calendarUnderTest(name="calendar2", home=self.uuid3))
+        yield home.setDefaultCalendar(calendar)
+        yield self.commit()
+
+
+    @inlineCallbacks
     def test_scanMismatchOnly(self):
         """
         CalVerifyService.doScan without fix for mismatches. Make sure it detects
         as much as it can. Make sure sync-token is not changed.
         """
 
-        sync_token_old1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_old2 = (yield (yield self.calendarUnderTest(self.uuid2)).syncToken())
-        sync_token_old3 = (yield (yield self.calendarUnderTest(self.uuid3)).syncToken())
+        sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_old2 = (yield (yield self.calendarUnderTest(home=self.uuid2, name="calendar")).syncToken())
+        sync_token_old3 = (yield (yield self.calendarUnderTest(home=self.uuid3, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -1508,9 +1442,9 @@
         self.assertTrue("Fix failures" not in calverify.results)
         self.assertTrue("Auto-Accepts" not in calverify.results)
 
-        sync_token_new1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_new2 = (yield (yield self.calendarUnderTest(self.uuid2)).syncToken())
-        sync_token_new3 = (yield (yield self.calendarUnderTest(self.uuid3)).syncToken())
+        sync_token_new1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_new2 = (yield (yield self.calendarUnderTest(home=self.uuid2, name="calendar")).syncToken())
+        sync_token_new3 = (yield (yield self.calendarUnderTest(home=self.uuid3, name="calendar")).syncToken())
         self.assertEqual(sync_token_old1, sync_token_new1)
         self.assertEqual(sync_token_old2, sync_token_new2)
         self.assertEqual(sync_token_old3, sync_token_new3)
@@ -1523,9 +1457,9 @@
         and fixes as much as it can. Make sure sync-token is not changed.
         """
 
-        sync_token_old1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_old2 = (yield (yield self.calendarUnderTest(self.uuid2)).syncToken())
-        sync_token_old3 = (yield (yield self.calendarUnderTest(self.uuid3)).syncToken())
+        sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_old2 = (yield (yield self.calendarUnderTest(home=self.uuid2, name="calendar")).syncToken())
+        sync_token_old3 = (yield (yield self.calendarUnderTest(home=self.uuid3, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -1599,19 +1533,19 @@
             (self.uuid3, "calendar", "missing_organizer.ics",),
             (self.uuid3, "calendar", "mismatched2_organizer.ics",),
         )))
-        obj = yield self.calendarObjectUnderTest(self.uuid2, "calendar", "missing_organizer.ics")
+        obj = yield self.calendarObjectUnderTest(home=self.uuid2, calendar_name="calendar", name="missing_organizer.ics")
         self.assertEqual(obj, None)
-        obj = yield self.calendarObjectUnderTest(self.uuid3, "calendar", "missing_organizer.ics")
+        obj = yield self.calendarObjectUnderTest(home=self.uuid3, calendar_name="calendar", name="missing_organizer.ics")
         self.assertEqual(obj, None)
-        obj = yield self.calendarObjectUnderTest(self.uuid3, "calendar", "mismatched2_organizer.ics")
+        obj = yield self.calendarObjectUnderTest(home=self.uuid3, calendar_name="calendar", name="mismatched2_organizer.ics")
         self.assertEqual(obj, None)
 
         self.assertEqual(calverify.results["Fix failures"], 0)
         self.assertEqual(calverify.results["Auto-Accepts"], [])
 
-        sync_token_new1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_new2 = (yield (yield self.calendarUnderTest(self.uuid2)).syncToken())
-        sync_token_new3 = (yield (yield self.calendarUnderTest(self.uuid3)).syncToken())
+        sync_token_new1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_new2 = (yield (yield self.calendarUnderTest(home=self.uuid2, name="calendar")).syncToken())
+        sync_token_new3 = (yield (yield self.calendarUnderTest(home=self.uuid3, name="calendar")).syncToken())
         self.assertEqual(sync_token_old1, sync_token_new1)
         self.assertNotEqual(sync_token_old2, sync_token_new2)
         self.assertNotEqual(sync_token_old3, sync_token_new3)
@@ -1733,8 +1667,8 @@
         as much as it can. Make sure sync-token is not changed.
         """
 
-        sync_token_old1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_oldl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -1771,8 +1705,8 @@
         self.assertTrue("Fix failures" not in calverify.results)
         self.assertTrue("Auto-Accepts" not in calverify.results)
 
-        sync_token_new1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_new1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_newl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.assertEqual(sync_token_old1, sync_token_new1)
         self.assertEqual(sync_token_oldl1, sync_token_newl1)
 
@@ -1784,8 +1718,8 @@
         and fixes as much as it can. Make sure sync-token is not changed.
         """
 
-        sync_token_old1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_oldl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -1838,8 +1772,8 @@
         self.assertEqual(testResults[1]["uid"], "MISSING_ATTENDEE_ICS")
         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())
+        sync_token_new1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_newl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.assertEqual(sync_token_old1, sync_token_new1)
         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
 
@@ -1960,8 +1894,8 @@
         as much as it can. Make sure sync-token is not changed.
         """
 
-        sync_token_old1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_oldl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -1996,8 +1930,8 @@
         self.assertTrue("Fix failures" not in calverify.results)
         self.assertTrue("Auto-Accepts" not in calverify.results)
 
-        sync_token_new1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_new1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_newl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.assertEqual(sync_token_old1, sync_token_new1)
         self.assertEqual(sync_token_oldl1, sync_token_newl1)
 
@@ -2009,8 +1943,8 @@
         and fixes as much as it can. Make sure sync-token is not changed.
         """
 
-        sync_token_old1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_oldl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -2056,8 +1990,8 @@
         self.assertEqual(testResults[0]["uid"], "MISMATCH_ATTENDEE_ICS")
         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())
+        sync_token_new1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_newl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.assertEqual(sync_token_old1, sync_token_new1)
         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
 
@@ -2469,8 +2403,8 @@
         as much as it can. Make sure sync-token is not changed.
         """
 
-        sync_token_old1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_oldl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_old1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -2506,8 +2440,8 @@
         self.assertEqual(calverify.results["Number of double-bookings"], 4)
         self.assertEqual(calverify.results["Number of unique double-bookings"], 3)
 
-        sync_token_new1 = (yield (yield self.calendarUnderTest(self.uuid1)).syncToken())
-        sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_new1 = (yield (yield self.calendarUnderTest(home=self.uuid1, name="calendar")).syncToken())
+        sync_token_newl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.assertEqual(sync_token_old1, sync_token_new1)
         self.assertEqual(sync_token_oldl1, sync_token_newl1)
 
@@ -2632,7 +2566,7 @@
         as much as it can. Make sure sync-token is not changed.
         """
 
-        sync_token_oldl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -2668,7 +2602,7 @@
         self.assertTrue("Fix dark events" not in calverify.results)
         self.assertTrue("Fix remove" not in calverify.results)
 
-        sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_newl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.assertEqual(sync_token_oldl1, sync_token_newl1)
 
 
@@ -2679,7 +2613,7 @@
         as much as it can. Make sure sync-token is changed.
         """
 
-        sync_token_oldl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -2715,7 +2649,7 @@
         self.assertEqual(calverify.results["Fix dark events"], 2)
         self.assertTrue("Fix remove" in calverify.results)
 
-        sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_newl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
 
         # Re-scan after changes to make sure there are no errors
@@ -2738,7 +2672,7 @@
         as much as it can. Make sure sync-token is changed.
         """
 
-        sync_token_oldl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -2774,7 +2708,7 @@
         self.assertEqual(calverify.results["Fix dark events"], 1)
         self.assertTrue("Fix remove" in calverify.results)
 
-        sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_newl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
 
         # Re-scan after changes to make sure there are no errors
@@ -2797,7 +2731,7 @@
         as much as it can. Make sure sync-token is changed.
         """
 
-        sync_token_oldl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_oldl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.commit()
 
         options = {
@@ -2833,7 +2767,7 @@
         self.assertEqual(calverify.results["Fix dark events"], 3)
         self.assertTrue("Fix remove" in calverify.results)
 
-        sync_token_newl1 = (yield (yield self.calendarUnderTest(self.uuidl1)).syncToken())
+        sync_token_newl1 = (yield (yield self.calendarUnderTest(home=self.uuidl1, name="calendar")).syncToken())
         self.assertNotEqual(sync_token_oldl1, sync_token_newl1)
 
         # Re-scan after changes to make sure there are no errors

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/twext/enterprise/dal/syntax.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/twext/enterprise/dal/syntax.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/twext/enterprise/dal/syntax.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -1602,8 +1602,9 @@
                     for (c, v) in sortedColumns]
             )
         )
-        result.append(SQLFragment(' where '))
-        result.append(self.Where.subSQL(queryGenerator, allTables))
+        if self.Where is not None:
+            result.append(SQLFragment(' where '))
+            result.append(self.Where.subSQL(queryGenerator, allTables))
         return self._returningClause(queryGenerator, result, allTables)
 
 

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/directory/test/test_calendar.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/directory/test/test_calendar.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/directory/test/test_calendar.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -110,43 +110,29 @@
 
         fbset = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
         self.assertEqual(fbset, caldavxml.CalendarFreeBusySet(
-            davxml.HRef.fromString("/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar"),
+            davxml.HRef.fromString("/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/"),
         ))
 
-        # Now remove the dead property to simulate the old calendar server state with
+        # Now remove the property to simulate the old calendar server state with
         # a calendar listed in the fbset
-        yield calendar.removeDeadProperty(caldavxml.ScheduleCalendarTransp)
+        yield calendar._newStoreObject.setUsedForFreeBusy(False)
         fbset = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
-        self.assertEqual(fbset, caldavxml.CalendarFreeBusySet(
-            davxml.HRef.fromString("/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar"),
-        ))
+        self.assertEqual(fbset, caldavxml.CalendarFreeBusySet())
 
         # Calendar has opaque property derived from inbox
         transp = (yield calendar.hasProperty(caldavxml.ScheduleCalendarTransp, request))
         self.assertTrue(transp)
 
         transp = (yield calendar.readProperty(caldavxml.ScheduleCalendarTransp, request))
-        self.assertEqual(transp, caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()))
-
-        # Now remove the dead property and the inbox fbset item to simulate the old calendar server state
-        yield calendar.removeDeadProperty(caldavxml.ScheduleCalendarTransp)
-        yield inbox.removeDeadProperty(caldavxml.CalendarFreeBusySet)
-
-        # Calendar has transp property derived from inbox
-        transp = (yield calendar.hasProperty(caldavxml.ScheduleCalendarTransp, request))
-        self.assertTrue(transp)
-
-        transp = (yield calendar.readProperty(caldavxml.ScheduleCalendarTransp, request))
         self.assertEqual(transp, caldavxml.ScheduleCalendarTransp(caldavxml.Transparent()))
 
         # Force trailing slash on fbset
-        inbox.writeDeadProperty(caldavxml.CalendarFreeBusySet(
+        yield inbox.writeProperty(caldavxml.CalendarFreeBusySet(
             davxml.HRef.fromString("/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/"),
-        ))
+        ), request)
 
         # Now remove the dead property to simulate the old calendar server state with
         # a calendar listed in the fbset
-        yield calendar.removeDeadProperty(caldavxml.ScheduleCalendarTransp)
         fbset = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
         self.assertEqual(fbset, caldavxml.CalendarFreeBusySet(
             davxml.HRef.fromString("/calendars/__uids__/6423F94A-6B76-4A3A-815B-D52CFD77935D/calendar/"),

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/resource.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/resource.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -670,17 +670,7 @@
                 ))
 
         elif qname == caldavxml.ScheduleCalendarTransp.qname() and self.isCalendarCollection():
-            # For backwards compatibility, if the property does not exist we need to create
-            # it and default to the old free-busy-set value.
-            if not self.hasDeadProperty(property):
-                # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
-                principal = (yield self.resourceOwnerPrincipal(request))
-                fbset = (yield principal.calendarFreeBusyURIs(request))
-                fbset = [fburl.rstrip("/") for fburl in fbset]
-                url = (yield self.canonicalURL(request))
-                url = url.rstrip("/")
-                opaque = url in fbset
-                self.writeDeadProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque() if opaque else caldavxml.Transparent()))
+            returnValue(caldavxml.ScheduleCalendarTransp(caldavxml.Opaque() if self._newStoreObject.isUsedForFreeBusy() else caldavxml.Transparent()))
 
         elif qname == carddavxml.SupportedAddressData.qname() and self.isAddressBookCollection():
             # CardDAV, section 6.2.2
@@ -734,7 +724,6 @@
         returnValue(res)
 
 
-    @inlineCallbacks
     def _preProcessWriteProperty(self, property, request, isShare=False):
         if property.qname() == caldavxml.SupportedCalendarComponentSet.qname():
             if not self.isPseudoCalendarCollection():
@@ -793,21 +782,16 @@
                     "Property %s may only be set on calendar collection." % (property,)
                 ))
 
-            # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
-            principal = (yield self.resourceOwnerPrincipal(request))
 
-            # Map owner to their inbox
-            inboxURL = principal.scheduleInboxURL()
-            if inboxURL:
-                inbox = (yield request.locateResource(inboxURL))
-                myurl = (yield self.canonicalURL(request))
-                inbox.processFreeBusyCalendar(myurl, property.children[0] == caldavxml.Opaque())
-
-
     @inlineCallbacks
     def _writeGlobalProperty(self, property, request):
 
-        yield self._preProcessWriteProperty(property, request)
+        self._preProcessWriteProperty(property, request)
+
+        if property.qname() == caldavxml.ScheduleCalendarTransp.qname():
+            yield self._newStoreObject.setUsedForFreeBusy(property == caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()))
+            returnValue(None)
+
         result = (yield super(CalDAVResource, self).writeProperty(property, request))
         returnValue(result)
 
@@ -1072,49 +1056,6 @@
 
     findSpecialCollections = findSpecialCollectionsFaster
 
-    @inlineCallbacks
-    def deletedCalendar(self, request):
-        """
-        Calendar has been deleted. Need to do some extra clean-up.
-
-        @param request:
-        @type request:
-        """
-
-        # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
-        principal = (yield self.resourceOwnerPrincipal(request))
-        inboxURL = principal.scheduleInboxURL()
-        if inboxURL:
-            inbox = (yield request.locateResource(inboxURL))
-            inbox.processFreeBusyCalendar(request.path, False)
-
-
-    @inlineCallbacks
-    def movedCalendar(self, request, destination, destination_uri):
-        """
-        Calendar has been moved. Need to do some extra clean-up.
-        """
-
-        # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
-        principal = (yield self.resourceOwnerPrincipal(request))
-        inboxURL = principal.scheduleInboxURL()
-        if inboxURL:
-            inbox = (yield request.locateResource(inboxURL))
-            inbox.processFreeBusyCalendar(request.path, False)
-            inbox.processFreeBusyCalendar(destination_uri, destination.isCalendarOpaque())
-
-
-    def isCalendarOpaque(self):
-
-        assert self.isCalendarCollection()
-
-        if self.hasDeadProperty((caldav_namespace, "schedule-calendar-transp")):
-            property = self.readDeadProperty((caldav_namespace, "schedule-calendar-transp"))
-            return property.children[0] == caldavxml.Opaque()
-        else:
-            return False
-
-
     def isDefaultCalendar(self, request):
 
         assert self.isCalendarCollection()
@@ -2091,11 +2032,9 @@
     @classmethod
     @inlineCallbacks
     def createHomeResource(cls, parent, name, transaction):
-        home, created = yield cls.homeFromTransaction(
+        home, _ignored_created = yield cls.homeFromTransaction(
             transaction, name)
         resource = cls(parent, name, transaction, home)
-        if created:
-            yield resource.postCreateHome()
         returnValue(resource)
 
 
@@ -2116,10 +2055,6 @@
         pass
 
 
-    def postCreateHome(self):
-        pass
-
-
     def liveProperties(self):
 
         props = super(CommonHomeResource, self).liveProperties() + (
@@ -2551,16 +2486,6 @@
             self._provisionedChildren["notification"] = NotificationCollectionResource
 
 
-    @inlineCallbacks
-    def postCreateHome(self):
-        # This is a bit of a hack.  Really we ought to be always generating
-        # this URL live from a back-end method that tells us what the
-        # default calendar is.
-        inbox = yield self.getChild("inbox")
-        childURL = joinURL(self.url(), "calendar")
-        inbox.processFreeBusyCalendar(childURL, True)
-
-
     def canShare(self):
         return config.Sharing.Enabled and config.Sharing.Calendars.Enabled and self.exists()
 

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/scheduling_store/caldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/scheduling_store/caldav/resource.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/scheduling_store/caldav/resource.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -43,14 +43,12 @@
 from twisted.python.failure import Failure
 
 from twistedcaldav import caldavxml, customxml
-from twistedcaldav.caldavxml import caldav_namespace, Opaque, \
-    CalendarFreeBusySet, ScheduleCalendarTransp
+from twistedcaldav.caldavxml import caldav_namespace, CalendarFreeBusySet
 from twistedcaldav.customxml import calendarserver_namespace
 from twistedcaldav.ical import allowedComponents, Component
 from twistedcaldav.resource import CalDAVResource
 from twistedcaldav.resource import isCalendarCollectionResource
 
-from txdav.base.propertystore.base import PropertyName
 from txdav.caldav.datastore.scheduling.caldav.scheduler import CalDAVScheduler
 from txdav.caldav.icalendarstore import InvalidDefaultCalendar
 from txdav.xml import element as davxml
@@ -155,6 +153,24 @@
         return davxml.ResourceType.scheduleInbox
 
 
+    def hasProperty(self, property, request):
+        """
+        Need to special case calendar-free-busy-set for backwards compatability.
+        """
+
+        if type(property) is tuple:
+            qname = property
+        else:
+            qname = property.qname()
+
+        # Force calendar collections to always appear to have the property
+        if qname == caldavxml.CalendarFreeBusySet.qname():
+            return succeed(True)
+
+        else:
+            return super(ScheduleInboxResource, self).hasProperty(property, request)
+
+
     @inlineCallbacks
     def readProperty(self, property, request):
         if type(property) is tuple:
@@ -163,15 +179,14 @@
             qname = property.qname()
 
         if qname == caldavxml.CalendarFreeBusySet.qname():
-            # Always return at least an empty list
-            if not self.hasDeadProperty(property):
-                top = self.parent.url()
-                values = []
-                for cal in (yield self.parent._newStoreHome.calendars()):
-                    prop = cal.properties().get(PropertyName.fromString(ScheduleCalendarTransp.sname()))
-                    if prop == ScheduleCalendarTransp(Opaque()):
-                        values.append(HRef(joinURL(top, cal.name())))
-                returnValue(CalendarFreeBusySet(*values))
+            # Synthesize value for calendar transparency state
+            top = self.parent.url()
+            values = []
+            for cal in (yield self.parent._newStoreHome.calendars()):
+                if cal.isUsedForFreeBusy():
+                    values.append(HRef(joinURL(top, cal.name()) + "/"))
+            returnValue(CalendarFreeBusySet(*values))
+
         elif qname in (caldavxml.ScheduleDefaultCalendarURL.qname(), customxml.ScheduleDefaultTasksURL.qname()):
             result = (yield self.readDefaultCalendarProperty(request, qname))
             returnValue(result)
@@ -201,10 +216,10 @@
             # whether existing items in the property are still valid - only new ones.
             property.children = [davxml.HRef(normalizeURL(str(href))) for href in property.children]
             new_calendars = set([str(href) for href in property.children])
-            if not self.hasDeadProperty(property):
-                old_calendars = set()
-            else:
-                old_calendars = set([normalizeURL(str(href)) for href in self.readDeadProperty(property).children])
+            old_calendars = set()
+            for cal in (yield self.parent._newStoreHome.calendars()):
+                if cal.isUsedForFreeBusy():
+                    old_calendars.add(HRef(joinURL(self.parent.url(), cal.name())))
             added_calendars = new_calendars.difference(old_calendars)
             for href in added_calendars:
                 cal = (yield request.locateResource(str(href)))
@@ -215,12 +230,21 @@
                         (caldav_namespace, "valid-calendar-url"),
                         "Invalid URI",
                     ))
-            for href in tuple(new_calendars):
+
+            # Remove old ones
+            for href in old_calendars.difference(new_calendars):
                 cal = (yield request.locateResource(str(href)))
-                if cal is None or not cal.exists() or not isCalendarCollectionResource(cal):
-                    new_calendars.remove(href)
-            property.children = [davxml.HRef(href) for href in new_calendars]
+                if cal is not None and cal.exists() and isCalendarCollectionResource(cal) and cal._newStoreObject.isUsedForFreeBusy():
+                    yield cal._newStoreObject.setUsedForFreeBusy(False)
 
+            # Add new ones
+            for href in new_calendars:
+                cal = (yield request.locateResource(str(href)))
+                if cal is not None and cal.exists() and isCalendarCollectionResource(cal) and not cal._newStoreObject.isUsedForFreeBusy():
+                    yield cal._newStoreObject.setUsedForFreeBusy(True)
+
+            returnValue(None)
+
         elif property.qname() in (caldavxml.ScheduleDefaultCalendarURL.qname(), customxml.ScheduleDefaultTasksURL.qname()):
             yield self.writeDefaultCalendarProperty(request, property)
             returnValue(None)
@@ -228,23 +252,6 @@
         yield super(ScheduleInboxResource, self).writeProperty(property, request)
 
 
-    def processFreeBusyCalendar(self, uri, addit):
-        uri = normalizeURL(uri)
-
-        if not self.hasDeadProperty(caldavxml.CalendarFreeBusySet.qname()):
-            fbset = set()
-        else:
-            fbset = set([normalizeURL(str(href)) for href in self.readDeadProperty(caldavxml.CalendarFreeBusySet.qname()).children])
-        if addit:
-            if uri not in fbset:
-                fbset.add(uri)
-                self.writeDeadProperty(caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in fbset]))
-        else:
-            if uri in fbset:
-                fbset.remove(uri)
-                self.writeDeadProperty(caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in fbset]))
-
-
     @inlineCallbacks
     def readDefaultCalendarProperty(self, request, qname):
         """

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/scheduling_store/caldav/test/test_resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/scheduling_store/caldav/test/test_resource.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/scheduling_store/caldav/test/test_resource.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -14,158 +14,114 @@
 # limitations under the License.
 ##
 
-from twext.web2 import responsecode, http_headers
-from twext.web2.dav.util import davXMLFromStream
-from twext.web2.iweb import IResponse
-from twext.web2.stream import MemoryStream
 from twext.web2.test.test_server import SimpleRequest
 
 from twisted.internet.defer import inlineCallbacks
 
 from twistedcaldav import caldavxml, customxml
-from twistedcaldav.test.util import HomeTestCase, StoreTestCase, \
-    SimpleStoreRequest
+from twistedcaldav.test.util import StoreTestCase, SimpleStoreRequest
 
 from txdav.xml import element as davxml
+from twext.web2.http import HTTPError
 
-class Properties (HomeTestCase):
+class Properties (StoreTestCase):
     """
     CalDAV properties
     """
-    def test_free_busy_set_prop(self):
-        """
-        Test for PROPFIND on Inbox with missing calendar-free-busy-set property.
-        """
 
-        inbox_uri = "/inbox/"
-
-        def propfind_cb(response):
-            response = IResponse(response)
-
-            if response.code != responsecode.MULTI_STATUS:
-                self.fail("Incorrect response to PROPFIND: %s" % (response.code,))
-
-            def got_xml(doc):
-                if not isinstance(doc.root_element, davxml.MultiStatus):
-                    self.fail("PROPFIND response XML root element is not multistatus: %r" % (doc.root_element,))
-
-                response = doc.root_element.childOfType(davxml.Response)
-                href = response.childOfType(davxml.HRef)
-                self.failUnless(str(href) == inbox_uri)
-
-                for propstat in response.childrenOfType(davxml.PropertyStatus):
-                    status = propstat.childOfType(davxml.Status)
-                    if status.code != responsecode.OK:
-                        self.fail("Unable to read requested properties (%s): %r"
-                                  % (status, propstat.childOfType(davxml.PropertyContainer).toxml()))
-
-                container = propstat.childOfType(davxml.PropertyContainer)
-
-                #
-                # Check CalDAV:calendar-free-busy-set
-                #
-
-                free_busy_set = container.childOfType(caldavxml.CalendarFreeBusySet)
-                if not free_busy_set:
-                    self.fail("Expected CalDAV:calendar-free-busy-set element; but got none.")
-
-                if not free_busy_set.children:
-                    self.fail("Expected non-empty CalDAV:calendar-free-busy-set element.")
-
-            return davXMLFromStream(response.stream).addCallback(got_xml)
-
-        query = davxml.PropertyFind(
-                    davxml.PropertyContainer(
-                        caldavxml.CalendarFreeBusySet(),
-                    ),
-                )
-
-        request = SimpleRequest(
-            self.site,
-            "PROPFIND",
-            inbox_uri,
-            headers=http_headers.Headers({"Depth": "0"}),
-        )
-        request.stream = MemoryStream(query.toxml())
-        return self.send(request, propfind_cb)
-
-
     @inlineCallbacks
-    def test_free_busy_set_remove_broken(self):
+    def test_free_busy_set_same(self):
         """
-        ???
+        Test that calendar-free-busy-set has the correct value and can be reset to the same.
         """
 
-        request = SimpleRequest(self.site, "GET", "/inbox/")
-        inbox = yield request.locateResource("/inbox/")
-        self.assertTrue(inbox.hasDeadProperty(caldavxml.CalendarFreeBusySet))
-        oldfbset = set(("/calendar",))
-        oldset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in oldfbset])
+        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
+        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
+        self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request)))
+        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
+        self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar/"))
 
         newfbset = set()
-        newfbset.update(oldfbset)
-        newfbset.add("/calendar-broken")
+        newfbset.add("/calendars/users/user01/calendar/")
         newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset])
 
-        inbox.writeDeadProperty(newset)
-        changedset = inbox.readDeadProperty(caldavxml.CalendarFreeBusySet)
-        self.assertEqual(tuple(changedset.children), tuple(newset.children))
-
         yield inbox.writeProperty(newset, request)
+        yield request._newStoreTransaction.commit()
 
-        changedset = inbox.readDeadProperty(caldavxml.CalendarFreeBusySet)
-        self.assertEqual(tuple(changedset.children), tuple(oldset.children))
+        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
+        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
+        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
+        self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar/"))
+        yield request._newStoreTransaction.commit()
+        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/")
+        self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
 
 
     @inlineCallbacks
-    def test_free_busy_set_strip_slash(self):
+    def test_free_busy_set_different(self):
         """
-        ???
+        Test that calendar-free-busy-set has the correct value and can be reset to the same.
         """
 
-        request = SimpleRequest(self.site, "GET", "/inbox/")
-        inbox = yield request.locateResource("/inbox/")
-        self.assertTrue(inbox.hasDeadProperty(caldavxml.CalendarFreeBusySet))
+        txn = self.transactionUnderTest()
+        home = (yield txn.calendarHomeWithUID("user01", create=True))
+        yield home.createCalendarWithName("calendar_new")
+        yield self.commit()
 
-        oldfbset = set(("/calendar/",))
-        oldset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in oldfbset])
-        inbox.writeDeadProperty(oldset)
+        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
+        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
+        self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request)))
+        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
+        self.assertEqual(
+            set([str(child) for child in prop.children]),
+            set((
+                "/calendars/__uids__/user01/calendar/",
+                "/calendars/__uids__/user01/calendar_new/",
+            ))
+        )
+        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar_new/")
+        self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
+        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/")
+        self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
 
-        writefbset = set(("/calendar/",))
-        writeset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in writefbset])
-        yield inbox.writeProperty(writeset, request)
+        newfbset = set()
+        newfbset.add("/calendars/users/user01/calendar_new/")
+        newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset])
 
-        correctfbset = set(("/calendar",))
-        correctset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in correctfbset])
-        changedset = inbox.readDeadProperty(caldavxml.CalendarFreeBusySet)
-        self.assertEqual(tuple(changedset.children), tuple(correctset.children))
+        yield inbox.writeProperty(newset, request)
+        yield request._newStoreTransaction.commit()
 
+        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
+        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
+        prop = (yield inbox.readProperty(caldavxml.CalendarFreeBusySet, request))
+        self.assertEqual(prop.children[0], davxml.HRef("/calendars/__uids__/user01/calendar_new/"))
+        yield request._newStoreTransaction.commit()
+        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar_new/")
+        self.assertTrue(calendar._newStoreObject.isUsedForFreeBusy())
+        calendar = yield request.locateResource("/calendars/__uids__/user01/calendar/")
+        self.assertFalse(calendar._newStoreObject.isUsedForFreeBusy())
 
+
     @inlineCallbacks
-    def test_free_busy_set_strip_slash_remove(self):
+    def test_free_busy_set_invalid_url(self):
         """
-        ???
+        Test that calendar-free-busy-set will generate an error if an invalid value is used.
         """
 
-        request = SimpleRequest(self.site, "GET", "/inbox/")
-        inbox = yield request.locateResource("/inbox/")
-        self.assertTrue(inbox.hasDeadProperty(caldavxml.CalendarFreeBusySet))
+        request = SimpleRequest(self.site, "GET", "/calendars/users/user01/inbox/")
+        inbox = yield request.locateResource("/calendars/users/user01/inbox/")
+        self.assertTrue((yield inbox.hasProperty(caldavxml.CalendarFreeBusySet, request)))
+        oldfbset = set(("/calendar",))
 
-        oldfbset = set(("/calendar/", "/broken/"))
-        oldset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in oldfbset])
-        inbox.writeDeadProperty(oldset)
+        newfbset = set()
+        newfbset.update(oldfbset)
+        newfbset.add("/calendar-broken")
+        newset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in newfbset])
 
-        writefbset = set(("/calendar/", "/broken/"))
-        writeset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in writefbset])
-        yield inbox.writeProperty(writeset, request)
+        self.failUnlessFailure(inbox.writeProperty(newset, request), HTTPError)
 
-        correctfbset = set(("/calendar",))
-        correctset = caldavxml.CalendarFreeBusySet(*[davxml.HRef(url) for url in correctfbset])
-        changedset = inbox.readDeadProperty(caldavxml.CalendarFreeBusySet)
-        self.assertEqual(tuple(changedset.children), tuple(correctset.children))
 
 
-
 class DefaultCalendar (StoreTestCase):
 
     @inlineCallbacks

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/sharing.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/sharing.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/sharing.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -1228,7 +1228,7 @@
 
         # Calendars always start out transparent and with empty default alarms
         if isNewShare and shareeCollection.isCalendarCollection():
-            yield shareeCollection.writeProperty(caldavxml.ScheduleCalendarTransp(caldavxml.Transparent()), request)
+            yield shareeCollection._newStoreObject.setUsedForFreeBusy(False)
             yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDateTime.fromString(""), request)
             yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVEventDate.fromString(""), request)
             yield shareeCollection.writeProperty(caldavxml.DefaultAlarmVToDoDateTime.fromString(""), request)
@@ -1287,14 +1287,6 @@
         shared = (yield request.locateResource(shareURL))
         displayname = shared.displayName()
 
-        if self.isCalendarCollection():
-            # For backwards compatibility we need to sync this up with the calendar-free-busy-set on the inbox
-            principal = (yield self.resourceOwnerPrincipal(request))
-            inboxURL = principal.scheduleInboxURL()
-            if inboxURL:
-                inbox = (yield request.locateResource(inboxURL))
-                inbox.processFreeBusyCalendar(shareURL, False)
-
         if share.direct():
             yield share._sharerHomeChild.unshareWith(share._shareeHomeChild.viewerHome())
         else:

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/storebridge.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/twistedcaldav/storebridge.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -1256,10 +1256,6 @@
             yield super(CalendarCollectionResource, self).storeRemove(request)
         )
 
-        if response == NO_CONTENT:
-            # Do some clean up
-            yield self.deletedCalendar(request)
-
         returnValue(response)
 
 
@@ -1271,10 +1267,6 @@
         that calendar's name.
         """
         result = (yield super(CalendarCollectionResource, self).http_MOVE(request))
-        if result == NO_CONTENT:
-            destinationURI = urlsplit(request.headers.getHeader("destination"))[2]
-            destination = yield request.locateResource(destinationURI)
-            yield self.movedCalendar(request, destination, destinationURI)
         returnValue(result)
 
 

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/sql.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/caldav/datastore/sql.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -50,7 +50,6 @@
 from twisted.python import hashlib
 
 from twistedcaldav import caldavxml, customxml
-from twistedcaldav.caldavxml import ScheduleCalendarTransp, Opaque
 from twistedcaldav.config import config
 from twistedcaldav.datafilters.peruserdata import PerUserDataFilter
 from twistedcaldav.dateops import normalizeForIndex, datetimeMktime, \
@@ -85,7 +84,7 @@
     CALENDAR_HOME_TABLE, CALENDAR_HOME_METADATA_TABLE, \
     CALENDAR_AND_CALENDAR_BIND, CALENDAR_OBJECT_REVISIONS_AND_BIND_TABLE, \
     CALENDAR_OBJECT_AND_BIND_TABLE, schema, _BIND_MODE_OWN, \
-    _ATTACHMENTS_MODE_READ
+    _ATTACHMENTS_MODE_READ, _TRANSP_OPAQUE, _TRANSP_TRANSPARENT
 from txdav.common.icommondatastore import IndexedSearchException, \
     InternalDataStoreError, HomeChildNameAlreadyExistsError, \
     HomeChildNameNotAllowedError, ObjectResourceTooBigError, \
@@ -552,8 +551,6 @@
 
         # Default calendar
         defaultCal = yield self.createCalendarWithName("calendar")
-        props = defaultCal.properties()
-        props[PropertyName(*ScheduleCalendarTransp.qname())] = ScheduleCalendarTransp(Opaque())
 
         # Check whether components type must be separate
         if config.RestrictCalendarsToOneComponentType:
@@ -562,8 +559,10 @@
             # Default tasks
             defaultTasks = yield self.createCalendarWithName("tasks")
             yield defaultTasks.setSupportedComponents("VTODO")
+            yield defaultTasks.setUsedForFreeBusy(False)
 
-        yield self.createCalendarWithName("inbox")
+        inbox = yield self.createCalendarWithName("inbox")
+        yield inbox.setUsedForFreeBusy(False)
 
 
     @inlineCallbacks
@@ -848,6 +847,7 @@
             self._index = PostgresLegacyInboxIndexEmulator(self)
         else:
             self._index = PostgresLegacyIndexEmulator(self)
+        self._transp = _TRANSP_OPAQUE
 
 
     @classmethod
@@ -884,6 +884,32 @@
         )
 
 
+    @classmethod
+    def additionalBindColumns(cls):
+        """
+        Return a list of column names for retrieval during creation. This allows
+        different child classes to have their own type specific data, but still make use of the
+        common base logic.
+        """
+
+        return (
+            cls._bindSchema.TRANSP,
+        )
+
+
+    @classmethod
+    def additionalBindAttributes(cls):
+        """
+        Return a list of attribute names for retrieval of during creation. This allows
+        different child classes to have their own type specific data, but still make use of the
+        common base logic.
+        """
+
+        return (
+            "_transp",
+        )
+
+
     @property
     def _calendarHome(self):
         return self._home
@@ -1023,6 +1049,27 @@
         return self.name() == "inbox"
 
 
+    @inlineCallbacks
+    def setUsedForFreeBusy(self, use_it):
+        """
+        Mark this calendar as being used for free busy request. Note this is a per-user setting so we are setting
+        this on the bind table entry which is related to the user viewing the calendar.
+
+        @param use_it: C{True} if used for free busy, C{False} otherwise
+        @type use_it: C{bool}
+        """
+
+        self._transp = _TRANSP_OPAQUE if use_it else _TRANSP_TRANSPARENT
+        cal = self._bindSchema
+        yield Update(
+            {
+                cal.TRANSP : self._transp
+            },
+            Where=(cal.CALENDAR_HOME_RESOURCE_ID == self.viewerHome()._resourceID).And(cal.CALENDAR_RESOURCE_ID == self._resourceID)
+        ).on(self._txn)
+        yield self.invalidateQueryCache()
+
+
     def isUsedForFreeBusy(self):
         """
         Indicates whether the contents of this calendar contributes to free busy.
@@ -1030,8 +1077,7 @@
         @return: C{True} if it does, C{False} otherwise
         @rtype: C{bool}
         """
-        opaque = self.properties().get(PropertyName(*ScheduleCalendarTransp.qname()), ScheduleCalendarTransp(Opaque())) == ScheduleCalendarTransp(Opaque())
-        return opaque and not self.isInbox()
+        return self._transp == _TRANSP_OPAQUE
 
 
     def initPropertyStore(self, props):

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -2610,6 +2610,28 @@
 
 
     @classmethod
+    def additionalBindColumns(cls):
+        """
+        Return a list of column names for retrieval during creation. This allows
+        different child classes to have their own type specific data, but still make use of the
+        common base logic.
+        """
+
+        return ()
+
+
+    @classmethod
+    def additionalBindAttributes(cls):
+        """
+        Return a list of attribute names for retrieval of during creation. This allows
+        different child classes to have their own type specific data, but still make use of the
+        common base logic.
+        """
+
+        return ()
+
+
+    @classmethod
     @inlineCallbacks
     def listObjects(cls, home):
         """
@@ -2658,6 +2680,7 @@
                    bind.RESOURCE_NAME,
                    bind.BIND_STATUS,
                    bind.MESSAGE]
+        columns.extend(cls.additionalBindColumns())
         columns.extend(cls.metadataColumns())
         return Select(columns,
                      From=child.join(
@@ -2920,15 +2943,17 @@
     @classmethod
     def _bindFor(cls, condition): #@NoSelf
         bind = cls._bindSchema
+        columns = [bind.BIND_MODE,
+                   bind.HOME_RESOURCE_ID,
+                   bind.RESOURCE_ID,
+                   bind.RESOURCE_NAME,
+                   bind.BIND_STATUS,
+                   bind.MESSAGE]
+        columns.extend(cls.additionalBindColumns())
         return Select(
-            [bind.BIND_MODE,
-             bind.HOME_RESOURCE_ID,
-             bind.RESOURCE_ID,
-             bind.RESOURCE_NAME,
-             bind.BIND_STATUS,
-             bind.MESSAGE],
-                  From=bind,
-                  Where=condition
+            columns,
+            From=bind,
+            Where=condition
         )
 
 
@@ -2963,7 +2988,10 @@
 
         cls = self.__class__ # for ease of grepping...
         result = []
-        for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in acceptedRows: #@UnusedVariable
+        for item in acceptedRows:
+            bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = item[:6] #@UnusedVariable
+            additionalBind = item[6:]
+
             assert bindStatus == _BIND_STATUS_ACCEPTED
             # TODO: this could all be issued in parallel; no need to serialize
             # the loop.
@@ -2973,7 +3001,7 @@
                 mode=bindMode, status=bindStatus,
                 message=bindMessage, ownerHome=self._home
             )
-            yield new.initFromStore()
+            yield new.initFromStore(additionalBind)
             result.append(new)
         returnValue(result)
 
@@ -3007,7 +3035,9 @@
         cls = self.__class__ # for ease of grepping...
 
         result = []
-        for bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage in rows: #@UnusedVariable
+        for item in rows:
+            bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = item[:6] #@UnusedVariable
+            additionalBind = item[6:]
             # TODO: this could all be issued in parallel; no need to serialize
             # the loop.
             new = cls(
@@ -3016,7 +3046,7 @@
                 mode=bindMode, status=bindStatus,
                 message=bindMessage, ownerHome=self._home
             )
-            yield new.initFromStore()
+            yield new.initFromStore(additionalBind)
             result.append(new)
         returnValue(result)
 
@@ -3059,7 +3089,8 @@
         # Create the actual objects merging in properties
         for items in dataRows:
             bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = items[:6] #@UnusedVariable
-            metadata = items[6:]
+            additionalBind = items[6:6 + len(cls.additionalBindColumns())]
+            metadata = items[6 + len(cls.additionalBindColumns()):]
 
             if bindStatus == _BIND_MODE_OWN:
                 ownerHome = home
@@ -3076,6 +3107,8 @@
                 message=bindMessage,
                 ownerHome=ownerHome, ownerName=ownerName
             )
+            for attr, value in zip(cls.additionalBindAttributes(), additionalBind):
+                setattr(child, attr, value)
             for attr, value in zip(cls.metadataAttributes(), metadata):
                 setattr(child, attr, value)
             child._syncTokenRevision = revisions[resourceID]
@@ -3120,7 +3153,9 @@
         if not rows:
             returnValue(None)
 
-        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+        item = rows[0]
+        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = item[:6] #@UnusedVariable
+        additionalBind = item[6:]
 
         #TODO:  combine with _invitedBindForNameAndHomeID and sort results
         ownerHomeID, ownerName = (yield cls._ownerHomeWithResourceID.on(home._txn, resourceID=resourceID))[0]
@@ -3133,7 +3168,7 @@
             message=bindMessage,
             ownerHome=ownerHome, ownerName=ownerName,
         )
-        yield child.initFromStore()
+        yield child.initFromStore(additionalBind)
         returnValue(child)
 
 
@@ -3174,7 +3209,8 @@
             rows = yield cls._childForNameAndHomeID.on(home._txn, name=name, homeID=home._resourceID)
 
             if rows:
-                bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+                item = rows[0]
+                bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = item[:6] #@UnusedVariable
                 # get ownerHomeID
                 if bindMode == _BIND_MODE_OWN:
                     ownerHomeID = homeID
@@ -3182,8 +3218,8 @@
                 else:
                     ownerHomeID, ownerName = (yield cls._ownerHomeWithResourceID.on(
                                     home._txn, resourceID=resourceID))[0]
-                rows[0].append(ownerHomeID)
-                rows[0].append(ownerName)
+                rows[0].insert(6, ownerHomeID)
+                rows[0].insert(7, ownerName)
 
             if rows and queryCacher:
                 # Cache the result
@@ -3192,7 +3228,9 @@
         if not rows:
             returnValue(None)
 
-        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage, ownerHomeID, ownerName = rows[0] #@UnusedVariable
+        item = rows[0] #@UnusedVariable
+        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage, ownerHomeID, ownerName = item[:8]
+        additionalBind = item[8:]
 
         if bindMode == _BIND_MODE_OWN:
             ownerHome = home
@@ -3206,7 +3244,7 @@
             message=bindMessage,
             ownerHome=ownerHome, ownerName=ownerName,
         )
-        yield child.initFromStore()
+        yield child.initFromStore(additionalBind)
         returnValue(child)
 
 
@@ -3239,7 +3277,9 @@
         if not rows:
             returnValue(None)
 
-        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = rows[0] #@UnusedVariable
+        item = rows[0]
+        bindMode, homeID, resourceID, resourceName, bindStatus, bindMessage = item[:6] #@UnusedVariable
+        additionalBind = item[6:]
 
         if bindMode == _BIND_MODE_OWN:
             ownerHome = home
@@ -3254,7 +3294,7 @@
             message=bindMessage,
             ownerHome=ownerHome, ownerName=ownerName,
         )
-        yield child.initFromStore()
+        yield child.initFromStore(additionalBind)
         returnValue(child)
 
 
@@ -3352,7 +3392,7 @@
 
 
     @inlineCallbacks
-    def initFromStore(self):
+    def initFromStore(self, additionalBind=None):
         """
         Initialise this object from the store, based on its already-populated
         resource ID. We read in and cache all the extra metadata from the DB to
@@ -3374,6 +3414,10 @@
                 # Cache the results
                 yield queryCacher.setAfterCommit(self._txn, cacheKey, dataRows)
 
+        if additionalBind:
+            for attr, value in zip(self.additionalBindAttributes(), additionalBind):
+                setattr(self, attr, value)
+
         for attr, value in zip(self.metadataAttributes(), dataRows):
             setattr(self, attr, value)
         yield self._loadPropertyStore()
@@ -3416,6 +3460,8 @@
         if queryCacher is not None:
             cacheKey = queryCacher.keyForHomeChildMetaData(self._resourceID)
             yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
+            cacheKey = queryCacher.keyForObjectWithName(self._home._resourceID, self._name)
+            yield queryCacher.invalidateAfterCommit(self._txn, cacheKey)
 
 
     def exists(self):

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/current-oracle-dialect.sql	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/current-oracle-dialect.sql	2013-05-01 16:33:40 UTC (rev 11116)
@@ -64,7 +64,8 @@
     "CALENDAR_RESOURCE_NAME" nvarchar2(255),
     "BIND_MODE" integer not null,
     "BIND_STATUS" integer not null,
-    "MESSAGE" nclob, 
+    "MESSAGE" nclob,
+    "TRANSP" integer default 0 not null, 
     primary key("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_ID"), 
     unique("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_NAME")
 );
@@ -87,6 +88,13 @@
 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_TRANSP (
+    "ID" integer primary key,
+    "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
 create table CALENDAR_OBJECT (
     "RESOURCE_ID" integer primary key,
     "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/current.sql	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/current.sql	2013-05-01 16:33:40 UTC (rev 11116)
@@ -127,6 +127,7 @@
   BIND_MODE                 integer      not null, -- enum CALENDAR_BIND_MODE
   BIND_STATUS               integer      not null, -- enum CALENDAR_BIND_STATUS
   MESSAGE                   text,
+  TRANSP					integer		 default 0 not null, -- enum CALENDAR_TRANSP
 
   primary key(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
   unique(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME)     -- implicit index
@@ -159,6 +160,17 @@
 insert into CALENDAR_BIND_STATUS values (3, 'invalid');
 
 
+-- Enumeration of transparency
+
+create table CALENDAR_TRANSP (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_TRANSP values (0, 'opaque' );
+insert into CALENDAR_TRANSP values (1, 'transparent');
+
+
 ---------------------
 -- Calendar Object --
 ---------------------

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_18_to_19.sql	2013-05-01 16:33:40 UTC (rev 11116)
@@ -24,7 +24,20 @@
  add ("DEFAULT_EVENTS" integer default null,
  	  "DEFAULT_TASKS"  integer default null);
 
+ 	  
+-- Calendar bind related updates
 
+alter table CALENDAR_BIND
+ add ("TRANSP" integer default 0 not null);
+
+create table CALENDAR_TRANSP (
+    "ID" integer primary key,
+    "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('opaque', 0);
+insert into CALENDAR_TRANSP (DESCRIPTION, ID) values ('transparent', 1);
+
 -- Now update the version
 -- No data upgrades
 update CALENDARSERVER set VALUE = '19' where NAME = 'VERSION';

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_18_to_19.sql	2013-05-01 16:33:40 UTC (rev 11116)
@@ -26,6 +26,19 @@
  add column DEFAULT_TASKS integer default null;
 
 
+-- Calendar bind related updates
+
+alter table CALENDAR_BIND
+ add column TRANSP integer default 0 not null;
+
+create table CALENDAR_TRANSP (
+  ID          integer     primary key,
+  DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_TRANSP values (0, 'opaque' );
+insert into CALENDAR_TRANSP values (1, 'transparent');
+
 -- Now update the version
 -- No data upgrades
 update CALENDARSERVER set VALUE = '19' where NAME = 'VERSION';

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_tables.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_tables.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/sql_tables.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -153,6 +153,16 @@
 _BIND_STATUS_DECLINED = _bindStatus('declined')
 _BIND_STATUS_INVALID = _bindStatus('invalid')
 
+
+_transpValues = _schemaConstants(
+    schema.CALENDAR_TRANSP.DESCRIPTION,
+    schema.CALENDAR_TRANSP.ID
+)
+
+_TRANSP_OPAQUE = _transpValues('opaque')
+_TRANSP_TRANSPARENT = _transpValues('transparent')
+
+
 _attachmentsMode = _schemaConstants(
     schema.CALENDAR_OBJECT_ATTACHMENTS_MODE.DESCRIPTION,
     schema.CALENDAR_OBJECT_ATTACHMENTS_MODE.ID

Added: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/test/__init__.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/test/__init__.py	                        (rev 0)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/test/__init__.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -0,0 +1,15 @@
+##
+# Copyright (c) 2011-2013 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.
+##

Added: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py	                        (rev 0)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/test/test_upgrade_from_3_to_4.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -0,0 +1,108 @@
+##
+# Copyright (c) 2010-2013 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.
+##
+from twistedcaldav.caldavxml import ScheduleDefaultCalendarURL, \
+    CalendarFreeBusySet, Opaque, ScheduleCalendarTransp
+from txdav.base.propertystore.base import PropertyName
+from txdav.caldav.datastore.test.util import CommonStoreTests
+from txdav.xml.element import HRef
+from twext.enterprise.dal.syntax import Update
+from txdav.common.datastore.upgrade.sql.upgrades.upgrade_from_3_to_4 import moveDefaultCalendarProperties, \
+    moveCalendarTranspProperties
+
+"""
+Tests for L{txdav.common.datastore.upgrade.sql.upgrade}.
+"""
+
+from twisted.internet.defer import inlineCallbacks
+
+class Upgrade_from_3_to_4(CommonStoreTests):
+    """
+    Tests for L{DefaultCalendarPropertyUpgrade}.
+    """
+
+    @inlineCallbacks
+    def test_defaultCalendarUpgrade(self):
+
+        # Set dead property on inbox
+        inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
+        inbox.properties()[PropertyName.fromElement(ScheduleDefaultCalendarURL)] = ScheduleDefaultCalendarURL(HRef.fromString("/calendars/__uids__/user01/calendar_1"))
+
+        # Force current default to null
+        home = (yield self.homeUnderTest(name="user01"))
+        chm = home._homeMetaDataSchema
+        yield Update(
+            {chm.DEFAULT_EVENTS: None},
+            Where=chm.RESOURCE_ID == home._resourceID,
+        ).on(self.transactionUnderTest())
+
+        # Force data version to previous
+        ch = home._homeSchema
+        yield Update(
+            {ch.DATAVERSION: 3},
+            Where=ch.RESOURCE_ID == home._resourceID,
+        ).on(self.transactionUnderTest())
+
+        yield self.commit()
+
+        # Trigger upgrade
+        yield moveDefaultCalendarProperties(self._sqlCalendarStore)
+
+        # Test results
+        home = (yield self.homeUnderTest(name="user01"))
+        calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
+        self.assertTrue(home.isDefaultCalendar(calendar))
+        inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
+        self.assertTrue(PropertyName.fromElement(ScheduleDefaultCalendarURL) not in inbox.properties())
+
+
+    @inlineCallbacks
+    def test_calendarTranspUpgrade(self):
+
+        # Set dead property on inbox
+        inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
+        inbox.properties()[PropertyName.fromElement(CalendarFreeBusySet)] = CalendarFreeBusySet(HRef.fromString("/calendars/__uids__/user01/calendar_1"))
+
+        # Force current to transparent
+        calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
+        yield calendar.setUsedForFreeBusy(False)
+        calendar.properties()[PropertyName.fromElement(ScheduleCalendarTransp)] = ScheduleCalendarTransp(Opaque())
+
+        # Force data version to previous
+        home = (yield self.homeUnderTest(name="user01"))
+        ch = home._homeSchema
+        yield Update(
+            {ch.DATAVERSION: 3},
+            Where=ch.RESOURCE_ID == home._resourceID,
+        ).on(self.transactionUnderTest())
+
+        yield self.commit()
+
+        calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
+        self.assertFalse(calendar.isUsedForFreeBusy())
+        self.assertTrue(PropertyName.fromElement(ScheduleCalendarTransp) in calendar.properties())
+        inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
+        self.assertTrue(PropertyName.fromElement(CalendarFreeBusySet) in inbox.properties())
+        yield self.commit()
+
+        # Trigger upgrade
+        yield moveCalendarTranspProperties(self._sqlCalendarStore)
+
+        # Test results
+        home = (yield self.homeUnderTest(name="user01"))
+        calendar = (yield self.calendarUnderTest(name="calendar_1", home="user01"))
+        self.assertTrue(calendar.isUsedForFreeBusy())
+        inbox = (yield self.calendarUnderTest(name="inbox", home="user01"))
+        self.assertTrue(PropertyName.fromElement(CalendarFreeBusySet) not in inbox.properties())

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/upgrade_from_3_to_4.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -15,15 +15,16 @@
 # limitations under the License.
 ##
 
-from twext.enterprise.dal.syntax import Update, Select, Delete, Parameter
+from twext.enterprise.dal.syntax import Select, Delete, Parameter
 
 from twisted.internet.defer import inlineCallbacks
 
 from twistedcaldav import caldavxml, customxml
 
 from txdav.base.propertystore.base import PropertyName
-from txdav.common.datastore.sql_tables import schema
-from txdav.common.datastore.upgrade.sql.upgrades.util import rowsForProperty, updateDataVersion
+from txdav.common.datastore.sql_tables import schema, _BIND_MODE_OWN
+from txdav.common.datastore.upgrade.sql.upgrades.util import rowsForProperty, updateDataVersion, \
+    updateAllCalendarHomeDataVersions, removeProperty, cleanPropertyStore
 from txdav.xml.parser import WebDAVDocument
 
 """
@@ -39,9 +40,11 @@
     Do the required upgrade steps.
     """
     yield moveDefaultCalendarProperties(sqlStore)
+    yield moveCalendarTranspProperties(sqlStore)
 
     # Always bump the DB value
     yield updateDataVersion(sqlStore, "CALENDAR-DATAVERSION", UPGRADE_TO_VERSION)
+    yield updateAllCalendarHomeDataVersions(sqlStore, UPGRADE_TO_VERSION)
 
 
 
@@ -67,7 +70,6 @@
     Since the number of calendar homes may well be large, we need to do this in batches.
     """
 
-    meta = schema.CALENDAR_HOME_METADATA
     cb = schema.CALENDAR_BIND
     rp = schema.RESOURCE_PROPERTY
 
@@ -103,12 +105,8 @@
 
                                 calendar = (yield calendarHome.calendarWithName(calendarName))
                                 if calendar is not None:
+                                    yield calendarHome.setDefaultCalendar(calendar, tasks=(propname == sqlStore, customxml.ScheduleDefaultTasksURL))
 
-                                    yield Update(
-                                        {colname : calendar.id(), },
-                                        Where=(meta.RESOURCE_ID == calendarHome.id())
-                                    ).on(sqlTxn)
-
                 # Always delete the row so that batch processing works correctly
                 yield Delete(
                     From=rp,
@@ -118,6 +116,73 @@
 
             yield sqlTxn.commit()
 
+        yield cleanPropertyStore()
+
     except RuntimeError:
         yield sqlTxn.abort()
         raise
+
+
+
+ at inlineCallbacks
+def moveCalendarTranspProperties(sqlStore):
+    """
+    Need to move all the CalDAV:schedule-calendar-transp properties in the
+    RESOURCE_PROPERTY table to the new CALENDAR_BIND table columns, extracting
+    the new value from the XML property.
+    """
+
+    cb = schema.CALENDAR_BIND
+    rp = schema.RESOURCE_PROPERTY
+
+    try:
+        calendars_for_id = {}
+        while True:
+            sqlTxn = sqlStore.newTransaction()
+            rows = (yield rowsForProperty(sqlTxn, caldavxml.ScheduleCalendarTransp, with_uid=True, batch=BATCH_SIZE))
+            if len(rows) == 0:
+                yield sqlTxn.commit()
+                break
+            delete_ids = []
+            for calendar_rid, value, viewer in rows:
+                delete_ids.append(calendar_rid)
+                if calendar_rid not in calendars_for_id:
+                    ids = yield Select(
+                        [cb.CALENDAR_HOME_RESOURCE_ID, cb.BIND_MODE, ],
+                        From=cb,
+                        Where=cb.CALENDAR_RESOURCE_ID == calendar_rid,
+                    ).on(sqlTxn)
+                    calendars_for_id[calendar_rid] = ids
+
+                if viewer:
+                    calendarHome = (yield sqlTxn.calendarHomeWithUID(viewer))
+                else:
+                    calendarHome = None
+                    for row in calendars_for_id[calendar_rid]:
+                        home_id, bind_mode = row
+                        if bind_mode == _BIND_MODE_OWN:
+                            calendarHome = (yield sqlTxn.calendarHomeWithResourceID(home_id))
+                            break
+
+                if calendarHome is not None:
+                    prop = WebDAVDocument.fromString(value).root_element
+                    calendar = (yield calendarHome.childWithID(calendar_rid))
+                    yield calendar.setUsedForFreeBusy(prop == caldavxml.ScheduleCalendarTransp(caldavxml.Opaque()))
+
+                # Always delete the row so that batch processing works correctly
+                yield Delete(
+                    From=rp,
+                    Where=(rp.RESOURCE_ID.In(Parameter("ids", len(delete_ids)))).And
+                          (rp.NAME == PropertyName.fromElement(caldavxml.ScheduleCalendarTransp).toString()),
+                ).on(sqlTxn, ids=delete_ids)
+
+            yield sqlTxn.commit()
+
+        sqlTxn = sqlStore.newTransaction()
+        yield removeProperty(sqlTxn, PropertyName.fromElement(caldavxml.CalendarFreeBusySet))
+        yield sqlTxn.commit()
+        yield cleanPropertyStore()
+
+    except RuntimeError:
+        yield sqlTxn.abort()
+        raise

Modified: CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/util.py
===================================================================
--- CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/util.py	2013-04-30 19:20:15 UTC (rev 11115)
+++ CalendarServer/branches/users/cdaboo/store-scheduling/txdav/common/datastore/upgrade/sql/upgrades/util.py	2013-05-01 16:33:40 UTC (rev 11116)
@@ -18,14 +18,18 @@
 from twisted.internet.defer import inlineCallbacks, returnValue
 from txdav.base.propertystore.base import PropertyName
 from txdav.common.datastore.sql_tables import schema
+from txdav.base.propertystore.sql import PropertyStore
 
 @inlineCallbacks
-def rowsForProperty(txn, propelement, batch=None):
+def rowsForProperty(txn, propelement, with_uid=False, batch=None):
     pname = PropertyName.fromElement(propelement)
 
     rp = schema.RESOURCE_PROPERTY
+    columns = [rp.RESOURCE_ID, rp.VALUE, ]
+    if with_uid:
+        columns.append(rp.VIEWER_UID)
     rows = yield Select(
-        [rp.RESOURCE_ID, rp.VALUE, ],
+        columns,
         From=rp,
         Where=rp.NAME == pname.toString(),
         Limit=batch,
@@ -36,6 +40,16 @@
 
 
 @inlineCallbacks
+def cleanPropertyStore():
+    """
+    We have manually manipulated the SQL property store by-passing the underlying implementation's caching
+    mechanism. We need to clear out the cache.
+    """
+    yield PropertyStore._cacher.flushAll()
+
+
+
+ at inlineCallbacks
 def removeProperty(txn, propelement):
     pname = PropertyName.fromElement(propelement)
 
@@ -48,6 +62,31 @@
 
 
 @inlineCallbacks
+def updateAllCalendarHomeDataVersions(store, version):
+
+    txn = store.newTransaction("updateAllCalendarHomeDataVersions")
+    ch = schema.CALENDAR_HOME
+    yield Update(
+        {ch.DATAVERSION: version},
+        Where=None,
+    ).on(txn)
+    yield txn.commit()
+
+
+
+ at inlineCallbacks
+def updateAllAddressBookHomeDataVersions(store, version):
+
+    txn = store.newTransaction("updateAllAddressBookHomeDataVersions")
+    ah = schema.ADDRESSBOOK_HOME
+    yield Update(
+        {ah.DATAVERSION: version},
+    ).on(txn)
+    yield txn.commit()
+
+
+
+ at inlineCallbacks
 def updateDataVersion(store, key, version):
 
     txn = store.newTransaction("updateDataVersion")
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130501/7ac2c79c/attachment-0001.html>


More information about the calendarserver-changes mailing list