[CalendarServer-changes] [13732] CalendarServer/branches/users/gaya/groupsharee2
source_changes at macosforge.org
source_changes at macosforge.org
Tue Jul 8 00:05:29 PDT 2014
Revision: 13732
http://trac.calendarserver.org//changeset/13732
Author: gaya at apple.com
Date: 2014-07-08 00:05:29 -0700 (Tue, 08 Jul 2014)
Log Message:
-----------
merge in trunk to r13731; fix problem where group membership cache is out of sync when first added
Revision Links:
--------------
http://trac.calendarserver.org//changeset/13731
Modified Paths:
--------------
CalendarServer/branches/users/gaya/groupsharee2/bin/test
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/provision/root.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/provision/test/test_root.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/push/notifier.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tap/caldav.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/anonymize.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/calverify.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/dashboard.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/dbinspect.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/gateway.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/principals.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/purge.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/cmd.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/directory.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/vfs.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/deprovision/caldavd.plist
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/gateway/caldavd.plist
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/principals/caldavd.plist
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/test_calverify.py
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/util.py
CalendarServer/branches/users/gaya/groupsharee2/conf/auth/generate_test_accounts.py
CalendarServer/branches/users/gaya/groupsharee2/conf/caldavd-test.plist
CalendarServer/branches/users/gaya/groupsharee2/conf/resources/caldavd-resources.plist
CalendarServer/branches/users/gaya/groupsharee2/contrib/performance/loadtest/ical.py
CalendarServer/branches/users/gaya/groupsharee2/requirements-dev.txt
CalendarServer/branches/users/gaya/groupsharee2/requirements-stable.txt
CalendarServer/branches/users/gaya/groupsharee2/setup.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/datafilters/hiddeninstance.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/augment.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/digest.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/principal.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/test/test_principal.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/util.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/ical.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/resource.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/scheduling_store/caldav/resource.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/stdconfig.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/storebridge.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/test/test_icalendar.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/test/test_upgrade.py
CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/upgrade.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/schedule.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/implicit.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/itip.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/processing.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/test/test_implicit.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/work.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/sql.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/test/test_sql.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/carddav/datastore/sql.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/carddav/datastore/test/test_sql.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current-oracle-dialect-extras.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_43_to_44.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_tables.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/dps/client.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/dps/server.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/augment.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/delegates.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/directory.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/groups.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/opendirectory.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_delegates.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_group_attendees.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_groups.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/util.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/who/wiki.py
Added Paths:
-----------
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/platform/darwin/sacl.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/test/test_work.py
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/oracle-dialect/v44.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/oracle-dialect/v45.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/postgres-dialect/v44.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/postgres-dialect/v45.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_44_to_45.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_45_to_46.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_44_to_45.sql
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_45_to_46.sql
Removed Paths:
-------------
CalendarServer/branches/users/gaya/groupsharee2/calendarserver/platform/darwin/_sacl.c
CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql
Modified: CalendarServer/branches/users/gaya/groupsharee2/bin/test
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/bin/test 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/bin/test 2014-07-08 07:05:29 UTC (rev 13732)
@@ -83,15 +83,7 @@
done;
shift $((${OPTIND} - 1));
-if [ $# -eq 0 ]; then
- lint="true";
- set - calendarserver twistedcaldav txdav txweb2 contrib twext;
-else
- lint="false";
-fi;
-
-
#
# Dependencies
#
@@ -112,11 +104,10 @@
# Unit tests
#
-for module in "$@"; do
- if [ -f "${module}" ]; then
- module="--testmodule=${module}";
- fi;
-
+if [ $# -eq 0 ]; then
+ lint="true";
+ # Test these modules with a single invocation of trial
+ set - calendarserver twistedcaldav txdav txweb2 contrib
cd "${wd}" && \
"${wd}/bin/trial" \
--temp-directory="${dev_home}/trial" \
@@ -127,10 +118,30 @@
${no_color} \
${coverage} \
${numjobs} \
- "${module}";
-done;
+ "$@";
+else
+ lint="false";
+ # Loop over the passed-in modules
+ for module in "$@"; do
+ if [ -f "${module}" ]; then
+ module="--testmodule=${module}";
+ fi;
+ cd "${wd}" && \
+ "${wd}/bin/trial" \
+ --temp-directory="${dev_home}/trial" \
+ --rterrors \
+ ${reactor} \
+ ${random} \
+ ${until_fail} \
+ ${no_color} \
+ ${coverage} \
+ ${numjobs} \
+ "${module}";
+ done;
+fi;
+
if ! "${lint}"; then
exit 0;
fi;
Deleted: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/platform/darwin/_sacl.c
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/platform/darwin/_sacl.c 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/platform/darwin/_sacl.c 2014-07-08 07:05:29 UTC (rev 13732)
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2006-2014 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.
- */
-
-#include "Python.h"
-#include <Security/Security.h>
-#include <membership.h>
-
-int mbr_check_service_membership(const uuid_t user, const char* servicename, int* ismember);
-int mbr_user_name_to_uuid(const char* name, uuid_t uu);
-int mbr_group_name_to_uuid(const char* name, uuid_t uu);
-
-/*
- CheckSACL(userOrGroupName, service)
- Checks user or group membership in a service.
-*/
-static PyObject *appleauth_CheckSACL(PyObject *self, PyObject *args) {
- char *username;
- int usernameSize;
- char *serviceName;
- int serviceNameSize;
-
- char *prefix = "com.apple.access_";
- char groupName[256];
- uuid_t group_uu;
-
- // get the args
- if (!PyArg_ParseTuple(args, "s#s#", &username,
- &usernameSize, &serviceName, &serviceNameSize)) {
- return NULL;
- }
-
- // If the username is empty, see if there is a com.apple.access_<service>
- // group
- if ( usernameSize == 0 ) {
- if ( strlen(serviceName) > 255 - strlen(prefix) ) {
- return Py_BuildValue("i", (-3));
- }
- memcpy(groupName, prefix, strlen(prefix));
- strcpy(groupName + strlen(prefix), serviceName);
- if ( mbr_group_name_to_uuid(groupName, group_uu) == 0 ) {
- // com.apple.access_<serviceName> group does exist, so
- // unauthenticated users are not allowed
- return Py_BuildValue("i", (-1));
- } else {
- // com.apple.access_<serviceName> group doesn't exist, so
- // unauthenticated users are allowed
- return Py_BuildValue("i", 0);
- }
- }
-
- // get a uuid for the user
- uuid_t user;
- int result = mbr_user_name_to_uuid(username, user);
- int isMember = 0;
-
- if ( result != 0 ) {
- // no uuid for the user, we might be a group.
- result = mbr_group_name_to_uuid(username, user);
- }
-
- if ( result != 0 ) {
- return Py_BuildValue("i", (-1));
- }
-
- result = mbr_check_service_membership(user, serviceName, &isMember);
-
- if ( ( result == 0 && isMember == 1 ) || ( result == ENOENT ) ) {
- // passed
- return Py_BuildValue("i", 0);
- }
-
- return Py_BuildValue("i", (-2));
-}
-
-/* Method definitions. */
-static struct PyMethodDef _sacl_methods[] = {
- {"CheckSACL", appleauth_CheckSACL},
- {NULL, NULL} /* Sentinel */
-};
-
-void init_sacl(void) {
- Py_InitModule("_sacl", _sacl_methods);
-}
Copied: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/platform/darwin/sacl.py (from rev 13731, CalendarServer/trunk/calendarserver/platform/darwin/sacl.py)
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/platform/darwin/sacl.py (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/platform/darwin/sacl.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,85 @@
+##
+# Copyright (c) 2005-2014 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 __future__ import print_function
+
+__all__ = [
+ "checkSACL"
+]
+
+from cffi import FFI, VerificationError
+
+ffi = FFI()
+
+definitions = """
+ typedef unsigned char uuid_t[16];
+ int mbr_check_service_membership(const uuid_t user, const char* servicename, int* ismember);
+ int mbr_user_name_to_uuid(const char* name, uuid_t uu);
+ int mbr_group_name_to_uuid(const char* name, uuid_t uu);
+"""
+
+ffi.cdef(definitions)
+
+try:
+ lib = ffi.verify(definitions, libraries=[])
+except VerificationError as ve:
+ raise ImportError(ve)
+
+
+def checkSACL(userOrGroupName, serviceName):
+ """
+ Check to see if a given user or group is a member of an OS X Server
+ service's access group. If userOrGroupName is an empty string, we
+ want to know if unauthenticated access is allowed for the given service.
+
+ @param userOrGroupName: the name of the user or group
+ @type userOrGroupName: C{unicode}
+
+ @param serviceName: the name of the service (e.g. calendar, addressbook)
+ @type serviceName: C{str}
+
+ @return: True if the user or group is allowed access to service
+ @rtype: C{bool}
+ """
+
+ userOrGroupName = userOrGroupName.encode("utf-8")
+ prefix = "com.apple.access_"
+ uu = ffi.new("uuid_t")
+
+ # See if the access group exists. If it does not, then there are no
+ # restrictions
+ groupName = prefix + serviceName
+ groupMissing = lib.mbr_group_name_to_uuid(groupName, uu)
+ if groupMissing:
+ return True
+
+ # See if userOrGroupName matches a user
+ result = lib.mbr_user_name_to_uuid(userOrGroupName, uu)
+ if result:
+ # Not a user, try looking up a group of that name
+ result = lib.mbr_group_name_to_uuid(userOrGroupName, uu)
+
+ if result:
+ # Neither a user nor a group matches the name
+ return False
+
+ # See if the uuid is a member of the service access group
+ isMember = ffi.new("int *")
+ result = lib.mbr_check_service_membership(uu, serviceName, isMember)
+ if not result and isMember[0]:
+ return True
+
+ return False
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/provision/root.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/provision/root.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/provision/root.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -19,6 +19,12 @@
"RootResource",
]
+try:
+ from calendarserver.platform.darwin.sacl import checkSACL
+except ImportError:
+ # OS X Server SACLs not supported on this system, make SACL check a no-op
+ checkSACL = lambda *ignored: True
+
from twext.python.log import Logger
from twisted.cred.error import LoginFailed, UnauthorizedLogin
from twisted.internet.defer import inlineCallbacks, returnValue, succeed
@@ -75,10 +81,7 @@
super(RootResource, self).__init__(path, *args, **kwargs)
if config.EnableSACLs:
- if RootResource.CheckSACL:
- self.useSacls = True
- else:
- log.warn("SACLs are enabled, but SACLs are not supported.")
+ self.useSacls = True
self.contentFilters = []
@@ -122,7 +125,7 @@
@inlineCallbacks
- def checkSacl(self, request):
+ def checkSACL(self, request):
"""
Check SACLs against the current request
"""
@@ -147,7 +150,7 @@
# with an empty string.
if authzUser is None:
for saclService in saclServices:
- if RootResource.CheckSACL("", saclService) == 0:
+ if checkSACL("", saclService):
# No group actually exists for this SACL, so allow
# unauthenticated access
returnValue(True)
@@ -169,7 +172,7 @@
access = False
for saclService in saclServices:
- if RootResource.CheckSACL(username, saclService) == 0:
+ if checkSACL(username, saclService):
# Access is allowed
access = True
break
@@ -346,7 +349,7 @@
self.useSacls and
not hasattr(request, "checkedSACL")
):
- yield self.checkSacl(request)
+ yield self.checkSACL(request)
if config.RejectClients:
#
@@ -432,11 +435,3 @@
def http_DELETE(self, request):
return responsecode.FORBIDDEN
-
-# So CheckSACL will be parameterized
-# We do this after RootResource is defined
-try:
- from calendarserver.platform.darwin._sacl import CheckSACL
- RootResource.CheckSACL = CheckSACL
-except ImportError:
- RootResource.CheckSACL = None
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/provision/test/test_root.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/provision/test/test_root.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/provision/test/test_root.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -26,22 +26,27 @@
from twistedcaldav.test.util import StoreTestCase, SimpleStoreRequest
from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
-from calendarserver.provision.root import RootResource
+import calendarserver.provision.root # for patching checkSACL
-class FakeCheckSACL(object):
- def __init__(self, sacls=None):
- self.sacls = sacls or {}
+TEST_SACLS = {
+ "calendar": [
+ "dreid"
+ ],
+ "addressbook": [
+ "dreid"
+ ],
+}
- def __call__(self, username, service):
- if service not in self.sacls:
- return 1
+def stubCheckSACL(username, service):
+ if service not in TEST_SACLS:
+ return True
- if username in self.sacls[service]:
- return 0
+ if username in TEST_SACLS[service]:
+ return True
- return 1
+ return False
@@ -51,7 +56,7 @@
def setUp(self):
yield super(RootTests, self).setUp()
- RootResource.CheckSACL = FakeCheckSACL(sacls={"calendar": ["dreid"]})
+ self.patch(calendarserver.provision.root, "checkSACL", stubCheckSACL)
@@ -337,7 +342,7 @@
"PROPFIND",
"/principals/users/dreid/",
headers=http_headers.Headers({
- 'Depth': '1',
+ 'Depth': '1',
}),
authPrincipal=principal,
content=body
@@ -353,7 +358,7 @@
"PROPFIND",
"/principals/users/dreid/",
headers=http_headers.Headers({
- 'Depth': '1',
+ 'Depth': '1',
}),
authPrincipal=principal,
content=body
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/push/notifier.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/push/notifier.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/push/notifier.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -20,7 +20,7 @@
from twext.enterprise.dal.record import fromTable
from twext.enterprise.dal.syntax import Delete, Select, Parameter
-from twext.enterprise.jobqueue import WorkItem, WORK_PRIORITY_HIGH, \
+from twext.enterprise.jobqueue import JobItem, WorkItem, WORK_PRIORITY_HIGH, \
WORK_WEIGHT_1
from twext.python.log import Logger
@@ -50,7 +50,7 @@
# Find all work items with the same push ID and find the highest
# priority. Delete matching work items.
- results = (yield Select([self.table.WORK_ID, self.table.PUSH_PRIORITY],
+ results = (yield Select([self.table.WORK_ID, self.table.JOB_ID, self.table.PUSH_PRIORITY],
From=self.table, Where=self.table.PUSH_ID == self.pushID).on(
self.transaction))
@@ -59,17 +59,20 @@
# If there are other enqueued work items for this push ID, find the
# highest priority one and use that value
if results:
- workIDs = []
- for workID, priority in results:
- if priority > maxPriority:
- maxPriority = priority
- workIDs.append(workID)
+ workIDs, jobIDs, priorities = zip(*results)
+ maxPriority = max(priorities)
- # Delete the work items we selected
+ # Delete the work items and jobs we selected - deleting the job will ensure that there are no
+ # orphaned" jobs left in the job queue which would otherwise get to run at some later point,
+ # though not do anything because there is no related work item.
yield Delete(
From=self.table,
Where=self.table.WORK_ID.In(Parameter("workIDs", len(workIDs)))
).on(self.transaction, workIDs=workIDs)
+ yield Delete(
+ From=JobItem.table, #@UndefinedVariable
+ Where=JobItem.jobID.In(Parameter("jobIDs", len(jobIDs))) #@UndefinedVariable
+ ).on(self.transaction, jobIDs=jobIDs)
pushDistributor = self.transaction._pushDistributor
if pushDistributor is not None:
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tap/caldav.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tap/caldav.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -67,7 +67,7 @@
from twext.enterprise.adbapi2 import ConnectionPool
from twext.enterprise.ienterprise import ORACLE_DIALECT
from twext.enterprise.ienterprise import POSTGRES_DIALECT
-from twext.enterprise.jobqueue import NonPerformingQueuer
+from twext.enterprise.jobqueue import NonPerformingQueuer, JobItem
from twext.enterprise.jobqueue import PeerConnectionPool
from twext.enterprise.jobqueue import WorkerFactory as QueueWorkerFactory
from twext.application.service import ReExecService
@@ -881,6 +881,8 @@
if pool is not None:
pool.setServiceParent(result)
+ self._initJobQueue(None)
+
if config.ControlSocket:
id = config.ControlSocket
self.log.info("Control via AF_UNIX: {id}", id=id)
@@ -1281,6 +1283,7 @@
pool = PeerConnectionPool(
reactor, store.newTransaction, config.WorkQueue.ampPort
)
+ self._initJobQueue(pool)
store.queuer = store.queuer.transferProposalCallbacks(pool)
pool.setServiceParent(result)
@@ -1869,6 +1872,7 @@
pool = PeerConnectionPool(
reactor, store.newTransaction, config.WorkQueue.ampPort
)
+ self._initJobQueue(pool)
store.queuer = store.queuer.transferProposalCallbacks(pool)
controlSocket.addFactory(
_QUEUE_ROUTE, pool.workerListenerFactory()
@@ -1991,7 +1995,34 @@
remove(checkSocket)
+ def _initJobQueue(self, pool):
+ """
+ Common job queue initialization
+ @param pool: the connection pool to init or L{None}
+ @type pool: L{PeerConnectionPool} or C{None}
+ """
+
+ # Initialize queue polling parameters from config settings
+ if pool is not None:
+ for attr in (
+ "queuePollInterval",
+ "queueOverdueTimeout",
+ "overloadLevel",
+ "highPriorityLevel",
+ "mediumPriorityLevel",
+ ):
+ setattr(pool, attr, getattr(config.WorkQueue, attr))
+
+ # Initialize job parameters from config settings
+ for attr in (
+ "failureRescheduleInterval",
+ "lockRescheduleInterval",
+ ):
+ setattr(JobItem, attr, getattr(config.WorkQueue, attr))
+
+
+
class TwistdSlaveProcess(object):
"""
A L{TwistdSlaveProcess} is information about how to start a slave process
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/anonymize.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/anonymize.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/anonymize.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -342,7 +342,7 @@
except KeyError:
pass
- return pyobj.getText(includeTimezones=True)
+ return pyobj.getText(includeTimezones=Calendar.ALL_TIMEZONES)
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/calverify.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/calverify.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/calverify.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -255,7 +255,6 @@
Options for --ical:
---badcua : only look for bad calendar user addresses.
--uuid : only scan specified calendar homes. Can be a partial GUID
to scan all GUIDs with that as a prefix.
--uid : scan only calendar data with the specific iCalendar UID.
@@ -2719,7 +2718,7 @@
return NukeService(store, options, output, reactor, config)
elif options["missing"]:
return OrphansService(store, options, output, reactor, config)
- elif options["ical"] or options["badcua"]:
+ elif options["ical"]:
return BadDataService(store, options, output, reactor, config)
elif options["mismatch"]:
return SchedulingMismatchService(store, options, output, reactor, config)
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/dashboard.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/dashboard.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/dashboard.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -545,8 +545,8 @@
"Total:",
total_queued,
total_assigned,
+ total_late,
total_failed,
- total_late,
total_completed,
safeDivision(total_time, total_completed, 1000.0)
)
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/dbinspect.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/dbinspect.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/dbinspect.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -96,26 +96,27 @@
+ at inlineCallbacks
def UserNameFromUID(txn, uid):
- record = txn.directoryService().recordWithGUID(uid)
- return record.shortNames[0] if record else "(%s)" % (uid,)
+ record = yield txn.directoryService().recordWithGUID(uid)
+ returnValue(record.shortNames[0] if record else "(%s)" % (uid,))
-
+ at inlineCallbacks
def UIDFromInput(txn, value):
try:
- return str(UUID(value)).upper()
+ returnValue(str(UUID(value)).upper())
except (ValueError, TypeError):
pass
- record = txn.directoryService().recordWithShortName(RecordType.user, value)
+ record = yield txn.directoryService().recordWithShortName(RecordType.user, value)
if record is None:
- record = txn.directoryService().recordWithShortName(CalRecordType.location, value)
+ record = yield txn.directoryService().recordWithShortName(CalRecordType.location, value)
if record is None:
- record = txn.directoryService().recordWithShortName(CalRecordType.resource, value)
+ record = yield txn.directoryService().recordWithShortName(CalRecordType.resource, value)
if record is None:
- record = txn.directoryService().recordWithShortName(RecordType.group, value)
- return record.guid if record else None
+ record = yield txn.directoryService().recordWithShortName(RecordType.group, value)
+ returnValue(record.guid if record else None)
@@ -184,7 +185,7 @@
table = tables.Table()
table.addHeader(("Owner UID", "Short Name"))
for uid in sorted(uids):
- shortname = UserNameFromUID(txn, uid)
+ shortname = yield UserNameFromUID(txn, uid)
if shortname.startswith("("):
missing += 1
table.addRow((
@@ -230,7 +231,7 @@
table.addHeader(("Owner UID", "Short Name", "Calendars", "Resources"))
totals = [0, 0, 0]
for uid in sorted(results.keys()):
- shortname = UserNameFromUID(txn, uid)
+ shortname = yield UserNameFromUID(txn, uid)
table.addRow((
uid,
shortname,
@@ -287,7 +288,7 @@
table = tables.Table()
table.addHeader(("Owner UID", "Short Name", "Calendar", "Resources"))
for uid, calname, count in sorted(uids, key=lambda x: (x[0], x[1])):
- shortname = UserNameFromUID(txn, uid)
+ shortname = yield UserNameFromUID(txn, uid)
table.addRow((
uid,
shortname,
@@ -329,7 +330,7 @@
def doIt(self, txn):
uid = raw_input("Owner UID/Name: ")
- uid = UIDFromInput(txn, uid)
+ uid = yield UIDFromInput(txn, uid)
uids = yield self.getCalendars(txn, uid)
# Print table of results
@@ -337,7 +338,7 @@
table.addHeader(("Owner UID", "Short Name", "Calendars", "ID", "Resources"))
totals = [0, 0, ]
for uid, calname, resid, count in sorted(uids, key=lambda x: x[1]):
- shortname = UserNameFromUID(txn, uid)
+ shortname = yield UserNameFromUID(txn, uid)
table.addRow((
uid if totals[0] == 0 else "",
shortname if totals[0] == 0 else "",
@@ -390,7 +391,7 @@
table = tables.Table()
table.addHeader(("Owner UID", "Short Name", "Calendar", "ID", "Type", "UID"))
for uid, calname, id, caltype, caluid in sorted(uids, key=lambda x: (x[0], x[1])):
- shortname = UserNameFromUID(txn, uid)
+ shortname = yield UserNameFromUID(txn, uid)
table.addRow((
uid,
shortname,
@@ -484,9 +485,10 @@
"""
Base class for common event details commands.
"""
+ @inlineCallbacks
def printEventDetails(self, txn, details):
owner, calendar, resource_id, resource, created, modified, data = details
- shortname = UserNameFromUID(txn, owner)
+ shortname = yield UserNameFromUID(txn, owner)
table = tables.Table()
table.addRow(("Owner UID:", owner,))
table.addRow(("User Name:", shortname,))
@@ -540,7 +542,7 @@
returnValue(None)
result = yield self.getData(txn, rid)
if result:
- self.printEventDetails(txn, result[0])
+ yield self.printEventDetails(txn, result[0])
else:
print("Could not find resource")
@@ -562,7 +564,7 @@
rows = yield self.getData(txn, uid)
if rows:
for result in rows:
- self.printEventDetails(txn, result)
+ yield self.printEventDetails(txn, result)
else:
print("Could not find icalendar data")
@@ -584,7 +586,7 @@
rows = yield self.getData(txn, name)
if rows:
for result in rows:
- self.printEventDetails(txn, result)
+ yield self.printEventDetails(txn, result)
else:
print("Could not find icalendar data")
@@ -603,11 +605,11 @@
def doIt(self, txn):
uid = raw_input("Owner UID/Name: ")
- uid = UIDFromInput(txn, uid)
+ uid = yield UIDFromInput(txn, uid)
rows = yield self.getData(txn, uid)
if rows:
for result in rows:
- self.printEventDetails(txn, result)
+ yield self.printEventDetails(txn, result)
else:
print("Could not find icalendar data")
@@ -626,12 +628,12 @@
def doIt(self, txn):
uid = raw_input("Owner UID/Name: ")
- uid = UIDFromInput(txn, uid)
+ uid = yield UIDFromInput(txn, uid)
name = raw_input("Calendar resource name: ")
rows = yield self.getData(txn, uid, name)
if rows:
for result in rows:
- self.printEventDetails(txn, result)
+ yield self.printEventDetails(txn, result)
else:
print("Could not find icalendar data")
@@ -661,7 +663,7 @@
rows = yield self.getData(txn, homeName, calendarName, resourceName)
if rows:
for result in rows:
- self.printEventDetails(txn, result)
+ yield self.printEventDetails(txn, result)
else:
print("Could not find icalendar data")
@@ -693,7 +695,7 @@
rows = yield self.getData(txn, uid)
if rows:
for result in rows:
- self.printEventDetails(txn, result)
+ yield self.printEventDetails(txn, result)
else:
print("Could not find icalendar data")
@@ -772,7 +774,7 @@
event = yield calendar.calendarObjectWithName(name)
ical_data = yield event.component()
ical_data = PerUserDataFilter(uid).filter(ical_data)
- ical_data.stripKnownTimezones()
+ ical_data.stripStandardTimezones()
table = tables.Table()
table.addRow(("Calendar:", calendar.name(),))
@@ -782,7 +784,7 @@
table.addRow(("Modified", event.modified()))
print("\n")
table.printTable()
- print(ical_data.getTextWithTimezones(includeTimezones=False))
+ print(ical_data.getTextWithoutTimezones())
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/gateway.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/gateway.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/gateway.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -380,7 +380,7 @@
self.respondWithError("Principal not found: %s" % (uid,))
return
recordDict = recordToDict(record)
- # recordDict['AutoSchedule'] = principal.getAutoSchedule()
+ # recordDict['AutoSchedule'] = yield principal.getAutoSchedule()
try:
recordDict['AutoAcceptGroup'] = record.autoAcceptGroup
except AttributeError:
@@ -398,7 +398,7 @@
# Resources
def command_getResourceList(self, command):
- self.respondWithRecordsOfTypes(self.dir, command, ["resources"])
+ return self.respondWithRecordsOfTypes(self.dir, command, ["resources"])
# deferred
@@ -416,7 +416,7 @@
def _delete(self, typeName, command):
uid = command['GeneratedUID']
yield self.dir.removeRecords([uid])
- self.respondWithRecordsOfTypes(self.dir, command, [typeName])
+ yield self.respondWithRecordsOfTypes(self.dir, command, [typeName])
@inlineCallbacks
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/principals.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/principals.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/principals.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -409,12 +409,15 @@
)
)
print(" UID: {u}".format(u=record.uid,))
- print(
- " Record name{plural}: {names}".format(
- plural=("s" if len(record.shortNames) > 1 else ""),
- names=(", ".join(record.shortNames))
+ try:
+ print(
+ " Record name{plural}: {names}".format(
+ plural=("s" if len(record.shortNames) > 1 else ""),
+ names=(", ".join(record.shortNames))
+ )
)
- )
+ except AttributeError:
+ pass
try:
if record.emailAddresses:
print(
@@ -787,7 +790,9 @@
txn = store.newTransaction()
groupUIDs = yield txn.allGroupDelegates()
for groupUID in groupUIDs:
- groupID, name, _ignore_membershipHash, modified = yield txn.groupByUID(
+ (
+ groupID, name, _ignore_membershipHash, modified, extant
+ ) = yield txn.groupByUID(
groupUID
)
print("Group: \"{name}\" ({uid})".format(name=name, uid=groupUID))
@@ -803,7 +808,7 @@
)
print("Group members:")
- memberUIDs = yield txn.membersOfGroup(groupID)
+ memberUIDs = yield txn.groupMemberUIDs(groupID)
for memberUID in memberUIDs:
record = yield directory.recordWithUID(memberUID)
print(prettyRecord(record))
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/purge.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/purge.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/purge.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -234,6 +234,7 @@
# Check for pending scheduling operations
sow = schema.SCHEDULE_ORGANIZER_WORK
+ sosw = schema.SCHEDULE_ORGANIZER_SEND_WORK
srw = schema.SCHEDULE_REPLY_WORK
srcw = schema.SCHEDULE_REPLY_CANCEL_WORK
rows = yield Select(
@@ -242,14 +243,21 @@
Where=(sow.HOME_RESOURCE_ID == self.homeResourceID),
SetExpression=Union(
Select(
- [srw.HOME_RESOURCE_ID],
- From=srw,
- Where=(srw.HOME_RESOURCE_ID == self.homeResourceID),
+ [sosw.HOME_RESOURCE_ID],
+ From=sosw,
+ Where=(sosw.HOME_RESOURCE_ID == self.homeResourceID),
SetExpression=Union(
Select(
- [srcw.HOME_RESOURCE_ID],
- From=srcw,
- Where=(srcw.HOME_RESOURCE_ID == self.homeResourceID),
+ [srw.HOME_RESOURCE_ID],
+ From=srw,
+ Where=(srw.HOME_RESOURCE_ID == self.homeResourceID),
+ SetExpression=Union(
+ Select(
+ [srcw.HOME_RESOURCE_ID],
+ From=srcw,
+ Where=(srcw.HOME_RESOURCE_ID == self.homeResourceID),
+ )
+ ),
)
),
)
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/cmd.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/cmd.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/cmd.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -163,6 +163,7 @@
returnValue(())
+ @inlineCallbacks
def directoryRecordWithID(self, id):
"""
Obtains a directory record corresponding to the given C{id}.
@@ -173,7 +174,7 @@
"""
directory = self.protocol.service.directory
- record = directory.recordWithUID(id)
+ record = yield directory.recordWithUID(id)
if not record:
# Try type:name form
@@ -182,9 +183,9 @@
except ValueError:
pass
else:
- record = directory.recordWithShortName(recordType, shortName)
+ record = yield directory.recordWithShortName(recordType, shortName)
- return record
+ returnValue(record)
def commands(self, showHidden=False):
@@ -628,7 +629,7 @@
directory = self.protocol.service.directory
- record = self.directoryRecordWithID(id)
+ record = yield self.directoryRecordWithID(id)
if record:
self.terminal.write((yield recordInfo(directory, record)))
@@ -657,7 +658,7 @@
records = []
for id in tokens:
- record = self.directoryRecordWithID(id)
+ record = yield self.directoryRecordWithID(id)
records.append(record)
if not record:
@@ -701,6 +702,7 @@
# Sharing
#
+ @inlineCallbacks
def cmd_share(self, tokens):
"""
Share a resource with a principal.
@@ -715,12 +717,12 @@
mode = tokens.pop(0)
principalID = tokens.pop(0)
- record = self.directoryRecordWithID(principalID)
+ record = yield self.directoryRecordWithID(principalID)
if not record:
self.terminal.write("Principal not found: %s\n" % (principalID,))
- targets = self.getTargets(tokens)
+ targets = yield self.getTargets(tokens)
if mode == "r":
mode = None
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/directory.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/directory.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/directory.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -155,7 +155,7 @@
# I don't know how to get DirectoryRecord objects for the proxyUID here, so, let's cheat for now.
proxyUID, proxyType = proxyUID.split("#")
if (proxyUID, proxyType) not in proxyInfoSeen:
- proxyRecord = directory.recordWithUID(proxyUID)
+ proxyRecord = yield directory.recordWithUID(proxyUID)
rows.append((proxyUID, proxyRecord.recordType, proxyRecord.shortNames[0], proxyRecord.fullName, proxyType))
proxyInfoSeen.add((proxyUID, proxyType))
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/vfs.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/vfs.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/shell/vfs.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -290,10 +290,11 @@
# FIXME: Merge in directory UIDs also?
# FIXME: Add directory info (eg. name) to list entry
+ @inlineCallbacks
def addResult(ignoredTxn, home):
uid = home.uid()
- record = self.service.directory.recordWithUID(uid)
+ record = yield self.service.directory.recordWithUID(uid)
if record:
info = {
"Record Type": record.recordType,
@@ -331,12 +332,13 @@
)
+ @inlineCallbacks
def list(self):
names = set()
- for record in self.service.directory.recordsWithRecordType(
+ for record in (yield self.service.directory.recordsWithRecordType(
self.recordType
- ):
+ )):
for shortName in record.shortNames:
if shortName in names:
continue
@@ -395,6 +397,7 @@
Folder.__init__(self, service, path)
if record is None:
+ # FIXME: recordWithUID returns a Deferred but we cannot return or yield it in an __init__ method
record = self.service.directory.recordWithUID(uid)
if record is not None:
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/deprovision/caldavd.plist
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/deprovision/caldavd.plist 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/deprovision/caldavd.plist 2014-07-08 07:05:29 UTC (rev 13732)
@@ -115,12 +115,6 @@
<key>MaxAttendeesPerInstance</key>
<integer>100</integer>
- <!-- Maximum number of instances allowed for a single RRULE -->
- <!-- 0 for no limit -->
- <key>MaxInstancesForRRULE</key>
- <integer>400</integer>
-
-
<!--
Directory service
@@ -135,7 +129,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.xmlfile.XMLDirectoryService</string>
-
+
<key>params</key>
<dict>
<key>xmlFile</key>
@@ -155,7 +149,7 @@
<true/>
<key>type</key>
<string>twistedcaldav.directory.xmlfile.XMLDirectoryService</string>
-
+
<key>params</key>
<dict>
<key>xmlFile</key>
@@ -167,14 +161,14 @@
</array>
</dict>
</dict>
-
+
<!-- Open Directory Service (Mac OS X) -->
<!--
<key>DirectoryService</key>
<dict>
<key>type</key>
<string>twistedcaldav.directory.appleopendirectory.OpenDirectoryService</string>
-
+
<key>params</key>
<dict>
<key>node</key>
@@ -198,7 +192,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.augment.AugmentXMLDB</string>
-
+
<key>params</key>
<dict>
<key>xmlFiles</key>
@@ -207,14 +201,14 @@
</array>
</dict>
</dict>
-
+
<!-- Sqlite Augment Service -->
<!--
<key>AugmentService</key>
<dict>
<key>type</key>
<string>twistedcaldav.directory.augment.AugmentSqliteDB</string>
-
+
<key>params</key>
<dict>
<key>dbpath</key>
@@ -229,7 +223,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.augment.AugmentPostgreSQLDB</string>
-
+
<key>params</key>
<dict>
<key>host</key>
@@ -245,7 +239,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.calendaruserproxy.ProxySqliteDB</string>
-
+
<key>params</key>
<dict>
<key>dbpath</key>
@@ -259,7 +253,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.calendaruserproxy.ProxyPostgreSQLDB</string>
-
+
<key>params</key>
<dict>
<key>host</key>
@@ -687,7 +681,7 @@
<!-- Support for Content-Encoding compression options as specified in RFC2616 Section 3.5 -->
<key>ResponseCompression</key>
<false/>
-
+
<!-- The retry-after value (in seconds) to return with a 503 error. -->
<key>HTTPRetryAfter</key>
<integer>180</integer>
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/gateway/caldavd.plist
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/gateway/caldavd.plist 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/gateway/caldavd.plist 2014-07-08 07:05:29 UTC (rev 13732)
@@ -127,12 +127,6 @@
<key>MaxAttendeesPerInstance</key>
<integer>100</integer>
- <!-- Maximum number of instances allowed for a single RRULE -->
- <!-- 0 for no limit -->
- <key>MaxInstancesForRRULE</key>
- <integer>400</integer>
-
-
<!--
Directory service
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/principals/caldavd.plist
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/principals/caldavd.plist 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/principals/caldavd.plist 2014-07-08 07:05:29 UTC (rev 13732)
@@ -119,12 +119,6 @@
<key>MaxAttendeesPerInstance</key>
<integer>100</integer>
- <!-- Maximum number of instances allowed for a single RRULE -->
- <!-- 0 for no limit -->
- <key>MaxInstancesForRRULE</key>
- <integer>400</integer>
-
-
<!--
Directory service
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/test_calverify.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/test_calverify.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/test/test_calverify.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -2541,9 +2541,9 @@
UID:INVITE_VALID_ORGANIZER_ICS
DTSTART:%(now_fwd11)s
DURATION:PT1H
-ATTENDEE;CN=Example User1;EMAIL=example1 at example.com:urn:x-uid:%(uuid1)s
-ATTENDEE;CN=Example User2;EMAIL=example2 at example.com:urn:x-uid:%(uuid2)s
-ORGANIZER;CN=Example User1;EMAIL=example1 at example.com:urn:x-uid:%(uuid1)s
+ATTENDEE:urn:x-uid:%(uuid1)s
+ATTENDEE:urn:x-uid:%(uuid2)s
+ORGANIZER:urn:x-uid:%(uuid1)s
RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
RRULE:FREQ=DAILY
SEQUENCE:1
@@ -2560,9 +2560,9 @@
UID:INVITE_VALID_ORGANIZER_ICS
DTSTART:%(now_fwd11)s
DURATION:PT1H
-ATTENDEE;CN=Example User1;EMAIL=example1 at example.com:urn:x-uid:%(uuid1)s
-ATTENDEE;CN=Example User2;EMAIL=example2 at example.com:urn:x-uid:%(uuid2)s
-ORGANIZER;CN=Example User1;EMAIL=example1 at example.com:urn:x-uid:%(uuid1)s
+ATTENDEE:urn:x-uid:%(uuid1)s
+ATTENDEE:urn:x-uid:%(uuid2)s
+ORGANIZER:urn:x-uid:%(uuid1)s
RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
RRULE:FREQ=DAILY
SEQUENCE:1
@@ -2579,9 +2579,9 @@
UID:%(uid)s
DTSTART:%(now)s
DURATION:PT1H
-ATTENDEE;CN=Example User1;EMAIL=example1 at example.com:urn:x-uid:%(uuid1)s
-ATTENDEE;CN=Example User2;EMAIL=example2 at example.com:urn:x-uid:%(uuid2)s
-ORGANIZER;CN=Example User1;EMAIL=example1 at example.com:urn:x-uid:%(uuid1)s
+ATTENDEE:urn:x-uid:%(uuid1)s
+ATTENDEE:urn:x-uid:%(uuid2)s
+ORGANIZER:urn:x-uid:%(uuid1)s
RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
RRULE:FREQ=DAILY;UNTIL=%(now_fwd11_1)s
SEQUENCE:1
@@ -2598,9 +2598,9 @@
UID:%(uid)s
DTSTART:%(now)s
DURATION:PT1H
-ATTENDEE;CN=Example User1;EMAIL=example1 at example.com:urn:x-uid:%(uuid1)s
-ATTENDEE;CN=Example User2;EMAIL=example2 at example.com:urn:x-uid:%(uuid2)s
-ORGANIZER;CN=Example User1;EMAIL=example1 at example.com:urn:x-uid:%(uuid1)s
+ATTENDEE:urn:x-uid:%(uuid1)s
+ATTENDEE:urn:x-uid:%(uuid2)s
+ORGANIZER:urn:x-uid:%(uuid1)s
RELATED-TO;RELTYPE=X-CALENDARSERVER-RECURRENCE-SET:%(relID)s
RRULE:FREQ=DAILY;UNTIL=%(now_fwd11_1)s
SEQUENCE:1
Modified: CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/util.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/util.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/calendarserver/tools/util.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -560,11 +560,15 @@
def prettyRecord(record):
+ try:
+ shortNames = record.shortNames
+ except AttributeError:
+ shortNames = []
return "\"{d}\" {uid} ({rt}) {sn}".format(
d=record.displayName,
rt=record.recordType.name,
uid=record.uid,
- sn=(", ".join(record.shortNames))
+ sn=(", ".join(shortNames))
)
Modified: CalendarServer/branches/users/gaya/groupsharee2/conf/auth/generate_test_accounts.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/conf/auth/generate_test_accounts.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/conf/auth/generate_test_accounts.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -24,6 +24,8 @@
"""
+EXTRA_GROUPS = False
+
# The uids and guids for CDT test accounts are the same
# The short name is of the form userNN
USERGUIDS = "10000000-0000-0000-0000-000000000%03d"
@@ -58,7 +60,7 @@
""".format(uid=uid, guid=guid, fullName=fullName))
# user01-100
-for i in xrange(1, 101):
+for i in xrange(1, 501 if EXTRA_GROUPS else 101):
out.write("""<record type="user">
<uid>{guid}</uid>
<guid>{guid}</guid>
@@ -92,6 +94,621 @@
GROUPGUIDS % 7: (USERGUIDS % 22, USERGUIDS % 23, USERGUIDS % 24),
}
+if EXTRA_GROUPS:
+ members.update({
+ GROUPGUIDS % 8: (
+ USERGUIDS % 1,
+ USERGUIDS % 2,
+ USERGUIDS % 3,
+ USERGUIDS % 4,
+ USERGUIDS % 5,
+ ),
+ GROUPGUIDS % 9: (
+ USERGUIDS % 1,
+ USERGUIDS % 2,
+ USERGUIDS % 3,
+ USERGUIDS % 4,
+ USERGUIDS % 5,
+ USERGUIDS % 6,
+ USERGUIDS % 7,
+ USERGUIDS % 8,
+ USERGUIDS % 9,
+ USERGUIDS % 10,
+ USERGUIDS % 11,
+ USERGUIDS % 12,
+ USERGUIDS % 13,
+ USERGUIDS % 14,
+ USERGUIDS % 15,
+ USERGUIDS % 16,
+ USERGUIDS % 17,
+ USERGUIDS % 18,
+ USERGUIDS % 19,
+ USERGUIDS % 20,
+ USERGUIDS % 21,
+ USERGUIDS % 22,
+ USERGUIDS % 23,
+ USERGUIDS % 24,
+ USERGUIDS % 25,
+ USERGUIDS % 26,
+ USERGUIDS % 27,
+ USERGUIDS % 28,
+ USERGUIDS % 29,
+ USERGUIDS % 30,
+ USERGUIDS % 31,
+ USERGUIDS % 32,
+ USERGUIDS % 33,
+ USERGUIDS % 34,
+ USERGUIDS % 35,
+ USERGUIDS % 36,
+ USERGUIDS % 37,
+ USERGUIDS % 38,
+ USERGUIDS % 39,
+ USERGUIDS % 40,
+ USERGUIDS % 41,
+ USERGUIDS % 42,
+ USERGUIDS % 43,
+ USERGUIDS % 44,
+ USERGUIDS % 45,
+ USERGUIDS % 46,
+ USERGUIDS % 47,
+ USERGUIDS % 48,
+ USERGUIDS % 49,
+ USERGUIDS % 50,
+ USERGUIDS % 51,
+ USERGUIDS % 52,
+ USERGUIDS % 53,
+ USERGUIDS % 54,
+ USERGUIDS % 55,
+ USERGUIDS % 56,
+ USERGUIDS % 57,
+ USERGUIDS % 58,
+ USERGUIDS % 59,
+ USERGUIDS % 60,
+ USERGUIDS % 61,
+ USERGUIDS % 62,
+ USERGUIDS % 63,
+ USERGUIDS % 64,
+ USERGUIDS % 65,
+ USERGUIDS % 66,
+ USERGUIDS % 67,
+ USERGUIDS % 68,
+ USERGUIDS % 69,
+ USERGUIDS % 70,
+ USERGUIDS % 71,
+ USERGUIDS % 72,
+ USERGUIDS % 73,
+ USERGUIDS % 74,
+ USERGUIDS % 75,
+ USERGUIDS % 76,
+ USERGUIDS % 77,
+ USERGUIDS % 78,
+ USERGUIDS % 79,
+ USERGUIDS % 80,
+ USERGUIDS % 81,
+ USERGUIDS % 82,
+ USERGUIDS % 83,
+ USERGUIDS % 84,
+ USERGUIDS % 85,
+ USERGUIDS % 86,
+ USERGUIDS % 87,
+ USERGUIDS % 88,
+ USERGUIDS % 89,
+ USERGUIDS % 90,
+ USERGUIDS % 91,
+ USERGUIDS % 92,
+ USERGUIDS % 93,
+ USERGUIDS % 94,
+ USERGUIDS % 95,
+ USERGUIDS % 96,
+ USERGUIDS % 97,
+ USERGUIDS % 98,
+ USERGUIDS % 99,
+ USERGUIDS % 100,
+ ),
+ GROUPGUIDS % 10: (
+ USERGUIDS % 1,
+ USERGUIDS % 2,
+ USERGUIDS % 3,
+ USERGUIDS % 4,
+ USERGUIDS % 5,
+ USERGUIDS % 6,
+ USERGUIDS % 7,
+ USERGUIDS % 8,
+ USERGUIDS % 9,
+ USERGUIDS % 10,
+ USERGUIDS % 11,
+ USERGUIDS % 12,
+ USERGUIDS % 13,
+ USERGUIDS % 14,
+ USERGUIDS % 15,
+ USERGUIDS % 16,
+ USERGUIDS % 17,
+ USERGUIDS % 18,
+ USERGUIDS % 19,
+ USERGUIDS % 20,
+ USERGUIDS % 21,
+ USERGUIDS % 22,
+ USERGUIDS % 23,
+ USERGUIDS % 24,
+ USERGUIDS % 25,
+ USERGUIDS % 26,
+ USERGUIDS % 27,
+ USERGUIDS % 28,
+ USERGUIDS % 29,
+ USERGUIDS % 30,
+ USERGUIDS % 31,
+ USERGUIDS % 32,
+ USERGUIDS % 33,
+ USERGUIDS % 34,
+ USERGUIDS % 35,
+ USERGUIDS % 36,
+ USERGUIDS % 37,
+ USERGUIDS % 38,
+ USERGUIDS % 39,
+ USERGUIDS % 40,
+ USERGUIDS % 41,
+ USERGUIDS % 42,
+ USERGUIDS % 43,
+ USERGUIDS % 44,
+ USERGUIDS % 45,
+ USERGUIDS % 46,
+ USERGUIDS % 47,
+ USERGUIDS % 48,
+ USERGUIDS % 49,
+ USERGUIDS % 50,
+ USERGUIDS % 51,
+ USERGUIDS % 52,
+ USERGUIDS % 53,
+ USERGUIDS % 54,
+ USERGUIDS % 55,
+ USERGUIDS % 56,
+ USERGUIDS % 57,
+ USERGUIDS % 58,
+ USERGUIDS % 59,
+ USERGUIDS % 60,
+ USERGUIDS % 61,
+ USERGUIDS % 62,
+ USERGUIDS % 63,
+ USERGUIDS % 64,
+ USERGUIDS % 65,
+ USERGUIDS % 66,
+ USERGUIDS % 67,
+ USERGUIDS % 68,
+ USERGUIDS % 69,
+ USERGUIDS % 70,
+ USERGUIDS % 71,
+ USERGUIDS % 72,
+ USERGUIDS % 73,
+ USERGUIDS % 74,
+ USERGUIDS % 75,
+ USERGUIDS % 76,
+ USERGUIDS % 77,
+ USERGUIDS % 78,
+ USERGUIDS % 79,
+ USERGUIDS % 80,
+ USERGUIDS % 81,
+ USERGUIDS % 82,
+ USERGUIDS % 83,
+ USERGUIDS % 84,
+ USERGUIDS % 85,
+ USERGUIDS % 86,
+ USERGUIDS % 87,
+ USERGUIDS % 88,
+ USERGUIDS % 89,
+ USERGUIDS % 90,
+ USERGUIDS % 91,
+ USERGUIDS % 92,
+ USERGUIDS % 93,
+ USERGUIDS % 94,
+ USERGUIDS % 95,
+ USERGUIDS % 96,
+ USERGUIDS % 97,
+ USERGUIDS % 98,
+ USERGUIDS % 99,
+ USERGUIDS % 100,
+ USERGUIDS % 101,
+ USERGUIDS % 102,
+ USERGUIDS % 103,
+ USERGUIDS % 104,
+ USERGUIDS % 105,
+ USERGUIDS % 106,
+ USERGUIDS % 107,
+ USERGUIDS % 108,
+ USERGUIDS % 109,
+ USERGUIDS % 110,
+ USERGUIDS % 111,
+ USERGUIDS % 112,
+ USERGUIDS % 113,
+ USERGUIDS % 114,
+ USERGUIDS % 115,
+ USERGUIDS % 116,
+ USERGUIDS % 117,
+ USERGUIDS % 118,
+ USERGUIDS % 119,
+ USERGUIDS % 120,
+ USERGUIDS % 121,
+ USERGUIDS % 122,
+ USERGUIDS % 123,
+ USERGUIDS % 124,
+ USERGUIDS % 125,
+ USERGUIDS % 126,
+ USERGUIDS % 127,
+ USERGUIDS % 128,
+ USERGUIDS % 129,
+ USERGUIDS % 130,
+ USERGUIDS % 131,
+ USERGUIDS % 132,
+ USERGUIDS % 133,
+ USERGUIDS % 134,
+ USERGUIDS % 135,
+ USERGUIDS % 136,
+ USERGUIDS % 137,
+ USERGUIDS % 138,
+ USERGUIDS % 139,
+ USERGUIDS % 140,
+ USERGUIDS % 141,
+ USERGUIDS % 142,
+ USERGUIDS % 143,
+ USERGUIDS % 144,
+ USERGUIDS % 145,
+ USERGUIDS % 146,
+ USERGUIDS % 147,
+ USERGUIDS % 148,
+ USERGUIDS % 149,
+ USERGUIDS % 150,
+ USERGUIDS % 151,
+ USERGUIDS % 152,
+ USERGUIDS % 153,
+ USERGUIDS % 154,
+ USERGUIDS % 155,
+ USERGUIDS % 156,
+ USERGUIDS % 157,
+ USERGUIDS % 158,
+ USERGUIDS % 159,
+ USERGUIDS % 160,
+ USERGUIDS % 161,
+ USERGUIDS % 162,
+ USERGUIDS % 163,
+ USERGUIDS % 164,
+ USERGUIDS % 165,
+ USERGUIDS % 166,
+ USERGUIDS % 167,
+ USERGUIDS % 168,
+ USERGUIDS % 169,
+ USERGUIDS % 170,
+ USERGUIDS % 171,
+ USERGUIDS % 172,
+ USERGUIDS % 173,
+ USERGUIDS % 174,
+ USERGUIDS % 175,
+ USERGUIDS % 176,
+ USERGUIDS % 177,
+ USERGUIDS % 178,
+ USERGUIDS % 179,
+ USERGUIDS % 180,
+ USERGUIDS % 181,
+ USERGUIDS % 182,
+ USERGUIDS % 183,
+ USERGUIDS % 184,
+ USERGUIDS % 185,
+ USERGUIDS % 186,
+ USERGUIDS % 187,
+ USERGUIDS % 188,
+ USERGUIDS % 189,
+ USERGUIDS % 190,
+ USERGUIDS % 191,
+ USERGUIDS % 192,
+ USERGUIDS % 193,
+ USERGUIDS % 194,
+ USERGUIDS % 195,
+ USERGUIDS % 196,
+ USERGUIDS % 197,
+ USERGUIDS % 198,
+ USERGUIDS % 199,
+ USERGUIDS % 200,
+ USERGUIDS % 201,
+ USERGUIDS % 202,
+ USERGUIDS % 203,
+ USERGUIDS % 204,
+ USERGUIDS % 205,
+ USERGUIDS % 206,
+ USERGUIDS % 207,
+ USERGUIDS % 208,
+ USERGUIDS % 209,
+ USERGUIDS % 210,
+ USERGUIDS % 211,
+ USERGUIDS % 212,
+ USERGUIDS % 213,
+ USERGUIDS % 214,
+ USERGUIDS % 215,
+ USERGUIDS % 216,
+ USERGUIDS % 217,
+ USERGUIDS % 218,
+ USERGUIDS % 219,
+ USERGUIDS % 220,
+ USERGUIDS % 221,
+ USERGUIDS % 222,
+ USERGUIDS % 223,
+ USERGUIDS % 224,
+ USERGUIDS % 225,
+ USERGUIDS % 226,
+ USERGUIDS % 227,
+ USERGUIDS % 228,
+ USERGUIDS % 229,
+ USERGUIDS % 230,
+ USERGUIDS % 231,
+ USERGUIDS % 232,
+ USERGUIDS % 233,
+ USERGUIDS % 234,
+ USERGUIDS % 235,
+ USERGUIDS % 236,
+ USERGUIDS % 237,
+ USERGUIDS % 238,
+ USERGUIDS % 239,
+ USERGUIDS % 240,
+ USERGUIDS % 241,
+ USERGUIDS % 242,
+ USERGUIDS % 243,
+ USERGUIDS % 244,
+ USERGUIDS % 245,
+ USERGUIDS % 246,
+ USERGUIDS % 247,
+ USERGUIDS % 248,
+ USERGUIDS % 249,
+ USERGUIDS % 250,
+ USERGUIDS % 251,
+ USERGUIDS % 252,
+ USERGUIDS % 253,
+ USERGUIDS % 254,
+ USERGUIDS % 255,
+ USERGUIDS % 256,
+ USERGUIDS % 257,
+ USERGUIDS % 258,
+ USERGUIDS % 259,
+ USERGUIDS % 260,
+ USERGUIDS % 261,
+ USERGUIDS % 262,
+ USERGUIDS % 263,
+ USERGUIDS % 264,
+ USERGUIDS % 265,
+ USERGUIDS % 266,
+ USERGUIDS % 267,
+ USERGUIDS % 268,
+ USERGUIDS % 269,
+ USERGUIDS % 270,
+ USERGUIDS % 271,
+ USERGUIDS % 272,
+ USERGUIDS % 273,
+ USERGUIDS % 274,
+ USERGUIDS % 275,
+ USERGUIDS % 276,
+ USERGUIDS % 277,
+ USERGUIDS % 278,
+ USERGUIDS % 279,
+ USERGUIDS % 280,
+ USERGUIDS % 281,
+ USERGUIDS % 282,
+ USERGUIDS % 283,
+ USERGUIDS % 284,
+ USERGUIDS % 285,
+ USERGUIDS % 286,
+ USERGUIDS % 287,
+ USERGUIDS % 288,
+ USERGUIDS % 289,
+ USERGUIDS % 290,
+ USERGUIDS % 291,
+ USERGUIDS % 292,
+ USERGUIDS % 293,
+ USERGUIDS % 294,
+ USERGUIDS % 295,
+ USERGUIDS % 296,
+ USERGUIDS % 297,
+ USERGUIDS % 298,
+ USERGUIDS % 299,
+ USERGUIDS % 300,
+ USERGUIDS % 301,
+ USERGUIDS % 302,
+ USERGUIDS % 303,
+ USERGUIDS % 304,
+ USERGUIDS % 305,
+ USERGUIDS % 306,
+ USERGUIDS % 307,
+ USERGUIDS % 308,
+ USERGUIDS % 309,
+ USERGUIDS % 310,
+ USERGUIDS % 311,
+ USERGUIDS % 312,
+ USERGUIDS % 313,
+ USERGUIDS % 314,
+ USERGUIDS % 315,
+ USERGUIDS % 316,
+ USERGUIDS % 317,
+ USERGUIDS % 318,
+ USERGUIDS % 319,
+ USERGUIDS % 320,
+ USERGUIDS % 321,
+ USERGUIDS % 322,
+ USERGUIDS % 323,
+ USERGUIDS % 324,
+ USERGUIDS % 325,
+ USERGUIDS % 326,
+ USERGUIDS % 327,
+ USERGUIDS % 328,
+ USERGUIDS % 329,
+ USERGUIDS % 330,
+ USERGUIDS % 331,
+ USERGUIDS % 332,
+ USERGUIDS % 333,
+ USERGUIDS % 334,
+ USERGUIDS % 335,
+ USERGUIDS % 336,
+ USERGUIDS % 337,
+ USERGUIDS % 338,
+ USERGUIDS % 339,
+ USERGUIDS % 340,
+ USERGUIDS % 341,
+ USERGUIDS % 342,
+ USERGUIDS % 343,
+ USERGUIDS % 344,
+ USERGUIDS % 345,
+ USERGUIDS % 346,
+ USERGUIDS % 347,
+ USERGUIDS % 348,
+ USERGUIDS % 349,
+ USERGUIDS % 350,
+ USERGUIDS % 351,
+ USERGUIDS % 352,
+ USERGUIDS % 353,
+ USERGUIDS % 354,
+ USERGUIDS % 355,
+ USERGUIDS % 356,
+ USERGUIDS % 357,
+ USERGUIDS % 358,
+ USERGUIDS % 359,
+ USERGUIDS % 360,
+ USERGUIDS % 361,
+ USERGUIDS % 362,
+ USERGUIDS % 363,
+ USERGUIDS % 364,
+ USERGUIDS % 365,
+ USERGUIDS % 366,
+ USERGUIDS % 367,
+ USERGUIDS % 368,
+ USERGUIDS % 369,
+ USERGUIDS % 370,
+ USERGUIDS % 371,
+ USERGUIDS % 372,
+ USERGUIDS % 373,
+ USERGUIDS % 374,
+ USERGUIDS % 375,
+ USERGUIDS % 376,
+ USERGUIDS % 377,
+ USERGUIDS % 378,
+ USERGUIDS % 379,
+ USERGUIDS % 380,
+ USERGUIDS % 381,
+ USERGUIDS % 382,
+ USERGUIDS % 383,
+ USERGUIDS % 384,
+ USERGUIDS % 385,
+ USERGUIDS % 386,
+ USERGUIDS % 387,
+ USERGUIDS % 388,
+ USERGUIDS % 389,
+ USERGUIDS % 390,
+ USERGUIDS % 391,
+ USERGUIDS % 392,
+ USERGUIDS % 393,
+ USERGUIDS % 394,
+ USERGUIDS % 395,
+ USERGUIDS % 396,
+ USERGUIDS % 397,
+ USERGUIDS % 398,
+ USERGUIDS % 399,
+ USERGUIDS % 400,
+ USERGUIDS % 401,
+ USERGUIDS % 402,
+ USERGUIDS % 403,
+ USERGUIDS % 404,
+ USERGUIDS % 405,
+ USERGUIDS % 406,
+ USERGUIDS % 407,
+ USERGUIDS % 408,
+ USERGUIDS % 409,
+ USERGUIDS % 410,
+ USERGUIDS % 411,
+ USERGUIDS % 412,
+ USERGUIDS % 413,
+ USERGUIDS % 414,
+ USERGUIDS % 415,
+ USERGUIDS % 416,
+ USERGUIDS % 417,
+ USERGUIDS % 418,
+ USERGUIDS % 419,
+ USERGUIDS % 420,
+ USERGUIDS % 421,
+ USERGUIDS % 422,
+ USERGUIDS % 423,
+ USERGUIDS % 424,
+ USERGUIDS % 425,
+ USERGUIDS % 426,
+ USERGUIDS % 427,
+ USERGUIDS % 428,
+ USERGUIDS % 429,
+ USERGUIDS % 430,
+ USERGUIDS % 431,
+ USERGUIDS % 432,
+ USERGUIDS % 433,
+ USERGUIDS % 434,
+ USERGUIDS % 435,
+ USERGUIDS % 436,
+ USERGUIDS % 437,
+ USERGUIDS % 438,
+ USERGUIDS % 439,
+ USERGUIDS % 440,
+ USERGUIDS % 441,
+ USERGUIDS % 442,
+ USERGUIDS % 443,
+ USERGUIDS % 444,
+ USERGUIDS % 445,
+ USERGUIDS % 446,
+ USERGUIDS % 447,
+ USERGUIDS % 448,
+ USERGUIDS % 449,
+ USERGUIDS % 450,
+ USERGUIDS % 451,
+ USERGUIDS % 452,
+ USERGUIDS % 453,
+ USERGUIDS % 454,
+ USERGUIDS % 455,
+ USERGUIDS % 456,
+ USERGUIDS % 457,
+ USERGUIDS % 458,
+ USERGUIDS % 459,
+ USERGUIDS % 460,
+ USERGUIDS % 461,
+ USERGUIDS % 462,
+ USERGUIDS % 463,
+ USERGUIDS % 464,
+ USERGUIDS % 465,
+ USERGUIDS % 466,
+ USERGUIDS % 467,
+ USERGUIDS % 468,
+ USERGUIDS % 469,
+ USERGUIDS % 470,
+ USERGUIDS % 471,
+ USERGUIDS % 472,
+ USERGUIDS % 473,
+ USERGUIDS % 474,
+ USERGUIDS % 475,
+ USERGUIDS % 476,
+ USERGUIDS % 477,
+ USERGUIDS % 478,
+ USERGUIDS % 479,
+ USERGUIDS % 480,
+ USERGUIDS % 481,
+ USERGUIDS % 482,
+ USERGUIDS % 483,
+ USERGUIDS % 484,
+ USERGUIDS % 485,
+ USERGUIDS % 486,
+ USERGUIDS % 487,
+ USERGUIDS % 488,
+ USERGUIDS % 489,
+ USERGUIDS % 490,
+ USERGUIDS % 491,
+ USERGUIDS % 492,
+ USERGUIDS % 493,
+ USERGUIDS % 494,
+ USERGUIDS % 495,
+ USERGUIDS % 496,
+ USERGUIDS % 497,
+ USERGUIDS % 498,
+ USERGUIDS % 499,
+ USERGUIDS % 500,
+ ),
+})
+
for i in xrange(1, 101):
memberElements = []
Modified: CalendarServer/branches/users/gaya/groupsharee2/conf/caldavd-test.plist
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/conf/caldavd-test.plist 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/conf/caldavd-test.plist 2014-07-08 07:05:29 UTC (rev 13732)
@@ -816,6 +816,8 @@
<dict>
<key>Enabled</key>
<true/>
+
+ <!-- Make these short for testing -->
<key>RequestDelaySeconds</key>
<real>0.1</real>
<key>ReplyDelaySeconds</key>
@@ -830,6 +832,14 @@
</dict>
</dict>
+ <key>WorkQueue</key>
+ <dict>
+ <!-- Make these short for testing -->
+ <key>failureRescheduleInterval</key>
+ <integer>1</integer>
+ <key>lockRescheduleInterval</key>
+ <integer>1</integer>
+ </dict>
<!--
Free-busy URL protocol
Modified: CalendarServer/branches/users/gaya/groupsharee2/conf/resources/caldavd-resources.plist
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/conf/resources/caldavd-resources.plist 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/conf/resources/caldavd-resources.plist 2014-07-08 07:05:29 UTC (rev 13732)
@@ -99,12 +99,6 @@
<key>MaxAttendeesPerInstance</key>
<integer>100</integer>
- <!-- Maximum number of instances allowed for a single RRULE -->
- <!-- 0 for no limit -->
- <key>MaxInstancesForRRULE</key>
- <integer>400</integer>
-
-
<!--
Directory service
@@ -119,7 +113,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.xmlfile.XMLDirectoryService</string>
-
+
<key>params</key>
<dict>
<key>xmlFile</key>
@@ -131,14 +125,14 @@
</array>
</dict>
</dict>
-
+
<key>ResourceService</key>
<dict>
<key>Enabled</key>
<true/>
<key>type</key>
<string>twistedcaldav.directory.xmlfile.XMLDirectoryService</string>
-
+
<key>params</key>
<dict>
<key>xmlFile</key>
@@ -150,14 +144,14 @@
</array>
</dict>
</dict>
-
+
<!-- Open Directory Service (Mac OS X) -->
<!--
<key>DirectoryService</key>
<dict>
<key>type</key>
<string>twistedcaldav.directory.appleopendirectory.OpenDirectoryService</string>
-
+
<key>params</key>
<dict>
<key>node</key>
@@ -181,7 +175,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.augment.AugmentXMLDB</string>
-
+
<key>params</key>
<dict>
<key>xmlFiles</key>
@@ -190,14 +184,14 @@
</array>
</dict>
</dict>
-
+
<!-- Sqlite Augment Service -->
<!--
<key>AugmentService</key>
<dict>
<key>type</key>
<string>twistedcaldav.directory.augment.AugmentSqliteDB</string>
-
+
<key>params</key>
<dict>
<key>dbpath</key>
@@ -212,7 +206,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.augment.AugmentPostgreSQLDB</string>
-
+
<key>params</key>
<dict>
<key>host</key>
@@ -228,7 +222,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.calendaruserproxy.ProxySqliteDB</string>
-
+
<key>params</key>
<dict>
<key>dbpath</key>
@@ -242,7 +236,7 @@
<dict>
<key>type</key>
<string>twistedcaldav.directory.calendaruserproxy.ProxyPostgreSQLDB</string>
-
+
<key>params</key>
<dict>
<key>host</key>
@@ -672,7 +666,7 @@
<!-- Support for Content-Encoding compression -->
<key>ResponseCompression</key>
<false/>
-
+
<!-- The retry-after value (in seconds) to return with a 503 error. -->
<key>HTTPRetryAfter</key>
<integer>180</integer>
Modified: CalendarServer/branches/users/gaya/groupsharee2/contrib/performance/loadtest/ical.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/contrib/performance/loadtest/ical.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/contrib/performance/loadtest/ical.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -1477,7 +1477,7 @@
)
# Finally, re-retrieve the event to update the etag
- self._updateEvent(response, href)
+ yield self._updateEvent(response, href)
@inlineCallbacks
Modified: CalendarServer/branches/users/gaya/groupsharee2/requirements-dev.txt
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/requirements-dev.txt 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/requirements-dev.txt 2014-07-08 07:05:29 UTC (rev 13732)
@@ -7,4 +7,4 @@
mockldap
q
--editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVClientLibrary/trunk@13420#egg=CalDAVClientLibrary
---editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@13670#egg=CalDAVTester
+--editable svn+http://svn.calendarserver.org/repository/calendarserver/CalDAVTester/trunk@13716#egg=CalDAVTester
Modified: CalendarServer/branches/users/gaya/groupsharee2/requirements-stable.txt
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/requirements-stable.txt 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/requirements-stable.txt 2014-07-08 07:05:29 UTC (rev 13732)
@@ -5,9 +5,9 @@
# For CalendarServer development, don't try to get these projects from PyPI; use svn.
-e .
--e svn+http://svn.calendarserver.org/repository/calendarserver/twext/trunk@13660#egg=twextpy
+-e svn+http://svn.calendarserver.org/repository/calendarserver/twext/trunk@13724#egg=twextpy
-e svn+http://svn.calendarserver.org/repository/calendarserver/PyKerberos/trunk@13420#egg=kerberos
--e svn+http://svn.calendarserver.org/repository/calendarserver/PyCalendar/trunk@13621#egg=pycalendar
+-e svn+http://svn.calendarserver.org/repository/calendarserver/PyCalendar/trunk@13711#egg=pycalendar
# Specify specific versions of our dependencies so that we're all testing the same config.
Modified: CalendarServer/branches/users/gaya/groupsharee2/setup.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/setup.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/setup.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -256,17 +256,8 @@
extensions = []
-# if sys.platform == "darwin":
-# extensions.append(
-# Extension(
-# "calendarserver.platform.darwin._sacl",
-# extra_link_args=["-framework", "Security"],
-# sources=["calendarserver/platform/darwin/_sacl.c"]
-# )
-# )
-
#
# Run setup
#
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/datafilters/hiddeninstance.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/datafilters/hiddeninstance.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/datafilters/hiddeninstance.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -15,7 +15,7 @@
##
from twistedcaldav.datafilters.filter import CalendarFilter
-from twistedcaldav.ical import Component, ignoredComponents, Property
+from twistedcaldav.ical import Component, ignoredComponents
__all__ = [
"HiddenInstanceFilter",
@@ -50,10 +50,7 @@
# Add EXDATE and try to preserve same timezone as DTSTART
if master is not None:
- dtstart = master.getProperty("DTSTART")
- if dtstart is not None and not dtstart.value().isDateOnly() and dtstart.value().local():
- rid.adjustTimezone(dtstart.value().getTimezone())
- master.addProperty(Property("EXDATE", [rid, ]))
+ master.addExdate(rid)
return ical
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/augment.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/augment.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/augment.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -504,8 +504,7 @@
Remove all records.
"""
- self.removeAugmentRecords(self.db.keys())
- return succeed(None)
+ return self.removeAugmentRecords(self.db.keys())
def _shouldReparse(self, xmlFiles):
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/calendaruserproxy.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/calendaruserproxy.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -858,7 +858,7 @@
yield self.open()
for group in [row[0] for row in (yield self.query("select GROUPNAME from GROUPS"))]:
- self.removeGroup(group)
+ yield self.removeGroup(group)
yield super(ProxyDB, self).clean()
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/digest.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/digest.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/digest.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -167,8 +167,7 @@
header.
"""
- challenge = yield (super(QopDigestCredentialFactory, self)
- .getChallenge(peer))
+ challenge = yield (super(QopDigestCredentialFactory, self).getChallenge(peer))
c = challenge['nonce']
# Make sure it is not a duplicate
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/principal.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/principal.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -290,15 +290,17 @@
#
# Create children
#
-
- self.supportedChildTypes = (
+ self.supportedChildTypes = [
self.directory.recordType.user,
self.directory.recordType.group,
self.directory.recordType.location,
self.directory.recordType.resource,
self.directory.recordType.address,
- self.directory.recordType.macOSXServerWiki,
- )
+ ]
+ if config.Authentication.Wiki.Enabled:
+ self.supportedChildTypes.append(
+ self.directory.recordType.macOSXServerWiki
+ )
for name, recordType in [
(self.directory.recordTypeToOldName(r), r)
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/test/test_principal.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/test/test_principal.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -97,7 +97,9 @@
self.directory.recordType.location,
self.directory.recordType.resource,
self.directory.recordType.address,
- self.directory.recordType.macOSXServerWiki,
+ # FIXME: add a test where wikis are enabled, then this
+ # resource should appear:
+ # self.directory.recordType.macOSXServerWiki,
)
]
)
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/util.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/util.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/directory/util.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -39,6 +39,7 @@
log = Logger()
+
def uuidFromName(namespace, name):
"""
Generate a version 5 (SHA-1) UUID from a namespace UUID and a name.
@@ -69,6 +70,7 @@
TRANSACTION_KEY = '_newStoreTransaction'
+
def transactionFromRequest(request, newStore):
"""
Return the associated transaction from the given HTTP request, creating a
@@ -97,6 +99,7 @@
else:
authz_uid = None
transaction = newStore.newTransaction(repr(request), authz_uid=authz_uid)
+
def abortIfUncommitted(request, response):
try:
# TODO: missing 'yield' here. For formal correctness as per
@@ -186,7 +189,11 @@
record = principal.parent.record
except:
return None
- return (record.recordType, record.shortNames[0])
+ try:
+ shortName = record.shortNames[0]
+ except AttributeError:
+ shortName = u""
+ return (record.recordType, shortName)
def describe(principal):
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/ical.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/ical.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/ical.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -45,7 +45,7 @@
from twistedcaldav.dateops import timeRangesOverlap, normalizeForIndex, differenceDateTime, \
normalizeForExpand
from twistedcaldav.instance import InstanceList, InvalidOverriddenInstanceError
-from twistedcaldav.timezones import hasTZ, TimezoneException
+from twistedcaldav.timezones import hasTZ
from txdav.caldav.datastore.scheduling.utils import normalizeCUAddr
@@ -602,13 +602,31 @@
def getText(self, format=None):
- return self.getTextWithTimezones(False, format)
+ """
+ Return text representation and include non-standard timezones.
+ """
+ return self._getTextWithTimezones(includeTimezones=Calendar.NONSTD_TIMEZONES, format=format)
def getTextWithTimezones(self, includeTimezones, format=None):
"""
Return text representation and include timezones if the option is on.
"""
+ includeTimezones = Calendar.ALL_TIMEZONES if includeTimezones else Calendar.NONSTD_TIMEZONES
+ return self._getTextWithTimezones(includeTimezones=includeTimezones, format=format)
+
+
+ def getTextWithoutTimezones(self, format=None):
+ """
+ Return text representation without including timezones.
+ """
+ return self._getTextWithTimezones(includeTimezones=Calendar.NO_TIMEZONES, format=format)
+
+
+ def _getTextWithTimezones(self, includeTimezones, format=None):
+ """
+ Return text representation and include timezones if the option is on.
+ """
assert self.name() == "VCALENDAR", "Must be a VCALENDAR: {0!r}".format(self,)
result = self._pycalendar.getText(includeTimezones=includeTimezones, format=format)
@@ -1708,6 +1726,21 @@
return rid in new_rids
+ def addExdate(self, exdate):
+ """
+ Add an EXDATE to a master recurring component and ensure the value type, TZID
+ etc match the DTSTART of the master. This method assumes that L{self} is the
+ master component - no checking of that will be done.
+
+ @param exdate: the exdate to add
+ @type exdate: L{DateTime}
+ """
+ dtstart = self.getProperty("DTSTART")
+ if dtstart is not None and not dtstart.value().isDateOnly() and dtstart.value().local():
+ exdate.adjustTimezone(dtstart.value().getTimezone())
+ self.addProperty(Property("EXDATE", [exdate, ]))
+
+
def resourceUID(self):
"""
@return: the UID of the subcomponents in this component.
@@ -1766,28 +1799,13 @@
return self._resource_type
- def stripKnownTimezones(self):
+ def stripStandardTimezones(self):
"""
Remove timezones that this server knows about
"""
+ return self._pycalendar.stripStandardTimezones()
- changed = False
- for subcomponent in tuple(self.subcomponents()):
- if subcomponent.name() == "VTIMEZONE":
- tzid = subcomponent.propertyValue("TZID")
- try:
- hasTZ(tzid)
- except TimezoneException:
- # tzid not available - do not strip
- pass
- else:
- # tzid known - strip component out
- self.removeComponent(subcomponent)
- changed = True
- return changed
-
-
def validCalendarData(self, doFix=True, doRaise=True, validateRecurrences=False):
"""
@return: tuple of fixed, unfixed issues
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/resource.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/resource.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -886,7 +886,7 @@
@inlineCallbacks
def ownerPrincipal(self, request):
"""
- Return the DAV:owner property value (MUST be a DAV:href or None).
+ Return the principal resource for the owner of this resource.
"""
if hasattr(self, "_newStoreObject"):
if not hasattr(self._newStoreObject, "ownerHome"):
@@ -906,7 +906,7 @@
@inlineCallbacks
def resourceOwnerPrincipal(self, request):
"""
- This is the owner of the resource based on the URI used to access it. For a shared
+ This is the principal resource of the owner of the resource based on the URI used to access it. For a shared
collection it will be the sharee, otherwise it will be the regular the ownerPrincipal.
"""
parent = (yield self.locateParent(
@@ -1884,7 +1884,7 @@
))
# elif name == "auto-schedule" and self.calendarsEnabled():
- # autoSchedule = self.getAutoSchedule()
+ # autoSchedule = yield self.getAutoSchedule()
# returnValue(customxml.AutoSchedule("true" if autoSchedule else "false"))
elif name == "auto-schedule-mode" and self.calendarsEnabled():
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/scheduling_store/caldav/resource.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/scheduling_store/caldav/resource.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/scheduling_store/caldav/resource.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -471,17 +471,13 @@
@inlineCallbacks
def loadOriginatorFromRequestDetails(self, request):
- # Get the originator who is the authenticated user
- originatorPrincipal = None
+ # The originator is the owner of the Outbox. We will have checked prior to this
+ # that the authenticated user has privileges to schedule as the owner.
originator = ""
- authz_principal = self.currentPrincipal(request).children[0]
- if isinstance(authz_principal, davxml.HRef):
- originatorPrincipalURL = str(authz_principal)
- if originatorPrincipalURL:
- originatorPrincipal = (yield request.locateResource(originatorPrincipalURL))
- if originatorPrincipal:
- # Pick the canonical CUA:
- originator = originatorPrincipal.canonicalCalendarUserAddress()
+ originatorPrincipal = (yield self.ownerPrincipal(request))
+ if originatorPrincipal:
+ # Pick the canonical CUA:
+ originator = originatorPrincipal.canonicalCalendarUserAddress()
if not originator:
self.log.error("%s request must have Originator" % (self.method,))
@@ -545,7 +541,8 @@
)
)
else:
- returnValue(super(ScheduleOutboxResource, self).defaultAccessControlList())
+ result = yield super(ScheduleOutboxResource, self).defaultAccessControlList()
+ returnValue(result)
def report_urn_ietf_params_xml_ns_caldav_calendar_query(self, request, calendar_query):
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/stdconfig.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/stdconfig.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -323,7 +323,17 @@
# Work queue configuration information
#
"WorkQueue": {
- "ampPort": 7654, # Port used for hosts in a cluster to take to each other
+ "ampPort": 7654, # Port used for hosts in a cluster to talk to each other
+
+ "queuePollInterval": 0.1, # Interval in seconds for job queue polling
+ "queueOverdueTimeout": 300, # Number of seconds before an assigned job is considered overdue
+
+ "overloadLevel": 95, # Queue capacity (percentage) which causes job processing to halt
+ "highPriorityLevel": 80, # Queue capacity (percentage) at which only high priority items are run
+ "mediumPriorityLevel": 50, # Queue capacity (percentage) at which only high/medium priority items are run
+
+ "failureRescheduleInterval": 60, # When a job fails, reschedule it this number of seconds in the future
+ "lockRescheduleInterval": 60, # When a job can't run because of a lock, reschedule it this number of seconds in the future
},
#
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/storebridge.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/storebridge.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -2888,7 +2888,7 @@
except ResourceDeletedError:
# This is OK - it just means the server deleted the resource during the PUT. We make it look
# like the PUT succeeded.
- response = responsecode.CREATED if self.exists() else responsecode.NO_CONTENT
+ response = responsecode.NO_CONTENT if self.exists() else responsecode.CREATED
# Re-initialize to get stuff setup again now we have no object
self._initializeWithObject(None, self._newStoreParent)
@@ -3622,7 +3622,7 @@
except ResourceDeletedError:
# This is OK - it just means the server deleted the resource during the PUT. We make it look
# like the PUT succeeded.
- response = responsecode.CREATED if self.exists() else responsecode.NO_CONTENT
+ response = responsecode.NO_CONTENT if self.exists() else responsecode.CREATED
# Re-initialize to get stuff setup again now we have no object
self._initializeWithObject(None, self._newStoreParent)
@@ -3804,7 +3804,7 @@
@return: a sequence of the names of all known children of this resource.
"""
children = set(self.putChildren.keys())
- children.update(self._newStoreNotifications.listNotificationObjects())
+ children.update((yield self._newStoreNotifications.listNotificationObjects()))
returnValue(children)
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/test/test_icalendar.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/test/test_icalendar.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/test/test_icalendar.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -5673,6 +5673,93 @@
self.fail("Valid calendar should validate")
+
+
+ def test_add_exdate(self):
+ data = ((
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//iCal 3.0//EN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:FB81D520-ED27-4DBA-8894-45B7612A7621
+DTSTART;TZID=US/Pacific:20090705T100000
+DTEND;TZID=US/Pacific:20090730T103000
+CREATED:20090604T225706Z
+DTSTAMP:20090604T230500Z
+RRULE:FREQ=DAILY
+SEQUENCE:1
+SUMMARY:TEST
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+""",
+ (
+ DateTime(2009, 7, 6, 17, 0, 0, tzid=Timezone(utc=True)),
+ DateTime(2009, 7, 6, 10, 0, 0, tzid=Timezone(tzid="US/Pacific")),
+ ),
+
+ """BEGIN:VCALENDAR
+VERSION:2.0
+CALSCALE:GREGORIAN
+PRODID:-//Apple Inc.//iCal 3.0//EN
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:STANDARD
+DTSTART:20071104T020000
+RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
+TZNAME:PST
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:20070311T020000
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
+TZNAME:PDT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+END:DAYLIGHT
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:FB81D520-ED27-4DBA-8894-45B7612A7621
+DTSTART;TZID=US/Pacific:20090705T100000
+DTEND;TZID=US/Pacific:20090730T103000
+CREATED:20090604T225706Z
+DTSTAMP:20090604T230500Z
+EXDATE;TZID=US/Pacific:20090706T100000
+RRULE:FREQ=DAILY
+SEQUENCE:1
+SUMMARY:TEST
+TRANSP:OPAQUE
+END:VEVENT
+END:VCALENDAR
+""",
+ ))
+
+ for exdate in data[1]:
+ calendar = Component.fromString(data[0])
+ result = Component.fromString(data[2])
+ calendar.masterComponent().addExdate(exdate)
+ self.assertEqual(normalize_iCalStr(calendar), normalize_iCalStr(result), "Failed exdate add: {}".format(exdate))
+
+
def test_allperuseruids(self):
data = """BEGIN:VCALENDAR
VERSION:2.0
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/test/test_upgrade.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/test/test_upgrade.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/test/test_upgrade.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -14,26 +14,26 @@
# limitations under the License.
##
+import cPickle
import hashlib
import os
import zlib
-import cPickle
from twisted.internet.defer import inlineCallbacks, succeed
-
-from txdav.xml.parser import WebDAVDocument
-from txdav.caldav.datastore.index_file import db_basename
-
+from twisted.python.filepath import FilePath
from twistedcaldav.config import config
-from txdav.caldav.datastore.scheduling.imip.mailgateway import MailGatewayTokensDatabase
+from twistedcaldav.directory.calendaruserproxy import ProxySqliteDB
+from twistedcaldav.test.util import StoreTestCase
from twistedcaldav.upgrade import (
xattrname, upgradeData, updateFreeBusySet,
removeIllegalCharacters, normalizeCUAddrs,
- loadDelegatesFromXML, migrateDelegatesToStore
+ loadDelegatesFromXML, migrateDelegatesToStore,
+ upgradeResourcesXML
)
-from twistedcaldav.test.util import StoreTestCase
+from txdav.caldav.datastore.index_file import db_basename
+from txdav.caldav.datastore.scheduling.imip.mailgateway import MailGatewayTokensDatabase
from txdav.who.delegates import delegatesOf
-from twistedcaldav.directory.calendaruserproxy import ProxySqliteDB
+from txdav.xml.parser import WebDAVDocument
@@ -1503,7 +1503,34 @@
yield txn.commit()
+ def test_resourcesXML(self):
+ """
+ Verify conversion of old resources.xml format to twext.who.xml format
+ """
+ fileName = self.mktemp()
+ fp = FilePath(fileName)
+ fp.setContent(oldResourcesFormat)
+ upgradeResourcesXML(fp)
+ self.assertEquals(fp.getContent(), newResourcesFormat)
+
+oldResourcesFormat = """<accounts realm="/Search">
+ <location>
+ <uid>location1</uid>
+ <guid>C4F46062-9094-4D34-8591-61A42D993FAA</guid>
+ <name>location name</name>
+ </location>
+ <resource>
+ <uid>resource1</uid>
+ <guid>60B771CC-D727-4453-ACE0-0FE13CD7445A</guid>
+ <name>resource name</name>
+ </resource>
+</accounts>
+"""
+
+newResourcesFormat = """<directory realm="/Search"><record type="location"><short-name>location1</short-name><guid>C4F46062-9094-4D34-8591-61A42D993FAA</guid><uid>C4F46062-9094-4D34-8591-61A42D993FAA</uid><full-name>location name</full-name></record><record type="resource"><short-name>resource1</short-name><guid>60B771CC-D727-4453-ACE0-0FE13CD7445A</guid><uid>60B771CC-D727-4453-ACE0-0FE13CD7445A</uid><full-name>resource name</full-name></record></directory>"""
+
+
normalizeEvent = """BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
Modified: CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/upgrade.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/upgrade.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/twistedcaldav/upgrade.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -30,6 +30,10 @@
from zlib import compress
from cPickle import loads as unpickle, UnpicklingError
+from xml.etree.ElementTree import (
+ parse as parseXML, ParseError as XMLParseError,
+ tostring as etreeToString, Element as XMLElement
+)
from twext.python.log import Logger
from txdav.xml import element
@@ -48,6 +52,7 @@
from twisted.internet.defer import (
inlineCallbacks, succeed, returnValue
)
+from twisted.python.filepath import FilePath
from twisted.python.reflect import namedAny
from twisted.python.reflect import namedClass
@@ -646,7 +651,54 @@
raise UpgradeError("Data upgrade failed, see error.log for details")
+def upgradeResourcesXML(resourcesFilePath):
+ """
+ Convert the old XML format to the twext.who.xml format
+ @param resourcesFilePath: the file to convert
+ @type resourcesFilePath: L{FilePath}
+ """
+ try:
+ with resourcesFilePath.open() as fh:
+ try:
+ etree = parseXML(fh)
+ except XMLParseError:
+ log.error("Cannot parse {path}", path=resourcesFilePath.path)
+ return
+ except (OSError, IOError):
+ # Can't read the file
+ log.error("Cannot read {path}", path=resourcesFilePath.path)
+ return
+
+ accountsNode = etree.getroot()
+ if accountsNode.tag != "accounts":
+ return
+
+ tagMap = {
+ "uid": ("short-name",),
+ "guid": ("guid", "uid"),
+ "name": ("full-name",),
+ }
+ log.info("Converting resources.xml")
+ directoryNode = XMLElement("directory")
+ directoryNode.set("realm", accountsNode.get("realm"))
+ for sourceNode in accountsNode:
+ recordType = sourceNode.tag
+ destNode = XMLElement("record")
+ destNode.set("type", recordType)
+ for sourceFieldNode in sourceNode:
+ tags = tagMap.get(sourceFieldNode.tag, None)
+ if tags:
+ for tag in tags:
+ destFieldNode = XMLElement(tag)
+ destFieldNode.text = sourceFieldNode.text
+ destNode.append(destFieldNode)
+
+ directoryNode.append(destNode)
+
+ resourcesFilePath.setContent(etreeToString(directoryNode, "utf-8"))
+
+
# The on-disk version number (which defaults to zero if .calendarserver_version
# doesn't exist), is compared with each of the numbers in the upgradeMethods
# array. If it is less than the number, the associated method is called.
@@ -660,6 +712,14 @@
@inlineCallbacks
def upgradeData(config, directory):
+ if config.ResourceService.Enabled:
+ resourcesFileName = config.ResourceService.params.xmlFile
+ if resourcesFileName[0] not in ("/", "."):
+ resourcesFileName = os.path.join(config.DataRoot, resourcesFileName)
+ resourcesFilePath = FilePath(resourcesFileName)
+ if resourcesFilePath.exists():
+ upgradeResourcesXML(resourcesFilePath)
+
triggerPath = os.path.join(config.ServerRoot, TRIGGER_FILE)
if os.path.exists(triggerPath):
try:
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/schedule.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/schedule.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/schedule.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -43,8 +43,7 @@
@inlineCallbacks
def calendarHomeWithUID(self, uid, create=False):
# FIXME: 'create' flag
- newHome = yield super(ImplicitTransaction, self
- ).calendarHomeWithUID(uid, create)
+ newHome = yield super(ImplicitTransaction, self).calendarHomeWithUID(uid, create)
# return ImplicitCalendarHome(newHome, self)
if newHome is None:
returnValue(None)
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/implicit.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/implicit.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -30,12 +30,13 @@
LocalCalendarUser, OtherServerCalendarUser, \
calendarUserFromCalendarUserAddress, \
calendarUserFromCalendarUserUID
-from txdav.caldav.datastore.scheduling.utils import normalizeCUAddr
+from txdav.caldav.datastore.scheduling.utils import normalizeCUAddr,\
+ uidFromCalendarUserAddress
from txdav.caldav.datastore.scheduling.icaldiff import iCalDiff
from txdav.caldav.datastore.scheduling.itip import iTipGenerator, iTIPRequestStatus
from txdav.caldav.datastore.scheduling.utils import getCalendarObjectForRecord
from txdav.caldav.datastore.scheduling.work import ScheduleReplyWork, \
- ScheduleReplyCancelWork, ScheduleOrganizerWork
+ ScheduleReplyCancelWork, ScheduleOrganizerWork, ScheduleOrganizerSendWork
import collections
@@ -468,6 +469,38 @@
@inlineCallbacks
+ def queuedOrganizerSending(self, txn, action, home, resource, uid, organizer, attendee, itipmsg, no_refresh):
+ """
+ Process an organizer scheduling work queue item. The basic goal here is to setup the ImplicitScheduler as if
+ this operation were the equivalent of the PUT that enqueued the work, and then do the actual work.
+ """
+
+ self.txn = txn
+ self.action = action
+ self.state = "organizer"
+ self.calendar_home = home
+ self.resource = resource
+ self.queuedResponses = []
+ self.suppress_refresh = no_refresh
+ self.uid = uid
+ self.calendar = None
+ self.oldcalendar = None
+
+ self.organizer = organizer
+ self.attendees = None
+ self.organizerAddress = None
+
+ # Originator is the organizer in this case
+ self.originator = self.organizer
+
+ self.except_attendees = ()
+ self.only_refresh_attendees = None
+ self.split_details = None
+
+ yield self.processSend(attendee, itipmsg, jobqueue=False)
+
+
+ @inlineCallbacks
def sendAttendeeReply(self, txn, resource):
self.txn = txn
@@ -591,8 +624,24 @@
if not self.organizer:
returnValue(False)
- # Check to see whether any attendee is the owner
+ # Performance optimization: calling L{calendarUserFromCalendarUserAddress} results
+ # in a directory lookup which may be expensive and we may end up doing it for every
+ # attendee. However, all we need is the uid from the cu-address, so do one loop first
+ # just using L{uidFromCalendarUserAddress} which is super fast, and if that does not
+ # match, then do the slower loop
+
+ # Fast loop: Check to see whether any attendee is the owner
for attendee in self.attendees:
+ uid = uidFromCalendarUserAddress(attendee)
+ if uid is not None and uid == self.calendar_home.uid():
+ attendeeAddress = yield calendarUserFromCalendarUserAddress(attendee, self.txn)
+ if attendeeAddress.hosted() and attendeeAddress.record.uid == self.calendar_home.uid():
+ self.attendee = attendee
+ self.attendeeAddress = attendeeAddress
+ returnValue(True)
+
+ # Slow Loop: Check to see whether any attendee is the owner
+ for attendee in self.attendees:
attendeeAddress = yield calendarUserFromCalendarUserAddress(attendee, self.txn)
if attendeeAddress.hosted() and attendeeAddress.record.uid == self.calendar_home.uid():
self.attendee = attendee
@@ -1226,7 +1275,7 @@
# Process regular requests next
if self.action in ("create", "modify",):
- total += (yield self.processRequests())
+ total += (yield self.processRequests(total))
if self.logItems is not None:
self.logItems["itip.requests"] = total
@@ -1280,21 +1329,15 @@
itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-RID", rid))
itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-OLDER-UID" if newer_piece else "X-CALENDARSERVER-SPLIT-NEWER-UID", uid))
- # This is a local CALDAV scheduling operation.
- scheduler = self.makeScheduler()
+ yield self.processSend(attendee, itipmsg, count=count)
- # Do the PUT processing
- log.info("Implicit CANCEL - organizer: '{organizer}' to attendee: '{attendee}', UID: '{uid}', RIDs: '{rids}'", organizer=self.organizer, attendee=attendee, uid=self.uid, rids=rids)
- response = (yield scheduler.doSchedulingViaPUT(self.originator, (attendee,), itipmsg, internal_request=True, suppress_refresh=self.suppress_refresh))
- self.handleSchedulingResponse(response, True)
-
count += 1
returnValue(count)
@inlineCallbacks
- def processRequests(self):
+ def processRequests(self, cancel_count=0):
# TODO: a better policy here is to aggregate by attendees with the same set of instances
# being requested, but for now we will do one scheduling message per attendee.
@@ -1341,19 +1384,57 @@
itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-RID", rid))
itipmsg.addProperty(Property("X-CALENDARSERVER-SPLIT-OLDER-UID" if newer_piece else "X-CALENDARSERVER-SPLIT-NEWER-UID", uid))
- # This is a local CALDAV scheduling operation.
- scheduler = self.makeScheduler()
+ yield self.processSend(attendee, itipmsg, count=count + cancel_count)
- # Do the PUT processing
- log.info("Implicit REQUEST - organizer: '{organizer}' to attendee: '{attendee}', UID: '{uid}'", organizer=self.organizer, attendee=attendee, uid=self.uid)
- response = (yield scheduler.doSchedulingViaPUT(self.originator, (attendee,), itipmsg, internal_request=True, suppress_refresh=self.suppress_refresh))
- self.handleSchedulingResponse(response, True)
-
count += 1
returnValue(count)
+ @inlineCallbacks
+ def processSend(self, attendee, itipmsg, jobqueue=True, count=0):
+ """
+ Send an iTIP message to an attendee. This might send it directly, or it might create job to
+ send it later.
+
+ @param attendee: the calendar user address of the attendee to send the message to
+ @type attendee: L{str}
+ @param itipmsg: the iTIP message to send
+ @type itipmsg: L{Component}
+ @param jobqueue: if allowed, queue up a job to do the actual work
+ @type jobqueue: L{bool}
+ """
+
+ # Attendee refreshes are already executed in a job (in batches) so don't create more
+ if jobqueue and config.Scheduling.Options.WorkQueues.Enabled and not hasattr(self.txn, "doing_attendee_refresh"):
+ # Create job for the work
+ yield ScheduleOrganizerSendWork.schedule(
+ self.txn,
+ self.action,
+ self.calendar_home,
+ self.resource,
+ self.organizerAddress.record.canonicalCalendarUserAddress(),
+ attendee,
+ itipmsg,
+ self.suppress_refresh,
+ count,
+ )
+ else:
+ # Execute the work right now
+ scheduler = self.makeScheduler()
+
+ # Do the PUT processing
+ log.info(
+ "Implicit {method} - organizer: '{organizer}' to attendee: '{attendee}', UID: '{uid}'",
+ method=itipmsg.propertyValue("METHOD"),
+ organizer=self.organizer,
+ attendee=attendee,
+ uid=self.uid,
+ )
+ response = (yield scheduler.doSchedulingViaPUT(self.originator, (attendee,), itipmsg, internal_request=True, suppress_refresh=self.suppress_refresh))
+ self.handleSchedulingResponse(response, True)
+
+
def handleSchedulingResponse(self, response, is_organizer):
# For a queued operation we stash the response away for the work item to deal with
@@ -1475,9 +1556,13 @@
if doScheduling:
# Check to see whether all instances are CANCELLED
if self.calendar.hasPropertyValueInAllComponents(Property("STATUS", "CANCELLED")):
- log.debug("Attendee '{attendee}' is creating CANCELLED event for missing UID: '{uid}' - removing entire event", attendee=self.attendee, uid=self.uid)
- self.return_status = ImplicitScheduler.STATUS_ORPHANED_CANCELLED_EVENT
- returnValue(None)
+ if self.action == "create":
+ log.debug("Attendee '{attendee}' is creating CANCELLED event for missing UID: '{uid}' - removing entire event", attendee=self.attendee, uid=self.uid)
+ self.return_status = ImplicitScheduler.STATUS_ORPHANED_CANCELLED_EVENT
+ returnValue(None)
+ else:
+ log.debug("Attendee '{attendee}' is modifying CANCELLED event for missing UID: '{uid}'", attendee=self.attendee, uid=self.uid)
+ returnValue(None)
else:
# Check to see whether existing event is SCHEDULE-AGENT=CLIENT/NONE
if self.oldcalendar:
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/itip.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/itip.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/itip.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -174,10 +174,17 @@
hidden = component.hasProperty(Component.HIDDEN_INSTANCE_PROPERTY)
new_component = new_calendar.deriveInstance(rid, allowCancelled=allowCancelled and not hidden)
if new_component is not None:
- new_calendar.addComponent(new_component)
- iTipProcessing.transferItems(calendar, new_component, needs_action_rids, reschedule, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee, attendee_dtstamp, other_props, recipient)
- if hidden:
- new_component.addProperty(Property(Component.HIDDEN_INSTANCE_PROPERTY, "T"))
+ # If the new component is not CANCELLED then add the one derived from the new master and
+ # sync over attendee properties from the existing attendee data. However, if the new
+ # component is cancelled, we need to preserve the original state of the attendee's
+ # version as it may differ from the one derived from the new master.
+ if allowCancelled:
+ new_calendar.addComponent(component.duplicate())
+ else:
+ new_calendar.addComponent(new_component)
+ iTipProcessing.transferItems(calendar, new_component, needs_action_rids, reschedule, valarms, private_comments, transps, completeds, organizer_schedule_status, attendee, attendee_dtstamp, other_props, recipient)
+ if hidden:
+ new_component.addProperty(Property(Component.HIDDEN_INSTANCE_PROPERTY, "T"))
iTipProcessing.addTranspForNeedsAction(new_calendar.subcomponents(), recipient)
@@ -298,11 +305,12 @@
overridden.replaceProperty(Property("STATUS", "CANCELLED"))
calendar.addComponent(overridden)
newseq = component.propertyValue("SEQUENCE")
- overridden.replacePropertyInAllComponents(Property("SEQUENCE", newseq))
+ overridden.replaceProperty(Property("SEQUENCE", newseq))
# If we have any EXDATEs lets add them to the existing calendar object.
if exdates and calendar_master:
- calendar_master.addProperty(Property("EXDATE", exdates))
+ for exdate in exdates:
+ calendar_master.addExdate(exdate)
# See if there are still components in the calendar - we might have deleted the last overridden instance
# in which case the calendar object is empty (except for VTIMEZONEs) or has only hidden components.
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/processing.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/processing.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/processing.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -463,7 +463,7 @@
if send_reply:
# Track outstanding auto-reply processing
log.debug("ImplicitProcessing - recipient '%s' processing UID: '%s' - auto-reply queued" % (self.recipient.cuaddr, self.uid,))
- ScheduleAutoReplyWork.autoReply(self.txn, new_resource, partstat)
+ yield ScheduleAutoReplyWork.autoReply(self.txn, new_resource, partstat)
# Build the schedule-changes XML element
changes = customxml.ScheduleChanges(
@@ -511,7 +511,7 @@
if send_reply:
# Track outstanding auto-reply processing
log.debug("ImplicitProcessing - recipient '%s' processing UID: '%s' - auto-reply queued" % (self.recipient.cuaddr, self.uid,))
- ScheduleAutoReplyWork.autoReply(self.txn, new_resource, partstat)
+ yield ScheduleAutoReplyWork.autoReply(self.txn, new_resource, partstat)
# Build the schedule-changes XML element
update_details = []
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/test/test_implicit.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/test/test_implicit.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/test/test_implicit.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -34,6 +34,7 @@
from txdav.caldav.datastore.scheduling.scheduler import ScheduleResponseQueue
from txdav.caldav.icalendarstore import AttendeeAllowedError, \
ComponentUpdateState
+from txdav.caldav.datastore.sql import CalendarObject
from txdav.common.datastore.test.util import CommonCommonTests, populateCalendarsFrom
from twext.enterprise.jobqueue import JobItem
@@ -1275,7 +1276,10 @@
yield self._createCalendarObject(data1, "user01", "test.ics")
cobj = yield self.calendarObjectUnderTest(home="user01", name="test.ics")
+ actualVersion = CalendarObject._currentDataVersion
+ self.patch(CalendarObject, "_currentDataVersion", 0)
yield cobj._setComponentInternal(Component.fromString(data1), internal_state=ComponentUpdateState.RAW)
+ CalendarObject._currentDataVersion = actualVersion
yield self.commit()
cobj = yield self.calendarObjectUnderTest(home="user01", name="test.ics")
@@ -1285,7 +1289,10 @@
self.assertFalse(comp.getOrganizerScheduleAgent())
cobj = yield self.calendarObjectUnderTest(home="user01", name="test.ics")
+ actualVersion = CalendarObject._currentDataVersion
+ self.patch(CalendarObject, "_currentDataVersion", 0)
yield cobj.setComponent(Component.fromString(data2))
+ CalendarObject._currentDataVersion = actualVersion
yield self.commit()
cobj = yield self.calendarObjectUnderTest(home="user01", name="test.ics")
Copied: CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/test/test_work.py (from rev 13731, CalendarServer/trunk/txdav/caldav/datastore/scheduling/test/test_work.py)
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/test/test_work.py (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/test/test_work.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,267 @@
+##
+# Copyright (c) 2013-2014 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.ical import Component
+from twext.enterprise.jobqueue import JobItem, WorkItem
+from txdav.common.datastore.sql_tables import scheduleActionFromSQL
+from twisted.internet import reactor
+
+"""
+Tests for txdav.caldav.datastore.utils
+"""
+
+from twisted.internet.defer import inlineCallbacks
+from twisted.trial import unittest
+
+from txdav.caldav.datastore.scheduling.work import ScheduleOrganizerWork, \
+ ScheduleWorkMixin, ScheduleWork, ScheduleOrganizerSendWork
+from txdav.common.datastore.test.util import populateCalendarsFrom, CommonCommonTests
+
+
+
+class BaseWorkTests(CommonCommonTests, unittest.TestCase):
+ """
+ Tests for scheduling work.
+ """
+ @inlineCallbacks
+ def setUp(self):
+
+ yield super(BaseWorkTests, self).setUp()
+ yield self.buildStoreAndDirectory()
+ yield self.populate()
+
+
+ @inlineCallbacks
+ def populate(self):
+ yield populateCalendarsFrom(self.requirements, self.storeUnderTest())
+ self.notifierFactory.reset()
+
+ requirements = {
+ "user01": {
+ "calendar": {
+ },
+ "inbox": {
+ },
+ },
+ "user02": {
+ "calendar": {
+ },
+ "inbox": {
+ },
+ },
+ "user03": {
+ "calendar": {
+ },
+ "inbox": {
+ },
+ },
+ }
+
+
+ def storeUnderTest(self):
+ """
+ Create and return a L{CalendarStore} for testing.
+ """
+ return self._sqlCalendarStore
+
+
+
+class TestScheduleOrganizerWork(BaseWorkTests):
+ """
+ Test creation of L{ScheduleOrganizerWork} items.
+ """
+
+ calendar_old = Component.fromString("""BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T120000Z
+DURATION:PT1H
+ORGANIZER:urn:uuid:user01
+ATTENDEE:urn:uuid:user01
+ATTENDEE:urn:uuid:user02
+END:VEVENT
+END:VCALENDAR
+""")
+
+ calendar_new = Component.fromString("""BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T130000Z
+DURATION:PT1H
+ORGANIZER:urn:uuid:user01
+ATTENDEE:urn:uuid:user01
+ATTENDEE:urn:uuid:user02
+END:VEVENT
+END:VCALENDAR
+""")
+
+
+ @inlineCallbacks
+ def test_create(self):
+ """
+ Test that jobs associated with L{txdav.caldav.datastore.scheduling.work.ScheduleOrganizerWork}
+ can be created and correctly removed.
+ """
+
+ ScheduleWorkMixin._queued = 0
+ txn = self.transactionUnderTest()
+ home = yield self.homeUnderTest(name="user01")
+ yield ScheduleOrganizerWork.schedule(
+ txn,
+ "12345-67890",
+ "create",
+ home,
+ None,
+ None,
+ self.calendar_new,
+ "urn:uuid:user01",
+ 2,
+ True,
+ )
+ yield self.commit()
+ self.assertEqual(ScheduleWorkMixin._queued, 1)
+
+ jobs = yield JobItem.all(self.transactionUnderTest())
+ self.assertEqual(len(jobs), 1)
+
+ work = yield jobs[0].workItem()
+ self.assertTrue(isinstance(work, ScheduleOrganizerWork))
+ self.assertEqual(work.icalendarUid, "12345-67890")
+ self.assertEqual(scheduleActionFromSQL[work.scheduleAction], "create")
+
+ yield work.delete()
+ yield jobs[0].delete()
+ yield self.commit()
+
+ jobs = yield JobItem.all(self.transactionUnderTest())
+ self.assertEqual(len(jobs), 0)
+ work = yield ScheduleOrganizerWork.all(self.transactionUnderTest())
+ self.assertEqual(len(work), 0)
+ baseWork = yield ScheduleWork.all(self.transactionUnderTest())
+ self.assertEqual(len(baseWork), 0)
+
+
+ @inlineCallbacks
+ def test_cascade_delete_cleanup(self):
+ """
+ Test that when work associated with L{txdav.caldav.datastore.scheduling.work.ScheduleWork}
+ is removed with the L{ScheduleWork} item being removed, the associated L{JobItem} runs and
+ removes itself and the L{ScheduleWork}.
+ """
+
+ ScheduleWorkMixin._queued = 0
+ txn = self.transactionUnderTest()
+ home = yield self.homeUnderTest(name="user01")
+ yield ScheduleOrganizerWork.schedule(
+ txn,
+ "12345-67890",
+ "create",
+ home,
+ None,
+ None,
+ self.calendar_new,
+ "urn:uuid:user01",
+ 2,
+ True,
+ )
+ yield self.commit()
+ self.assertEqual(ScheduleWorkMixin._queued, 1)
+
+ jobs = yield JobItem.all(self.transactionUnderTest())
+ work = yield jobs[0].workItem()
+ yield WorkItem.delete(work)
+ yield self.commit()
+
+ jobs = yield JobItem.all(self.transactionUnderTest())
+ self.assertEqual(len(jobs), 1)
+ baseWork = yield ScheduleWork.all(self.transactionUnderTest())
+ self.assertEqual(len(baseWork), 1)
+ self.assertEqual(baseWork[0].jobID, jobs[0].jobID)
+
+ work = yield jobs[0].workItem()
+ self.assertTrue(work is None)
+ yield self.commit()
+
+ yield JobItem.waitEmpty(self.storeUnderTest().newTransaction, reactor, 60)
+
+ jobs = yield JobItem.all(self.transactionUnderTest())
+ self.assertEqual(len(jobs), 0)
+ work = yield ScheduleOrganizerWork.all(self.transactionUnderTest())
+ self.assertEqual(len(work), 0)
+ baseWork = yield ScheduleWork.all(self.transactionUnderTest())
+ self.assertEqual(len(baseWork), 0)
+
+
+
+class TestScheduleOrganizerSendWork(BaseWorkTests):
+ """
+ Test creation of L{ScheduleOrganizerSendWork} items.
+ """
+
+ itip_new = Component.fromString("""BEGIN:VCALENDAR
+VERSION:2.0
+METHOD:REQUEST
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20080601T130000Z
+DURATION:PT1H
+ORGANIZER:urn:x-uid:user01
+{attendees}
+END:VEVENT
+END:VCALENDAR
+""".format(attendees="\n".join(["ATTENDEE:urn:x-uid:user%02d" % i for i in range(1, 100)]))
+)
+
+
+ @inlineCallbacks
+ def test_create(self):
+ """
+ Test that jobs associated with L{txdav.caldav.datastore.scheduling.work.ScheduleOrganizerSendWork}
+ can be created and correctly removed.
+ """
+
+ txn = self.transactionUnderTest()
+ home = yield self.homeUnderTest(name="user01")
+ yield ScheduleOrganizerSendWork.schedule(
+ txn,
+ "create",
+ home,
+ None,
+ "urn:x-uid:user01",
+ "urn:x-uid:user02",
+ self.itip_new,
+ True,
+ 1000,
+ )
+
+ jobs = yield JobItem.all(self.transactionUnderTest())
+ self.assertEqual(len(jobs), 1)
+
+ work = yield jobs[0].workItem()
+ yield work.doWork()
+
+ home2 = yield self.calendarUnderTest(home="user02", name="calendar")
+ cobjs = yield home2.calendarObjects()
+ self.assertEqual(len(cobjs), 1)
+ #cal2 = yield cobjs[0].component()
+
+ yield work.delete()
+ yield jobs[0].delete()
+ yield self.commit()
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/work.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/work.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/scheduling/work.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -14,10 +14,10 @@
# limitations under the License.
##
-from twext.enterprise.dal.record import fromTable
+from twext.enterprise.dal.record import fromTable, Record
from twext.enterprise.dal.syntax import Select, Insert, Delete, Parameter
from twext.enterprise.locking import NamedLock
-from twext.enterprise.jobqueue import WorkItem, WORK_PRIORITY_MEDIUM
+from twext.enterprise.jobqueue import WorkItem, WORK_PRIORITY_MEDIUM, JobItem
from twext.python.log import Logger
from twisted.internet.defer import inlineCallbacks, returnValue, Deferred
@@ -51,7 +51,10 @@
class ScheduleWorkMixin(WorkItem):
"""
- Base class for common schedule work item behavior.
+ Base class for common schedule work item behavior. Sub-classes have their own class specific data
+ stored in per-class tables. This class manages a SCHEDULE_WORK table that contains the work id, job id
+ and iCalendar UID. That table is used for locking all scheduling items with the same UID, as well as
+ allow smart re-scheduling/ordering etc of items with the same UID.
"""
# Track when all work is complete (needed for unit tests)
@@ -59,12 +62,132 @@
_queued = 0
# Schedule work is grouped based on calendar object UID
- group = property(lambda self: (self.table.ICALENDAR_UID == self.icalendarUid))
default_priority = WORK_PRIORITY_MEDIUM
default_weight = 5
+ @classmethod
+ @inlineCallbacks
+ def create(cls, transaction, **kwargs):
+ """
+ A new work item needs to be created. First we create a SCHEDULE_WORK record, then
+ we create the actual work item.
+ @param transaction: the transaction to use
+ @type transaction: L{IAsyncTransaction}
+ """
+
+ baseargs = {
+ "jobID": kwargs.pop("jobID"),
+ "icalendarUid": kwargs.pop("icalendarUid"),
+ "workType": cls.workType()
+ }
+
+ baseWork = yield ScheduleWork.create(transaction, **baseargs)
+
+ kwargs["workID"] = baseWork.workID
+ work = yield super(ScheduleWorkMixin, cls).create(transaction, **kwargs)
+ work.addBaseWork(baseWork)
+ returnValue(work)
+
+
@classmethod
+ @inlineCallbacks
+ def loadForJob(cls, txn, jobID):
+ baseItems = yield ScheduleWork.query(txn, (ScheduleWork.jobID == jobID))
+ workItems = []
+ for baseItem in baseItems:
+ workItem = yield cls.query(txn, (cls.workID == baseItem.workID))
+ if len(workItem) == 0:
+ # This can happen if a cascade delete is done on the actual work item - that will not
+ # remove the corresponding L{JobItem} or L{ScheduleWork}
+ yield baseItem.delete()
+ continue
+ workItem[0].addBaseWork(baseItem)
+ workItems.append(workItem[0])
+ returnValue(workItems)
+
+
+ @inlineCallbacks
+ def runlock(self):
+ """
+ Lock the "group" which is all the base items with the same UID. Also make sure
+ to lock this item after.
+
+ @return: an L{Deferred} that fires with L{True} if the L{WorkItem} was locked,
+ L{False} if not.
+ @rtype: L{Deferred}
+ """
+
+ # Do the group lock first since this can impact multiple rows and thus could
+ # cause deadlocks if done in the wrong order
+
+ # Row level lock on this item
+ locked = yield self.baseWork.trylock(ScheduleWork.icalendarUid == self.icalendarUid)
+ if locked:
+ yield self.trylock()
+ returnValue(locked)
+
+
+ def addBaseWork(self, baseWork):
+ """
+ Add the base work fields into the sub-classes as non-record attributes.
+
+ @param baseWork: the base work item to add
+ @type baseWork: L{ScheduleWork}
+ """
+ self.__dict__["baseWork"] = baseWork
+ self.__dict__["jobID"] = baseWork.jobID
+ self.__dict__["icalendarUid"] = baseWork.icalendarUid
+
+
+ def delete(self):
+ """
+ Delete the base work item which will delete this one via cascade.
+
+ @return: a L{Deferred} which fires with C{None} when the underlying row
+ has been deleted, or fails with L{NoSuchRecord} if the underlying
+ row was already deleted.
+ """
+ return self.baseWork.delete()
+
+
+ @classmethod
+ @inlineCallbacks
+ def hasWork(cls, txn):
+ sch = cls.table
+ rows = (yield Select(
+ (sch.WORK_ID,),
+ From=sch,
+ ).on(txn))
+ returnValue(len(rows) > 0)
+
+
+ @inlineCallbacks
+ def afterWork(self):
+ """
+ A hook that gets called after the L{WorkItem} does its real work. This can be used
+ for common clean-up behaviors. The base implementation does nothing.
+ """
+ yield super(ScheduleWorkMixin, self).afterWork()
+
+ # Find the next item and schedule to run immediately after this.
+ # We only coalesce ScheduleOrganizerSendWork.
+ if self.workType() == ScheduleOrganizerSendWork.workType():
+ all = yield self.baseWork.query(
+ self.transaction,
+ (ScheduleWork.icalendarUid == self.icalendarUid).And(ScheduleWork.workID != self.workID),
+ order=ScheduleWork.workID,
+ limit=1,
+ )
+ if all:
+ work = all[0]
+ if work.workType == self.workType():
+ job = yield JobItem.load(self.transaction, work.jobID)
+ yield job.update(notBefore=datetime.datetime.utcnow())
+ log.debug("ScheduleOrganizerSendWork - promoted job: {id}, UID: '{uid}'", id=work.workID, uid=self.icalendarUid)
+
+
+ @classmethod
def allDone(cls):
d = Deferred()
cls._allDoneCallback = d.callback
@@ -94,6 +217,36 @@
self.transaction.postCommit(_post)
+ def extractSchedulingResponse(self, queuedResponses):
+ """
+ Extract a list of (recipient, status) pairs from a scheduling response, returning that list
+ and an indicator of whether any have a schedule status other than delivered.
+
+ @param queuedResponses: the scheduling response object
+ @type queuedResponses: L{list} of L{caldavxml.ScheduleResponse}
+
+ @return: a L{tuple} of the list and the status state
+ @rtype: L{tuple} of (L{list}, L{bool})
+ """
+
+ # Map each recipient in the response to a status code
+ results = []
+ all_delivered = True
+ for response in queuedResponses:
+ for item in response.responses:
+ recipient = str(item.recipient.children[0])
+ status = str(item.reqstatus)
+ statusCode = status.split(";")[0]
+
+ results.append((recipient, statusCode,))
+
+ # Now apply to each ATTENDEE/ORGANIZER in the original data only if not 1.2
+ if statusCode != iTIPRequestStatus.MESSAGE_DELIVERED_CODE:
+ all_delivered = False
+
+ return results, all_delivered
+
+
def handleSchedulingResponse(self, response, calendar, is_organizer):
"""
Update a user's calendar object resource based on the results of a queued scheduling
@@ -101,8 +254,8 @@
as we will already have updated the calendar object resource to make it look like scheduling
worked prior to the work queue item being enqueued.
- @param response: the scheduling response object
- @type response: L{caldavxml.ScheduleResponse}
+ @param response: the scheduling response summary data
+ @type response: L{list} of L{tuple} of (L{str} - recipient, L{str} - status)
@param calendar: original calendar component
@type calendar: L{Component}
@param is_organizer: whether or not iTIP message was sent by the organizer
@@ -112,11 +265,7 @@
# Map each recipient in the response to a status code
changed = False
propname = calendar.mainComponent().recipientPropertyName() if is_organizer else "ORGANIZER"
- for item in response.responses:
- recipient = str(item.recipient.children[0])
- status = str(item.reqstatus)
- statusCode = status.split(";")[0]
-
+ for recipient, statusCode in response:
# Now apply to each ATTENDEE/ORGANIZER in the original data only if not 1.2
if statusCode != iTIPRequestStatus.MESSAGE_DELIVERED_CODE:
calendar.setParameterToValueForPropertyWithValue(
@@ -131,12 +280,22 @@
+class ScheduleWork(Record, fromTable(schema.SCHEDULE_WORK)):
+ """
+ A L{Record} based table whose rows are used for locking scheduling work by iCalendar UID value.
+ as well as helping to determine the next work for a particular UID.
+ """
+ pass
+
+
+
class ScheduleOrganizerWork(ScheduleWorkMixin, fromTable(schema.SCHEDULE_ORGANIZER_WORK)):
"""
The associated work item table is SCHEDULE_ORGANIZER_WORK.
- This work item is used to send a iTIP request and cancel messages when an organizer changes
- their calendar object resource.
+ This work item is used to generate a set of L{ScheduleOrganizerSendWork} work items for
+ each set of iTIP messages that need to be sent as the result of an organizer changing
+ their copy of the event.
"""
@classmethod
@@ -177,18 +336,7 @@
log.debug("ScheduleOrganizerWork - enqueued for ID: {id}, UID: {uid}, organizer: {org}", id=proposal.workItem.workID, uid=uid, org=organizer)
- @classmethod
@inlineCallbacks
- def hasWork(cls, txn):
- srw = schema.SCHEDULE_ORGANIZER_WORK
- rows = (yield Select(
- (srw.WORK_ID,),
- From=srw,
- ).on(txn))
- returnValue(len(rows) > 0)
-
-
- @inlineCallbacks
def doWork(self):
try:
@@ -217,31 +365,142 @@
self.smartMerge
)
+ self._dequeued()
+
+ except Exception, e:
+ log.debug("ScheduleOrganizerWork - exception ID: {id}, UID: '{uid}', {err}", id=self.workID, uid=self.icalendarUid, err=str(e))
+ log.debug(traceback.format_exc())
+ raise
+ except:
+ log.debug("ScheduleOrganizerWork - bare exception ID: {id}, UID: '{uid}'", id=self.workID, uid=self.icalendarUid)
+ log.debug(traceback.format_exc())
+ raise
+
+ log.debug("ScheduleOrganizerWork - done for ID: {id}, UID: {uid}, organizer: {org}", id=self.workID, uid=self.icalendarUid, org=organizer)
+
+
+
+class ScheduleOrganizerSendWork(ScheduleWorkMixin, fromTable(schema.SCHEDULE_ORGANIZER_SEND_WORK)):
+ """
+ The associated work item table is SCHEDULE_ORGANIZER_SEND_WORK.
+
+ This work item is used to send iTIP request and cancel messages when an organizer changes
+ their calendar object resource. One of these will be created for each iTIP message that
+ L{ScheduleOrganizerWork} needs to have sent.
+ """
+
+ @classmethod
+ @inlineCallbacks
+ def schedule(cls, txn, action, home, resource, organizer, attendee, itipmsg, no_refresh, stagger):
+ """
+ Create the work item. Because there may be lots of these dumped onto the server in one go, we will
+ stagger them via notBefore. However, we are using a "chained" work item so when one completes, it
+ will reschedule the next one to run immediately after it, so if work is being done quickly, the
+ stagger interval is effectively ignored.
+
+ @param txn: the transaction to use
+ @type txn: L{CommonStoreTransaction}
+ @param organizer: the calendar user address of the organizer
+ @type organizer: L{str}
+ @param attendee: the calendar user address of the attendee to send the message to
+ @type attendee: L{str}
+ @param itipmsg: the iTIP message to send
+ @type itipmsg: L{Component}
+ @param no_refresh: whether or not refreshes are allowed
+ @type no_refresh: L{bool}
+ @param stagger: number of seconds into the future for notBefore
+ @type stagger: L{int}
+ """
+
+ # Always queue up new work - coalescing happens when work is executed
+ notBefore = datetime.datetime.utcnow() + datetime.timedelta(seconds=config.Scheduling.Options.WorkQueues.RequestDelaySeconds + stagger)
+ uid = itipmsg.resourceUID()
+ proposal = (yield txn.enqueue(
+ cls,
+ notBefore=notBefore,
+ icalendarUid=uid,
+ scheduleAction=scheduleActionToSQL[action],
+ homeResourceID=home.id(),
+ resourceID=resource.id() if resource else None,
+ attendee=attendee,
+ itipMsg=itipmsg.getTextWithTimezones(includeTimezones=not config.EnableTimezonesByReference),
+ noRefresh=no_refresh,
+ ))
+ cls._enqueued()
+ log.debug(
+ "ScheduleOrganizerSendWork - enqueued for ID: {id}, UID: {uid}, organizer: {org}, attendee: {att}",
+ id=proposal.workItem.workID,
+ uid=uid,
+ org=organizer,
+ att=attendee
+ )
+
+
+ @inlineCallbacks
+ def doWork(self):
+
+ try:
+ home = (yield self.transaction.calendarHomeWithResourceID(self.homeResourceID))
+ resource = (yield home.objectResourceWithID(self.resourceID))
+ itipmsg = Component.fromString(self.itipMsg)
+
+ organizerAddress = yield calendarUserFromCalendarUserUID(home.uid(), self.transaction)
+ organizer = organizerAddress.record.canonicalCalendarUserAddress()
+ log.debug(
+ "ScheduleOrganizerSendWork - running for ID: {id}, UID: {uid}, organizer: {org}, attendee: {att}",
+ id=self.workID,
+ uid=self.icalendarUid,
+ org=organizer,
+ att=self.attendee
+ )
+
+ # We need to get the UID lock for implicit processing.
+ yield NamedLock.acquire(self.transaction, "ImplicitUIDLock:%s" % (hashlib.md5(self.icalendarUid).hexdigest(),))
+
+ from txdav.caldav.datastore.scheduling.implicit import ImplicitScheduler
+ scheduler = ImplicitScheduler()
+ yield scheduler.queuedOrganizerSending(
+ self.transaction,
+ scheduleActionFromSQL[self.scheduleAction],
+ home,
+ resource,
+ self.icalendarUid,
+ organizer,
+ self.attendee,
+ itipmsg,
+ self.noRefresh
+ )
+
# Handle responses - update the actual resource in the store. Note that for a create the resource did not previously
# exist and is stored as None for the work item, but the scheduler will attempt to find the new resources and use
# that. We need to grab the scheduler's resource for further processing.
resource = scheduler.resource
if resource is not None:
- changed = False
- calendar = (yield resource.componentForUser())
- for response in scheduler.queuedResponses:
- changed |= yield self.handleSchedulingResponse(response, calendar, True)
+ responses, all_delivered = self.extractSchedulingResponse(scheduler.queuedResponses)
+ if not all_delivered:
+ calendar = (yield resource.componentForUser())
+ changed = self.handleSchedulingResponse(responses, calendar, True)
+ if changed:
+ yield resource._setComponentInternal(calendar, internal_state=ComponentUpdateState.ORGANIZER_ITIP_UPDATE)
- if changed:
- yield resource._setComponentInternal(calendar, internal_state=ComponentUpdateState.ORGANIZER_ITIP_UPDATE)
-
self._dequeued()
except Exception, e:
- log.debug("ScheduleOrganizerWork - exception ID: {id}, UID: '{uid}', {err}", id=self.workID, uid=self.icalendarUid, err=str(e))
+ log.debug("ScheduleOrganizerSendWork - exception ID: {id}, UID: '{uid}', {err}", id=self.workID, uid=self.icalendarUid, err=str(e))
log.debug(traceback.format_exc())
raise
except:
- log.debug("ScheduleOrganizerWork - bare exception ID: {id}, UID: '{uid}'", id=self.workID, uid=self.icalendarUid)
+ log.debug("ScheduleOrganizerSendWork - bare exception ID: {id}, UID: '{uid}'", id=self.workID, uid=self.icalendarUid)
log.debug(traceback.format_exc())
raise
- log.debug("ScheduleOrganizerWork - done for ID: {id}, UID: {uid}, organizer: {org}", id=self.workID, uid=self.icalendarUid, org=organizer)
+ log.debug(
+ "ScheduleOrganizerSendWork - for ID: {id}, UID: {uid}, organizer: {org}, attendee: {att}",
+ id=self.workID,
+ uid=self.icalendarUid,
+ org=organizer,
+ att=self.attendee
+ )
@@ -298,18 +557,7 @@
log.debug("ScheduleReplyWork - enqueued for ID: {id}, UID: {uid}, attendee: {att}", id=proposal.workItem.workID, uid=resource.uid(), att=attendee)
- @classmethod
@inlineCallbacks
- def hasWork(cls, txn):
- srw = schema.SCHEDULE_REPLY_WORK
- rows = (yield Select(
- (srw.WORK_ID,),
- From=srw,
- ).on(txn))
- returnValue(len(rows) > 0)
-
-
- @inlineCallbacks
def doWork(self):
try:
@@ -332,11 +580,12 @@
# Send scheduling message and process response
response = (yield self.sendToOrganizer(home, "REPLY", itipmsg, attendee, organizer))
- changed = yield self.handleSchedulingResponse(response, calendar, False)
+ responses, all_delivered = self.extractSchedulingResponse((response,))
+ if not all_delivered:
+ changed = yield self.handleSchedulingResponse(responses, calendar, False)
+ if changed:
+ yield resource._setComponentInternal(calendar, internal_state=ComponentUpdateState.ATTENDEE_ITIP_UPDATE)
- if changed:
- yield resource._setComponentInternal(calendar, internal_state=ComponentUpdateState.ATTENDEE_ITIP_UPDATE)
-
self._dequeued()
except Exception, e:
@@ -360,10 +609,6 @@
of the original resource data.
"""
- # Schedule work is grouped based on calendar object UID
- group = property(lambda self: "ScheduleWork:%s" % (self.icalendarUid,))
-
-
@classmethod
@inlineCallbacks
def replyCancel(cls, txn, home, calendar, attendee):
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/sql.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/sql.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -1365,13 +1365,13 @@
# Initialize these for all shares
for ename in self._shadowProperties:
if ename not in self.properties() and ename.toString() in props:
- self.properties()[ename] = WebDAVDocument.fromString(props[ename]).root_element
+ self.properties()[ename] = WebDAVDocument.fromString(props[ename.toString()]).root_element
# Only initialize these for direct shares
if self.direct():
for ename in (PropertyName.fromElement(element.DisplayName),):
if ename not in self.properties() and ename.toString() in props:
- self.properties()[ename] = WebDAVDocument.fromString(props[ename]).root_element
+ self.properties()[ename] = WebDAVDocument.fromString(props[ename.toString()]).root_element
# FIXME: this is DAV-ish. Data store calendar objects don't have
@@ -1781,7 +1781,7 @@
record = yield self._txn.directoryService().recordWithUID(shareeUID.decode("utf-8"))
if (
record is None or
- record.recordType != RecordType.group or not (False and
+ record.type() != RecordType.group or not (False and
config.Sharing.Enabled and
config.Sharing.Calendars.Enabled and
config.Sharing.Calendars.Groups.Enabled
@@ -1793,8 +1793,8 @@
)
# shareWith every member of group not already shared to
- groupID, _ignore_name, _ignore_membershipHash, _ignore_modDate = yield self._txn.groupByUID(record.uid)
- memberUIDs = yield self._txn.membersOfGroup(groupID)
+ groupID = (yield self._txn.groupByUID(record.uid))[0]
+ memberUIDs = yield self._txn.groupMemberUIDs(groupID)
for memberUID in memberUIDs:
shareeHome = yield self._txn.calendarHomeWithUID(memberUID, create=True)
if (yield shareeHome.childWithID(self._resourceID)) is None:
@@ -1814,8 +1814,8 @@
record = (
yield self._txn.directoryService().recordWithUID(groupUID.decode("utf-8"))
)
- groupID, _ignore_name, _ignore_membershipHash, _ignore_modDate = yield self._txn.groupByUID(record.uid)
- memberUIDs = yield self._txn.membersOfGroup(groupID)
+ groupID = (yield self._txn.groupByUID(record.uid))[0]
+ memberUIDs = yield self._txn.groupMemberUIDs(groupID)
boundUIDs = set()
bind = schema.CALENDAR_BIND
@@ -1851,7 +1851,10 @@
update schema.GROUP_SHAREE
"""
changed = False
- groupID, _ignore_name, membershipHash, _ignore_modDate = yield self._txn.groupByUID(groupUID)
+ (
+ groupID, _ignore_name, membershipHash, _ignore_modDate,
+ _ignore_extant
+ ) = yield self._txn.groupByUID(groupUID)
gs = schema.GROUP_SHAREE
rows = yield Select(
@@ -1923,33 +1926,26 @@
"""
# see if after share is removed, user is still shared by a group sharee
- effectiveShareMode = None
- oldShareMode = shareeView.shareMode()
- if oldShareMode in (_BIND_MODE_DIRECT, _BIND_MODE_READ, _BIND_MODE_WRITE, _BIND_MODE_GROUP,):
+ if shareeView.shareMode() in (_BIND_MODE_DIRECT, _BIND_MODE_READ, _BIND_MODE_WRITE, _BIND_MODE_GROUP):
gs = schema.GROUP_SHAREE
rows = yield Select(
- [gs.GROUP_ID, gs.GROUP_BIND_MODE],
+ [gs.GROUP_ID],
From=gs,
Where=(gs.CALENDAR_HOME_ID == self.ownerHome()._resourceID).And(
gs.CALENDAR_ID == self._resourceID)
).on(self._txn)
+ groupIDs = [row[0] for row in rows]
+
shareeHomeUID = shareeView.viewerHome().uid()
- for groupID, groupShareMode in rows:
- memberUIDs = yield self._txn.membersOfGroup(groupID)
+ for groupID in groupIDs:
+ memberUIDs = yield self._txn.groupMemberUIDs(groupID) # must be cached
if shareeHomeUID in memberUIDs:
- if effectiveShareMode is None:
- effectiveShareMode = groupShareMode
- elif groupShareMode > effectiveShareMode:
- effectiveShareMode = groupShareMode
+ yield self.updateShare(shareeView, mode=_BIND_MODE_GROUP)
+ returnValue(None)
- if effectiveShareMode is None:
- # no group sharee for this user so let super do work
- returnValue((yield super(Calendar, self).removeShare(shareeView)))
- elif oldShareMode != _BIND_MODE_GROUP:
- # change to group share
- yield self.updateShare(shareeView, mode=_BIND_MODE_GROUP)
- returnValue(None)
+ # no group sharee for this user so let super do work
+ returnValue((yield super(Calendar, self).removeShare(shareeView)))
#TODO: effectiveShareMode may change between _BIND_MODE_READ & _BIND_MODE_READ.
# Is that OK?
@@ -1975,8 +1971,8 @@
returnValue(None)
# get group membership
- groupID, _ignore_name, _ignore_membershipHash, _ignore_modDate = yield self._txn.groupByUID(record.uid)
- memberUIDs = yield self._txn.membersOfGroup(groupID)
+ groupID = (yield self._txn.groupByUID(record.uid))[0]
+ memberUIDs = yield self._txn.groupMemberUIDs(groupID)
# update groupsharee so that removeShare works
gs = schema.GROUP_SHAREE
@@ -2116,6 +2112,8 @@
_objectSchema = schema.CALENDAR_OBJECT
_componentClass = VComponent
+ _currentDataVersion = 1
+
def __init__(self, calendar, name, uid, resourceID=None, options=None):
super(CalendarObject, self).__init__(calendar, name, uid, resourceID)
@@ -2177,7 +2175,8 @@
obj.SCHEDULE_ETAGS,
obj.PRIVATE_COMMENTS,
obj.CREATED,
- obj.MODIFIED
+ obj.MODIFIED,
+ obj.DATAVERSION,
]
@@ -2198,6 +2197,7 @@
"_private_comments",
"_created",
"_modified",
+ "_dataversion",
)
@@ -2221,7 +2221,7 @@
# Possible timezone stripping
if config.EnableTimezonesByReference:
- component.stripKnownTimezones()
+ component.stripStandardTimezones()
# Do validation on external requests
if internal_state == ComponentUpdateState.NORMAL:
@@ -2250,7 +2250,7 @@
yield self.validAttendeeListSizeCheck(component, inserting)
# Check location/resource organizer requirement
- self.validLocationResourceOrganizer(component, inserting, internal_state)
+ yield self.validLocationResourceOrganizer(component, inserting, internal_state)
# Check access
if config.EnablePrivateEvents:
@@ -2277,19 +2277,16 @@
groupCUAToAttendeeMemberPropMap = {}
for groupCUA in groupCUAs:
+ groupCUAToAttendeeMemberPropMap[groupCUA] = ()
groupRecord = yield self.directoryService().recordWithCalendarUserAddress(groupCUA)
if groupRecord:
- # get members from cached membership
- groupID, _ignore_name, _ignore_membershipHash, _ignore_modDate = yield self._txn.groupByUID(groupRecord.uid)
- members = [(yield self.directoryService().recordWithUID(memberUID))
- for memberUID in
- (yield self._txn.membersOfGroup(groupID))
- ]
- groupCUAToAttendeeMemberPropMap[groupRecord.canonicalCalendarUserAddress()] = tuple(
- [member.attendeeProperty(params={"MEMBER": groupCUA}) for member in sorted(members, key=lambda x: x.uid)]
- )
- else:
- groupCUAToAttendeeMemberPropMap[groupCUA] = ()
+ # get members
+ groupID = (yield self._txn.groupByUID(groupRecord.uid))[0]
+ if groupID is not None:
+ members = yield self._txn.groupMembers(groupID)
+ groupCUAToAttendeeMemberPropMap[groupRecord.canonicalCalendarUserAddress()] = tuple(
+ [member.attendeeProperty(params={"MEMBER": groupCUA}) for member in sorted(members, key=lambda x: x.uid)]
+ )
# sync group attendee members if inserting or group changed
changed = False
@@ -2328,7 +2325,10 @@
groupUID = groupRecord.uid
else:
groupUID = uidFromCalendarUserAddress(groupCUA)
- groupID, _ignore_name, membershipHash, _ignore_modDate = yield self._txn.groupByUID(groupUID)
+ (
+ groupID, _ignore_name, membershipHash, _ignore_modDate,
+ _ignore_extant
+ ) = yield self._txn.groupByUID(groupUID)
if groupID in groupIDToMembershipHashMap:
if groupIDToMembershipHashMap[groupID] != membershipHash:
@@ -3309,7 +3309,8 @@
co.SCHEDULE_TAG : self._schedule_tag,
co.SCHEDULE_ETAGS : self._schedule_etags,
co.PRIVATE_COMMENTS : self._private_comments,
- co.MD5 : self._md5
+ co.MD5 : self._md5,
+ co.DATAVERSION : self._currentDataVersion,
}
# Only needed if indexing being changed
@@ -3328,8 +3329,9 @@
values[co.MODIFIED] = utcNowSQL
self._modified = (
yield Update(
- values, Return=co.MODIFIED,
- Where=co.RESOURCE_ID == self._resourceID
+ values,
+ Where=co.RESOURCE_ID == self._resourceID,
+ Return=co.MODIFIED,
).on(txn)
)[0][0]
@@ -3483,14 +3485,6 @@
# Fix any bogus data we can
fixed, unfixed = component.validCalendarData(doFix=True, doRaise=False)
- # Normalize CUAs:
- # FIXME: update the DB copy as well so we don't keep going through
- # this normalization?
- yield component.normalizeCalendarUserAddresses(
- normalizationLookup,
- self.directoryService().recordWithCalendarUserAddress
- )
-
if unfixed:
self.log.error(
"Calendar data id={0} had unfixable problems:\n {1}".format(
@@ -3505,6 +3499,10 @@
)
)
+ # Check for on-demand data upgrade
+ if self._dataversion < self._currentDataVersion:
+ yield self.upgradeData(component)
+
self._cachedComponent = component
self._cachedCommponentPerUser = {}
@@ -3533,6 +3531,25 @@
returnValue(self._cachedCommponentPerUser[user_uuid])
+ @inlineCallbacks
+ def upgradeData(self, component):
+ """
+ Implement in sub-classes. If the data version of this item does not match
+ the current data version, call this method and implement a data upgrade,
+ writing back the new data and updating the data version.
+ """
+
+ if self._dataversion < 1:
+ # Normalize CUAs:
+ yield component.normalizeCalendarUserAddresses(
+ normalizationLookup,
+ self.directoryService().recordWithCalendarUserAddress
+ )
+
+ self._dataversion = self._currentDataVersion
+ yield self.updateDatabase(component)
+
+
def moveValidation(self, destination, name):
"""
Validate whether a move to the specified collection is allowed.
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/test/test_sql.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/caldav/datastore/test/test_sql.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -39,6 +39,7 @@
from twistedcaldav.dateops import datetimeMktime
from twistedcaldav.ical import Component, normalize_iCalStr, diff_iCalStrs
from twistedcaldav.instance import InvalidOverriddenInstanceError
+from twistedcaldav.timezones import TimezoneCache
from txdav.base.propertystore.base import PropertyName
from txdav.caldav.datastore.query.filter import Filter
@@ -2017,7 +2018,195 @@
yield self.abort()
+ @inlineCallbacks
+ def test_standardTimezone(self):
+ """
+ Make sure a standard timezone is not stored and not returned in the calendar data when timezones
+ by reference is on.
+ """
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:America/New_York
+X-LIC-LOCATION:America/New_York
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+1
+TZOFFSETFROM:-0100
+TZOFFSETTO:-0100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;TZID=America/New_York:20130806T000000
+DURATION:PT1H
+DTSTAMP:20051222T210507Z
+SUMMARY:1
+END:VEVENT
+END:VCALENDAR
+"""
+ self.patch(config, "EnableTimezonesByReference", True)
+ TimezoneCache.create()
+ self.addCleanup(TimezoneCache.clear)
+
+ yield self.homeUnderTest(name="user01", create=True)
+ calendar = yield self.calendarUnderTest(name="calendar", home="user01")
+ yield calendar.createCalendarObjectWithName("data1.ics", Component.fromString(data))
+ yield self.commit()
+
+ obj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+ txt = yield obj._text()
+ self.assertTrue("BEGIN:VTIMEZONE" not in txt)
+ cal = yield obj.componentForUser("user01")
+ self.assertEqual(len(tuple(cal.subcomponents())), 1)
+ txt = cal.getTextWithTimezones(False)
+ self.assertTrue("BEGIN:VTIMEZONE" not in txt)
+
+
+ @inlineCallbacks
+ def test_nonStandardTimezone(self):
+ """
+ Make sure a non-standard timezone is stored and returned in the calendar data when timezones
+ by reference is on.
+ """
+ data = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VTIMEZONE
+TZID:GMTPlusOne
+X-LIC-LOCATION:GMTPlusOne
+BEGIN:STANDARD
+DTSTART:18000101T000000
+RDATE:18000101T000000
+TZNAME:GMT+1
+TZOFFSETFROM:-0100
+TZOFFSETTO:-0100
+END:STANDARD
+END:VTIMEZONE
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART;TZID=GMTPlusOne:20130806T000000
+DURATION:PT1H
+DTSTAMP:20051222T210507Z
+SUMMARY:1
+END:VEVENT
+END:VCALENDAR
+"""
+
+ self.patch(config, "EnableTimezonesByReference", True)
+ TimezoneCache.create()
+ self.addCleanup(TimezoneCache.clear)
+
+ yield self.homeUnderTest(name="user01", create=True)
+ calendar = yield self.calendarUnderTest(name="calendar", home="user01")
+ yield calendar.createCalendarObjectWithName("data1.ics", Component.fromString(data))
+ yield self.commit()
+
+ obj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+ txt = yield obj._text()
+ self.assertTrue("TZID:GMTPlusOne" in txt)
+ cal = yield obj.componentForUser("user01")
+ self.assertEqual(len(tuple(cal.subcomponents())), 2)
+ txt = cal.getTextWithTimezones(False)
+ self.assertTrue("BEGIN:VTIMEZONE" in txt)
+
+
+ @inlineCallbacks
+ def test_dataVersion(self):
+ """
+ Make sure L{CalendarObject}'s data version is set when object is created.
+ """
+ olddata = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890-dataversion
+DTSTART:20130806T000000Z
+DURATION:PT1H
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE:mailto:user01 at example.com
+SUMMARY:1
+END:VEVENT
+END:VCALENDAR
+"""
+
+ yield self.homeUnderTest(name="user01", create=True)
+ calendar = yield self.calendarUnderTest(name="calendar", home="user01")
+ yield calendar.createCalendarObjectWithName("data1.ics", Component.fromString(olddata))
+ yield self.commit()
+
+ obj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+ self.assertEqual(obj._dataversion, obj._currentDataVersion)
+ yield self.commit()
+
+
+ @inlineCallbacks
+ def test_dataUpgrade(self):
+ """
+ Make sure L{CalendarObject.upgradeData} works correctly.
+ """
+ olddata = """BEGIN:VCALENDAR
+VERSION:2.0
+PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
+BEGIN:VEVENT
+UID:12345-67890
+DTSTART:20130806T000000Z
+DURATION:PT1H
+DTSTAMP:20051222T210507Z
+ORGANIZER:mailto:user01 at example.com
+ATTENDEE:mailto:user01 at example.com
+SUMMARY:1
+END:VEVENT
+END:VCALENDAR
+"""
+
+ yield self.homeUnderTest(name="user01", create=True)
+ calendar = yield self.calendarUnderTest(name="calendar", home="user01")
+ yield calendar.createCalendarObjectWithName("data1.ics", Component.fromString(olddata))
+ yield self.commit()
+
+ # Make it look old
+ obj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+ co = schema.CALENDAR_OBJECT
+ yield Update(
+ {
+ co.ICALENDAR_TEXT: olddata,
+ co.DATAVERSION: 0,
+ },
+ Where=co.RESOURCE_ID == obj._resourceID,
+ ).on(self.transactionUnderTest())
+ yield self.commit()
+
+ # Still looks old
+ obj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+ txt = yield obj._text()
+ self.assertTrue("mailto:user01 at example.com" in txt)
+ self.assertEqual(obj._dataversion, 0)
+ yield self.commit()
+
+ # Now it is new
+ obj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+ cal = yield obj.componentForUser("user01")
+ txt = cal.getTextWithTimezones(False)
+ self.assertTrue("mailto:user01 at example.com" not in txt)
+ self.assertTrue("urn:x-uid:user01" in txt)
+ self.assertEqual(obj._dataversion, obj._currentDataVersion)
+ yield self.commit()
+
+ # Still new
+ obj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="user01")
+ txt = yield obj._text()
+ self.assertTrue("mailto:user01 at example.com" not in txt)
+ self.assertTrue("urn:x-uid:user01" in txt)
+ self.assertEqual(obj._dataversion, obj._currentDataVersion)
+ yield self.commit()
+
+
+
class SchedulingTests(CommonCommonTests, unittest.TestCase):
"""
CalendarObject splitting tests
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/carddav/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/carddav/datastore/sql.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/carddav/datastore/sql.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -224,7 +224,7 @@
Unbinds any collections that have been shared to this home but not yet
accepted. Associated invite entries are also removed.
"""
- super(AddressBookHome, self).removeUnacceptedShares()
+ yield super(AddressBookHome, self).removeUnacceptedShares()
# Remove group binds too
bind = AddressBookObject._bindSchema
@@ -358,7 +358,7 @@
class AddressBookSharingMixIn(SharingMixIn):
"""
- Sharing code shared between AddressBook and AddressBookObject
+ Sharing code shared between AddressBook and AddressBookObject
"""
def sharedResourceType(self):
@@ -805,7 +805,7 @@
self.ownerHome()._addressbookPropertyStoreID, # not ._resourceID as in CommonHomeChild._loadPropertyStore()
notifyCallback=self.notifyPropertyChanged
)
- super(AddressBook, self)._loadPropertyStore(props)
+ yield super(AddressBook, self)._loadPropertyStore(props)
def initPropertyStore(self, props):
@@ -839,13 +839,13 @@
# Initialize these for all shares
for ename in self._shadowProperties:
if ename not in self.properties() and ename.toString() in props:
- self.properties()[ename] = WebDAVDocument.fromString(props[ename]).root_element
+ self.properties()[ename] = WebDAVDocument.fromString(props[ename.toString()]).root_element
# Only initialize these for direct shares
if self.direct():
for ename in (PropertyName.fromElement(element.DisplayName),):
if ename not in self.properties() and ename.toString() in props:
- self.properties()[ename] = WebDAVDocument.fromString(props[ename]).root_element
+ self.properties()[ename] = WebDAVDocument.fromString(props[ename.toString()]).root_element
def contentType(self):
@@ -868,7 +868,7 @@
@inlineCallbacks
def removedObjectResource(self, child):
"""
- just like CommonHomeChild.removedObjectResource() but does not call self._deleteRevision()
+ Just like CommonHomeChild.removedObjectResource() but does not call self._deleteRevision()
"""
self._objects.pop(child.name(), None)
self._objects.pop(child.uid(), None)
@@ -1856,6 +1856,8 @@
_componentClass = VCard
+ _currentDataVersion = 0
+
# used by CommonHomeChild._childrenAndMetadataForHomeID() only
# _homeChildSchema = schema.ADDRESSBOOK_OBJECT
# _homeChildMetaDataSchema = schema.ADDRESSBOOK_OBJECT
@@ -2232,7 +2234,8 @@
obj.MD5,
Len(obj.TEXT),
obj.CREATED,
- obj.MODIFIED
+ obj.MODIFIED,
+ obj.DATAVERSION,
]
@@ -2248,6 +2251,7 @@
"_size",
"_created",
"_modified",
+ "_dataversion",
)
@@ -2451,17 +2455,21 @@
"""
abo = schema.ADDRESSBOOK_OBJECT
return Insert(
- {abo.RESOURCE_ID: schema.RESOURCE_ID_SEQ,
- abo.ADDRESSBOOK_HOME_RESOURCE_ID: Parameter("addressbookResourceID"),
- abo.RESOURCE_NAME: Parameter("name"),
- abo.VCARD_TEXT: Parameter("text"),
- abo.VCARD_UID: Parameter("uid"),
- abo.KIND: Parameter("kind"),
- abo.MD5: Parameter("md5"),
- },
- Return=(abo.RESOURCE_ID,
- abo.CREATED,
- abo.MODIFIED))
+ {
+ abo.RESOURCE_ID: schema.RESOURCE_ID_SEQ,
+ abo.ADDRESSBOOK_HOME_RESOURCE_ID: Parameter("addressbookResourceID"),
+ abo.RESOURCE_NAME: Parameter("name"),
+ abo.VCARD_TEXT: Parameter("text"),
+ abo.VCARD_UID: Parameter("uid"),
+ abo.KIND: Parameter("kind"),
+ abo.MD5: Parameter("md5"),
+ abo.DATAVERSION: Parameter("dataVersion"),
+ },
+ Return=(
+ abo.RESOURCE_ID,
+ abo.CREATED,
+ abo.MODIFIED
+ ))
@classproperty
@@ -2578,6 +2586,7 @@
uid=self._uid,
md5=self._md5,
kind=self._kind,
+ dataVersion=self._currentDataVersion,
)
)[0]
@@ -2611,9 +2620,12 @@
else:
self._modified = (yield Update(
- {abo.VCARD_TEXT: self._objectText,
- abo.MD5: self._md5,
- abo.MODIFIED: utcNowSQL},
+ {
+ abo.VCARD_TEXT: self._objectText,
+ abo.MD5: self._md5,
+ abo.DATAVERSION: self._dataversion,
+ abo.MODIFIED: utcNowSQL,
+ },
Where=abo.RESOURCE_ID == self._resourceID,
Return=abo.MODIFIED).on(self._txn))[0][0]
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/carddav/datastore/test/test_sql.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/carddav/datastore/test/test_sql.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/carddav/datastore/test/test_sql.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -877,3 +877,31 @@
obj = (yield self.addressbookObjectUnderTest())
addressbookObject = (yield home.objectResourceWithID(obj._resourceID))
self.assertNotEquals(addressbookObject, None)
+
+
+ @inlineCallbacks
+ def test_dataVersion(self):
+ """
+ Make sure L{AddressBookObject}'s data version is set when object is created.
+ """
+ olddata = """BEGIN:VCARD
+VERSION:3.0
+N:Thompson;Default1;;;
+FN:Default1 Thompson
+EMAIL;type=INTERNET;type=WORK;type=pref:lthompson1 at example.com
+TEL;type=WORK;type=pref:1-555-555-5555
+TEL;type=CELL:1-444-444-4444
+item1.ADR;type=WORK;type=pref:;;1245 Test;Sesame Street;California;11111;USA
+item1.X-ABADR:us
+UID:uid-dataversion-test
+END:VCARD
+"""
+
+ yield self.homeUnderTest()
+ adbk = yield self.addressbookUnderTest(name="addressbook")
+ yield adbk.createAddressBookObjectWithName("data1.ics", VCard.fromString(olddata))
+ yield self.commit()
+
+ obj = yield self.addressbookObjectUnderTest(name="data1.ics", addressbook_name="addressbook")
+ self.assertEqual(obj._dataversion, obj._currentDataVersion)
+ yield self.commit()
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -81,6 +81,7 @@
from txdav.common.inotifications import INotificationCollection, \
INotificationObject
from txdav.idav import ChangeCategory
+from twext.who.idirectory import RecordType
from txdav.xml import element
from uuid import uuid4, UUID
@@ -1033,8 +1034,8 @@
{
gr.MEMBERSHIP_HASH: Parameter("membershipHash"),
gr.NAME: Parameter("name"),
- gr.MODIFIED:
- Parameter("timestamp")
+ gr.MODIFIED: Parameter("timestamp"),
+ gr.EXTANT: Parameter("extant"),
},
Where=(gr.GROUP_UID == Parameter("groupUID"))
)
@@ -1044,7 +1045,7 @@
def _groupByUID(cls):
gr = schema.GROUPS
return Select(
- [gr.GROUP_ID, gr.NAME, gr.MEMBERSHIP_HASH, gr.MODIFIED],
+ [gr.GROUP_ID, gr.NAME, gr.MEMBERSHIP_HASH, gr.MODIFIED, gr.EXTANT],
From=gr,
Where=(gr.GROUP_UID == Parameter("groupUID"))
)
@@ -1054,7 +1055,7 @@
def _groupByID(cls):
gr = schema.GROUPS
return Select(
- [gr.GROUP_UID, gr.NAME, gr.MEMBERSHIP_HASH],
+ [gr.GROUP_UID, gr.NAME, gr.MEMBERSHIP_HASH, gr.EXTANT],
From=gr,
Where=(gr.GROUP_ID == Parameter("groupID"))
)
@@ -1069,25 +1070,33 @@
)
+ @inlineCallbacks
def addGroup(self, groupUID, name, membershipHash):
"""
@type groupUID: C{unicode}
@type name: C{unicode}
@type membershipHash: C{str}
"""
- return self._addGroupQuery.on(
+ groupID = yield self._addGroupQuery.on(
self,
name=name.encode("utf-8"),
groupUID=groupUID.encode("utf-8"),
membershipHash=membershipHash
)
+ record = yield self.directoryService().recordWithUID(groupUID)
+ yield self._refreshGroup(
+ groupUID, record, groupID, name.encode("utf-8"), membershipHash
+ )
+ returnValue(groupID)
- def updateGroup(self, groupUID, name, membershipHash):
+
+ def updateGroup(self, groupUID, name, membershipHash, extant=True):
"""
@type groupUID: C{unicode}
@type name: C{unicode}
@type membershipHash: C{str}
+ @type extant: C{boolean}
"""
timestamp = datetime.datetime.utcnow()
return self._updateGroupQuery.on(
@@ -1095,7 +1104,8 @@
name=name.encode("utf-8"),
groupUID=groupUID.encode("utf-8"),
timestamp=timestamp,
- membershipHash=membershipHash
+ membershipHash=membershipHash,
+ extant=(1 if extant else 0)
)
@@ -1107,7 +1117,8 @@
@type groupUID: C{unicode}
@return: Deferred firing with tuple of group ID C{str}, group name
- C{unicode}, membership hash C{str}, and modified timestamp
+ C{unicode}, membership hash C{str}, modified timestamp, and
+ extant C{boolean}
"""
results = (
yield self._groupByUID.on(
@@ -1120,6 +1131,7 @@
results[0][1].decode("utf-8"), # name
results[0][2], # membership hash
results[0][3], # modified timestamp
+ bool(results[0][4]), # extant
))
elif create:
savepoint = SavepointAction("groupByUID")
@@ -1139,6 +1151,7 @@
results[0][1].decode("utf-8"), # name
results[0][2], # membership hash
results[0][3], # modified timestamp
+ bool(results[0][4]), # extant
))
else:
raise
@@ -1155,11 +1168,12 @@
results[0][1].decode("utf-8"), # name
results[0][2], # membership hash
results[0][3], # modified timestamp
+ bool(results[0][4]), # extant
))
else:
raise
else:
- returnValue((None, None, None, None))
+ returnValue((None, None, None, None, None))
@inlineCallbacks
@@ -1169,7 +1183,7 @@
@type groupID: C{str}
@return: Deferred firing with a tuple of group UID C{unicode},
- group name C{unicode}, and membership hash C{str}
+ group name C{unicode}, membership hash C{str}, and extant C{boolean}
"""
try:
results = (yield self._groupByID.on(self, groupID=groupID))[0]
@@ -1177,7 +1191,8 @@
results = (
results[0].decode("utf-8"),
results[1].decode("utf-8"),
- results[2]
+ results[2],
+ bool(results[3])
)
returnValue(results)
except IndexError:
@@ -1263,7 +1278,7 @@
@inlineCallbacks
- def membersOfGroup(self, groupID):
+ def groupMemberUIDs(self, groupID):
"""
Returns the cached set of UIDs for members of the given groupID.
Sub-groups are not returned in the results but their members are,
@@ -1283,6 +1298,131 @@
@inlineCallbacks
+ def refreshGroup(self, groupUID):
+ """
+ Refreshes the group membership cache.
+
+ @param groupUID: the group UID
+ @type groupUID: C{unicode}
+
+ @return: Deferred firing with tuple of group ID C{str}, and
+ membershipChanged C{boolean}
+
+ """
+ log.debug("Faulting in group: {g}", g=groupUID)
+ record = (yield self.directoryService().recordWithUID(groupUID))
+ if record is None:
+ # the group has disappeared from the directory
+ log.info("Group is missing: {g}", g=groupUID)
+ else:
+ log.debug("Got group record: {u}", u=record.uid)
+
+ (
+ groupID, cachedName, cachedMembershipHash, _ignore_modified,
+ _ignore_extant
+ ) = yield self.groupByUID(
+ groupUID,
+ create=(record is not None)
+ )
+
+ membershipChanged = False
+ if groupID:
+ membershipChanged = yield self._refreshGroup(
+ groupUID, record, groupID, cachedName, cachedMembershipHash
+ )
+
+ returnValue((groupID, membershipChanged))
+
+
+ @inlineCallbacks
+ def _refreshGroup(self, groupUID, record, groupID, cachedName, cachedMembershipHash):
+ """
+ @param groupUID: the directory record
+ @type groupUID: C{unicode}
+ @param record: the directory record
+ @type record: C{iDirectoryRecord}
+ @param groupID: group resource id
+ @type groupID: C{str}
+ @param cachedName: group name in the database
+ @type cachedName: C{unicode}
+ @param cachedMembershipHash: membership hash in the database
+ @type cachedMembershipHash: C{str}
+
+ @return: Deferred firing with membershipChanged C{boolean}
+
+ """
+ if record is not None:
+ members = yield record.expandedMembers()
+ name = record.displayName
+ extant = True
+ else:
+ members = frozenset()
+ name = cachedName
+ extant = False
+
+ membershipHashContent = hashlib.md5()
+ members = list(members)
+ members.sort(key=lambda x: x.uid)
+ for member in members:
+ membershipHashContent.update(str(member.uid))
+ membershipHash = membershipHashContent.hexdigest()
+
+ if cachedMembershipHash != membershipHash:
+ membershipChanged = True
+ log.debug(
+ "Group '{group}' changed", group=name
+ )
+ else:
+ membershipChanged = False
+
+ if membershipChanged or record is not None:
+ # also updates group mod date
+ yield self.updateGroup(
+ groupUID, name, membershipHash, extant=extant
+ )
+
+ if membershipChanged:
+ newMemberUIDs = set()
+ for member in members:
+ newMemberUIDs.add(member.uid)
+ yield self.synchronizeMembers(groupID, newMemberUIDs)
+
+ returnValue(membershipChanged)
+
+
+ @inlineCallbacks
+ def synchronizeMembers(self, groupID, newMemberUIDs):
+ numRemoved = numAdded = 0
+ cachedMemberUIDs = (yield self.groupMemberUIDs(groupID))
+
+ for memberUID in cachedMemberUIDs:
+ if memberUID not in newMemberUIDs:
+ numRemoved += 1
+ yield self.removeMemberFromGroup(memberUID, groupID)
+
+ for memberUID in newMemberUIDs:
+ if memberUID not in cachedMemberUIDs:
+ numAdded += 1
+ yield self.addMemberToGroup(memberUID, groupID)
+
+ returnValue((numAdded, numRemoved))
+
+
+ @inlineCallbacks
+ def groupMembers(self, groupID):
+ """
+ The members of the given group as recorded in the db
+ """
+ members = set()
+ memberUIDs = (yield self.groupMemberUIDs(groupID))
+ for uid in memberUIDs:
+ record = (yield self.directoryService().recordWithUID(uid))
+ if record is not None:
+ members.add(record)
+ returnValue(members)
+
+
+ @inlineCallbacks
def groupsFor(self, uid):
"""
Returns the cached set of UIDs for the groups this given uid is
@@ -3475,6 +3615,11 @@
We do the same SQL query for both depth "1" and "infinity", but filter the results for
"1" to only account for a collection change.
+ Now that we are truncating the revision table, we need to handle the full sync (revision == 0)
+ case a little differently as the revision table will not contain data for resources that exist,
+ but were last modified before the revision cut-off. Instead for revision == 0 we need to list
+ all existing child resources.
+
We need to handle shared collection a little differently from owned ones. When a shared collection
is bound into a home we record a revision for it using the sharee home id and sharee collection name.
That revision is the "starting point" for changes: so if sync occurs with a revision earlier than
@@ -3494,61 +3639,96 @@
@type depth: C{str}
"""
- changed = set()
- deleted = set()
- invalid = set()
if revision:
minValidRevision = yield self._txn.calendarserverValue("MIN-VALID-REVISION")
if revision < int(minValidRevision):
raise SyncTokenValidException
+ else:
+ results = yield self.resourceNamesSinceRevisionZero(depth)
+ returnValue(results)
- results = [
- (
- path if path else (collection if collection else ""),
- name if name else "",
- wasdeleted
- )
- for path, collection, name, wasdeleted in
- (yield self.doChangesQuery(revision))
- ]
+ # Use revision table to find changes since the last revision - this will not include
+ # changes to child resources of shared collections - those we will get later
+ results = [
+ (
+ path if path else (collection if collection else ""),
+ name if name else "",
+ wasdeleted
+ )
+ for path, collection, name, wasdeleted in
+ (yield self.doChangesQuery(revision))
+ ]
- deleted_collections = set()
- for path, name, wasdeleted in results:
- if wasdeleted:
- if name:
- # Resource deleted - for depth "1" report collection as changed,
- # otherwise report resource as deleted
- if depth == "1":
- changed.add("%s/" % (path,))
- else:
- deleted.add("%s/%s" % (path, name,))
+ changed = set()
+ deleted = set()
+ invalid = set()
+ deleted_collections = set()
+ for path, name, wasdeleted in results:
+ if wasdeleted:
+ if name:
+ # Resource deleted - for depth "1" report collection as changed,
+ # otherwise report resource as deleted
+ if depth == "1":
+ changed.add("%s/" % (path,))
else:
- # Collection was deleted
- deleted.add("%s/" % (path,))
- deleted_collections.add(path)
+ deleted.add("%s/%s" % (path, name,))
+ else:
+ # Collection was deleted
+ deleted.add("%s/" % (path,))
+ deleted_collections.add(path)
- if path not in deleted_collections:
- # Always report collection as changed
- changed.add("%s/" % (path,))
- if name:
- # Resource changed - for depth "infinity" report resource as changed
- if depth != "1":
- changed.add("%s/%s" % (path, name,))
+ if path not in deleted_collections:
+ # Always report collection as changed
+ changed.add("%s/" % (path,))
- # Now deal with shared collections (and owned if revision == 0)
+ # Resource changed - for depth "infinity" report resource as changed
+ if name and depth != "1":
+ changed.add("%s/%s" % (path, name,))
+
+ # Now deal with existing shared collections
+ # TODO: think about whether this can be done in one query rather than looping over each share
for share in (yield self.children()):
- if share.owned():
- if not revision:
- path = share.name()
- # Always report collection as changed
- changed.add("%s/" % (path,))
+ if not share.owned():
+ sharedChanged, sharedDeleted, sharedInvalid = yield share.sharedChildResourceNamesSinceRevision(revision, depth)
+ changed |= sharedChanged
+ changed -= sharedInvalid
+ deleted |= sharedDeleted
+ deleted -= sharedInvalid
+ invalid |= sharedInvalid
- # Resource changed - for depth "infinity" report resource as changed
- if depth != "1":
- for name in (yield share.listObjectResources()):
- changed.add("%s/%s" % (path, name,))
+ changed = sorted(changed)
+ deleted = sorted(deleted)
+ invalid = sorted(invalid)
+ returnValue((changed, deleted, invalid,))
+
+
+
+
+ @inlineCallbacks
+ def resourceNamesSinceRevisionZero(self, depth):
+ """
+ Revision == 0 specialization of L{resourceNamesSinceRevision} .
+
+ @param depth: depth for determine what changed
+ @type depth: C{str}
+ """
+
+ # Scan each child
+ changed = set()
+ deleted = set()
+ invalid = set()
+ for child in (yield self.children()):
+ if child.owned():
+ path = child.name()
+ # Always report collection as changed
+ changed.add("%s/" % (path,))
+
+ # Resource changed - for depth "infinity" report resource as changed
+ if depth != "1":
+ for name in (yield child.listObjectResources()):
+ changed.add("%s/%s" % (path, name,))
else:
- sharedChanged, sharedDeleted, sharedInvalid = yield share.sharedChildResourceNamesSinceRevision(revision, depth)
+ sharedChanged, sharedDeleted, sharedInvalid = yield child.sharedChildResourceNamesSinceRevisionZero(depth)
changed |= sharedChanged
changed -= sharedInvalid
deleted |= sharedDeleted
@@ -6235,57 +6415,83 @@
else:
invalid.add(self.name() + "/")
else:
+ # If revision is prior to when the share was created, then treat as a full sync of the share
if revision != 0 and revision < self._bindRevision:
if depth != "1":
+ # This should never happen unless the client the share existed, was removed and then
+ # re-added and the client has a token from before the remove. In that case the token is no
+ # longer valid - a full sync has to be done.
raise SyncTokenValidException
else:
- revision = 0
+ results = yield self.sharedChildResourceNamesSinceRevisionZero(depth)
+ returnValue(results)
- if revision:
- rev = self._revisionsSchema
- results = [
- (
- self.name(),
- name if name else "",
- wasdeleted
- )
- for name, wasdeleted in
- (yield Select(
- [rev.RESOURCE_NAME, rev.DELETED],
- From=rev,
- Where=(rev.REVISION > revision).And(
- rev.RESOURCE_ID == self._resourceID)
- ).on(self._txn))
- if name
- ]
+ rev = self._revisionsSchema
+ results = [
+ (
+ self.name(),
+ name if name else "",
+ wasdeleted
+ )
+ for name, wasdeleted in
+ (yield Select(
+ [rev.RESOURCE_NAME, rev.DELETED],
+ From=rev,
+ Where=(rev.REVISION > revision).And(
+ rev.RESOURCE_ID == self._resourceID)
+ ).on(self._txn))
+ if name
+ ]
- for path, name, wasdeleted in results:
- if wasdeleted:
- if depth == "1":
- changed.add("%s/" % (path,))
- else:
- deleted.add("%s/%s" % (path, name,))
+ for path, name, wasdeleted in results:
+ if wasdeleted:
+ if depth == "1":
+ changed.add("%s/" % (path,))
+ else:
+ deleted.add("%s/%s" % (path, name,))
- # Always report collection as changed
- changed.add("%s/" % (path,))
-
- # Resource changed - for depth "infinity" report resource as changed
- if depth != "1":
- changed.add("%s/%s" % (path, name,))
- else:
- path = self.name()
# Always report collection as changed
changed.add("%s/" % (path,))
# Resource changed - for depth "infinity" report resource as changed
- if depth != "1":
- for name in (yield self.listObjectResources()):
- changed.add("%s/%s" % (path, name,))
+ if name and depth != "1":
+ changed.add("%s/%s" % (path, name,))
returnValue((changed, deleted, invalid,))
@inlineCallbacks
+ def sharedChildResourceNamesSinceRevisionZero(self, depth):
+ """
+ Revision == 0 specialization of L{sharedChildResourceNamesSinceRevision}. We report on all
+ existing resources -= this collection and children (if depth == infinite).
+
+ @param depth: depth for determine what changed
+ @type depth: C{str}
+ """
+ changed = set()
+ deleted = set()
+ invalid = set()
+ path = self.name()
+ if self.external():
+ if depth == "1":
+ changed.add("{}/".format(path))
+ else:
+ invalid.add("{}/".format(path))
+ else:
+ path = self.name()
+ # Always report collection as changed
+ changed.add(path + "/")
+
+ # Resource changed - for depth "infinity" report resource as changed
+ if depth != "1":
+ for name in (yield self.listObjectResources()):
+ changed.add("%s/%s" % (path, name,))
+
+ returnValue((changed, deleted, invalid,))
+
+
+ @inlineCallbacks
def _loadPropertyStore(self, props=None):
if props is None:
# Use any authz uid in place of the viewer uid so delegates have their own
@@ -6482,6 +6688,11 @@
_objectSchema = None
_componentClass = None
+ # Sub-classes must override and set their version number. This is used for
+ # on-demand data upgrades - i.e., any time old data is read it will be
+ # converted to the latest format and written back.
+ _currentDataVersion = 0
+
BATCH_LOAD_SIZE = 50
@@ -6569,6 +6780,7 @@
self._size = None
self._created = None
self._modified = None
+ self._dataversion = None
self._textData = None
self._cachedComponent = None
@@ -6814,7 +7026,8 @@
obj.MD5,
Len(obj.TEXT),
obj.CREATED,
- obj.MODIFIED
+ obj.MODIFIED,
+ obj.DATAVERSION,
]
@@ -6828,6 +7041,7 @@
"_size",
"_created",
"_modified",
+ "_dataversion",
)
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current-oracle-dialect-extras.sql
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current-oracle-dialect-extras.sql 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current-oracle-dialect-extras.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -1,11 +1,17 @@
-create or replace function next_job return integer is
-declare
- cursor c1 is select JOB_ID from JOB for update skip locked;
- result integer;
-begin
- open c1;
- fetch c1 into result;
- select JOB_ID from JOB where ID = result for update;
- return result;
-end;
-/
+----
+-- Copyright (c) 2010-2014 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.
+----
+
+-- Extra schema to add to current-oracle-dialect.sql
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -116,7 +116,6 @@
insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('indirect', 4);
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('group', 5);
create table CALENDAR_BIND_STATUS (
"ID" integer primary key,
"DESCRIPTION" nvarchar2(16) unique
@@ -153,7 +152,8 @@
"PRIVATE_COMMENTS" integer default 0 not null,
"MD5" nchar(32),
"CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "DATAVERSION" integer default 0 not null,
unique ("CALENDAR_RESOURCE_ID", "RESOURCE_NAME")
);
@@ -269,7 +269,8 @@
"KIND" integer not null,
"MD5" nchar(32),
"CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
- "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "DATAVERSION" integer default 0 not null,
unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "RESOURCE_NAME"),
unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "VCARD_UID")
);
@@ -401,6 +402,13 @@
"GROUP_UID" nvarchar2(255)
);
+create table GROUP_ATTENDEE_RECONCILE_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "RESOURCE_ID" integer,
+ "GROUP_ID" integer
+);
+
create table GROUPS (
"GROUP_ID" integer primary key,
"NAME" nvarchar2(255),
@@ -417,13 +425,6 @@
primary key ("GROUP_ID", "MEMBER_UID")
);
-create table GROUP_ATTENDEE_RECONCILE_WORK (
- "WORK_ID" integer primary key not null,
- "JOB_ID" integer not null references JOB,
- "RESOURCE_ID" integer,
- "GROUP_ID" integer
-);
-
create table GROUP_ATTENDEE (
"GROUP_ID" integer not null references GROUPS on delete cascade,
"RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
@@ -431,22 +432,6 @@
primary key ("GROUP_ID", "RESOURCE_ID")
);
-create table GROUP_SHAREE_RECONCILE_WORK (
- "WORK_ID" integer primary key not null,
- "JOB_ID" integer not null references JOB,
- "CALENDAR_ID" integer not null references CALENDAR on delete cascade,
- "GROUP_ID" integer not null references GROUPS on delete cascade
-);
-
-create table GROUP_SHAREE (
- "GROUP_ID" integer not null references GROUPS on delete cascade,
- "CALENDAR_HOME_ID" integer not null references CALENDAR_HOME on delete cascade,
- "CALENDAR_ID" integer not null references CALENDAR on delete cascade,
- "GROUP_BIND_MODE" integer not null,
- "MEMBERSHIP_HASH" nvarchar2(255),
- primary key ("GROUP_ID", "CALENDAR_HOME_ID", "CALENDAR_ID")
-);
-
create table DELEGATES (
"DELEGATOR" nvarchar2(255),
"DELEGATE" nvarchar2(255),
@@ -495,10 +480,15 @@
"HOME_ID" integer not null unique references CALENDAR_HOME on delete cascade
);
-create table SCHEDULE_REFRESH_WORK (
+create table SCHEDULE_WORK (
"WORK_ID" integer primary key not null,
"JOB_ID" integer not null references JOB,
"ICALENDAR_UID" nvarchar2(255),
+ "WORK_TYPE" nvarchar2(255)
+);
+
+create table SCHEDULE_REFRESH_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
"HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
"RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
"ATTENDEE_COUNT" integer
@@ -511,18 +501,14 @@
);
create table SCHEDULE_AUTO_REPLY_WORK (
- "WORK_ID" integer primary key not null,
- "JOB_ID" integer not null references JOB,
- "ICALENDAR_UID" nvarchar2(255),
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
"HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
"RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
"PARTSTAT" nvarchar2(255)
);
create table SCHEDULE_ORGANIZER_WORK (
- "WORK_ID" integer primary key not null,
- "JOB_ID" integer not null references JOB,
- "ICALENDAR_UID" nvarchar2(255),
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
"SCHEDULE_ACTION" integer not null,
"HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
"RESOURCE_ID" integer,
@@ -541,19 +527,25 @@
insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('modify', 1);
insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('modify-cancelled', 2);
insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('remove', 3);
+create table SCHEDULE_ORGANIZER_SEND_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "SCHEDULE_ACTION" integer not null,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer,
+ "ATTENDEE" nvarchar2(255),
+ "ITIP_MSG" nclob,
+ "NO_REFRESH" integer
+);
+
create table SCHEDULE_REPLY_WORK (
- "WORK_ID" integer primary key not null,
- "JOB_ID" integer not null references JOB,
- "ICALENDAR_UID" nvarchar2(255),
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
"HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
"RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
"CHANGED_RIDS" nclob
);
create table SCHEDULE_REPLY_CANCEL_WORK (
- "WORK_ID" integer primary key not null,
- "JOB_ID" integer not null references JOB,
- "ICALENDAR_UID" nvarchar2(255),
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
"HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
"ICALENDAR_TEXT" nclob
);
@@ -586,7 +578,7 @@
"VALUE" nvarchar2(255)
);
-insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '44');
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '45');
insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '6');
insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
insert into CALENDARSERVER (NAME, VALUE) values ('NOTIFICATION-DATAVERSION', '1');
@@ -744,6 +736,10 @@
JOB_ID
);
+create index GROUP_ATTENDEE_RECONC_da73d3c2 on GROUP_ATTENDEE_RECONCILE_WORK (
+ JOB_ID
+);
+
create index GROUPS_GROUP_UID_b35cce23 on GROUPS (
GROUP_UID
);
@@ -752,22 +748,10 @@
MEMBER_UID
);
-create index GROUP_ATTENDEE_RECONC_da73d3c2 on GROUP_ATTENDEE_RECONCILE_WORK (
- JOB_ID
-);
-
-create index GROUP_ATTENDEE_ID_d497ffdb on GROUP_ATTENDEE (
+create index GROUP_ATTENDEE_RESOUR_855124dc on GROUP_ATTENDEE (
RESOURCE_ID
);
-create index GROUP_SHAREE_RECONCIL_9aad0858 on GROUP_SHAREE_RECONCILE_WORK (
- JOB_ID
-);
-
-create index GROUP_SHAREE_CALENDAR_28a88850 on GROUP_SHAREE (
- CALENDAR_ID
-);
-
create index DELEGATE_TO_DELEGATOR_5e149b11 on DELEGATES (
DELEGATE,
READ_WRITE,
@@ -802,6 +786,14 @@
JOB_ID
);
+create index SCHEDULE_WORK_JOB_ID_65e810ee on SCHEDULE_WORK (
+ JOB_ID
+);
+
+create index SCHEDULE_WORK_ICALEND_089f33dc on SCHEDULE_WORK (
+ ICALENDAR_UID
+);
+
create index SCHEDULE_REFRESH_WORK_26084c7b on SCHEDULE_REFRESH_WORK (
HOME_RESOURCE_ID
);
@@ -810,10 +802,6 @@
RESOURCE_ID
);
-create index SCHEDULE_REFRESH_WORK_3ffa2718 on SCHEDULE_REFRESH_WORK (
- JOB_ID
-);
-
create index SCHEDULE_REFRESH_ATTE_83053b91 on SCHEDULE_REFRESH_ATTENDEES (
RESOURCE_ID,
ATTENDEE
@@ -827,10 +815,6 @@
RESOURCE_ID
);
-create index SCHEDULE_AUTO_REPLY_W_4d7bb5a8 on SCHEDULE_AUTO_REPLY_WORK (
- JOB_ID
-);
-
create index SCHEDULE_ORGANIZER_WO_18ce4edd on SCHEDULE_ORGANIZER_WORK (
HOME_RESOURCE_ID
);
@@ -839,10 +823,14 @@
RESOURCE_ID
);
-create index SCHEDULE_ORGANIZER_WO_1e9f246d on SCHEDULE_ORGANIZER_WORK (
- JOB_ID
+create index SCHEDULE_ORGANIZER_SE_9ec9f827 on SCHEDULE_ORGANIZER_SEND_WORK (
+ HOME_RESOURCE_ID
);
+create index SCHEDULE_ORGANIZER_SE_699fefc4 on SCHEDULE_ORGANIZER_SEND_WORK (
+ RESOURCE_ID
+);
+
create index SCHEDULE_REPLY_WORK_H_745af8cf on SCHEDULE_REPLY_WORK (
HOME_RESOURCE_ID
);
@@ -851,18 +839,10 @@
RESOURCE_ID
);
-create index SCHEDULE_REPLY_WORK_J_5913b4a4 on SCHEDULE_REPLY_WORK (
- JOB_ID
-);
-
create index SCHEDULE_REPLY_CANCEL_dab513ef on SCHEDULE_REPLY_CANCEL_WORK (
HOME_RESOURCE_ID
);
-create index SCHEDULE_REPLY_CANCEL_94a0c766 on SCHEDULE_REPLY_CANCEL_WORK (
- JOB_ID
-);
-
create index PRINCIPAL_PURGE_POLLI_6383e68a on PRINCIPAL_PURGE_POLLING_WORK (
JOB_ID
);
@@ -883,18 +863,4 @@
HOME_RESOURCE_ID
);
--- Skipped Function next_job
-
--- Extras
-
-create or replace function next_job return integer is
-declare
- cursor c1 is select JOB_ID from JOB for update skip locked;
- result integer;
-begin
- open c1;
- fetch c1 into result;
- select JOB_ID from JOB where ID = result for update;
- return result;
-end;
-/
+-- Extra schema to add to current-oracle-dialect.sql
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current.sql 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/current.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -61,18 +61,9 @@
NOT_BEFORE timestamp not null,
ASSIGNED timestamp default null,
OVERDUE timestamp default null,
- FAILED integer default 0
+ FAILED integer default 0
);
-create or replace function next_job() returns integer as $$
-declare
- result integer;
-begin
- select JOB_ID into result from JOB where pg_try_advisory_xact_lock(JOB_ID) limit 1 for update;
- return result;
-end
-$$ LANGUAGE plpgsql;
-
-------------------
-- Calendar Home --
-------------------
@@ -264,6 +255,7 @@
MD5 char(32) not null,
CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ DATAVERSION integer default 0 not null,
unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
@@ -362,7 +354,7 @@
TIME_RANGE_INSTANCE_ID integer not null references TIME_RANGE on delete cascade,
USER_ID varchar(255) not null,
TRANSPARENT boolean not null,
- ADJUSTED_START_DATE timestamp default null,
+ ADJUSTED_START_DATE timestamp default null,
ADJUSTED_END_DATE timestamp default null
);
@@ -484,6 +476,7 @@
MD5 char(32) not null,
CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ DATAVERSION integer default 0 not null,
unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
unique (ADDRESSBOOK_HOME_RESOURCE_ID, VCARD_UID) -- implicit index
@@ -808,7 +801,7 @@
primary key (GROUP_ID, RESOURCE_ID)
);
-create index GROUP_ATTENDEE_ID on
+create index GROUP_ATTENDEE_ID on -- FIXME: Rename to GROUP_ATTENDEE_RESOURCE_ID
GROUP_ATTENDEE(RESOURCE_ID);
@@ -923,14 +916,28 @@
create index CLEANUP_ONE_INBOX_WORK_JOB_ID on
CLEANUP_ONE_INBOX_WORK(JOB_ID);
+-------------------
+-- Schedule Work --
+-------------------
+
+create table SCHEDULE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ ICALENDAR_UID varchar(255) not null,
+ WORK_TYPE varchar(255) not null
+);
+
+create index SCHEDULE_WORK_JOB_ID on
+ SCHEDULE_WORK(JOB_ID);
+create index SCHEDULE_WORK_ICALENDAR_UID on
+ SCHEDULE_WORK(ICALENDAR_UID);
+
---------------------------
-- Schedule Refresh Work --
---------------------------
create table SCHEDULE_REFRESH_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
- JOB_ID integer references JOB not null,
- ICALENDAR_UID varchar(255) not null,
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
ATTENDEE_COUNT integer
@@ -940,8 +947,6 @@
SCHEDULE_REFRESH_WORK(HOME_RESOURCE_ID);
create index SCHEDULE_REFRESH_WORK_RESOURCE_ID on
SCHEDULE_REFRESH_WORK(RESOURCE_ID);
-create index SCHEDULE_REFRESH_WORK_JOB_ID on
- SCHEDULE_REFRESH_WORK(JOB_ID);
create table SCHEDULE_REFRESH_ATTENDEES (
RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
@@ -958,9 +963,7 @@
------------------------------
create table SCHEDULE_AUTO_REPLY_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
- JOB_ID integer references JOB not null,
- ICALENDAR_UID varchar(255) not null,
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
PARTSTAT varchar(255) not null
@@ -970,17 +973,13 @@
SCHEDULE_AUTO_REPLY_WORK(HOME_RESOURCE_ID);
create index SCHEDULE_AUTO_REPLY_WORK_RESOURCE_ID on
SCHEDULE_AUTO_REPLY_WORK(RESOURCE_ID);
-create index SCHEDULE_AUTO_REPLY_WORK_JOB_ID on
- SCHEDULE_AUTO_REPLY_WORK(JOB_ID);
-----------------------------
-- Schedule Organizer Work --
-----------------------------
create table SCHEDULE_ORGANIZER_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
- JOB_ID integer references JOB not null,
- ICALENDAR_UID varchar(255) not null,
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
SCHEDULE_ACTION integer not null, -- Enum SCHEDULE_ACTION
HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
RESOURCE_ID integer, -- this references a possibly non-existent CALENDR_OBJECT
@@ -994,8 +993,6 @@
SCHEDULE_ORGANIZER_WORK(HOME_RESOURCE_ID);
create index SCHEDULE_ORGANIZER_WORK_RESOURCE_ID on
SCHEDULE_ORGANIZER_WORK(RESOURCE_ID);
-create index SCHEDULE_ORGANIZER_WORK_JOB_ID on
- SCHEDULE_ORGANIZER_WORK(JOB_ID);
-- Enumeration of schedule actions
@@ -1009,14 +1006,31 @@
insert into SCHEDULE_ACTION values (2, 'modify-cancelled');
insert into SCHEDULE_ACTION values (3, 'remove');
+----------------------------------
+-- Schedule Organizer Send Work --
+----------------------------------
+
+create table SCHEDULE_ORGANIZER_SEND_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ SCHEDULE_ACTION integer not null, -- Enum SCHEDULE_ACTION
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer, -- this references a possibly non-existent CALENDAR_OBJECT
+ ATTENDEE varchar(255) not null,
+ ITIP_MSG text,
+ NO_REFRESH boolean
+);
+
+create index SCHEDULE_ORGANIZER_SEND_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_SEND_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_ORGANIZER_SEND_WORK_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_SEND_WORK(RESOURCE_ID);
+
-------------------------
-- Schedule Reply Work --
-------------------------
create table SCHEDULE_REPLY_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
- JOB_ID integer references JOB not null,
- ICALENDAR_UID varchar(255) not null,
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
CHANGED_RIDS text
@@ -1026,25 +1040,19 @@
SCHEDULE_REPLY_WORK(HOME_RESOURCE_ID);
create index SCHEDULE_REPLY_WORK_RESOURCE_ID on
SCHEDULE_REPLY_WORK(RESOURCE_ID);
-create index SCHEDULE_REPLY_WORK_JOB_ID on
- SCHEDULE_REPLY_WORK(JOB_ID);
--------------------------------
-- Schedule Reply Cancel Work --
--------------------------------
create table SCHEDULE_REPLY_CANCEL_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
- JOB_ID integer references JOB not null,
- ICALENDAR_UID varchar(255) not null,
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
ICALENDAR_TEXT text not null
);
create index SCHEDULE_REPLY_CANCEL_WORK_HOME_RESOURCE_ID on
SCHEDULE_REPLY_CANCEL_WORK(HOME_RESOURCE_ID);
-create index SCHEDULE_REPLY_CANCEL_WORK_JOB_ID on
- SCHEDULE_REPLY_CANCEL_WORK(JOB_ID);
----------------------------------
-- Principal Purge Polling Work --
@@ -1110,7 +1118,7 @@
VALUE varchar(255)
);
-insert into CALENDARSERVER values ('VERSION', '44');
+insert into CALENDARSERVER values ('VERSION', '45');
insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '6');
insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
insert into CALENDARSERVER values ('NOTIFICATION-DATAVERSION', '1');
Copied: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/oracle-dialect/v44.sql (from rev 13731, CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v44.sql)
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/oracle-dialect/v44.sql (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/oracle-dialect/v44.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,866 @@
+create sequence RESOURCE_ID_SEQ;
+create sequence JOB_SEQ;
+create sequence INSTANCE_ID_SEQ;
+create sequence ATTACHMENT_ID_SEQ;
+create sequence REVISION_SEQ;
+create sequence WORKITEM_SEQ;
+create table NODE_INFO (
+ "HOSTNAME" nvarchar2(255),
+ "PID" integer not null,
+ "PORT" integer not null,
+ "TIME" timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null,
+ primary key ("HOSTNAME", "PORT")
+);
+
+create table NAMED_LOCK (
+ "LOCK_NAME" nvarchar2(255) primary key
+);
+
+create table JOB (
+ "JOB_ID" integer primary key not null,
+ "WORK_TYPE" nvarchar2(255),
+ "PRIORITY" integer default 0,
+ "WEIGHT" integer default 0,
+ "NOT_BEFORE" timestamp not null,
+ "ASSIGNED" timestamp default null,
+ "OVERDUE" timestamp default null,
+ "FAILED" integer default 0
+);
+
+create table CALENDAR_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "STATUS" integer default 0 not null,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table HOME_STATUS (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into HOME_STATUS (DESCRIPTION, ID) values ('normal', 0);
+insert into HOME_STATUS (DESCRIPTION, ID) values ('external', 1);
+insert into HOME_STATUS (DESCRIPTION, ID) values ('purging', 2);
+create table CALENDAR (
+ "RESOURCE_ID" integer primary key
+);
+
+create table CALENDAR_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "DEFAULT_EVENTS" integer default null references CALENDAR on delete set null,
+ "DEFAULT_TASKS" integer default null references CALENDAR on delete set null,
+ "DEFAULT_POLLS" integer default null references CALENDAR on delete set null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null,
+ "AVAILABILITY" nclob default null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR on delete cascade,
+ "SUPPORTED_COMPONENTS" nvarchar2(255) default null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "STATUS" integer default 0 not null,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table NOTIFICATION (
+ "RESOURCE_ID" integer primary key,
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME,
+ "NOTIFICATION_UID" nvarchar2(255),
+ "NOTIFICATION_TYPE" nvarchar2(255),
+ "NOTIFICATION_DATA" nclob,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique ("NOTIFICATION_UID", "NOTIFICATION_HOME_RESOURCE_ID")
+);
+
+create table CALENDAR_BIND (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "EXTERNAL_ID" integer default null,
+ "CALENDAR_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "BIND_REVISION" integer default 0 not null,
+ "MESSAGE" nclob,
+ "TRANSP" integer default 0 not null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null,
+ "TIMEZONE" nclob default null,
+ primary key ("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_ID"),
+ unique ("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_NAME")
+);
+
+create table CALENDAR_BIND_MODE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('indirect', 4);
+create table CALENDAR_BIND_STATUS (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('deleted', 4);
+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,
+ "RESOURCE_NAME" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob,
+ "ICALENDAR_UID" nvarchar2(255),
+ "ICALENDAR_TYPE" nvarchar2(255),
+ "ATTACHMENTS_MODE" integer default 0 not null,
+ "DROPBOX_ID" nvarchar2(255),
+ "ORGANIZER" nvarchar2(255),
+ "RECURRANCE_MIN" date,
+ "RECURRANCE_MAX" date,
+ "ACCESS" integer default 0 not null,
+ "SCHEDULE_OBJECT" integer default 0,
+ "SCHEDULE_TAG" nvarchar2(36) default null,
+ "SCHEDULE_ETAGS" nclob default null,
+ "PRIVATE_COMMENTS" integer default 0 not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique ("CALENDAR_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table CALENDAR_OBJ_ATTACHMENTS_MODE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE (DESCRIPTION, ID) values ('none', 0);
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE (DESCRIPTION, ID) values ('write', 2);
+create table CALENDAR_ACCESS_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(32) unique
+);
+
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
+create table TIME_RANGE (
+ "INSTANCE_ID" integer primary key,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "FLOATING" integer not null,
+ "START_DATE" timestamp not null,
+ "END_DATE" timestamp not null,
+ "FBTYPE" integer not null,
+ "TRANSPARENT" integer not null
+);
+
+create table FREE_BUSY_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
+create table PERUSER (
+ "TIME_RANGE_INSTANCE_ID" integer not null references TIME_RANGE on delete cascade,
+ "USER_ID" nvarchar2(255),
+ "TRANSPARENT" integer not null,
+ "ADJUSTED_START_DATE" timestamp default null,
+ "ADJUSTED_END_DATE" timestamp default null
+);
+
+create table ATTACHMENT (
+ "ATTACHMENT_ID" integer primary key,
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "DROPBOX_ID" nvarchar2(255),
+ "CONTENT_TYPE" nvarchar2(255),
+ "SIZE" integer not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "PATH" nvarchar2(1024)
+);
+
+create table ATTACHMENT_CALENDAR_OBJECT (
+ "ATTACHMENT_ID" integer not null references ATTACHMENT on delete cascade,
+ "MANAGED_ID" nvarchar2(255),
+ "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ primary key ("ATTACHMENT_ID", "CALENDAR_OBJECT_RESOURCE_ID"),
+ unique ("MANAGED_ID", "CALENDAR_OBJECT_RESOURCE_ID")
+);
+
+create table RESOURCE_PROPERTY (
+ "RESOURCE_ID" integer not null,
+ "NAME" nvarchar2(255),
+ "VALUE" nclob,
+ "VIEWER_UID" nvarchar2(255),
+ primary key ("RESOURCE_ID", "NAME", "VIEWER_UID")
+);
+
+create table ADDRESSBOOK_HOME (
+ "RESOURCE_ID" integer primary key,
+ "ADDRESSBOOK_PROPERTY_STORE_ID" integer not null,
+ "OWNER_UID" nvarchar2(255) unique,
+ "STATUS" integer default 0 not null,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table ADDRESSBOOK_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references ADDRESSBOOK_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table SHARED_ADDRESSBOOK_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "OWNER_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "EXTERNAL_ID" integer default null,
+ "ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "BIND_REVISION" integer default 0 not null,
+ "MESSAGE" nclob,
+ primary key ("ADDRESSBOOK_HOME_RESOURCE_ID", "OWNER_HOME_RESOURCE_ID"),
+ unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_NAME")
+);
+
+create table ADDRESSBOOK_OBJECT (
+ "RESOURCE_ID" integer primary key,
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "VCARD_TEXT" nclob,
+ "VCARD_UID" nvarchar2(255),
+ "KIND" integer not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "RESOURCE_NAME"),
+ unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "VCARD_UID")
+);
+
+create table ADDRESSBOOK_OBJECT_KIND (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('person', 0);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('group', 1);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('resource', 2);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('location', 3);
+create table ABO_MEMBERS (
+ "GROUP_ID" integer not null,
+ "ADDRESSBOOK_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "MEMBER_ID" integer not null,
+ "REVISION" integer not null,
+ "REMOVED" integer default 0 not null,
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ primary key ("GROUP_ID", "MEMBER_ID", "REVISION")
+);
+
+create table ABO_FOREIGN_MEMBERS (
+ "GROUP_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "ADDRESSBOOK_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "MEMBER_ADDRESS" nvarchar2(255),
+ primary key ("GROUP_ID", "MEMBER_ADDRESS")
+);
+
+create table SHARED_GROUP_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "GROUP_RESOURCE_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "EXTERNAL_ID" integer default null,
+ "GROUP_ADDRESSBOOK_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "BIND_REVISION" integer default 0 not null,
+ "MESSAGE" nclob,
+ primary key ("ADDRESSBOOK_HOME_RESOURCE_ID", "GROUP_RESOURCE_ID"),
+ unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "GROUP_ADDRESSBOOK_NAME")
+);
+
+create table CALENDAR_OBJECT_REVISIONS (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer references CALENDAR,
+ "CALENDAR_NAME" nvarchar2(255) default null,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null,
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "OWNER_HOME_RESOURCE_ID" integer references ADDRESSBOOK_HOME,
+ "ADDRESSBOOK_NAME" nvarchar2(255) default null,
+ "OBJECT_RESOURCE_ID" integer default 0,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null,
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null,
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique ("NOTIFICATION_HOME_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table APN_SUBSCRIPTIONS (
+ "TOKEN" nvarchar2(255),
+ "RESOURCE_KEY" nvarchar2(255),
+ "MODIFIED" integer not null,
+ "SUBSCRIBER_GUID" nvarchar2(255),
+ "USER_AGENT" nvarchar2(255) default null,
+ "IP_ADDR" nvarchar2(255) default null,
+ primary key ("TOKEN", "RESOURCE_KEY")
+);
+
+create table IMIP_TOKENS (
+ "TOKEN" nvarchar2(255),
+ "ORGANIZER" nvarchar2(255),
+ "ATTENDEE" nvarchar2(255),
+ "ICALUID" nvarchar2(255),
+ "ACCESSED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ primary key ("ORGANIZER", "ATTENDEE", "ICALUID")
+);
+
+create table IMIP_INVITATION_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "FROM_ADDR" nvarchar2(255),
+ "TO_ADDR" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob
+);
+
+create table IMIP_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table IMIP_REPLY_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "ORGANIZER" nvarchar2(255),
+ "ATTENDEE" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob
+);
+
+create table PUSH_NOTIFICATION_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "PUSH_ID" nvarchar2(255),
+ "PUSH_PRIORITY" integer not null
+);
+
+create table GROUP_CACHER_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table GROUP_REFRESH_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "GROUP_UID" nvarchar2(255)
+);
+
+create table GROUP_ATTENDEE_RECONCILE_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "RESOURCE_ID" integer,
+ "GROUP_ID" integer
+);
+
+create table GROUPS (
+ "GROUP_ID" integer primary key,
+ "NAME" nvarchar2(255),
+ "GROUP_UID" nvarchar2(255),
+ "MEMBERSHIP_HASH" nvarchar2(255),
+ "EXTANT" integer default 1,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table GROUP_MEMBERSHIP (
+ "GROUP_ID" integer not null references GROUPS on delete cascade,
+ "MEMBER_UID" nvarchar2(255),
+ primary key ("GROUP_ID", "MEMBER_UID")
+);
+
+create table GROUP_ATTENDEE (
+ "GROUP_ID" integer not null references GROUPS on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "MEMBERSHIP_HASH" nvarchar2(255),
+ primary key ("GROUP_ID", "RESOURCE_ID")
+);
+
+create table DELEGATES (
+ "DELEGATOR" nvarchar2(255),
+ "DELEGATE" nvarchar2(255),
+ "READ_WRITE" integer not null,
+ primary key ("DELEGATOR", "READ_WRITE", "DELEGATE")
+);
+
+create table DELEGATE_GROUPS (
+ "DELEGATOR" nvarchar2(255),
+ "GROUP_ID" integer not null references GROUPS on delete cascade,
+ "READ_WRITE" integer not null,
+ "IS_EXTERNAL" integer not null,
+ primary key ("DELEGATOR", "READ_WRITE", "GROUP_ID")
+);
+
+create table EXTERNAL_DELEGATE_GROUPS (
+ "DELEGATOR" nvarchar2(255) primary key,
+ "GROUP_UID_READ" nvarchar2(255),
+ "GROUP_UID_WRITE" nvarchar2(255)
+);
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade
+);
+
+create table FIND_MIN_VALID_REVISION_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table REVISION_CLEANUP_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table INBOX_CLEANUP_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table CLEANUP_ONE_INBOX_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "HOME_ID" integer not null unique references CALENDAR_HOME on delete cascade
+);
+
+create table SCHEDULE_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "ICALENDAR_UID" nvarchar2(255),
+ "WORK_TYPE" nvarchar2(255)
+);
+
+create table SCHEDULE_REFRESH_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "ATTENDEE_COUNT" integer
+);
+
+create table SCHEDULE_REFRESH_ATTENDEES (
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "ATTENDEE" nvarchar2(255),
+ primary key ("RESOURCE_ID", "ATTENDEE")
+);
+
+create table SCHEDULE_AUTO_REPLY_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "PARTSTAT" nvarchar2(255)
+);
+
+create table SCHEDULE_ORGANIZER_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "SCHEDULE_ACTION" integer not null,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer,
+ "ICALENDAR_TEXT_OLD" nclob,
+ "ICALENDAR_TEXT_NEW" nclob,
+ "ATTENDEE_COUNT" integer,
+ "SMART_MERGE" integer
+);
+
+create table SCHEDULE_ACTION (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('create', 0);
+insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('modify', 1);
+insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('modify-cancelled', 2);
+insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('remove', 3);
+create table SCHEDULE_ORGANIZER_SEND_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "SCHEDULE_ACTION" integer not null,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer,
+ "ATTENDEE" nvarchar2(255),
+ "ITIP_MSG" nclob,
+ "NO_REFRESH" integer
+);
+
+create table SCHEDULE_REPLY_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "CHANGED_RIDS" nclob
+);
+
+create table SCHEDULE_REPLY_CANCEL_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "ICALENDAR_TEXT" nclob
+);
+
+create table PRINCIPAL_PURGE_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table PRINCIPAL_PURGE_CHECK_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "UID" nvarchar2(255)
+);
+
+create table PRINCIPAL_PURGE_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "UID" nvarchar2(255)
+);
+
+create table PRINCIPAL_PURGE_HOME_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade
+);
+
+create table CALENDARSERVER (
+ "NAME" nvarchar2(255) primary key,
+ "VALUE" nvarchar2(255)
+);
+
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '44');
+insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '6');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
+insert into CALENDARSERVER (NAME, VALUE) values ('NOTIFICATION-DATAVERSION', '1');
+insert into CALENDARSERVER (NAME, VALUE) values ('MIN-VALID-REVISION', '1');
+create index CALENDAR_HOME_METADAT_3cb9049e on CALENDAR_HOME_METADATA (
+ DEFAULT_EVENTS
+);
+
+create index CALENDAR_HOME_METADAT_d55e5548 on CALENDAR_HOME_METADATA (
+ DEFAULT_TASKS
+);
+
+create index CALENDAR_HOME_METADAT_910264ce on CALENDAR_HOME_METADATA (
+ DEFAULT_POLLS
+);
+
+create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
+ NOTIFICATION_HOME_RESOURCE_ID
+);
+
+create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ RECURRANCE_MAX
+);
+
+create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
+ ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
+ DROPBOX_ID
+);
+
+create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
+ CALENDAR_RESOURCE_ID
+);
+
+create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
+ CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index PERUSER_TIME_RANGE_IN_5468a226 on PERUSER (
+ TIME_RANGE_INSTANCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
+ CALENDAR_HOME_RESOURCE_ID
+);
+
+create index ATTACHMENT_DROPBOX_ID_5073cf23 on ATTACHMENT (
+ DROPBOX_ID
+);
+
+create index ATTACHMENT_CALENDAR_O_81508484 on ATTACHMENT_CALENDAR_OBJECT (
+ CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index SHARED_ADDRESSBOOK_BI_e9a2e6d4 on SHARED_ADDRESSBOOK_BIND (
+ OWNER_HOME_RESOURCE_ID
+);
+
+create index ABO_MEMBERS_ADDRESSBO_4effa879 on ABO_MEMBERS (
+ ADDRESSBOOK_ID
+);
+
+create index ABO_MEMBERS_MEMBER_ID_8d66adcf on ABO_MEMBERS (
+ MEMBER_ID
+);
+
+create index ABO_FOREIGN_MEMBERS_A_1fd2c5e9 on ABO_FOREIGN_MEMBERS (
+ ADDRESSBOOK_ID
+);
+
+create index SHARED_GROUP_BIND_RES_cf52f95d on SHARED_GROUP_BIND (
+ GROUP_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID,
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_6d9d929c on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ RESOURCE_NAME,
+ DELETED,
+ REVISION
+);
+
+create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_2bfcf757 on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID,
+ OWNER_HOME_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_OBJECT_RE_00fe8288 on ADDRESSBOOK_OBJECT_REVISIONS (
+ OWNER_HOME_RESOURCE_ID,
+ RESOURCE_NAME,
+ DELETED,
+ REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_45004780 on ADDRESSBOOK_OBJECT_REVISIONS (
+ OWNER_HOME_RESOURCE_ID,
+ REVISION
+);
+
+create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID,
+ REVISION
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
+ RESOURCE_KEY
+);
+
+create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
+ TOKEN
+);
+
+create index IMIP_INVITATION_WORK__586d064c on IMIP_INVITATION_WORK (
+ JOB_ID
+);
+
+create index IMIP_POLLING_WORK_JOB_d5535891 on IMIP_POLLING_WORK (
+ JOB_ID
+);
+
+create index IMIP_REPLY_WORK_JOB_I_bf4ae73e on IMIP_REPLY_WORK (
+ JOB_ID
+);
+
+create index PUSH_NOTIFICATION_WOR_8bbab117 on PUSH_NOTIFICATION_WORK (
+ JOB_ID
+);
+
+create index GROUP_CACHER_POLLING__6eb3151c on GROUP_CACHER_POLLING_WORK (
+ JOB_ID
+);
+
+create index GROUP_REFRESH_WORK_JO_717ede20 on GROUP_REFRESH_WORK (
+ JOB_ID
+);
+
+create index GROUP_ATTENDEE_RECONC_da73d3c2 on GROUP_ATTENDEE_RECONCILE_WORK (
+ JOB_ID
+);
+
+create index GROUPS_GROUP_UID_b35cce23 on GROUPS (
+ GROUP_UID
+);
+
+create index GROUP_MEMBERSHIP_MEMB_0ca508e8 on GROUP_MEMBERSHIP (
+ MEMBER_UID
+);
+
+create index GROUP_ATTENDEE_RESOUR_855124dc on GROUP_ATTENDEE (
+ RESOURCE_ID
+);
+
+create index DELEGATE_TO_DELEGATOR_5e149b11 on DELEGATES (
+ DELEGATE,
+ READ_WRITE,
+ DELEGATOR
+);
+
+create index DELEGATE_GROUPS_GROUP_25117446 on DELEGATE_GROUPS (
+ GROUP_ID
+);
+
+create index CALENDAR_OBJECT_SPLIT_af71dcda on CALENDAR_OBJECT_SPLITTER_WORK (
+ RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_SPLIT_33603b72 on CALENDAR_OBJECT_SPLITTER_WORK (
+ JOB_ID
+);
+
+create index FIND_MIN_VALID_REVISI_78d17400 on FIND_MIN_VALID_REVISION_WORK (
+ JOB_ID
+);
+
+create index REVISION_CLEANUP_WORK_eb062686 on REVISION_CLEANUP_WORK (
+ JOB_ID
+);
+
+create index INBOX_CLEANUP_WORK_JO_799132bd on INBOX_CLEANUP_WORK (
+ JOB_ID
+);
+
+create index CLEANUP_ONE_INBOX_WOR_375dac36 on CLEANUP_ONE_INBOX_WORK (
+ JOB_ID
+);
+
+create index SCHEDULE_WORK_JOB_ID_65e810ee on SCHEDULE_WORK (
+ JOB_ID
+);
+
+create index SCHEDULE_WORK_ICALEND_089f33dc on SCHEDULE_WORK (
+ ICALENDAR_UID
+);
+
+create index SCHEDULE_REFRESH_WORK_26084c7b on SCHEDULE_REFRESH_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_REFRESH_WORK_989efe54 on SCHEDULE_REFRESH_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_REFRESH_ATTE_83053b91 on SCHEDULE_REFRESH_ATTENDEES (
+ RESOURCE_ID,
+ ATTENDEE
+);
+
+create index SCHEDULE_AUTO_REPLY_W_0256478d on SCHEDULE_AUTO_REPLY_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_AUTO_REPLY_W_0755e754 on SCHEDULE_AUTO_REPLY_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_ORGANIZER_WO_18ce4edd on SCHEDULE_ORGANIZER_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_ORGANIZER_WO_14702035 on SCHEDULE_ORGANIZER_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_ORGANIZER_SE_9ec9f827 on SCHEDULE_ORGANIZER_SEND_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_ORGANIZER_SE_699fefc4 on SCHEDULE_ORGANIZER_SEND_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_REPLY_WORK_H_745af8cf on SCHEDULE_REPLY_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_REPLY_WORK_R_11bd3fbb on SCHEDULE_REPLY_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_REPLY_CANCEL_dab513ef on SCHEDULE_REPLY_CANCEL_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index PRINCIPAL_PURGE_POLLI_6383e68a on PRINCIPAL_PURGE_POLLING_WORK (
+ JOB_ID
+);
+
+create index PRINCIPAL_PURGE_CHECK_b0c024c1 on PRINCIPAL_PURGE_CHECK_WORK (
+ JOB_ID
+);
+
+create index PRINCIPAL_PURGE_WORK__7a8141a3 on PRINCIPAL_PURGE_WORK (
+ JOB_ID
+);
+
+create index PRINCIPAL_PURGE_HOME__f35eea7a on PRINCIPAL_PURGE_HOME_WORK (
+ JOB_ID
+);
+
+create index PRINCIPAL_PURGE_HOME__967e4480 on PRINCIPAL_PURGE_HOME_WORK (
+ HOME_RESOURCE_ID
+);
+
+
+-- Extras
+
Added: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/oracle-dialect/v45.sql
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/oracle-dialect/v45.sql (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/oracle-dialect/v45.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,866 @@
+create sequence RESOURCE_ID_SEQ;
+create sequence JOB_SEQ;
+create sequence INSTANCE_ID_SEQ;
+create sequence ATTACHMENT_ID_SEQ;
+create sequence REVISION_SEQ;
+create sequence WORKITEM_SEQ;
+create table NODE_INFO (
+ "HOSTNAME" nvarchar2(255),
+ "PID" integer not null,
+ "PORT" integer not null,
+ "TIME" timestamp default CURRENT_TIMESTAMP at time zone 'UTC' not null,
+ primary key ("HOSTNAME", "PORT")
+);
+
+create table NAMED_LOCK (
+ "LOCK_NAME" nvarchar2(255) primary key
+);
+
+create table JOB (
+ "JOB_ID" integer primary key not null,
+ "WORK_TYPE" nvarchar2(255),
+ "PRIORITY" integer default 0,
+ "WEIGHT" integer default 0,
+ "NOT_BEFORE" timestamp not null,
+ "ASSIGNED" timestamp default null,
+ "OVERDUE" timestamp default null,
+ "FAILED" integer default 0
+);
+
+create table CALENDAR_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "STATUS" integer default 0 not null,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table HOME_STATUS (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into HOME_STATUS (DESCRIPTION, ID) values ('normal', 0);
+insert into HOME_STATUS (DESCRIPTION, ID) values ('external', 1);
+insert into HOME_STATUS (DESCRIPTION, ID) values ('purging', 2);
+create table CALENDAR (
+ "RESOURCE_ID" integer primary key
+);
+
+create table CALENDAR_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "DEFAULT_EVENTS" integer default null references CALENDAR on delete set null,
+ "DEFAULT_TASKS" integer default null references CALENDAR on delete set null,
+ "DEFAULT_POLLS" integer default null references CALENDAR on delete set null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null,
+ "AVAILABILITY" nclob default null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table CALENDAR_METADATA (
+ "RESOURCE_ID" integer primary key references CALENDAR on delete cascade,
+ "SUPPORTED_COMPONENTS" nvarchar2(255) default null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_HOME (
+ "RESOURCE_ID" integer primary key,
+ "OWNER_UID" nvarchar2(255) unique,
+ "STATUS" integer default 0 not null,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table NOTIFICATION (
+ "RESOURCE_ID" integer primary key,
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME,
+ "NOTIFICATION_UID" nvarchar2(255),
+ "NOTIFICATION_TYPE" nvarchar2(255),
+ "NOTIFICATION_DATA" nclob,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique ("NOTIFICATION_UID", "NOTIFICATION_HOME_RESOURCE_ID")
+);
+
+create table CALENDAR_BIND (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "EXTERNAL_ID" integer default null,
+ "CALENDAR_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "BIND_REVISION" integer default 0 not null,
+ "MESSAGE" nclob,
+ "TRANSP" integer default 0 not null,
+ "ALARM_VEVENT_TIMED" nclob default null,
+ "ALARM_VEVENT_ALLDAY" nclob default null,
+ "ALARM_VTODO_TIMED" nclob default null,
+ "ALARM_VTODO_ALLDAY" nclob default null,
+ "TIMEZONE" nclob default null,
+ primary key ("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_ID"),
+ unique ("CALENDAR_HOME_RESOURCE_ID", "CALENDAR_RESOURCE_NAME")
+);
+
+create table CALENDAR_BIND_MODE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('own', 0);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('write', 2);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('direct', 3);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('indirect', 4);
+create table CALENDAR_BIND_STATUS (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invited', 0);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('accepted', 1);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('declined', 2);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('invalid', 3);
+insert into CALENDAR_BIND_STATUS (DESCRIPTION, ID) values ('deleted', 4);
+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,
+ "RESOURCE_NAME" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob,
+ "ICALENDAR_UID" nvarchar2(255),
+ "ICALENDAR_TYPE" nvarchar2(255),
+ "ATTACHMENTS_MODE" integer default 0 not null,
+ "DROPBOX_ID" nvarchar2(255),
+ "ORGANIZER" nvarchar2(255),
+ "RECURRANCE_MIN" date,
+ "RECURRANCE_MAX" date,
+ "ACCESS" integer default 0 not null,
+ "SCHEDULE_OBJECT" integer default 0,
+ "SCHEDULE_TAG" nvarchar2(36) default null,
+ "SCHEDULE_ETAGS" nclob default null,
+ "PRIVATE_COMMENTS" integer default 0 not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "DATAVERSION" integer default 0 not null,
+ unique ("CALENDAR_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table CALENDAR_OBJ_ATTACHMENTS_MODE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE (DESCRIPTION, ID) values ('none', 0);
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE (DESCRIPTION, ID) values ('read', 1);
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE (DESCRIPTION, ID) values ('write', 2);
+create table CALENDAR_ACCESS_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(32) unique
+);
+
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('', 0);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('public', 1);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('private', 2);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('confidential', 3);
+insert into CALENDAR_ACCESS_TYPE (DESCRIPTION, ID) values ('restricted', 4);
+create table TIME_RANGE (
+ "INSTANCE_ID" integer primary key,
+ "CALENDAR_RESOURCE_ID" integer not null references CALENDAR on delete cascade,
+ "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "FLOATING" integer not null,
+ "START_DATE" timestamp not null,
+ "END_DATE" timestamp not null,
+ "FBTYPE" integer not null,
+ "TRANSPARENT" integer not null
+);
+
+create table FREE_BUSY_TYPE (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('unknown', 0);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('free', 1);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy', 2);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-unavailable', 3);
+insert into FREE_BUSY_TYPE (DESCRIPTION, ID) values ('busy-tentative', 4);
+create table PERUSER (
+ "TIME_RANGE_INSTANCE_ID" integer not null references TIME_RANGE on delete cascade,
+ "USER_ID" nvarchar2(255),
+ "TRANSPARENT" integer not null,
+ "ADJUSTED_START_DATE" timestamp default null,
+ "ADJUSTED_END_DATE" timestamp default null
+);
+
+create table ATTACHMENT (
+ "ATTACHMENT_ID" integer primary key,
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "DROPBOX_ID" nvarchar2(255),
+ "CONTENT_TYPE" nvarchar2(255),
+ "SIZE" integer not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "PATH" nvarchar2(1024)
+);
+
+create table ATTACHMENT_CALENDAR_OBJECT (
+ "ATTACHMENT_ID" integer not null references ATTACHMENT on delete cascade,
+ "MANAGED_ID" nvarchar2(255),
+ "CALENDAR_OBJECT_RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ primary key ("ATTACHMENT_ID", "CALENDAR_OBJECT_RESOURCE_ID"),
+ unique ("MANAGED_ID", "CALENDAR_OBJECT_RESOURCE_ID")
+);
+
+create table RESOURCE_PROPERTY (
+ "RESOURCE_ID" integer not null,
+ "NAME" nvarchar2(255),
+ "VALUE" nclob,
+ "VIEWER_UID" nvarchar2(255),
+ primary key ("RESOURCE_ID", "NAME", "VIEWER_UID")
+);
+
+create table ADDRESSBOOK_HOME (
+ "RESOURCE_ID" integer primary key,
+ "ADDRESSBOOK_PROPERTY_STORE_ID" integer not null,
+ "OWNER_UID" nvarchar2(255) unique,
+ "STATUS" integer default 0 not null,
+ "DATAVERSION" integer default 0 not null
+);
+
+create table ADDRESSBOOK_HOME_METADATA (
+ "RESOURCE_ID" integer primary key references ADDRESSBOOK_HOME on delete cascade,
+ "QUOTA_USED_BYTES" integer default 0 not null,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table SHARED_ADDRESSBOOK_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "OWNER_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "EXTERNAL_ID" integer default null,
+ "ADDRESSBOOK_RESOURCE_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "BIND_REVISION" integer default 0 not null,
+ "MESSAGE" nclob,
+ primary key ("ADDRESSBOOK_HOME_RESOURCE_ID", "OWNER_HOME_RESOURCE_ID"),
+ unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "ADDRESSBOOK_RESOURCE_NAME")
+);
+
+create table ADDRESSBOOK_OBJECT (
+ "RESOURCE_ID" integer primary key,
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "VCARD_TEXT" nclob,
+ "VCARD_UID" nvarchar2(255),
+ "KIND" integer not null,
+ "MD5" nchar(32),
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "DATAVERSION" integer default 0 not null,
+ unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "RESOURCE_NAME"),
+ unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "VCARD_UID")
+);
+
+create table ADDRESSBOOK_OBJECT_KIND (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('person', 0);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('group', 1);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('resource', 2);
+insert into ADDRESSBOOK_OBJECT_KIND (DESCRIPTION, ID) values ('location', 3);
+create table ABO_MEMBERS (
+ "GROUP_ID" integer not null,
+ "ADDRESSBOOK_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "MEMBER_ID" integer not null,
+ "REVISION" integer not null,
+ "REMOVED" integer default 0 not null,
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ primary key ("GROUP_ID", "MEMBER_ID", "REVISION")
+);
+
+create table ABO_FOREIGN_MEMBERS (
+ "GROUP_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "ADDRESSBOOK_ID" integer not null references ADDRESSBOOK_HOME on delete cascade,
+ "MEMBER_ADDRESS" nvarchar2(255),
+ primary key ("GROUP_ID", "MEMBER_ADDRESS")
+);
+
+create table SHARED_GROUP_BIND (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "GROUP_RESOURCE_ID" integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ "EXTERNAL_ID" integer default null,
+ "GROUP_ADDRESSBOOK_NAME" nvarchar2(255),
+ "BIND_MODE" integer not null,
+ "BIND_STATUS" integer not null,
+ "BIND_REVISION" integer default 0 not null,
+ "MESSAGE" nclob,
+ primary key ("ADDRESSBOOK_HOME_RESOURCE_ID", "GROUP_RESOURCE_ID"),
+ unique ("ADDRESSBOOK_HOME_RESOURCE_ID", "GROUP_ADDRESSBOOK_NAME")
+);
+
+create table CALENDAR_OBJECT_REVISIONS (
+ "CALENDAR_HOME_RESOURCE_ID" integer not null references CALENDAR_HOME,
+ "CALENDAR_RESOURCE_ID" integer references CALENDAR,
+ "CALENDAR_NAME" nvarchar2(255) default null,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null,
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ "ADDRESSBOOK_HOME_RESOURCE_ID" integer not null references ADDRESSBOOK_HOME,
+ "OWNER_HOME_RESOURCE_ID" integer references ADDRESSBOOK_HOME,
+ "ADDRESSBOOK_NAME" nvarchar2(255) default null,
+ "OBJECT_RESOURCE_ID" integer default 0,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null,
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ "NOTIFICATION_HOME_RESOURCE_ID" integer not null references NOTIFICATION_HOME on delete cascade,
+ "RESOURCE_NAME" nvarchar2(255),
+ "REVISION" integer not null,
+ "DELETED" integer not null,
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ unique ("NOTIFICATION_HOME_RESOURCE_ID", "RESOURCE_NAME")
+);
+
+create table APN_SUBSCRIPTIONS (
+ "TOKEN" nvarchar2(255),
+ "RESOURCE_KEY" nvarchar2(255),
+ "MODIFIED" integer not null,
+ "SUBSCRIBER_GUID" nvarchar2(255),
+ "USER_AGENT" nvarchar2(255) default null,
+ "IP_ADDR" nvarchar2(255) default null,
+ primary key ("TOKEN", "RESOURCE_KEY")
+);
+
+create table IMIP_TOKENS (
+ "TOKEN" nvarchar2(255),
+ "ORGANIZER" nvarchar2(255),
+ "ATTENDEE" nvarchar2(255),
+ "ICALUID" nvarchar2(255),
+ "ACCESSED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ primary key ("ORGANIZER", "ATTENDEE", "ICALUID")
+);
+
+create table IMIP_INVITATION_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "FROM_ADDR" nvarchar2(255),
+ "TO_ADDR" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob
+);
+
+create table IMIP_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table IMIP_REPLY_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "ORGANIZER" nvarchar2(255),
+ "ATTENDEE" nvarchar2(255),
+ "ICALENDAR_TEXT" nclob
+);
+
+create table PUSH_NOTIFICATION_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "PUSH_ID" nvarchar2(255),
+ "PUSH_PRIORITY" integer not null
+);
+
+create table GROUP_CACHER_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table GROUP_REFRESH_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "GROUP_UID" nvarchar2(255)
+);
+
+create table GROUP_ATTENDEE_RECONCILE_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "RESOURCE_ID" integer,
+ "GROUP_ID" integer
+);
+
+create table GROUPS (
+ "GROUP_ID" integer primary key,
+ "NAME" nvarchar2(255),
+ "GROUP_UID" nvarchar2(255),
+ "MEMBERSHIP_HASH" nvarchar2(255),
+ "EXTANT" integer default 1,
+ "CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
+ "MODIFIED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC'
+);
+
+create table GROUP_MEMBERSHIP (
+ "GROUP_ID" integer not null references GROUPS on delete cascade,
+ "MEMBER_UID" nvarchar2(255),
+ primary key ("GROUP_ID", "MEMBER_UID")
+);
+
+create table GROUP_ATTENDEE (
+ "GROUP_ID" integer not null references GROUPS on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "MEMBERSHIP_HASH" nvarchar2(255),
+ primary key ("GROUP_ID", "RESOURCE_ID")
+);
+
+create table DELEGATES (
+ "DELEGATOR" nvarchar2(255),
+ "DELEGATE" nvarchar2(255),
+ "READ_WRITE" integer not null,
+ primary key ("DELEGATOR", "READ_WRITE", "DELEGATE")
+);
+
+create table DELEGATE_GROUPS (
+ "DELEGATOR" nvarchar2(255),
+ "GROUP_ID" integer not null references GROUPS on delete cascade,
+ "READ_WRITE" integer not null,
+ "IS_EXTERNAL" integer not null,
+ primary key ("DELEGATOR", "READ_WRITE", "GROUP_ID")
+);
+
+create table EXTERNAL_DELEGATE_GROUPS (
+ "DELEGATOR" nvarchar2(255) primary key,
+ "GROUP_UID_READ" nvarchar2(255),
+ "GROUP_UID_WRITE" nvarchar2(255)
+);
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade
+);
+
+create table FIND_MIN_VALID_REVISION_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table REVISION_CLEANUP_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table INBOX_CLEANUP_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table CLEANUP_ONE_INBOX_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "HOME_ID" integer not null unique references CALENDAR_HOME on delete cascade
+);
+
+create table SCHEDULE_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "ICALENDAR_UID" nvarchar2(255),
+ "WORK_TYPE" nvarchar2(255)
+);
+
+create table SCHEDULE_REFRESH_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "ATTENDEE_COUNT" integer
+);
+
+create table SCHEDULE_REFRESH_ATTENDEES (
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "ATTENDEE" nvarchar2(255),
+ primary key ("RESOURCE_ID", "ATTENDEE")
+);
+
+create table SCHEDULE_AUTO_REPLY_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "PARTSTAT" nvarchar2(255)
+);
+
+create table SCHEDULE_ORGANIZER_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "SCHEDULE_ACTION" integer not null,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer,
+ "ICALENDAR_TEXT_OLD" nclob,
+ "ICALENDAR_TEXT_NEW" nclob,
+ "ATTENDEE_COUNT" integer,
+ "SMART_MERGE" integer
+);
+
+create table SCHEDULE_ACTION (
+ "ID" integer primary key,
+ "DESCRIPTION" nvarchar2(16) unique
+);
+
+insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('create', 0);
+insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('modify', 1);
+insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('modify-cancelled', 2);
+insert into SCHEDULE_ACTION (DESCRIPTION, ID) values ('remove', 3);
+create table SCHEDULE_ORGANIZER_SEND_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "SCHEDULE_ACTION" integer not null,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer,
+ "ATTENDEE" nvarchar2(255),
+ "ITIP_MSG" nclob,
+ "NO_REFRESH" integer
+);
+
+create table SCHEDULE_REPLY_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "CHANGED_RIDS" nclob
+);
+
+create table SCHEDULE_REPLY_CANCEL_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "ICALENDAR_TEXT" nclob
+);
+
+create table PRINCIPAL_PURGE_POLLING_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB
+);
+
+create table PRINCIPAL_PURGE_CHECK_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "UID" nvarchar2(255)
+);
+
+create table PRINCIPAL_PURGE_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "UID" nvarchar2(255)
+);
+
+create table PRINCIPAL_PURGE_HOME_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade
+);
+
+create table CALENDARSERVER (
+ "NAME" nvarchar2(255) primary key,
+ "VALUE" nvarchar2(255)
+);
+
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '45');
+insert into CALENDARSERVER (NAME, VALUE) values ('CALENDAR-DATAVERSION', '6');
+insert into CALENDARSERVER (NAME, VALUE) values ('ADDRESSBOOK-DATAVERSION', '2');
+insert into CALENDARSERVER (NAME, VALUE) values ('NOTIFICATION-DATAVERSION', '1');
+insert into CALENDARSERVER (NAME, VALUE) values ('MIN-VALID-REVISION', '1');
+create index CALENDAR_HOME_METADAT_3cb9049e on CALENDAR_HOME_METADATA (
+ DEFAULT_EVENTS
+);
+
+create index CALENDAR_HOME_METADAT_d55e5548 on CALENDAR_HOME_METADATA (
+ DEFAULT_TASKS
+);
+
+create index CALENDAR_HOME_METADAT_910264ce on CALENDAR_HOME_METADATA (
+ DEFAULT_POLLS
+);
+
+create index NOTIFICATION_NOTIFICA_f891f5f9 on NOTIFICATION (
+ NOTIFICATION_HOME_RESOURCE_ID
+);
+
+create index CALENDAR_BIND_RESOURC_e57964d4 on CALENDAR_BIND (
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_CALEN_a9a453a9 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_CALEN_96e83b73 on CALENDAR_OBJECT (
+ CALENDAR_RESOURCE_ID,
+ RECURRANCE_MAX
+);
+
+create index CALENDAR_OBJECT_ICALE_82e731d5 on CALENDAR_OBJECT (
+ ICALENDAR_UID
+);
+
+create index CALENDAR_OBJECT_DROPB_de041d80 on CALENDAR_OBJECT (
+ DROPBOX_ID
+);
+
+create index TIME_RANGE_CALENDAR_R_beb6e7eb on TIME_RANGE (
+ CALENDAR_RESOURCE_ID
+);
+
+create index TIME_RANGE_CALENDAR_O_acf37bd1 on TIME_RANGE (
+ CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index PERUSER_TIME_RANGE_IN_5468a226 on PERUSER (
+ TIME_RANGE_INSTANCE_ID
+);
+
+create index ATTACHMENT_CALENDAR_H_0078845c on ATTACHMENT (
+ CALENDAR_HOME_RESOURCE_ID
+);
+
+create index ATTACHMENT_DROPBOX_ID_5073cf23 on ATTACHMENT (
+ DROPBOX_ID
+);
+
+create index ATTACHMENT_CALENDAR_O_81508484 on ATTACHMENT_CALENDAR_OBJECT (
+ CALENDAR_OBJECT_RESOURCE_ID
+);
+
+create index SHARED_ADDRESSBOOK_BI_e9a2e6d4 on SHARED_ADDRESSBOOK_BIND (
+ OWNER_HOME_RESOURCE_ID
+);
+
+create index ABO_MEMBERS_ADDRESSBO_4effa879 on ABO_MEMBERS (
+ ADDRESSBOOK_ID
+);
+
+create index ABO_MEMBERS_MEMBER_ID_8d66adcf on ABO_MEMBERS (
+ MEMBER_ID
+);
+
+create index ABO_FOREIGN_MEMBERS_A_1fd2c5e9 on ABO_FOREIGN_MEMBERS (
+ ADDRESSBOOK_ID
+);
+
+create index SHARED_GROUP_BIND_RES_cf52f95d on SHARED_GROUP_BIND (
+ GROUP_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_3a3956c4 on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID,
+ CALENDAR_RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_REVIS_6d9d929c on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ RESOURCE_NAME,
+ DELETED,
+ REVISION
+);
+
+create index CALENDAR_OBJECT_REVIS_265c8acf on CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_RESOURCE_ID,
+ REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_2bfcf757 on ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID,
+ OWNER_HOME_RESOURCE_ID
+);
+
+create index ADDRESSBOOK_OBJECT_RE_00fe8288 on ADDRESSBOOK_OBJECT_REVISIONS (
+ OWNER_HOME_RESOURCE_ID,
+ RESOURCE_NAME,
+ DELETED,
+ REVISION
+);
+
+create index ADDRESSBOOK_OBJECT_RE_45004780 on ADDRESSBOOK_OBJECT_REVISIONS (
+ OWNER_HOME_RESOURCE_ID,
+ REVISION
+);
+
+create index NOTIFICATION_OBJECT_R_036a9cee on NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID,
+ REVISION
+);
+
+create index APN_SUBSCRIPTIONS_RES_9610d78e on APN_SUBSCRIPTIONS (
+ RESOURCE_KEY
+);
+
+create index IMIP_TOKENS_TOKEN_e94b918f on IMIP_TOKENS (
+ TOKEN
+);
+
+create index IMIP_INVITATION_WORK__586d064c on IMIP_INVITATION_WORK (
+ JOB_ID
+);
+
+create index IMIP_POLLING_WORK_JOB_d5535891 on IMIP_POLLING_WORK (
+ JOB_ID
+);
+
+create index IMIP_REPLY_WORK_JOB_I_bf4ae73e on IMIP_REPLY_WORK (
+ JOB_ID
+);
+
+create index PUSH_NOTIFICATION_WOR_8bbab117 on PUSH_NOTIFICATION_WORK (
+ JOB_ID
+);
+
+create index GROUP_CACHER_POLLING__6eb3151c on GROUP_CACHER_POLLING_WORK (
+ JOB_ID
+);
+
+create index GROUP_REFRESH_WORK_JO_717ede20 on GROUP_REFRESH_WORK (
+ JOB_ID
+);
+
+create index GROUP_ATTENDEE_RECONC_da73d3c2 on GROUP_ATTENDEE_RECONCILE_WORK (
+ JOB_ID
+);
+
+create index GROUPS_GROUP_UID_b35cce23 on GROUPS (
+ GROUP_UID
+);
+
+create index GROUP_MEMBERSHIP_MEMB_0ca508e8 on GROUP_MEMBERSHIP (
+ MEMBER_UID
+);
+
+create index GROUP_ATTENDEE_RESOUR_855124dc on GROUP_ATTENDEE (
+ RESOURCE_ID
+);
+
+create index DELEGATE_TO_DELEGATOR_5e149b11 on DELEGATES (
+ DELEGATE,
+ READ_WRITE,
+ DELEGATOR
+);
+
+create index DELEGATE_GROUPS_GROUP_25117446 on DELEGATE_GROUPS (
+ GROUP_ID
+);
+
+create index CALENDAR_OBJECT_SPLIT_af71dcda on CALENDAR_OBJECT_SPLITTER_WORK (
+ RESOURCE_ID
+);
+
+create index CALENDAR_OBJECT_SPLIT_33603b72 on CALENDAR_OBJECT_SPLITTER_WORK (
+ JOB_ID
+);
+
+create index FIND_MIN_VALID_REVISI_78d17400 on FIND_MIN_VALID_REVISION_WORK (
+ JOB_ID
+);
+
+create index REVISION_CLEANUP_WORK_eb062686 on REVISION_CLEANUP_WORK (
+ JOB_ID
+);
+
+create index INBOX_CLEANUP_WORK_JO_799132bd on INBOX_CLEANUP_WORK (
+ JOB_ID
+);
+
+create index CLEANUP_ONE_INBOX_WOR_375dac36 on CLEANUP_ONE_INBOX_WORK (
+ JOB_ID
+);
+
+create index SCHEDULE_WORK_JOB_ID_65e810ee on SCHEDULE_WORK (
+ JOB_ID
+);
+
+create index SCHEDULE_WORK_ICALEND_089f33dc on SCHEDULE_WORK (
+ ICALENDAR_UID
+);
+
+create index SCHEDULE_REFRESH_WORK_26084c7b on SCHEDULE_REFRESH_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_REFRESH_WORK_989efe54 on SCHEDULE_REFRESH_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_REFRESH_ATTE_83053b91 on SCHEDULE_REFRESH_ATTENDEES (
+ RESOURCE_ID,
+ ATTENDEE
+);
+
+create index SCHEDULE_AUTO_REPLY_W_0256478d on SCHEDULE_AUTO_REPLY_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_AUTO_REPLY_W_0755e754 on SCHEDULE_AUTO_REPLY_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_ORGANIZER_WO_18ce4edd on SCHEDULE_ORGANIZER_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_ORGANIZER_WO_14702035 on SCHEDULE_ORGANIZER_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_ORGANIZER_SE_9ec9f827 on SCHEDULE_ORGANIZER_SEND_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_ORGANIZER_SE_699fefc4 on SCHEDULE_ORGANIZER_SEND_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_REPLY_WORK_H_745af8cf on SCHEDULE_REPLY_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index SCHEDULE_REPLY_WORK_R_11bd3fbb on SCHEDULE_REPLY_WORK (
+ RESOURCE_ID
+);
+
+create index SCHEDULE_REPLY_CANCEL_dab513ef on SCHEDULE_REPLY_CANCEL_WORK (
+ HOME_RESOURCE_ID
+);
+
+create index PRINCIPAL_PURGE_POLLI_6383e68a on PRINCIPAL_PURGE_POLLING_WORK (
+ JOB_ID
+);
+
+create index PRINCIPAL_PURGE_CHECK_b0c024c1 on PRINCIPAL_PURGE_CHECK_WORK (
+ JOB_ID
+);
+
+create index PRINCIPAL_PURGE_WORK__7a8141a3 on PRINCIPAL_PURGE_WORK (
+ JOB_ID
+);
+
+create index PRINCIPAL_PURGE_HOME__f35eea7a on PRINCIPAL_PURGE_HOME_WORK (
+ JOB_ID
+);
+
+create index PRINCIPAL_PURGE_HOME__967e4480 on PRINCIPAL_PURGE_HOME_WORK (
+ HOME_RESOURCE_ID
+);
+
+-- Extra schema to add to current-oracle-dialect.sql
Copied: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/postgres-dialect/v44.sql (from rev 13731, CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v44.sql)
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/postgres-dialect/v44.sql (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/postgres-dialect/v44.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,1096 @@
+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2014 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+
+-------------------------
+-- Cluster Bookkeeping --
+-------------------------
+
+-- Information about a process connected to this database.
+
+-- Note that this must match the node info schema in twext.enterprise.queue.
+create table NODE_INFO (
+ HOSTNAME varchar(255) not null,
+ PID integer not null,
+ PORT integer not null,
+ TIME timestamp not null default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (HOSTNAME, PORT)
+);
+
+-- Unique named locks. This table should always be empty, but rows are
+-- temporarily created in order to prevent undesirable concurrency.
+create table NAMED_LOCK (
+ LOCK_NAME varchar(255) primary key
+);
+
+
+--------------------
+-- Jobs --
+--------------------
+
+create sequence JOB_SEQ;
+
+create table JOB (
+ JOB_ID integer primary key default nextval('JOB_SEQ') not null, --implicit index
+ WORK_TYPE varchar(255) not null,
+ PRIORITY integer default 0,
+ WEIGHT integer default 0,
+ NOT_BEFORE timestamp not null,
+ ASSIGNED timestamp default null,
+ OVERDUE timestamp default null,
+ FAILED integer default 0
+);
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ STATUS integer default 0 not null, -- enum HOME_STATUS
+ DATAVERSION integer default 0 not null
+);
+
+-- Enumeration of statuses
+
+create table HOME_STATUS (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into HOME_STATUS values (0, 'normal' );
+insert into HOME_STATUS values (1, 'external');
+insert into HOME_STATUS values (2, 'purging');
+
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+ RESOURCE_ID integer primary key references CALENDAR_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ DEFAULT_EVENTS integer default null references CALENDAR on delete set null,
+ DEFAULT_TASKS integer default null references CALENDAR on delete set null,
+ DEFAULT_POLLS integer default null references CALENDAR on delete set null,
+ ALARM_VEVENT_TIMED text default null,
+ ALARM_VEVENT_ALLDAY text default null,
+ ALARM_VTODO_TIMED text default null,
+ ALARM_VTODO_ALLDAY text default null,
+ AVAILABILITY text default null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index CALENDAR_HOME_METADATA_DEFAULT_EVENTS on
+ CALENDAR_HOME_METADATA(DEFAULT_EVENTS);
+create index CALENDAR_HOME_METADATA_DEFAULT_TASKS on
+ CALENDAR_HOME_METADATA(DEFAULT_TASKS);
+create index CALENDAR_HOME_METADATA_DEFAULT_POLLS on
+ CALENDAR_HOME_METADATA(DEFAULT_POLLS);
+
+
+-----------------------
+-- Calendar Metadata --
+-----------------------
+
+create table CALENDAR_METADATA (
+ RESOURCE_ID integer primary key references CALENDAR on delete cascade, -- implicit index
+ SUPPORTED_COMPONENTS varchar(255) default null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ STATUS integer default 0 not null, -- enum HOME_STATUS
+ DATAVERSION integer default 0 not null
+);
+
+create table NOTIFICATION (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME,
+ NOTIFICATION_UID varchar(255) not null,
+ NOTIFICATION_TYPE varchar(255) not null,
+ NOTIFICATION_DATA text not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+ NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ EXTERNAL_ID integer default null,
+ CALENDAR_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text,
+ TRANSP integer default 0 not null, -- enum CALENDAR_TRANSP
+ ALARM_VEVENT_TIMED text default null,
+ ALARM_VEVENT_ALLDAY text default null,
+ ALARM_VTODO_TIMED text default null,
+ ALARM_VTODO_ALLDAY text default null,
+ TIMEZONE text default null,
+
+ primary key (CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+ unique (CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME) -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on
+ CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own' );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+insert into CALENDAR_BIND_MODE values (4, 'indirect');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+insert into CALENDAR_BIND_STATUS values (4, 'deleted');
+
+
+-- 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 --
+---------------------
+
+create table CALENDAR_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ ICALENDAR_TEXT text not null,
+ ICALENDAR_UID varchar(255) not null,
+ ICALENDAR_TYPE varchar(255) not null,
+ ATTACHMENTS_MODE integer default 0 not null, -- enum CALENDAR_OBJ_ATTACHMENTS_MODE
+ DROPBOX_ID varchar(255),
+ ORGANIZER varchar(255),
+ RECURRANCE_MIN date, -- minimum date that recurrences have been expanded to.
+ RECURRANCE_MAX date, -- maximum date that recurrences have been expanded to.
+ ACCESS integer default 0 not null,
+ SCHEDULE_OBJECT boolean default false,
+ SCHEDULE_TAG varchar(36) default null,
+ SCHEDULE_ETAGS text default null,
+ PRIVATE_COMMENTS boolean default false not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+ -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+ -- calendar objects, this constraint has to be selectively enforced by the
+ -- application layer.
+
+ -- unique (CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ICALENDAR_UID on
+ CALENDAR_OBJECT(ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+ CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJ_ATTACHMENTS_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, '' );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public' );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private' );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted' );
+
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+ INSTANCE_ID integer primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ FLOATING boolean not null,
+ START_DATE timestamp not null,
+ END_DATE timestamp not null,
+ FBTYPE integer not null,
+ TRANSPARENT boolean not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown' );
+insert into FREE_BUSY_TYPE values (1, 'free' );
+insert into FREE_BUSY_TYPE values (2, 'busy' );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative' );
+
+
+-------------------
+-- Per-user data --
+-------------------
+
+create table PERUSER (
+ TIME_RANGE_INSTANCE_ID integer not null references TIME_RANGE on delete cascade,
+ USER_ID varchar(255) not null,
+ TRANSPARENT boolean not null,
+ ADJUSTED_START_DATE timestamp default null,
+ ADJUSTED_END_DATE timestamp default null
+);
+
+create index PERUSER_TIME_RANGE_INSTANCE_ID on
+ PERUSER(TIME_RANGE_INSTANCE_ID);
+
+
+----------------
+-- Attachment --
+----------------
+
+create sequence ATTACHMENT_ID_SEQ;
+
+create table ATTACHMENT (
+ ATTACHMENT_ID integer primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ DROPBOX_ID varchar(255),
+ CONTENT_TYPE varchar(255) not null,
+ SIZE integer not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ PATH varchar(1024) not null
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+ ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+create index ATTACHMENT_DROPBOX_ID on
+ ATTACHMENT(DROPBOX_ID);
+
+-- Many-to-many relationship between attachments and calendar objects
+create table ATTACHMENT_CALENDAR_OBJECT (
+ ATTACHMENT_ID integer not null references ATTACHMENT on delete cascade,
+ MANAGED_ID varchar(255) not null,
+ CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+
+ primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
+ unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
+);
+
+create index ATTACHMENT_CALENDAR_OBJECT_CALENDAR_OBJECT_RESOURCE_ID on
+ ATTACHMENT_CALENDAR_OBJECT(CALENDAR_OBJECT_RESOURCE_ID);
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+ RESOURCE_ID integer not null, -- foreign key: *.RESOURCE_ID
+ NAME varchar(255) not null,
+ VALUE text not null, -- FIXME: xml?
+ VIEWER_UID varchar(255),
+
+ primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ ADDRESSBOOK_PROPERTY_STORE_ID integer default nextval('RESOURCE_ID_SEQ') not null, -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ STATUS integer default 0 not null, -- enum HOME_STATUS
+ DATAVERSION integer default 0 not null
+);
+
+
+-------------------------------
+-- AddressBook Home Metadata --
+-------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+ RESOURCE_ID integer primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+-----------------------------
+-- Shared AddressBook Bind --
+-----------------------------
+
+-- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
+
+create table SHARED_ADDRESSBOOK_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ OWNER_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ EXTERNAL_ID integer default null,
+ ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME) -- implicit index
+);
+
+create index SHARED_ADDRESSBOOK_BIND_RESOURCE_ID on
+ SHARED_ADDRESSBOOK_BIND(OWNER_HOME_RESOURCE_ID);
+
+
+------------------------
+-- AddressBook Object --
+------------------------
+
+create table ADDRESSBOOK_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ VCARD_TEXT text not null,
+ VCARD_UID varchar(255) not null,
+ KIND integer not null, -- enum ADDRESSBOOK_OBJECT_KIND
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, VCARD_UID) -- implicit index
+);
+
+
+-----------------------------
+-- AddressBook Object kind --
+-----------------------------
+
+create table ADDRESSBOOK_OBJECT_KIND (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND values (0, 'person');
+insert into ADDRESSBOOK_OBJECT_KIND values (1, 'group' );
+insert into ADDRESSBOOK_OBJECT_KIND values (2, 'resource');
+insert into ADDRESSBOOK_OBJECT_KIND values (3, 'location');
+
+
+----------------------------------
+-- Revisions, forward reference --
+----------------------------------
+
+create sequence REVISION_SEQ;
+
+---------------------------------
+-- Address Book Object Members --
+---------------------------------
+
+create table ABO_MEMBERS (
+ GROUP_ID integer not null, -- references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ ADDRESSBOOK_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ MEMBER_ID integer not null, -- references ADDRESSBOOK_OBJECT, -- member AddressBook Object's RESOURCE_ID
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ REMOVED boolean default false not null,
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (GROUP_ID, MEMBER_ID, REVISION) -- implicit index
+);
+
+create index ABO_MEMBERS_ADDRESSBOOK_ID on
+ ABO_MEMBERS(ADDRESSBOOK_ID);
+create index ABO_MEMBERS_MEMBER_ID on
+ ABO_MEMBERS(MEMBER_ID);
+
+------------------------------------------
+-- Address Book Object Foreign Members --
+------------------------------------------
+
+create table ABO_FOREIGN_MEMBERS (
+ GROUP_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ ADDRESSBOOK_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ MEMBER_ADDRESS varchar(255) not null, -- member AddressBook Object's 'calendar' address
+
+ primary key (GROUP_ID, MEMBER_ADDRESS) -- implicit index
+);
+
+create index ABO_FOREIGN_MEMBERS_ADDRESSBOOK_ID on
+ ABO_FOREIGN_MEMBERS(ADDRESSBOOK_ID);
+
+-----------------------
+-- Shared Group Bind --
+-----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
+
+create table SHARED_GROUP_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ GROUP_RESOURCE_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ EXTERNAL_ID integer default null,
+ GROUP_ADDRESSBOOK_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_NAME) -- implicit index
+);
+
+create index SHARED_GROUP_BIND_RESOURCE_ID on
+ SHARED_GROUP_BIND(GROUP_RESOURCE_ID);
+
+
+---------------
+-- Revisions --
+---------------
+
+-- create sequence REVISION_SEQ;
+
+
+-------------------------------
+-- Calendar Object Revisions --
+-------------------------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer references CALENDAR,
+ CALENDAR_NAME varchar(255) default null,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null,
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
+
+
+----------------------------------
+-- AddressBook Object Revisions --
+----------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ OWNER_HOME_RESOURCE_ID integer references ADDRESSBOOK_HOME,
+ ADDRESSBOOK_NAME varchar(255) default null,
+ OBJECT_RESOURCE_ID integer default 0,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null,
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_HOME_RESOURCE_ID
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+ on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_REVISION
+ on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, REVISION);
+
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME on delete cascade,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null,
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+ TOKEN varchar(255) not null,
+ RESOURCE_KEY varchar(255) not null,
+ MODIFIED integer not null,
+ SUBSCRIBER_GUID varchar(255) not null,
+ USER_AGENT varchar(255) default null,
+ IP_ADDR varchar(255) default null,
+
+ primary key (TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+ on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+
+-----------------
+-- IMIP Tokens --
+-----------------
+
+create table IMIP_TOKENS (
+ TOKEN varchar(255) not null,
+ ORGANIZER varchar(255) not null,
+ ATTENDEE varchar(255) not null,
+ ICALUID varchar(255) not null,
+ ACCESSED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
+);
+
+create index IMIP_TOKENS_TOKEN
+ on IMIP_TOKENS(TOKEN);
+
+
+----------------
+-- Work Items --
+----------------
+
+create sequence WORKITEM_SEQ;
+
+
+---------------------------
+-- IMIP Inivitation Work --
+---------------------------
+
+create table IMIP_INVITATION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ FROM_ADDR varchar(255) not null,
+ TO_ADDR varchar(255) not null,
+ ICALENDAR_TEXT text not null
+);
+
+create index IMIP_INVITATION_WORK_JOB_ID on
+ IMIP_INVITATION_WORK(JOB_ID);
+
+-----------------------
+-- IMIP Polling Work --
+-----------------------
+
+create table IMIP_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index IMIP_POLLING_WORK_JOB_ID on
+ IMIP_POLLING_WORK(JOB_ID);
+
+
+---------------------
+-- IMIP Reply Work --
+---------------------
+
+create table IMIP_REPLY_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ ORGANIZER varchar(255) not null,
+ ATTENDEE varchar(255) not null,
+ ICALENDAR_TEXT text not null
+);
+
+create index IMIP_REPLY_WORK_JOB_ID on
+ IMIP_REPLY_WORK(JOB_ID);
+
+
+------------------------
+-- Push Notifications --
+------------------------
+
+create table PUSH_NOTIFICATION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ PUSH_ID varchar(255) not null,
+ PUSH_PRIORITY integer not null -- 1:low 5:medium 10:high
+);
+
+create index PUSH_NOTIFICATION_WORK_JOB_ID on
+ PUSH_NOTIFICATION_WORK(JOB_ID);
+
+-----------------
+-- GroupCacher --
+-----------------
+
+create table GROUP_CACHER_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index GROUP_CACHER_POLLING_WORK_JOB_ID on
+ GROUP_CACHER_POLLING_WORK(JOB_ID);
+
+create table GROUP_REFRESH_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ GROUP_UID varchar(255) not null
+);
+
+create index GROUP_REFRESH_WORK_JOB_ID on
+ GROUP_REFRESH_WORK(JOB_ID);
+
+create table GROUP_ATTENDEE_RECONCILE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ RESOURCE_ID integer,
+ GROUP_ID integer
+);
+
+create index GROUP_ATTENDEE_RECONCILE_WORK_JOB_ID on
+ GROUP_ATTENDEE_RECONCILE_WORK(JOB_ID);
+
+
+create table GROUPS (
+ GROUP_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ NAME varchar(255) not null,
+ GROUP_UID varchar(255) not null,
+ MEMBERSHIP_HASH varchar(255) not null,
+ EXTANT integer default 1,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+create index GROUPS_GROUP_UID on
+ GROUPS(GROUP_UID);
+
+create table GROUP_MEMBERSHIP (
+ GROUP_ID integer not null references GROUPS on delete cascade,
+ MEMBER_UID varchar(255) not null,
+
+ primary key (GROUP_ID, MEMBER_UID)
+);
+
+create index GROUP_MEMBERSHIP_MEMBER on
+ GROUP_MEMBERSHIP(MEMBER_UID);
+
+create table GROUP_ATTENDEE (
+ GROUP_ID integer not null references GROUPS on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ MEMBERSHIP_HASH varchar(255) not null,
+
+ primary key (GROUP_ID, RESOURCE_ID)
+);
+create index GROUP_ATTENDEE_RESOURCE_ID on
+ GROUP_ATTENDEE(RESOURCE_ID);
+
+---------------
+-- Delegates --
+---------------
+
+create table DELEGATES (
+ DELEGATOR varchar(255) not null,
+ DELEGATE varchar(255) not null,
+ READ_WRITE integer not null, -- 1 = ReadWrite, 0 = ReadOnly
+
+ primary key (DELEGATOR, READ_WRITE, DELEGATE)
+);
+create index DELEGATE_TO_DELEGATOR on
+ DELEGATES(DELEGATE, READ_WRITE, DELEGATOR);
+
+create table DELEGATE_GROUPS (
+ DELEGATOR varchar(255) not null,
+ GROUP_ID integer not null references GROUPS on delete cascade,
+ READ_WRITE integer not null, -- 1 = ReadWrite, 0 = ReadOnly
+ IS_EXTERNAL integer not null, -- 1 = ReadWrite, 0 = ReadOnly
+
+ primary key (DELEGATOR, READ_WRITE, GROUP_ID)
+);
+create index DELEGATE_GROUPS_GROUP_ID on
+ DELEGATE_GROUPS(GROUP_ID);
+
+create table EXTERNAL_DELEGATE_GROUPS (
+ DELEGATOR varchar(255) primary key not null,
+ GROUP_UID_READ varchar(255),
+ GROUP_UID_WRITE varchar(255)
+);
+
+--------------------------
+-- Object Splitter Work --
+--------------------------
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade
+);
+
+create index CALENDAR_OBJECT_SPLITTER_WORK_RESOURCE_ID on
+ CALENDAR_OBJECT_SPLITTER_WORK(RESOURCE_ID);
+create index CALENDAR_OBJECT_SPLITTER_WORK_JOB_ID on
+ CALENDAR_OBJECT_SPLITTER_WORK(JOB_ID);
+
+---------------------------
+-- Revision Cleanup Work --
+---------------------------
+
+create table FIND_MIN_VALID_REVISION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index FIND_MIN_VALID_REVISION_WORK_JOB_ID on
+ FIND_MIN_VALID_REVISION_WORK(JOB_ID);
+
+create table REVISION_CLEANUP_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index REVISION_CLEANUP_WORK_JOB_ID on
+ REVISION_CLEANUP_WORK(JOB_ID);
+
+------------------------
+-- Inbox Cleanup Work --
+------------------------
+
+create table INBOX_CLEANUP_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index INBOX_CLEANUP_WORK_JOB_ID on
+ INBOX_CLEANUP_WORK(JOB_ID);
+
+create table CLEANUP_ONE_INBOX_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ HOME_ID integer not null unique references CALENDAR_HOME on delete cascade
+);
+
+create index CLEANUP_ONE_INBOX_WORK_JOB_ID on
+ CLEANUP_ONE_INBOX_WORK(JOB_ID);
+
+-------------------
+-- Schedule Work --
+-------------------
+
+create table SCHEDULE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ ICALENDAR_UID varchar(255) not null,
+ WORK_TYPE varchar(255) not null
+);
+
+create index SCHEDULE_WORK_JOB_ID on
+ SCHEDULE_WORK(JOB_ID);
+create index SCHEDULE_WORK_ICALENDAR_UID on
+ SCHEDULE_WORK(ICALENDAR_UID);
+
+---------------------------
+-- Schedule Refresh Work --
+---------------------------
+
+create table SCHEDULE_REFRESH_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ ATTENDEE_COUNT integer
+);
+
+create index SCHEDULE_REFRESH_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_REFRESH_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_REFRESH_WORK_RESOURCE_ID on
+ SCHEDULE_REFRESH_WORK(RESOURCE_ID);
+
+create table SCHEDULE_REFRESH_ATTENDEES (
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ ATTENDEE varchar(255) not null,
+
+ primary key (RESOURCE_ID, ATTENDEE)
+);
+
+create index SCHEDULE_REFRESH_ATTENDEES_RESOURCE_ID_ATTENDEE on
+ SCHEDULE_REFRESH_ATTENDEES(RESOURCE_ID, ATTENDEE);
+
+------------------------------
+-- Schedule Auto Reply Work --
+------------------------------
+
+create table SCHEDULE_AUTO_REPLY_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ PARTSTAT varchar(255) not null
+);
+
+create index SCHEDULE_AUTO_REPLY_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_AUTO_REPLY_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_AUTO_REPLY_WORK_RESOURCE_ID on
+ SCHEDULE_AUTO_REPLY_WORK(RESOURCE_ID);
+
+-----------------------------
+-- Schedule Organizer Work --
+-----------------------------
+
+create table SCHEDULE_ORGANIZER_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ SCHEDULE_ACTION integer not null, -- Enum SCHEDULE_ACTION
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer, -- this references a possibly non-existent CALENDR_OBJECT
+ ICALENDAR_TEXT_OLD text,
+ ICALENDAR_TEXT_NEW text,
+ ATTENDEE_COUNT integer,
+ SMART_MERGE boolean
+);
+
+create index SCHEDULE_ORGANIZER_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_ORGANIZER_WORK_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_WORK(RESOURCE_ID);
+
+-- Enumeration of schedule actions
+
+create table SCHEDULE_ACTION (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into SCHEDULE_ACTION values (0, 'create');
+insert into SCHEDULE_ACTION values (1, 'modify');
+insert into SCHEDULE_ACTION values (2, 'modify-cancelled');
+insert into SCHEDULE_ACTION values (3, 'remove');
+
+----------------------------------
+-- Schedule Organizer Send Work --
+----------------------------------
+
+create table SCHEDULE_ORGANIZER_SEND_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ SCHEDULE_ACTION integer not null, -- Enum SCHEDULE_ACTION
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer, -- this references a possibly non-existent CALENDAR_OBJECT
+ ATTENDEE varchar(255) not null,
+ ITIP_MSG text,
+ NO_REFRESH boolean
+);
+
+create index SCHEDULE_ORGANIZER_SEND_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_SEND_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_ORGANIZER_SEND_WORK_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_SEND_WORK(RESOURCE_ID);
+
+-------------------------
+-- Schedule Reply Work --
+-------------------------
+
+create table SCHEDULE_REPLY_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ CHANGED_RIDS text
+);
+
+create index SCHEDULE_REPLY_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_REPLY_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_REPLY_WORK_RESOURCE_ID on
+ SCHEDULE_REPLY_WORK(RESOURCE_ID);
+
+--------------------------------
+-- Schedule Reply Cancel Work --
+--------------------------------
+
+create table SCHEDULE_REPLY_CANCEL_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ ICALENDAR_TEXT text not null
+);
+
+create index SCHEDULE_REPLY_CANCEL_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_REPLY_CANCEL_WORK(HOME_RESOURCE_ID);
+
+----------------------------------
+-- Principal Purge Polling Work --
+----------------------------------
+
+create table PRINCIPAL_PURGE_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index PRINCIPAL_PURGE_POLLING_WORK_JOB_ID on
+ PRINCIPAL_PURGE_POLLING_WORK(JOB_ID);
+
+--------------------------------
+-- Principal Purge Check Work --
+--------------------------------
+
+create table PRINCIPAL_PURGE_CHECK_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ UID varchar(255) not null
+);
+
+create index PRINCIPAL_PURGE_CHECK_WORK_JOB_ID on
+ PRINCIPAL_PURGE_CHECK_WORK(JOB_ID);
+
+--------------------------
+-- Principal Purge Work --
+--------------------------
+
+create table PRINCIPAL_PURGE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ UID varchar(255) not null
+);
+
+create index PRINCIPAL_PURGE_WORK_JOB_ID on
+ PRINCIPAL_PURGE_WORK(JOB_ID);
+
+
+--------------------------------
+-- Principal Home Remove Work --
+--------------------------------
+
+create table PRINCIPAL_PURGE_HOME_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade
+);
+
+create index PRINCIPAL_PURGE_HOME_WORK_JOB_ID on
+ PRINCIPAL_PURGE_HOME_WORK(JOB_ID);
+create index PRINCIPAL_PURGE_HOME_HOME_RESOURCE_ID on
+ PRINCIPAL_PURGE_HOME_WORK(HOME_RESOURCE_ID);
+
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+ NAME varchar(255) primary key, -- implicit index
+ VALUE varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '44');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '6');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
+insert into CALENDARSERVER values ('NOTIFICATION-DATAVERSION', '1');
+insert into CALENDARSERVER values ('MIN-VALID-REVISION', '1');
Added: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/postgres-dialect/v45.sql
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/postgres-dialect/v45.sql (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/old/postgres-dialect/v45.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,1098 @@
+-- -*- test-case-name: txdav.caldav.datastore.test.test_sql,txdav.carddav.datastore.test.test_sql -*-
+
+----
+-- Copyright (c) 2010-2014 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+
+-----------------
+-- Resource ID --
+-----------------
+
+create sequence RESOURCE_ID_SEQ;
+
+
+-------------------------
+-- Cluster Bookkeeping --
+-------------------------
+
+-- Information about a process connected to this database.
+
+-- Note that this must match the node info schema in twext.enterprise.queue.
+create table NODE_INFO (
+ HOSTNAME varchar(255) not null,
+ PID integer not null,
+ PORT integer not null,
+ TIME timestamp not null default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (HOSTNAME, PORT)
+);
+
+-- Unique named locks. This table should always be empty, but rows are
+-- temporarily created in order to prevent undesirable concurrency.
+create table NAMED_LOCK (
+ LOCK_NAME varchar(255) primary key
+);
+
+
+--------------------
+-- Jobs --
+--------------------
+
+create sequence JOB_SEQ;
+
+create table JOB (
+ JOB_ID integer primary key default nextval('JOB_SEQ') not null, --implicit index
+ WORK_TYPE varchar(255) not null,
+ PRIORITY integer default 0,
+ WEIGHT integer default 0,
+ NOT_BEFORE timestamp not null,
+ ASSIGNED timestamp default null,
+ OVERDUE timestamp default null,
+ FAILED integer default 0
+);
+
+-------------------
+-- Calendar Home --
+-------------------
+
+create table CALENDAR_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ STATUS integer default 0 not null, -- enum HOME_STATUS
+ DATAVERSION integer default 0 not null
+);
+
+-- Enumeration of statuses
+
+create table HOME_STATUS (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into HOME_STATUS values (0, 'normal' );
+insert into HOME_STATUS values (1, 'external');
+insert into HOME_STATUS values (2, 'purging');
+
+
+--------------
+-- Calendar --
+--------------
+
+create table CALENDAR (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ') -- implicit index
+);
+
+
+----------------------------
+-- Calendar Home Metadata --
+----------------------------
+
+create table CALENDAR_HOME_METADATA (
+ RESOURCE_ID integer primary key references CALENDAR_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ DEFAULT_EVENTS integer default null references CALENDAR on delete set null,
+ DEFAULT_TASKS integer default null references CALENDAR on delete set null,
+ DEFAULT_POLLS integer default null references CALENDAR on delete set null,
+ ALARM_VEVENT_TIMED text default null,
+ ALARM_VEVENT_ALLDAY text default null,
+ ALARM_VTODO_TIMED text default null,
+ ALARM_VTODO_ALLDAY text default null,
+ AVAILABILITY text default null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index CALENDAR_HOME_METADATA_DEFAULT_EVENTS on
+ CALENDAR_HOME_METADATA(DEFAULT_EVENTS);
+create index CALENDAR_HOME_METADATA_DEFAULT_TASKS on
+ CALENDAR_HOME_METADATA(DEFAULT_TASKS);
+create index CALENDAR_HOME_METADATA_DEFAULT_POLLS on
+ CALENDAR_HOME_METADATA(DEFAULT_POLLS);
+
+
+-----------------------
+-- Calendar Metadata --
+-----------------------
+
+create table CALENDAR_METADATA (
+ RESOURCE_ID integer primary key references CALENDAR on delete cascade, -- implicit index
+ SUPPORTED_COMPONENTS varchar(255) default null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+---------------------------
+-- Sharing Notifications --
+---------------------------
+
+create table NOTIFICATION_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ STATUS integer default 0 not null, -- enum HOME_STATUS
+ DATAVERSION integer default 0 not null
+);
+
+create table NOTIFICATION (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME,
+ NOTIFICATION_UID varchar(255) not null,
+ NOTIFICATION_TYPE varchar(255) not null,
+ NOTIFICATION_DATA text not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (NOTIFICATION_UID, NOTIFICATION_HOME_RESOURCE_ID) -- implicit index
+);
+
+create index NOTIFICATION_NOTIFICATION_HOME_RESOURCE_ID on
+ NOTIFICATION(NOTIFICATION_HOME_RESOURCE_ID);
+
+
+-------------------
+-- Calendar Bind --
+-------------------
+
+-- Joins CALENDAR_HOME and CALENDAR
+
+create table CALENDAR_BIND (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ EXTERNAL_ID integer default null,
+ CALENDAR_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text,
+ TRANSP integer default 0 not null, -- enum CALENDAR_TRANSP
+ ALARM_VEVENT_TIMED text default null,
+ ALARM_VEVENT_ALLDAY text default null,
+ ALARM_VTODO_TIMED text default null,
+ ALARM_VTODO_ALLDAY text default null,
+ TIMEZONE text default null,
+
+ primary key (CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID), -- implicit index
+ unique (CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_NAME) -- implicit index
+);
+
+create index CALENDAR_BIND_RESOURCE_ID on
+ CALENDAR_BIND(CALENDAR_RESOURCE_ID);
+
+-- Enumeration of calendar bind modes
+
+create table CALENDAR_BIND_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_MODE values (0, 'own' );
+insert into CALENDAR_BIND_MODE values (1, 'read' );
+insert into CALENDAR_BIND_MODE values (2, 'write');
+insert into CALENDAR_BIND_MODE values (3, 'direct');
+insert into CALENDAR_BIND_MODE values (4, 'indirect');
+
+-- Enumeration of statuses
+
+create table CALENDAR_BIND_STATUS (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_BIND_STATUS values (0, 'invited' );
+insert into CALENDAR_BIND_STATUS values (1, 'accepted');
+insert into CALENDAR_BIND_STATUS values (2, 'declined');
+insert into CALENDAR_BIND_STATUS values (3, 'invalid');
+insert into CALENDAR_BIND_STATUS values (4, 'deleted');
+
+
+-- 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 --
+---------------------
+
+create table CALENDAR_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ ICALENDAR_TEXT text not null,
+ ICALENDAR_UID varchar(255) not null,
+ ICALENDAR_TYPE varchar(255) not null,
+ ATTACHMENTS_MODE integer default 0 not null, -- enum CALENDAR_OBJ_ATTACHMENTS_MODE
+ DROPBOX_ID varchar(255),
+ ORGANIZER varchar(255),
+ RECURRANCE_MIN date, -- minimum date that recurrences have been expanded to.
+ RECURRANCE_MAX date, -- maximum date that recurrences have been expanded to.
+ ACCESS integer default 0 not null,
+ SCHEDULE_OBJECT boolean default false,
+ SCHEDULE_TAG varchar(36) default null,
+ SCHEDULE_ETAGS text default null,
+ PRIVATE_COMMENTS boolean default false not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ DATAVERSION integer default 0 not null,
+
+ unique (CALENDAR_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+
+ -- since the 'inbox' is a 'calendar resource' for the purpose of storing
+ -- calendar objects, this constraint has to be selectively enforced by the
+ -- application layer.
+
+ -- unique (CALENDAR_RESOURCE_ID, ICALENDAR_UID)
+);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_AND_ICALENDAR_UID on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_CALENDAR_RESOURCE_ID_RECURRANCE_MAX on
+ CALENDAR_OBJECT(CALENDAR_RESOURCE_ID, RECURRANCE_MAX);
+
+create index CALENDAR_OBJECT_ICALENDAR_UID on
+ CALENDAR_OBJECT(ICALENDAR_UID);
+
+create index CALENDAR_OBJECT_DROPBOX_ID on
+ CALENDAR_OBJECT(DROPBOX_ID);
+
+-- Enumeration of attachment modes
+
+create table CALENDAR_OBJ_ATTACHMENTS_MODE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE values (0, 'none' );
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE values (1, 'read' );
+insert into CALENDAR_OBJ_ATTACHMENTS_MODE values (2, 'write');
+
+
+-- Enumeration of calendar access types
+
+create table CALENDAR_ACCESS_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(32) not null unique
+);
+
+insert into CALENDAR_ACCESS_TYPE values (0, '' );
+insert into CALENDAR_ACCESS_TYPE values (1, 'public' );
+insert into CALENDAR_ACCESS_TYPE values (2, 'private' );
+insert into CALENDAR_ACCESS_TYPE values (3, 'confidential' );
+insert into CALENDAR_ACCESS_TYPE values (4, 'restricted' );
+
+
+-----------------
+-- Instance ID --
+-----------------
+
+create sequence INSTANCE_ID_SEQ;
+
+
+----------------
+-- Time Range --
+----------------
+
+create table TIME_RANGE (
+ INSTANCE_ID integer primary key default nextval('INSTANCE_ID_SEQ'), -- implicit index
+ CALENDAR_RESOURCE_ID integer not null references CALENDAR on delete cascade,
+ CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ FLOATING boolean not null,
+ START_DATE timestamp not null,
+ END_DATE timestamp not null,
+ FBTYPE integer not null,
+ TRANSPARENT boolean not null
+);
+
+create index TIME_RANGE_CALENDAR_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_RESOURCE_ID);
+create index TIME_RANGE_CALENDAR_OBJECT_RESOURCE_ID on
+ TIME_RANGE(CALENDAR_OBJECT_RESOURCE_ID);
+
+
+-- Enumeration of free/busy types
+
+create table FREE_BUSY_TYPE (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into FREE_BUSY_TYPE values (0, 'unknown' );
+insert into FREE_BUSY_TYPE values (1, 'free' );
+insert into FREE_BUSY_TYPE values (2, 'busy' );
+insert into FREE_BUSY_TYPE values (3, 'busy-unavailable');
+insert into FREE_BUSY_TYPE values (4, 'busy-tentative' );
+
+
+-------------------
+-- Per-user data --
+-------------------
+
+create table PERUSER (
+ TIME_RANGE_INSTANCE_ID integer not null references TIME_RANGE on delete cascade,
+ USER_ID varchar(255) not null,
+ TRANSPARENT boolean not null,
+ ADJUSTED_START_DATE timestamp default null,
+ ADJUSTED_END_DATE timestamp default null
+);
+
+create index PERUSER_TIME_RANGE_INSTANCE_ID on
+ PERUSER(TIME_RANGE_INSTANCE_ID);
+
+
+----------------
+-- Attachment --
+----------------
+
+create sequence ATTACHMENT_ID_SEQ;
+
+create table ATTACHMENT (
+ ATTACHMENT_ID integer primary key default nextval('ATTACHMENT_ID_SEQ'), -- implicit index
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ DROPBOX_ID varchar(255),
+ CONTENT_TYPE varchar(255) not null,
+ SIZE integer not null,
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ PATH varchar(1024) not null
+);
+
+create index ATTACHMENT_CALENDAR_HOME_RESOURCE_ID on
+ ATTACHMENT(CALENDAR_HOME_RESOURCE_ID);
+
+create index ATTACHMENT_DROPBOX_ID on
+ ATTACHMENT(DROPBOX_ID);
+
+-- Many-to-many relationship between attachments and calendar objects
+create table ATTACHMENT_CALENDAR_OBJECT (
+ ATTACHMENT_ID integer not null references ATTACHMENT on delete cascade,
+ MANAGED_ID varchar(255) not null,
+ CALENDAR_OBJECT_RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+
+ primary key (ATTACHMENT_ID, CALENDAR_OBJECT_RESOURCE_ID), -- implicit index
+ unique (MANAGED_ID, CALENDAR_OBJECT_RESOURCE_ID) --implicit index
+);
+
+create index ATTACHMENT_CALENDAR_OBJECT_CALENDAR_OBJECT_RESOURCE_ID on
+ ATTACHMENT_CALENDAR_OBJECT(CALENDAR_OBJECT_RESOURCE_ID);
+
+-----------------------
+-- Resource Property --
+-----------------------
+
+create table RESOURCE_PROPERTY (
+ RESOURCE_ID integer not null, -- foreign key: *.RESOURCE_ID
+ NAME varchar(255) not null,
+ VALUE text not null, -- FIXME: xml?
+ VIEWER_UID varchar(255),
+
+ primary key (RESOURCE_ID, NAME, VIEWER_UID) -- implicit index
+);
+
+
+----------------------
+-- AddressBook Home --
+----------------------
+
+create table ADDRESSBOOK_HOME (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ ADDRESSBOOK_PROPERTY_STORE_ID integer default nextval('RESOURCE_ID_SEQ') not null, -- implicit index
+ OWNER_UID varchar(255) not null unique, -- implicit index
+ STATUS integer default 0 not null, -- enum HOME_STATUS
+ DATAVERSION integer default 0 not null
+);
+
+
+-------------------------------
+-- AddressBook Home Metadata --
+-------------------------------
+
+create table ADDRESSBOOK_HOME_METADATA (
+ RESOURCE_ID integer primary key references ADDRESSBOOK_HOME on delete cascade, -- implicit index
+ QUOTA_USED_BYTES integer default 0 not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+
+-----------------------------
+-- Shared AddressBook Bind --
+-----------------------------
+
+-- Joins sharee ADDRESSBOOK_HOME and owner ADDRESSBOOK_HOME
+
+create table SHARED_ADDRESSBOOK_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ OWNER_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ EXTERNAL_ID integer default null,
+ ADDRESSBOOK_RESOURCE_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, ADDRESSBOOK_RESOURCE_NAME) -- implicit index
+);
+
+create index SHARED_ADDRESSBOOK_BIND_RESOURCE_ID on
+ SHARED_ADDRESSBOOK_BIND(OWNER_HOME_RESOURCE_ID);
+
+
+------------------------
+-- AddressBook Object --
+------------------------
+
+create table ADDRESSBOOK_OBJECT (
+ RESOURCE_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ RESOURCE_NAME varchar(255) not null,
+ VCARD_TEXT text not null,
+ VCARD_UID varchar(255) not null,
+ KIND integer not null, -- enum ADDRESSBOOK_OBJECT_KIND
+ MD5 char(32) not null,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ DATAVERSION integer default 0 not null,
+
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, RESOURCE_NAME), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, VCARD_UID) -- implicit index
+);
+
+
+-----------------------------
+-- AddressBook Object kind --
+-----------------------------
+
+create table ADDRESSBOOK_OBJECT_KIND (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into ADDRESSBOOK_OBJECT_KIND values (0, 'person');
+insert into ADDRESSBOOK_OBJECT_KIND values (1, 'group' );
+insert into ADDRESSBOOK_OBJECT_KIND values (2, 'resource');
+insert into ADDRESSBOOK_OBJECT_KIND values (3, 'location');
+
+
+----------------------------------
+-- Revisions, forward reference --
+----------------------------------
+
+create sequence REVISION_SEQ;
+
+---------------------------------
+-- Address Book Object Members --
+---------------------------------
+
+create table ABO_MEMBERS (
+ GROUP_ID integer not null, -- references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ ADDRESSBOOK_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ MEMBER_ID integer not null, -- references ADDRESSBOOK_OBJECT, -- member AddressBook Object's RESOURCE_ID
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ REMOVED boolean default false not null,
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (GROUP_ID, MEMBER_ID, REVISION) -- implicit index
+);
+
+create index ABO_MEMBERS_ADDRESSBOOK_ID on
+ ABO_MEMBERS(ADDRESSBOOK_ID);
+create index ABO_MEMBERS_MEMBER_ID on
+ ABO_MEMBERS(MEMBER_ID);
+
+------------------------------------------
+-- Address Book Object Foreign Members --
+------------------------------------------
+
+create table ABO_FOREIGN_MEMBERS (
+ GROUP_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade, -- AddressBook Object's (kind=='group') RESOURCE_ID
+ ADDRESSBOOK_ID integer not null references ADDRESSBOOK_HOME on delete cascade,
+ MEMBER_ADDRESS varchar(255) not null, -- member AddressBook Object's 'calendar' address
+
+ primary key (GROUP_ID, MEMBER_ADDRESS) -- implicit index
+);
+
+create index ABO_FOREIGN_MEMBERS_ADDRESSBOOK_ID on
+ ABO_FOREIGN_MEMBERS(ADDRESSBOOK_ID);
+
+-----------------------
+-- Shared Group Bind --
+-----------------------
+
+-- Joins ADDRESSBOOK_HOME and ADDRESSBOOK_OBJECT (kind == group)
+
+create table SHARED_GROUP_BIND (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ GROUP_RESOURCE_ID integer not null references ADDRESSBOOK_OBJECT on delete cascade,
+ EXTERNAL_ID integer default null,
+ GROUP_ADDRESSBOOK_NAME varchar(255) not null,
+ BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ BIND_STATUS integer not null, -- enum CALENDAR_BIND_STATUS
+ BIND_REVISION integer default 0 not null,
+ MESSAGE text, -- FIXME: xml?
+
+ primary key (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_RESOURCE_ID), -- implicit index
+ unique (ADDRESSBOOK_HOME_RESOURCE_ID, GROUP_ADDRESSBOOK_NAME) -- implicit index
+);
+
+create index SHARED_GROUP_BIND_RESOURCE_ID on
+ SHARED_GROUP_BIND(GROUP_RESOURCE_ID);
+
+
+---------------
+-- Revisions --
+---------------
+
+-- create sequence REVISION_SEQ;
+
+
+-------------------------------
+-- Calendar Object Revisions --
+-------------------------------
+
+create table CALENDAR_OBJECT_REVISIONS (
+ CALENDAR_HOME_RESOURCE_ID integer not null references CALENDAR_HOME,
+ CALENDAR_RESOURCE_ID integer references CALENDAR,
+ CALENDAR_NAME varchar(255) default null,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null,
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index CALENDAR_OBJECT_REVISIONS_HOME_RESOURCE_ID_CALENDAR_RESOURCE_ID
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_HOME_RESOURCE_ID, CALENDAR_RESOURCE_ID);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index CALENDAR_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on CALENDAR_OBJECT_REVISIONS(CALENDAR_RESOURCE_ID, REVISION);
+
+
+----------------------------------
+-- AddressBook Object Revisions --
+----------------------------------
+
+create table ADDRESSBOOK_OBJECT_REVISIONS (
+ ADDRESSBOOK_HOME_RESOURCE_ID integer not null references ADDRESSBOOK_HOME,
+ OWNER_HOME_RESOURCE_ID integer references ADDRESSBOOK_HOME,
+ ADDRESSBOOK_NAME varchar(255) default null,
+ OBJECT_RESOURCE_ID integer default 0,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null,
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_HOME_RESOURCE_ID_OWNER_HOME_RESOURCE_ID
+ on ADDRESSBOOK_OBJECT_REVISIONS(ADDRESSBOOK_HOME_RESOURCE_ID, OWNER_HOME_RESOURCE_ID);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_RESOURCE_NAME_DELETED_REVISION
+ on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, RESOURCE_NAME, DELETED, REVISION);
+
+create index ADDRESSBOOK_OBJECT_REVISIONS_OWNER_HOME_RESOURCE_ID_REVISION
+ on ADDRESSBOOK_OBJECT_REVISIONS(OWNER_HOME_RESOURCE_ID, REVISION);
+
+
+-----------------------------------
+-- Notification Object Revisions --
+-----------------------------------
+
+create table NOTIFICATION_OBJECT_REVISIONS (
+ NOTIFICATION_HOME_RESOURCE_ID integer not null references NOTIFICATION_HOME on delete cascade,
+ RESOURCE_NAME varchar(255),
+ REVISION integer default nextval('REVISION_SEQ') not null,
+ DELETED boolean not null,
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ unique (NOTIFICATION_HOME_RESOURCE_ID, RESOURCE_NAME) -- implicit index
+);
+
+create index NOTIFICATION_OBJECT_REVISIONS_RESOURCE_ID_REVISION
+ on NOTIFICATION_OBJECT_REVISIONS(NOTIFICATION_HOME_RESOURCE_ID, REVISION);
+
+
+-------------------------------------------
+-- Apple Push Notification Subscriptions --
+-------------------------------------------
+
+create table APN_SUBSCRIPTIONS (
+ TOKEN varchar(255) not null,
+ RESOURCE_KEY varchar(255) not null,
+ MODIFIED integer not null,
+ SUBSCRIBER_GUID varchar(255) not null,
+ USER_AGENT varchar(255) default null,
+ IP_ADDR varchar(255) default null,
+
+ primary key (TOKEN, RESOURCE_KEY) -- implicit index
+);
+
+create index APN_SUBSCRIPTIONS_RESOURCE_KEY
+ on APN_SUBSCRIPTIONS(RESOURCE_KEY);
+
+
+-----------------
+-- IMIP Tokens --
+-----------------
+
+create table IMIP_TOKENS (
+ TOKEN varchar(255) not null,
+ ORGANIZER varchar(255) not null,
+ ATTENDEE varchar(255) not null,
+ ICALUID varchar(255) not null,
+ ACCESSED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+
+ primary key (ORGANIZER, ATTENDEE, ICALUID) -- implicit index
+);
+
+create index IMIP_TOKENS_TOKEN
+ on IMIP_TOKENS(TOKEN);
+
+
+----------------
+-- Work Items --
+----------------
+
+create sequence WORKITEM_SEQ;
+
+
+---------------------------
+-- IMIP Inivitation Work --
+---------------------------
+
+create table IMIP_INVITATION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ FROM_ADDR varchar(255) not null,
+ TO_ADDR varchar(255) not null,
+ ICALENDAR_TEXT text not null
+);
+
+create index IMIP_INVITATION_WORK_JOB_ID on
+ IMIP_INVITATION_WORK(JOB_ID);
+
+-----------------------
+-- IMIP Polling Work --
+-----------------------
+
+create table IMIP_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index IMIP_POLLING_WORK_JOB_ID on
+ IMIP_POLLING_WORK(JOB_ID);
+
+
+---------------------
+-- IMIP Reply Work --
+---------------------
+
+create table IMIP_REPLY_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ ORGANIZER varchar(255) not null,
+ ATTENDEE varchar(255) not null,
+ ICALENDAR_TEXT text not null
+);
+
+create index IMIP_REPLY_WORK_JOB_ID on
+ IMIP_REPLY_WORK(JOB_ID);
+
+
+------------------------
+-- Push Notifications --
+------------------------
+
+create table PUSH_NOTIFICATION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ PUSH_ID varchar(255) not null,
+ PUSH_PRIORITY integer not null -- 1:low 5:medium 10:high
+);
+
+create index PUSH_NOTIFICATION_WORK_JOB_ID on
+ PUSH_NOTIFICATION_WORK(JOB_ID);
+
+-----------------
+-- GroupCacher --
+-----------------
+
+create table GROUP_CACHER_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index GROUP_CACHER_POLLING_WORK_JOB_ID on
+ GROUP_CACHER_POLLING_WORK(JOB_ID);
+
+create table GROUP_REFRESH_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ GROUP_UID varchar(255) not null
+);
+
+create index GROUP_REFRESH_WORK_JOB_ID on
+ GROUP_REFRESH_WORK(JOB_ID);
+
+create table GROUP_ATTENDEE_RECONCILE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ RESOURCE_ID integer,
+ GROUP_ID integer
+);
+
+create index GROUP_ATTENDEE_RECONCILE_WORK_JOB_ID on
+ GROUP_ATTENDEE_RECONCILE_WORK(JOB_ID);
+
+
+create table GROUPS (
+ GROUP_ID integer primary key default nextval('RESOURCE_ID_SEQ'), -- implicit index
+ NAME varchar(255) not null,
+ GROUP_UID varchar(255) not null,
+ MEMBERSHIP_HASH varchar(255) not null,
+ EXTANT integer default 1,
+ CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
+ MODIFIED timestamp default timezone('UTC', CURRENT_TIMESTAMP)
+);
+create index GROUPS_GROUP_UID on
+ GROUPS(GROUP_UID);
+
+create table GROUP_MEMBERSHIP (
+ GROUP_ID integer not null references GROUPS on delete cascade,
+ MEMBER_UID varchar(255) not null,
+
+ primary key (GROUP_ID, MEMBER_UID)
+);
+
+create index GROUP_MEMBERSHIP_MEMBER on
+ GROUP_MEMBERSHIP(MEMBER_UID);
+
+create table GROUP_ATTENDEE (
+ GROUP_ID integer not null references GROUPS on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ MEMBERSHIP_HASH varchar(255) not null,
+
+ primary key (GROUP_ID, RESOURCE_ID)
+);
+create index GROUP_ATTENDEE_RESOURCE_ID on
+ GROUP_ATTENDEE(RESOURCE_ID);
+
+---------------
+-- Delegates --
+---------------
+
+create table DELEGATES (
+ DELEGATOR varchar(255) not null,
+ DELEGATE varchar(255) not null,
+ READ_WRITE integer not null, -- 1 = ReadWrite, 0 = ReadOnly
+
+ primary key (DELEGATOR, READ_WRITE, DELEGATE)
+);
+create index DELEGATE_TO_DELEGATOR on
+ DELEGATES(DELEGATE, READ_WRITE, DELEGATOR);
+
+create table DELEGATE_GROUPS (
+ DELEGATOR varchar(255) not null,
+ GROUP_ID integer not null references GROUPS on delete cascade,
+ READ_WRITE integer not null, -- 1 = ReadWrite, 0 = ReadOnly
+ IS_EXTERNAL integer not null, -- 1 = ReadWrite, 0 = ReadOnly
+
+ primary key (DELEGATOR, READ_WRITE, GROUP_ID)
+);
+create index DELEGATE_GROUPS_GROUP_ID on
+ DELEGATE_GROUPS(GROUP_ID);
+
+create table EXTERNAL_DELEGATE_GROUPS (
+ DELEGATOR varchar(255) primary key not null,
+ GROUP_UID_READ varchar(255),
+ GROUP_UID_WRITE varchar(255)
+);
+
+--------------------------
+-- Object Splitter Work --
+--------------------------
+
+create table CALENDAR_OBJECT_SPLITTER_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade
+);
+
+create index CALENDAR_OBJECT_SPLITTER_WORK_RESOURCE_ID on
+ CALENDAR_OBJECT_SPLITTER_WORK(RESOURCE_ID);
+create index CALENDAR_OBJECT_SPLITTER_WORK_JOB_ID on
+ CALENDAR_OBJECT_SPLITTER_WORK(JOB_ID);
+
+---------------------------
+-- Revision Cleanup Work --
+---------------------------
+
+create table FIND_MIN_VALID_REVISION_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index FIND_MIN_VALID_REVISION_WORK_JOB_ID on
+ FIND_MIN_VALID_REVISION_WORK(JOB_ID);
+
+create table REVISION_CLEANUP_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index REVISION_CLEANUP_WORK_JOB_ID on
+ REVISION_CLEANUP_WORK(JOB_ID);
+
+------------------------
+-- Inbox Cleanup Work --
+------------------------
+
+create table INBOX_CLEANUP_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index INBOX_CLEANUP_WORK_JOB_ID on
+ INBOX_CLEANUP_WORK(JOB_ID);
+
+create table CLEANUP_ONE_INBOX_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ HOME_ID integer not null unique references CALENDAR_HOME on delete cascade
+);
+
+create index CLEANUP_ONE_INBOX_WORK_JOB_ID on
+ CLEANUP_ONE_INBOX_WORK(JOB_ID);
+
+-------------------
+-- Schedule Work --
+-------------------
+
+create table SCHEDULE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ ICALENDAR_UID varchar(255) not null,
+ WORK_TYPE varchar(255) not null
+);
+
+create index SCHEDULE_WORK_JOB_ID on
+ SCHEDULE_WORK(JOB_ID);
+create index SCHEDULE_WORK_ICALENDAR_UID on
+ SCHEDULE_WORK(ICALENDAR_UID);
+
+---------------------------
+-- Schedule Refresh Work --
+---------------------------
+
+create table SCHEDULE_REFRESH_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ ATTENDEE_COUNT integer
+);
+
+create index SCHEDULE_REFRESH_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_REFRESH_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_REFRESH_WORK_RESOURCE_ID on
+ SCHEDULE_REFRESH_WORK(RESOURCE_ID);
+
+create table SCHEDULE_REFRESH_ATTENDEES (
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ ATTENDEE varchar(255) not null,
+
+ primary key (RESOURCE_ID, ATTENDEE)
+);
+
+create index SCHEDULE_REFRESH_ATTENDEES_RESOURCE_ID_ATTENDEE on
+ SCHEDULE_REFRESH_ATTENDEES(RESOURCE_ID, ATTENDEE);
+
+------------------------------
+-- Schedule Auto Reply Work --
+------------------------------
+
+create table SCHEDULE_AUTO_REPLY_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ PARTSTAT varchar(255) not null
+);
+
+create index SCHEDULE_AUTO_REPLY_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_AUTO_REPLY_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_AUTO_REPLY_WORK_RESOURCE_ID on
+ SCHEDULE_AUTO_REPLY_WORK(RESOURCE_ID);
+
+-----------------------------
+-- Schedule Organizer Work --
+-----------------------------
+
+create table SCHEDULE_ORGANIZER_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ SCHEDULE_ACTION integer not null, -- Enum SCHEDULE_ACTION
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer, -- this references a possibly non-existent CALENDR_OBJECT
+ ICALENDAR_TEXT_OLD text,
+ ICALENDAR_TEXT_NEW text,
+ ATTENDEE_COUNT integer,
+ SMART_MERGE boolean
+);
+
+create index SCHEDULE_ORGANIZER_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_ORGANIZER_WORK_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_WORK(RESOURCE_ID);
+
+-- Enumeration of schedule actions
+
+create table SCHEDULE_ACTION (
+ ID integer primary key,
+ DESCRIPTION varchar(16) not null unique
+);
+
+insert into SCHEDULE_ACTION values (0, 'create');
+insert into SCHEDULE_ACTION values (1, 'modify');
+insert into SCHEDULE_ACTION values (2, 'modify-cancelled');
+insert into SCHEDULE_ACTION values (3, 'remove');
+
+----------------------------------
+-- Schedule Organizer Send Work --
+----------------------------------
+
+create table SCHEDULE_ORGANIZER_SEND_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ SCHEDULE_ACTION integer not null, -- Enum SCHEDULE_ACTION
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer, -- this references a possibly non-existent CALENDAR_OBJECT
+ ATTENDEE varchar(255) not null,
+ ITIP_MSG text,
+ NO_REFRESH boolean
+);
+
+create index SCHEDULE_ORGANIZER_SEND_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_SEND_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_ORGANIZER_SEND_WORK_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_SEND_WORK(RESOURCE_ID);
+
+-------------------------
+-- Schedule Reply Work --
+-------------------------
+
+create table SCHEDULE_REPLY_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ CHANGED_RIDS text
+);
+
+create index SCHEDULE_REPLY_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_REPLY_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_REPLY_WORK_RESOURCE_ID on
+ SCHEDULE_REPLY_WORK(RESOURCE_ID);
+
+--------------------------------
+-- Schedule Reply Cancel Work --
+--------------------------------
+
+create table SCHEDULE_REPLY_CANCEL_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ ICALENDAR_TEXT text not null
+);
+
+create index SCHEDULE_REPLY_CANCEL_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_REPLY_CANCEL_WORK(HOME_RESOURCE_ID);
+
+----------------------------------
+-- Principal Purge Polling Work --
+----------------------------------
+
+create table PRINCIPAL_PURGE_POLLING_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null
+);
+
+create index PRINCIPAL_PURGE_POLLING_WORK_JOB_ID on
+ PRINCIPAL_PURGE_POLLING_WORK(JOB_ID);
+
+--------------------------------
+-- Principal Purge Check Work --
+--------------------------------
+
+create table PRINCIPAL_PURGE_CHECK_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ UID varchar(255) not null
+);
+
+create index PRINCIPAL_PURGE_CHECK_WORK_JOB_ID on
+ PRINCIPAL_PURGE_CHECK_WORK(JOB_ID);
+
+--------------------------
+-- Principal Purge Work --
+--------------------------
+
+create table PRINCIPAL_PURGE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ UID varchar(255) not null
+);
+
+create index PRINCIPAL_PURGE_WORK_JOB_ID on
+ PRINCIPAL_PURGE_WORK(JOB_ID);
+
+
+--------------------------------
+-- Principal Home Remove Work --
+--------------------------------
+
+create table PRINCIPAL_PURGE_HOME_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade
+);
+
+create index PRINCIPAL_PURGE_HOME_WORK_JOB_ID on
+ PRINCIPAL_PURGE_HOME_WORK(JOB_ID);
+create index PRINCIPAL_PURGE_HOME_HOME_RESOURCE_ID on
+ PRINCIPAL_PURGE_HOME_WORK(HOME_RESOURCE_ID);
+
+
+--------------------
+-- Schema Version --
+--------------------
+
+create table CALENDARSERVER (
+ NAME varchar(255) primary key, -- implicit index
+ VALUE varchar(255)
+);
+
+insert into CALENDARSERVER values ('VERSION', '45');
+insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '6');
+insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
+insert into CALENDARSERVER values ('NOTIFICATION-DATAVERSION', '1');
+insert into CALENDARSERVER values ('MIN-VALID-REVISION', '1');
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_43_to_44.sql
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_43_to_44.sql 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_43_to_44.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -18,33 +18,153 @@
-- Upgrade database schema from VERSION 43 to 44 --
---------------------------------------------------
-insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('group', 5);
+-----------------
+-- Job Changes --
+-----------------
-create table GROUP_SHAREE_RECONCILE_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
- JOB_ID integer not null references JOB,
- CALENDAR_ID integer not null references CALENDAR on delete cascade,
- GROUP_ID integer not null references GROUPS on delete cascade
+drop function next_job;
+
+-- The scheduling work schema has changed a lot - to avoid a complex migration process this
+-- script just drops all the existing tables and adds back the new set
+
+-------------------
+-- Schedule Work --
+-------------------
+
+create table SCHEDULE_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "ICALENDAR_UID" nvarchar2(255),
+ "WORK_TYPE" nvarchar2(255)
);
-create index GROUP_SHAREE_RECONCILE_WORK_JOB_ID on GROUP_SHAREE_RECONCILE_WORK(
- JOB_ID
+create index SCHEDULE_WORK_JOB_ID_65e810ee on SCHEDULE_WORK (
+ JOB_ID
);
+create index SCHEDULE_WORK_ICALEND_089f33dc on SCHEDULE_WORK (
+ ICALENDAR_UID
+);
+---------------------------
+-- Schedule Refresh Work --
+---------------------------
-create table GROUP_SHAREE (
- GROUP_ID integer not null references GROUPS on delete cascade,
- CALENDAR_HOME_ID integer not null references CALENDAR_HOME on delete cascade,
- CALENDAR_ID integer not null references CALENDAR on delete cascade,
- GROUP_BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
- MEMBERSHIP_HASH varchar(255) not null,
-
- primary key (GROUP_ID, CALENDAR_HOME_ID, CALENDAR_ID) -- implicit index
+drop table SCHEDULE_REFRESH_WORK;
+
+create table SCHEDULE_REFRESH_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "ATTENDEE_COUNT" integer
);
-create index GROUP_SHAREE_CALENDAR_ID on GROUP_SHAREE(
- CALENDAR_ID
+create index SCHEDULE_REFRESH_WORK_26084c7b on SCHEDULE_REFRESH_WORK (
+ HOME_RESOURCE_ID
);
+create index SCHEDULE_REFRESH_WORK_989efe54 on SCHEDULE_REFRESH_WORK (
+ RESOURCE_ID
+);
+------------------------------
+-- Schedule Auto Reply Work --
+------------------------------
+
+drop table SCHEDULE_AUTO_REPLY_WORK;
+
+create table SCHEDULE_AUTO_REPLY_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "PARTSTAT" nvarchar2(255)
+);
+
+create index SCHEDULE_AUTO_REPLY_W_0256478d on SCHEDULE_AUTO_REPLY_WORK (
+ HOME_RESOURCE_ID
+);
+create index SCHEDULE_AUTO_REPLY_W_0755e754 on SCHEDULE_AUTO_REPLY_WORK (
+ RESOURCE_ID
+);
+
+-----------------------------
+-- Schedule Organizer Work --
+-----------------------------
+
+drop table SCHEDULE_ORGANIZER_WORK;
+
+create table SCHEDULE_ORGANIZER_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "SCHEDULE_ACTION" integer not null,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer,
+ "ICALENDAR_TEXT_OLD" nclob,
+ "ICALENDAR_TEXT_NEW" nclob,
+ "ATTENDEE_COUNT" integer,
+ "SMART_MERGE" integer
+);
+
+create index SCHEDULE_ORGANIZER_WO_18ce4edd on SCHEDULE_ORGANIZER_WORK (
+ HOME_RESOURCE_ID
+);
+create index SCHEDULE_ORGANIZER_WO_14702035 on SCHEDULE_ORGANIZER_WORK (
+ RESOURCE_ID
+);
+
+----------------------------------
+-- Schedule Organizer Send Work --
+----------------------------------
+
+create table SCHEDULE_ORGANIZER_SEND_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "SCHEDULE_ACTION" integer not null,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer,
+ "ATTENDEE" nvarchar2(255),
+ "ITIP_MSG" nclob,
+ "NO_REFRESH" integer
+);
+
+create index SCHEDULE_ORGANIZER_SE_9ec9f827 on SCHEDULE_ORGANIZER_SEND_WORK (
+ HOME_RESOURCE_ID
+);
+create index SCHEDULE_ORGANIZER_SE_699fefc4 on SCHEDULE_ORGANIZER_SEND_WORK (
+ RESOURCE_ID
+);
+
+-------------------------
+-- Schedule Reply Work --
+-------------------------
+
+drop table SCHEDULE_REPLY_WORK;
+
+create table SCHEDULE_REPLY_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "RESOURCE_ID" integer not null references CALENDAR_OBJECT on delete cascade,
+ "CHANGED_RIDS" nclob
+);
+
+create index SCHEDULE_REPLY_WORK_H_745af8cf on SCHEDULE_REPLY_WORK (
+ HOME_RESOURCE_ID
+);
+create index SCHEDULE_REPLY_WORK_R_11bd3fbb on SCHEDULE_REPLY_WORK (
+ RESOURCE_ID
+);
+
+--------------------------------
+-- Schedule Reply Cancel Work --
+--------------------------------
+
+drop table SCHEDULE_REPLY_CANCEL_WORK;
+
+create table SCHEDULE_REPLY_CANCEL_WORK (
+ "WORK_ID" integer primary key references SCHEDULE_WORK on delete cascade,
+ "HOME_RESOURCE_ID" integer not null references CALENDAR_HOME on delete cascade,
+ "ICALENDAR_TEXT" nclob
+);
+
+create index SCHEDULE_REPLY_CANCEL_dab513ef on SCHEDULE_REPLY_CANCEL_WORK (
+ HOME_RESOURCE_ID
+);
+
-- update the version
update CALENDARSERVER set VALUE = '44' where NAME = 'VERSION';
Copied: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_44_to_45.sql (from rev 13731, CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_44_to_45.sql)
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_44_to_45.sql (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_44_to_45.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,32 @@
+----
+-- Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 44 to 45 --
+---------------------------------------------------
+
+-------------------
+-- Data Versions --
+-------------------
+
+alter table CALENDAR_OBJECT
+ add ("DATAVERSION" integer default 0 not null);
+
+alter table ADDRESSBOOK_OBJECT
+ add ("DATAVERSION" integer default 0 not null);
+
+-- update the version
+update CALENDARSERVER set VALUE = '45' where NAME = 'VERSION';
Copied: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_45_to_46.sql (from rev 13684, CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_43_to_44.sql)
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_45_to_46.sql (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_45_to_46.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,50 @@
+----
+-- Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 45 to 46 --
+---------------------------------------------------
+
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('group', 5);
+
+create table GROUP_SHAREE_RECONCILE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer not null references JOB,
+ CALENDAR_ID integer not null references CALENDAR on delete cascade,
+ GROUP_ID integer not null references GROUPS on delete cascade
+);
+
+create index GROUP_SHAREE_RECONCILE_WORK_JOB_ID on GROUP_SHAREE_RECONCILE_WORK(
+ JOB_ID
+);
+
+
+create table GROUP_SHAREE (
+ GROUP_ID integer not null references GROUPS on delete cascade,
+ CALENDAR_HOME_ID integer not null references CALENDAR_HOME on delete cascade,
+ CALENDAR_ID integer not null references CALENDAR on delete cascade,
+ GROUP_BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ MEMBERSHIP_HASH varchar(255) not null,
+
+ primary key (GROUP_ID, CALENDAR_HOME_ID, CALENDAR_ID) -- implicit index
+);
+
+create index GROUP_SHAREE_CALENDAR_ID on GROUP_SHAREE(
+ CALENDAR_ID
+);
+
+-- update the version
+update CALENDARSERVER set VALUE = '44' where NAME = 'VERSION';
Deleted: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -1,48 +0,0 @@
-----
--- Copyright (c) 2012-2014 Apple Inc. All rights reserved.
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
-----
-
----------------------------------------------------
--- Upgrade database schema from VERSION 43 to 44 --
----------------------------------------------------
-
-insert into CALENDAR_BIND_MODE values (5, 'group');
-
-create table GROUP_SHAREE_RECONCILE_WORK (
- WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
- JOB_ID integer not null references JOB,
- CALENDAR_ID integer not null references CALENDAR on delete cascade,
- GROUP_ID integer not null references GROUPS on delete cascade
-);
-
-create index GROUP_SHAREE_RECONCILE_WORK_JOB_ID on
- GROUP_SHAREE_RECONCILE_WORK(JOB_ID);
-
-
-create table GROUP_SHAREE (
- GROUP_ID integer not null references GROUPS on delete cascade,
- CALENDAR_HOME_ID integer not null references CALENDAR_HOME on delete cascade,
- CALENDAR_ID integer not null references CALENDAR on delete cascade,
- GROUP_BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
- MEMBERSHIP_HASH varchar(255) not null,
-
- primary key (GROUP_ID, CALENDAR_HOME_ID, CALENDAR_ID) -- implicit index
-);
-
-create index GROUP_SHAREE_CALENDAR_ID on
- GROUP_SHAREE(CALENDAR_ID);
-
--- update the version
-update CALENDARSERVER set VALUE = '44' where NAME = 'VERSION';
Copied: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql (from rev 13731, CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql)
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,157 @@
+----
+-- Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 43 to 44 --
+---------------------------------------------------
+
+-----------------
+-- Job Changes --
+-----------------
+
+drop function next_job();
+
+-- The scheduling work schema has changed a lot - to avoid a complex migration process this
+-- script just drops all the existing tables and adds back the new set
+
+-------------------
+-- Schedule Work --
+-------------------
+
+create table SCHEDULE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ ICALENDAR_UID varchar(255) not null,
+ WORK_TYPE varchar(255) not null
+);
+
+create index SCHEDULE_WORK_JOB_ID on
+ SCHEDULE_WORK(JOB_ID);
+create index SCHEDULE_WORK_ICALENDAR_UID on
+ SCHEDULE_WORK(ICALENDAR_UID);
+
+---------------------------
+-- Schedule Refresh Work --
+---------------------------
+
+drop table SCHEDULE_REFRESH_WORK;
+
+create table SCHEDULE_REFRESH_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ ATTENDEE_COUNT integer
+);
+
+create index SCHEDULE_REFRESH_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_REFRESH_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_REFRESH_WORK_RESOURCE_ID on
+ SCHEDULE_REFRESH_WORK(RESOURCE_ID);
+
+------------------------------
+-- Schedule Auto Reply Work --
+------------------------------
+
+drop table SCHEDULE_AUTO_REPLY_WORK;
+
+create table SCHEDULE_AUTO_REPLY_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ PARTSTAT varchar(255) not null
+);
+
+create index SCHEDULE_AUTO_REPLY_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_AUTO_REPLY_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_AUTO_REPLY_WORK_RESOURCE_ID on
+ SCHEDULE_AUTO_REPLY_WORK(RESOURCE_ID);
+
+-----------------------------
+-- Schedule Organizer Work --
+-----------------------------
+
+drop table SCHEDULE_ORGANIZER_WORK;
+
+create table SCHEDULE_ORGANIZER_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ SCHEDULE_ACTION integer not null, -- Enum SCHEDULE_ACTION
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer, -- this references a possibly non-existent CALENDR_OBJECT
+ ICALENDAR_TEXT_OLD text,
+ ICALENDAR_TEXT_NEW text,
+ ATTENDEE_COUNT integer,
+ SMART_MERGE boolean
+);
+
+create index SCHEDULE_ORGANIZER_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_ORGANIZER_WORK_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_WORK(RESOURCE_ID);
+
+----------------------------------
+-- Schedule Organizer Send Work --
+----------------------------------
+
+create table SCHEDULE_ORGANIZER_SEND_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ SCHEDULE_ACTION integer not null, -- Enum SCHEDULE_ACTION
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer, -- this references a possibly non-existent CALENDAR_OBJECT
+ ATTENDEE varchar(255) not null,
+ ITIP_MSG text,
+ NO_REFRESH boolean
+);
+
+create index SCHEDULE_ORGANIZER_SEND_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_SEND_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_ORGANIZER_SEND_WORK_RESOURCE_ID on
+ SCHEDULE_ORGANIZER_SEND_WORK(RESOURCE_ID);
+
+-------------------------
+-- Schedule Reply Work --
+-------------------------
+
+drop table SCHEDULE_REPLY_WORK;
+
+create table SCHEDULE_REPLY_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ CHANGED_RIDS text
+);
+
+create index SCHEDULE_REPLY_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_REPLY_WORK(HOME_RESOURCE_ID);
+create index SCHEDULE_REPLY_WORK_RESOURCE_ID on
+ SCHEDULE_REPLY_WORK(RESOURCE_ID);
+
+--------------------------------
+-- Schedule Reply Cancel Work --
+--------------------------------
+
+drop table SCHEDULE_REPLY_CANCEL_WORK;
+
+create table SCHEDULE_REPLY_CANCEL_WORK (
+ WORK_ID integer primary key references SCHEDULE_WORK on delete cascade, -- implicit index
+ HOME_RESOURCE_ID integer not null references CALENDAR_HOME on delete cascade,
+ ICALENDAR_TEXT text not null
+);
+
+create index SCHEDULE_REPLY_CANCEL_WORK_HOME_RESOURCE_ID on
+ SCHEDULE_REPLY_CANCEL_WORK(HOME_RESOURCE_ID);
+
+-- update the version
+update CALENDARSERVER set VALUE = '44' where NAME = 'VERSION';
Copied: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_44_to_45.sql (from rev 13731, CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_44_to_45.sql)
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_44_to_45.sql (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_44_to_45.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,32 @@
+----
+-- Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 44 to 45 --
+---------------------------------------------------
+
+-------------------
+-- Data Versions --
+-------------------
+
+alter table CALENDAR_OBJECT
+ add column DATAVERSION integer default 0 not null;
+
+alter table ADDRESSBOOK_OBJECT
+ add column DATAVERSION integer default 0 not null;
+
+-- update the version
+update CALENDARSERVER set VALUE = '45' where NAME = 'VERSION';
Copied: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_45_to_46.sql (from rev 13684, CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_43_to_44.sql)
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_45_to_46.sql (rev 0)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_45_to_46.sql 2014-07-08 07:05:29 UTC (rev 13732)
@@ -0,0 +1,48 @@
+----
+-- Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+----
+
+---------------------------------------------------
+-- Upgrade database schema from VERSION 45 to 46 --
+---------------------------------------------------
+
+insert into CALENDAR_BIND_MODE values (5, 'group');
+
+create table GROUP_SHAREE_RECONCILE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer not null references JOB,
+ CALENDAR_ID integer not null references CALENDAR on delete cascade,
+ GROUP_ID integer not null references GROUPS on delete cascade
+);
+
+create index GROUP_SHAREE_RECONCILE_WORK_JOB_ID on
+ GROUP_SHAREE_RECONCILE_WORK(JOB_ID);
+
+
+create table GROUP_SHAREE (
+ GROUP_ID integer not null references GROUPS on delete cascade,
+ CALENDAR_HOME_ID integer not null references CALENDAR_HOME on delete cascade,
+ CALENDAR_ID integer not null references CALENDAR on delete cascade,
+ GROUP_BIND_MODE integer not null, -- enum CALENDAR_BIND_MODE
+ MEMBERSHIP_HASH varchar(255) not null,
+
+ primary key (GROUP_ID, CALENDAR_HOME_ID, CALENDAR_ID) -- implicit index
+);
+
+create index GROUP_SHAREE_CALENDAR_ID on
+ GROUP_SHAREE(CALENDAR_ID);
+
+-- update the version
+update CALENDARSERVER set VALUE = '46' where NAME = 'VERSION';
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_tables.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_tables.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/common/datastore/sql_tables.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -31,6 +31,7 @@
from sqlparse import parse
from re import compile
import hashlib
+import itertools
def _schemaFiles(version=None):
"""
@@ -70,8 +71,7 @@
"""
if extras.exists():
- out.write("\n-- Extras\n\n")
- out.write(extras.getContent())
+ out.write("\n".join(itertools.dropwhile(lambda x: not x.startswith("-- Extra schema to add"), extras.getContent().splitlines())) + "\n")
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/dps/client.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/dps/client.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/dps/client.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -15,6 +15,7 @@
##
import cPickle as pickle
+import time
import uuid
from twext.python.log import Logger
@@ -25,7 +26,7 @@
import twext.who.idirectory
from twext.who.util import ConstantsContainer
from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks, returnValue
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
from twisted.internet.protocol import ClientCreator
from twisted.protocols import amp
from twisted.python.constants import Names, NamedConstant
@@ -41,6 +42,7 @@
VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand,
WikiAccessForUIDCommand, ContinuationCommand
)
+from txdav.who.delegates import RecordType as DelegatesRecordType
from txdav.who.directory import (
CalendarDirectoryRecordMixin, CalendarDirectoryServiceMixin
)
@@ -59,13 +61,9 @@
## MOVE2WHO TODOs:
-## SACLs
## LDAP
-## Tests from old twistedcaldav/directory
-## Cmd line tools
## Store based directory service (records in the store, i.e.
## locations/resources)
-## Separate store for DPS (augments and delegates separate from calendar data)
## Store autoAcceptGroups in the group db?
@implementer(IDirectoryService, IStoreDirectoryService)
@@ -189,6 +187,20 @@
returnValue(results)
+ def _logResultTiming(self, command, startTime, results):
+ duration = time.time() - startTime
+ numResults = 0
+ if "fields" in results:
+ numResults = 1
+ if "fieldsList" in results:
+ numResults = len(results["fieldsList"])
+ log.debug(
+ "DPS call {command} duration={duration:.2f}s, results={numResults}",
+ command=command, duration=duration, numResults=numResults
+ )
+
+
+
@inlineCallbacks
def _call(self, command, postProcess, **kwds):
"""
@@ -204,9 +216,11 @@
L{Deferred} which fires with the post-processed results
@type postProcess: callable
"""
+ startTime = time.time()
results = yield self._sendCommand(command, **kwds)
if results.get("continuation", None) is None:
# We have all the results
+ self._logResultTiming(command, startTime, results)
returnValue(postProcess(results))
# There are more results to fetch, so loop until the continuation
@@ -225,6 +239,7 @@
for result in multi:
results["fieldsList"].extend(result["fieldsList"])
+ self._logResultTiming(command, startTime, results)
returnValue(postProcess(results))
@@ -367,11 +382,20 @@
def members(self):
- return self.service._call(
- MembersCommand,
- self.service._processMultipleRecords,
- uid=self.uid.encode("utf-8")
- )
+ if self.recordType in (
+ RecordType.group,
+ DelegatesRecordType.readDelegateGroup,
+ DelegatesRecordType.writeDelegateGroup,
+ DelegatesRecordType.readDelegatorGroup,
+ DelegatesRecordType.writeDelegatorGroup,
+ ):
+ return self.service._call(
+ MembersCommand,
+ self.service._processMultipleRecords,
+ uid=self.uid.encode("utf-8")
+ )
+ else:
+ return succeed([])
def groups(self):
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/dps/server.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/dps/server.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/dps/server.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -100,7 +100,7 @@
@return: an iterable of records, or None if the token does not exist
"""
if token in self._continuations:
- timestamp, records = self._continuations[token]
+ _ignore_timestamp, records = self._continuations[token]
del self._continuations[token]
else:
records = None
@@ -119,7 +119,7 @@
log.debug("Continuation: {c}", c=continuation)
records = self._retrieveContinuation(continuation)
response = self._recordsToResponse(records)
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
return response
@@ -194,7 +194,7 @@
response = {
"fields": pickle.dumps(fields),
}
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -212,7 +212,7 @@
response = {
"fields": pickle.dumps(fields),
}
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -226,7 +226,7 @@
response = {
"fields": pickle.dumps(fields),
}
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -239,7 +239,7 @@
self._directory.recordType.lookupByName(recordType))
)
response = self._recordsToResponse(records)
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -250,7 +250,7 @@
log.debug("RecordsWithEmailAddress: {e}", e=emailAddress)
records = (yield self._directory.recordsWithEmailAddress(emailAddress))
response = self._recordsToResponse(records)
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -265,7 +265,7 @@
tokens, context=context
)
response = self._recordsToResponse(records)
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -306,7 +306,7 @@
newFields, operand=operand, recordType=recordType
)
response = self._recordsToResponse(records)
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -327,7 +327,7 @@
records.append(member)
response = self._recordsToResponse(records)
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -357,7 +357,7 @@
response = {
"success": success,
}
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -376,7 +376,7 @@
for group in (yield record.groups()):
records.append(group)
response = self._recordsToResponse(records)
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -392,7 +392,7 @@
response = {
"authenticated": authenticated,
}
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -426,7 +426,7 @@
response = {
"authenticated": authenticated,
}
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
@@ -444,7 +444,7 @@
response = {
"access": access.name.encode("utf-8"),
}
- log.debug("Responding with: {response}", response=response)
+ # log.debug("Responding with: {response}", response=response)
returnValue(response)
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/augment.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/augment.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/augment.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -320,9 +320,10 @@
return (baseFields, augmentFields)
+ @inlineCallbacks
def removeRecords(self, uids):
- self._augmentDB.removeAugmentRecords(uids)
- return self._directory.removeRecords(uids)
+ yield self._augmentDB.removeAugmentRecords(uids)
+ yield self._directory.removeRecords(uids)
def _assignToField(self, fields, name, value):
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/delegates.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/delegates.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/delegates.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -236,7 +236,10 @@
"""
if delegate.recordType == BaseRecordType.group:
# find the groupID
- groupID, _ignore_name, _ignore_membershipHash, _ignore_modified = yield txn.groupByUID(
+ (
+ groupID, _ignore_name, _ignore_membershipHash, _ignore_modified,
+ _ignore_extant
+ ) = yield txn.groupByUID(
delegate.uid
)
yield txn.addDelegateGroup(delegator.uid, groupID, readWrite)
@@ -260,7 +263,10 @@
"""
if delegate.recordType == BaseRecordType.group:
# find the groupID
- groupID, _ignore_name, _ignore_membershipHash, _ignore_modified = yield txn.groupByUID(
+ (
+ groupID, _ignore_name, _ignore_membershipHash, _ignore_modified,
+ _ignore_extant
+ ) = yield txn.groupByUID(
delegate.uid
)
yield txn.removeDelegateGroup(delegator.uid, groupID, readWrite)
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/directory.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/directory.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/directory.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -175,8 +175,6 @@
else:
expression = CompoundExpression(outer, Operand.AND)
- results = []
-
if context is not None:
recordTypes = self.recordTypesForSearchContext(context)
else:
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/groups.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/groups.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/groups.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -157,12 +157,14 @@
if (component.masterComponent() is None or not component.isRecurring()):
# skip non-recurring old events, no instances
- if (yield calendarObject.removeOldEventGroupLink(
- component,
- instances=None,
- inserting=False,
- txn=self.transaction
- )):
+ if (
+ yield calendarObject.removeOldEventGroupLink(
+ component,
+ instances=None,
+ inserting=False,
+ txn=self.transaction
+ )
+ ):
returnValue(None)
else:
# skip recurring old events
@@ -180,12 +182,14 @@
lowerLimit=truncateLowerLimit,
ignoreInvalidInstances=True
)
- if (yield calendarObject.removeOldEventGroupLink(
- component,
- instances=instances,
- inserting=False,
- txn=self.transaction
- )):
+ if (
+ yield calendarObject.removeOldEventGroupLink(
+ component,
+ instances=instances,
+ inserting=False,
+ txn=self.transaction
+ )
+ ):
returnValue(None)
# split spanning events and only update present-future split result
@@ -345,11 +349,17 @@
) in changed:
readDelegateGroupID = writeDelegateGroupID = None
if readDelegateUID:
- readDelegateGroupID, _ignore_name, _ignore_hash, _ignore_modified = (
+ (
+ readDelegateGroupID, _ignore_name, _ignore_hash,
+ _ignore_modified, _ignore_extant
+ ) = (
yield txn.groupByUID(readDelegateUID)
)
if writeDelegateUID:
- writeDelegateGroupID, _ignore_name, _ignore_hash, _ignore_modified = (
+ (
+ writeDelegateGroupID, _ignore_name, _ignore_hash,
+ _ignore_modified, _ignore_extant
+ ) = (
yield txn.groupByUID(writeDelegateUID)
)
yield txn.assignExternalDelegates(
@@ -371,90 +381,25 @@
and updates the GROUP_MEMBERSHIP table
WorkProposal is returned for tests
"""
- self.log.debug("Faulting in group: {g}", g=groupUID)
- record = (yield self.directory.recordWithUID(groupUID))
- if record is None:
- # the group has disappeared from the directory
- self.log.info("Group is missing: {g}", g=groupUID)
+ groupID, membershipChanged = yield txn.refreshGroup(groupUID)
+
+ if membershipChanged:
+ wps = yield self.scheduleGroupAttendeeReconciliations(txn, groupID)
else:
- self.log.debug("Got group record: {u}", u=record.uid)
+ wps = ()
- groupID, cachedName, cachedMembershipHash, _ignore_modified = (
- yield txn.groupByUID(
- groupUID,
- create=(record is not None)
- )
- )
- wps = tuple()
- if groupID:
- if record is not None:
- members = yield record.expandedMembers()
- name = record.fullNames[0]
- else:
- members = frozenset()
- name = cachedName
-
- membershipHashContent = hashlib.md5()
- members = list(members)
- members.sort(key=lambda x: x.uid)
- for member in members:
- membershipHashContent.update(str(member.uid))
- membershipHash = membershipHashContent.hexdigest()
-
- if cachedMembershipHash != membershipHash:
- membershipChanged = True
- self.log.debug(
- "Group '{group}' changed", group=name
- )
- else:
- membershipChanged = False
-
- if membershipChanged or record is not None:
- # also updates group mod date
- yield txn.updateGroup(groupUID, name, membershipHash)
-
- if membershipChanged:
- newMemberUIDs = set()
- for member in members:
- newMemberUIDs.add(member.uid)
- yield self.synchronizeMembers(txn, groupID, newMemberUIDs)
-
- wps = yield self.scheduleGroupAttendeeReconciliations(txn, groupID)
- wps = wps + (yield self.scheduleGroupShareeReconciliations(txn, groupID))
-
returnValue(wps)
- @inlineCallbacks
def synchronizeMembers(self, txn, groupID, newMemberUIDs):
- numRemoved = numAdded = 0
- cachedMemberUIDs = (yield txn.membersOfGroup(groupID))
+ return txn.synchronizeMembers(groupID, newMemberUIDs)
- for memberUID in cachedMemberUIDs:
- if memberUID not in newMemberUIDs:
- numRemoved += 1
- yield txn.removeMemberFromGroup(memberUID, groupID)
- for memberUID in newMemberUIDs:
- if memberUID not in cachedMemberUIDs:
- numAdded += 1
- yield txn.addMemberToGroup(memberUID, groupID)
-
- returnValue((numAdded, numRemoved))
-
-
- @inlineCallbacks
def cachedMembers(self, txn, groupID):
"""
The members of the given group as recorded in the db
"""
- members = set()
- memberUIDs = (yield txn.membersOfGroup(groupID))
- for uid in memberUIDs:
- record = (yield self.directory.recordWithUID(uid))
- if record is not None:
- members.add(record)
- returnValue(members)
+ return txn.groupMembers(groupID)
def cachedGroupsFor(self, txn, uid):
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/opendirectory.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/opendirectory.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/opendirectory.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -28,6 +28,7 @@
from twext.who.opendirectory import DirectoryService
+DirectoryService # Something has to use the import
# Hoorj OMG haxx
from twext.who.opendirectory._constants import ODRecordType as _ODRecordType
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_delegates.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_delegates.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_delegates.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -207,7 +207,10 @@
yield self.directory.recordWithShortName(RecordType.user, name)
)
newSet.add(record.uid)
- groupID, name, _ignore_membershipHash, _ignore_modified = (yield txn.groupByUID(group1.uid))
+ (
+ groupID, name, _ignore_membershipHash, _ignore_modified,
+ _ignore_extant
+ ) = (yield txn.groupByUID(group1.uid))
_ignore_numAdded, _ignore_numRemoved = (
yield self.groupCacher.synchronizeMembers(txn, groupID, newSet)
)
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_group_attendees.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_group_attendees.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_group_attendees.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -841,8 +841,7 @@
wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "20000000-0000-0000-0000-000000000001")
yield self.commit()
- self.assertEqual(len(wps), 1)
- yield JobItem.waitEmpty(self._sqlCalendarStore.newTransaction, reactor, 60)
+ self.assertEqual(len(wps), 0)
cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000002")
vcalendar = yield cobj.component()
@@ -868,7 +867,10 @@
#finally, simulate an event that has become old
self.patch(CalendarDirectoryRecordMixin, "expandedMembers", unpatchedExpandedMembers)
- groupID, _ignore_name, _ignore_membershipHash, _ignore_modDate = yield self.transactionUnderTest().groupByUID("20000000-0000-0000-0000-000000000001")
+ (
+ groupID, _ignore_name, _ignore_membershipHash, _ignore_modDate,
+ _ignore_extant
+ ) = yield self.transactionUnderTest().groupByUID("20000000-0000-0000-0000-000000000001")
ga = schema.GROUP_ATTENDEE
yield Insert({
ga.RESOURCE_ID: cobj._resourceID,
@@ -1001,8 +1003,7 @@
wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "20000000-0000-0000-0000-000000000001")
yield self.commit()
- self.assertEqual(len(wps), 1)
- yield JobItem.waitEmpty(self._sqlCalendarStore.newTransaction, reactor, 60)
+ self.assertEqual(len(wps), 0)
cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000002")
vcalendar = yield cobj.component()
@@ -1029,7 +1030,10 @@
#finally, simulate an event that has become old
self.patch(CalendarDirectoryRecordMixin, "expandedMembers", unpatchedExpandedMembers)
- groupID, _ignore_name, _ignore_membershipHash, _ignore_modDate = yield self.transactionUnderTest().groupByUID("20000000-0000-0000-0000-000000000001")
+ (
+ groupID, _ignore_name, _ignore_membershipHash, _ignore_modDate,
+ _ignore_extant
+ ) = yield self.transactionUnderTest().groupByUID("20000000-0000-0000-0000-000000000001")
ga = schema.GROUP_ATTENDEE
yield Insert({
ga.RESOURCE_ID: cobj._resourceID,
@@ -1478,8 +1482,7 @@
wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "20000000-0000-0000-0000-000000000002")
yield self.commit()
- self.assertEqual(len(wps), 1)
- yield JobItem.waitEmpty(self._sqlCalendarStore.newTransaction, reactor, 60)
+ self.assertEqual(len(wps), 0)
cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000001")
vcalendar = yield cobj.component()
@@ -1637,12 +1640,10 @@
wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "20000000-0000-0000-0000-000000000002")
yield self.commit()
- self.assertEqual(len(wps), 1)
- yield JobItem.waitEmpty(self._sqlCalendarStore.newTransaction, reactor, 60)
+ self.assertEqual(len(wps), 0)
wps = yield groupCacher.refreshGroup(self.transactionUnderTest(), "20000000-0000-0000-0000-000000000003")
yield self.commit()
- self.assertEqual(len(wps), 1)
- yield JobItem.waitEmpty(self._sqlCalendarStore.newTransaction, reactor, 60)
+ self.assertEqual(len(wps), 0)
cobj = yield self.calendarObjectUnderTest(name="data1.ics", calendar_name="calendar", home="10000000-0000-0000-0000-000000000001")
vcalendar = yield cobj.component()
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_groups.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_groups.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/test/test_groups.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -18,11 +18,12 @@
Group membership caching implementation tests
"""
-from txdav.who.groups import GroupCacher, diffAssignments
from twext.who.idirectory import RecordType
from twisted.internet.defer import inlineCallbacks
from twistedcaldav.test.util import StoreTestCase
from txdav.common.icommondatastore import NotFoundError
+from txdav.who.groups import GroupCacher, diffAssignments
+from txdav.who.test.support import TestRecord, CalendarInMemoryDirectoryService
@@ -44,8 +45,8 @@
txn = store.newTransaction()
record = yield self.directory.recordWithUID(u"__top_group_1__")
- _ignore_groupID, _ignore_name, _ignore_membershipHash, _ignore_modified = (yield txn.groupByUID(record.uid))
- _ignore_groupID, _ignore_name, _ignore_membershipHash, _ignore_modified = (yield txn.groupByUID(record.uid))
+ yield txn.groupByUID(record.uid)
+ yield txn.groupByUID(record.uid)
yield txn.commit()
@@ -63,16 +64,21 @@
record = yield self.directory.recordWithUID(u"__top_group_1__")
yield self.groupCacher.refreshGroup(txn, record.uid)
- groupID, _ignore_name, membershipHash, _ignore_modified = (yield txn.groupByUID(record.uid))
+ (
+ groupID, _ignore_name, membershipHash, _ignore_modified,
+ extant
+ ) = (yield txn.groupByUID(record.uid))
+ self.assertEquals(extant, True)
self.assertEquals(membershipHash, "553eb54e3bbb26582198ee04541dbee4")
- groupUID, name, membershipHash = (yield txn.groupByID(groupID))
+ groupUID, name, membershipHash, extant = (yield txn.groupByID(groupID))
self.assertEquals(groupUID, record.uid)
self.assertEquals(name, u"Top Group 1")
self.assertEquals(membershipHash, "553eb54e3bbb26582198ee04541dbee4")
+ self.assertEquals(extant, True)
- members = (yield txn.membersOfGroup(groupID))
+ members = (yield txn.groupMemberUIDs(groupID))
self.assertEquals(
set([u'__cdaboo1__', u'__glyph1__', u'__sagen1__', u'__wsanchez1__']),
members
@@ -107,7 +113,10 @@
# Refresh the group so it's assigned a group_id
uid = u"__top_group_1__"
yield self.groupCacher.refreshGroup(txn, uid)
- groupID, name, _ignore_membershipHash, _ignore_modified = (yield txn.groupByUID(uid))
+ (
+ groupID, name, _ignore_membershipHash, _ignore_modified,
+ _ignore_extant
+ ) = yield txn.groupByUID(uid)
# Remove two members, and add one member
newSet = set()
@@ -156,9 +165,12 @@
uid = u"__top_group_1__"
hash = "553eb54e3bbb26582198ee04541dbee4"
yield self.groupCacher.refreshGroup(txn, uid)
- groupID, _ignore_name, _ignore_membershipHash, _ignore_modified = yield txn.groupByUID(uid)
- results = (yield txn.groupByID(groupID))
- self.assertEquals((uid, u"Top Group 1", hash), results)
+ (
+ groupID, _ignore_name, _ignore_membershipHash, _ignore_modified,
+ extant
+ ) = yield txn.groupByUID(uid)
+ results = yield txn.groupByID(groupID)
+ self.assertEquals((uid, u"Top Group 1", hash, True), results)
yield txn.commit()
@@ -414,3 +426,125 @@
{"D": ("7", "8"), "C": ("4", "5"), "A": ("1", "2")},
)
)
+
+
+class DynamicGroupTest(StoreTestCase):
+
+
+ @inlineCallbacks
+ def setUp(self):
+ yield super(DynamicGroupTest, self).setUp()
+
+ self.directory = CalendarInMemoryDirectoryService(None)
+ self.store.setDirectoryService(self.directory)
+ self.groupCacher = GroupCacher(self.directory)
+
+ self.numUsers = 100
+
+ # Add users
+ records = []
+ fieldName = self.directory.fieldName
+ for i in xrange(self.numUsers):
+ records.append(
+ TestRecord(
+ self.directory,
+ {
+ fieldName.uid: u"foo{ctr:05d}".format(ctr=i),
+ fieldName.shortNames: (u"foo{ctr:05d}".format(ctr=i),),
+ fieldName.fullNames: (u"foo{ctr:05d}".format(ctr=i),),
+ fieldName.recordType: RecordType.user,
+ }
+ )
+ )
+
+ # Add a group
+ records.append(
+ TestRecord(
+ self.directory,
+ {
+ fieldName.uid: u"testgroup",
+ fieldName.recordType: RecordType.group,
+ }
+ )
+ )
+
+ yield self.directory.updateRecords(records, create=True)
+
+ group = yield self.directory.recordWithUID(u"testgroup")
+ members = yield self.directory.recordsWithRecordType(RecordType.user)
+ yield group.setMembers(members)
+
+
+ @inlineCallbacks
+ def test_extant(self):
+ """
+ Verify that once a group is removed from the directory, the next call
+ to refreshGroup() will set the "extent" to False. Add the group back
+ to the directory and "extent" becomes True.
+ """
+ store = self.storeUnderTest()
+
+ txn = store.newTransaction()
+ yield self.groupCacher.refreshGroup(txn, u"testgroup")
+ (
+ groupID, _ignore_name, membershipHash, _ignore_modified,
+ extant
+ ) = (yield txn.groupByUID(u"testgroup"))
+ yield txn.commit()
+
+ self.assertTrue(extant)
+
+ # Remove the group
+ yield self.directory.removeRecords([u"testgroup"])
+
+ txn = store.newTransaction()
+ yield self.groupCacher.refreshGroup(txn, u"testgroup")
+ (
+ groupID, _ignore_name, membershipHash, _ignore_modified,
+ extant
+ ) = (yield txn.groupByUID(u"testgroup"))
+ yield txn.commit()
+
+ # Extant = False
+ self.assertFalse(extant)
+
+ # The list of members stored in the DB for this group is now empty
+ txn = store.newTransaction()
+ members = yield txn.groupMemberUIDs(groupID)
+ yield txn.commit()
+ self.assertEquals(members, set())
+
+ # Add the group back into the directory
+ fieldName = self.directory.fieldName
+ yield self.directory.updateRecords(
+ (
+ TestRecord(
+ self.directory,
+ {
+ fieldName.uid: u"testgroup",
+ fieldName.recordType: RecordType.group,
+ }
+ ),
+ ),
+ create=True
+ )
+ group = yield self.directory.recordWithUID(u"testgroup")
+ members = yield self.directory.recordsWithRecordType(RecordType.user)
+ yield group.setMembers(members)
+
+ txn = store.newTransaction()
+ yield self.groupCacher.refreshGroup(txn, u"testgroup")
+ (
+ groupID, _ignore_name, membershipHash, _ignore_modified,
+ extant
+ ) = (yield txn.groupByUID(u"testgroup"))
+ yield txn.commit()
+
+ # Extant = True
+ self.assertTrue(extant)
+
+ # The list of members stored in the DB for this group has 100 users
+ txn = store.newTransaction()
+ members = yield txn.groupMemberUIDs(groupID)
+ yield txn.commit()
+ self.assertEquals(len(members), 100)
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/util.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/util.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/util.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -168,12 +168,30 @@
),
),
+ CalRecordType.location: RecordTypeSchema(
+ relativeDN=u"ou=places",
+
+ attributes=(),
+ ),
+
+ CalRecordType.resource: RecordTypeSchema(
+ relativeDN=u"ou=resources",
+
+ attributes=(),
+ ),
+
+ CalRecordType.address: RecordTypeSchema(
+ relativeDN=u"ou=buildings",
+
+ attributes=(),
+ ),
+
})
)
elif "inmemory" in directoryType:
- from txdav.who.test.support import InMemoryDirectoryService
- directory = InMemoryDirectoryService()
+ from txdav.who.test.support import CalendarInMemoryDirectoryService
+ directory = CalendarInMemoryDirectoryService()
else:
log.error("Invalid DirectoryType: {dt}", dt=directoryType)
Modified: CalendarServer/branches/users/gaya/groupsharee2/txdav/who/wiki.py
===================================================================
--- CalendarServer/branches/users/gaya/groupsharee2/txdav/who/wiki.py 2014-07-07 23:41:26 UTC (rev 13731)
+++ CalendarServer/branches/users/gaya/groupsharee2/txdav/who/wiki.py 2014-07-08 07:05:29 UTC (rev 13732)
@@ -194,6 +194,7 @@
"in wiki {log_source}: {error}",
record=record, error=e
)
+ returnValue(WikiAccessLevel.none)
except WebError as e:
status = int(e.status)
@@ -216,6 +217,7 @@
"Unable to look up wiki access: {error}",
record=record, error=e
)
+ returnValue(WikiAccessLevel.none)
try:
returnValue({
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140708/9fd36d88/attachment-0001.html>
More information about the calendarserver-changes
mailing list