[CalendarServer-changes] [13868] CalendarServer/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Tue Aug 12 13:45:40 PDT 2014
Revision: 13868
http://trac.calendarserver.org//changeset/13868
Author: sagen at apple.com
Date: 2014-08-12 13:45:40 -0700 (Tue, 12 Aug 2014)
Log Message:
-----------
Added support for fetching delegate assignments from the directory
Modified Paths:
--------------
CalendarServer/trunk/calendarserver/tap/caldav.py
CalendarServer/trunk/calendarserver/tools/principals.py
CalendarServer/trunk/conf/caldavd-test.plist
CalendarServer/trunk/requirements-stable.txt
CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py
CalendarServer/trunk/twistedcaldav/stdconfig.py
CalendarServer/trunk/txdav/common/datastore/sql.py
CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql
CalendarServer/trunk/txdav/dps/client.py
CalendarServer/trunk/txdav/dps/commands.py
CalendarServer/trunk/txdav/dps/json.py
CalendarServer/trunk/txdav/dps/server.py
CalendarServer/trunk/txdav/dps/test/test_client.py
CalendarServer/trunk/txdav/who/cache.py
CalendarServer/trunk/txdav/who/directory.py
CalendarServer/trunk/txdav/who/groups.py
CalendarServer/trunk/txdav/who/idirectory.py
CalendarServer/trunk/txdav/who/test/test_groups.py
CalendarServer/trunk/txdav/who/util.py
Added Paths:
-----------
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v46.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v46.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_46_to_47.sql
CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_46_to_47.sql
Modified: CalendarServer/trunk/calendarserver/tap/caldav.py
===================================================================
--- CalendarServer/trunk/calendarserver/tap/caldav.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/calendarserver/tap/caldav.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -941,7 +941,8 @@
if config.GroupCaching.Enabled:
groupCacher = GroupCacher(
directory,
- updateSeconds=config.GroupCaching.UpdateSeconds
+ updateSeconds=config.GroupCaching.UpdateSeconds,
+ useDirectoryBasedDelegates=config.GroupCaching.UseDirectoryBasedDelegates,
)
else:
groupCacher = None
@@ -1091,7 +1092,7 @@
WorkSchedulingService(
store,
config.Scheduling.iMIP.Enabled,
- (config.GroupCaching.Enabled and config.GroupCaching.EnableUpdater),
+ config.GroupCaching.Enabled,
config.AutomaticPurging.Enabled
).setServiceParent(service)
@@ -1309,7 +1310,8 @@
if config.GroupCaching.Enabled:
groupCacher = GroupCacher(
directory,
- updateSeconds=config.GroupCaching.UpdateSeconds
+ updateSeconds=config.GroupCaching.UpdateSeconds,
+ useDirectoryBasedDelegates=config.GroupCaching.UseDirectoryBasedDelegates,
)
else:
groupCacher = None
@@ -1895,7 +1897,8 @@
if config.GroupCaching.Enabled:
groupCacher = GroupCacher(
directory,
- updateSeconds=config.GroupCaching.UpdateSeconds
+ updateSeconds=config.GroupCaching.UpdateSeconds,
+ useDirectoryBasedDelegates=config.GroupCaching.UseDirectoryBasedDelegates,
)
else:
groupCacher = None
Modified: CalendarServer/trunk/calendarserver/tools/principals.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/principals.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/calendarserver/tools/principals.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -883,10 +883,16 @@
def printRecordList(records):
- results = [
- (record.displayName, record.recordType.name, record.uid, record.shortNames)
- for record in records
- ]
+ results = []
+ for record in records:
+ try:
+ shortNames = record.shortNames
+ except AttributeError:
+ shortNames = []
+ results.append(
+ (record.displayName, record.recordType.name, record.uid, shortNames)
+ )
+
results.sort()
format = "%-22s %-10s %-20s %s"
print(format % ("Full name", "Type", "UID", "Short names"))
Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/conf/caldavd-test.plist 2014-08-12 20:45:40 UTC (rev 13868)
@@ -883,17 +883,9 @@
<dict>
<key>Enabled</key>
<true/>
- <key>EnableUpdater</key>
- <true/>
- <key>MemcachedPool</key>
- <string>Default</string>
<key>UpdateSeconds</key>
<integer>300</integer>
- <key>ExpireSeconds</key>
- <integer>3600</integer>
- <key>LockSeconds</key>
- <integer>300</integer>
- <key>UseExternalProxies</key>
+ <key>UseDirectoryBasedDelegates</key>
<false/>
</dict>
Modified: CalendarServer/trunk/requirements-stable.txt
===================================================================
--- CalendarServer/trunk/requirements-stable.txt 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/requirements-stable.txt 2014-08-12 20:45:40 UTC (rev 13868)
@@ -5,7 +5,7 @@
# 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@13857#egg=twextpy
+-e svn+http://svn.calendarserver.org/repository/calendarserver/twext/trunk@13867#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@13802#egg=pycalendar
Modified: CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/twistedcaldav/directory/calendaruserproxy.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -129,12 +129,16 @@
guid = record.guid
except AttributeError:
guid = ""
+ try:
+ shortNames = record.shortNames
+ except AttributeError:
+ shortNames = []
return tag.fillSlots(
directoryGUID=record.service.guid,
realm=record.service.realmName,
guid=guid,
recordType=record.service.recordTypeToOldName(record.recordType),
- shortNames=record.shortNames,
+ shortNames=shortNames,
fullName=record.displayName,
principalUID=parent.principalUID(),
principalURL=formatLink(parent.principalURL()),
Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -79,6 +79,8 @@
"fullNames": ["cn", ],
"emailAddresses": ["mail", ],
"memberDNs": ["uniqueMember", ],
+ "readWriteProxy": ["icsContact", ],
+ "readOnlyProxy": ["icsSecondaryOwners", ],
}
},
}
@@ -965,10 +967,8 @@
"GroupCaching" : {
"Enabled": True,
- "MemcachedPool" : "Default",
"UpdateSeconds" : 300,
- "EnableUpdater" : True,
- "UseExternalProxies" : False,
+ "UseDirectoryBasedDelegates" : False,
},
"GroupAttendees" : {
Modified: CalendarServer/trunk/txdav/common/datastore/sql.py
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/common/datastore/sql.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -1339,17 +1339,17 @@
"""
if record is not None:
- members = yield record.expandedMembers()
+ memberUIDs = yield record.expandedMemberUIDs()
name = record.displayName
extant = True
else:
- members = frozenset()
+ memberUIDs = frozenset()
name = cachedName
extant = False
membershipHashContent = hashlib.md5()
- for member in sorted(members, key=lambda x: x.uid):
- membershipHashContent.update(str(member.uid))
+ for memberUID in sorted(memberUIDs):
+ membershipHashContent.update(str(memberUID))
membershipHash = membershipHashContent.hexdigest()
if cachedMembershipHash != membershipHash:
@@ -1368,8 +1368,8 @@
if membershipChanged:
newMemberUIDs = set()
- for member in members:
- newMemberUIDs.add(member.uid)
+ for memberUID in memberUIDs:
+ newMemberUIDs.add(memberUID)
yield self.synchronizeMembers(groupID, newMemberUIDs)
returnValue(membershipChanged)
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/current-oracle-dialect.sql 2014-08-12 20:45:40 UTC (rev 13868)
@@ -405,10 +405,18 @@
"GROUP_UID" nvarchar2(255)
);
+create table GROUP_DELEGATE_CHANGES_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "DELEGATOR_UID" nvarchar2(255),
+ "READ_DELEGATE_UID" nvarchar2(255),
+ "WRITE_DELEGATE_UID" nvarchar2(255)
+);
+
create table GROUPS (
"GROUP_ID" integer primary key,
"NAME" nvarchar2(255),
- "GROUP_UID" nvarchar2(255),
+ "GROUP_UID" nvarchar2(255) unique,
"MEMBERSHIP_HASH" nvarchar2(255),
"EXTANT" integer default 1,
"CREATED" timestamp default CURRENT_TIMESTAMP at time zone 'UTC',
@@ -596,7 +604,7 @@
"VALUE" nvarchar2(255)
);
-insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '46');
+insert into CALENDARSERVER (NAME, VALUE) values ('VERSION', '47');
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');
@@ -754,6 +762,10 @@
JOB_ID
);
+create index GROUP_DELEGATE_CHANGE_8bf9e6d8 on GROUP_DELEGATE_CHANGES_WORK (
+ JOB_ID
+);
+
create index GROUPS_GROUP_UID_b35cce23 on GROUPS (
GROUP_UID
);
Modified: CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/current.sql 2014-08-12 20:45:40 UTC (rev 13868)
@@ -762,10 +762,21 @@
create index GROUP_REFRESH_WORK_JOB_ID on
GROUP_REFRESH_WORK(JOB_ID);
+create table GROUP_DELEGATE_CHANGES_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ DELEGATOR_UID varchar(255) not null,
+ READ_DELEGATE_UID varchar(255) not null,
+ WRITE_DELEGATE_UID varchar(255) not null
+);
+
+create index GROUP_DELEGATE_CHANGES_WORK_JOB_ID on
+ GROUP_DELEGATE_CHANGES_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,
+ GROUP_UID varchar(255) not null unique,
MEMBERSHIP_HASH varchar(255) not null,
EXTANT integer default 1,
CREATED timestamp default timezone('UTC', CURRENT_TIMESTAMP),
@@ -777,7 +788,7 @@
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)
);
@@ -798,19 +809,19 @@
create index GROUP_ATTENDEE_RECONCILE_WORK_GROUP_ID on
GROUP_ATTENDEE_RECONCILE_WORK(GROUP_ID);
-
+
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);
-
+
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,
@@ -831,7 +842,7 @@
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_ID)
);
@@ -960,7 +971,7 @@
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)
);
@@ -1127,7 +1138,7 @@
VALUE varchar(255)
);
-insert into CALENDARSERVER values ('VERSION', '46');
+insert into CALENDARSERVER values ('VERSION', '47');
insert into CALENDARSERVER values ('CALENDAR-DATAVERSION', '6');
insert into CALENDARSERVER values ('ADDRESSBOOK-DATAVERSION', '2');
insert into CALENDARSERVER values ('NOTIFICATION-DATAVERSION', '1');
Added: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v46.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v46.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/oracle-dialect/v46.sql 2014-08-12 20:45:40 UTC (rev 13868)
@@ -0,0 +1,908 @@
+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);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('group', 5);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('group_read', 6);
+insert into CALENDAR_BIND_MODE (DESCRIPTION, ID) values ('group_write', 7);
+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 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_RECONCILE_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,
+ "GROUP_ID" integer not null references GROUPS on delete cascade
+);
+
+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 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_ID" integer not null references CALENDAR on delete cascade,
+ "GROUP_BIND_MODE" integer not null,
+ "MEMBERSHIP_HASH" nvarchar2(255),
+ primary key ("GROUP_ID", "CALENDAR_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', '46');
+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 GROUPS_GROUP_UID_b35cce23 on GROUPS (
+ GROUP_UID
+);
+
+create index GROUP_MEMBERSHIP_MEMB_0ca508e8 on GROUP_MEMBERSHIP (
+ MEMBER_UID
+);
+
+create index GROUP_ATTENDEE_RECONC_da73d3c2 on GROUP_ATTENDEE_RECONCILE_WORK (
+ JOB_ID
+);
+
+create index GROUP_ATTENDEE_RECONC_b894ee7a on GROUP_ATTENDEE_RECONCILE_WORK (
+ RESOURCE_ID
+);
+
+create index GROUP_ATTENDEE_RECONC_5eabc549 on GROUP_ATTENDEE_RECONCILE_WORK (
+ GROUP_ID
+);
+
+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_RECONCIL_4dc60f78 on GROUP_SHAREE_RECONCILE_WORK (
+ CALENDAR_ID
+);
+
+create index GROUP_SHAREE_RECONCIL_1d14c921 on GROUP_SHAREE_RECONCILE_WORK (
+ GROUP_ID
+);
+
+create index GROUP_SHAREE_CALENDAR_28a88850 on GROUP_SHAREE (
+ CALENDAR_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
Added: CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v46.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v46.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/old/postgres-dialect/v46.sql 2014-08-12 20:45:40 UTC (rev 13868)
@@ -0,0 +1,1134 @@
+-- -*- 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');
+insert into CALENDAR_BIND_MODE values (5, 'group');
+insert into CALENDAR_BIND_MODE values (6, 'group_read');
+insert into CALENDAR_BIND_MODE values (7, 'group_write');
+
+-- 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 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_RECONCILE_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer not null references JOB,
+ RESOURCE_ID integer not null references CALENDAR_OBJECT on delete cascade,
+ GROUP_ID integer not null references GROUPS on delete cascade
+);
+
+create index GROUP_ATTENDEE_RECONCILE_WORK_JOB_ID on
+ GROUP_ATTENDEE_RECONCILE_WORK(JOB_ID);
+create index GROUP_ATTENDEE_RECONCILE_WORK_RESOURCE_ID on
+ GROUP_ATTENDEE_RECONCILE_WORK(RESOURCE_ID);
+create index GROUP_ATTENDEE_RECONCILE_WORK_GROUP_ID on
+ GROUP_ATTENDEE_RECONCILE_WORK(GROUP_ID);
+
+
+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);
+
+
+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 index GROUP_SHAREE_RECONCILE_WORK_CALENDAR_ID on
+ GROUP_SHAREE_RECONCILE_WORK(CALENDAR_ID);
+create index GROUP_SHAREE_RECONCILE_WORK_GROUP_ID on
+ GROUP_SHAREE_RECONCILE_WORK(GROUP_ID);
+
+
+create table GROUP_SHAREE (
+ GROUP_ID integer not null references GROUPS 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_ID)
+);
+
+create index GROUP_SHAREE_CALENDAR_ID on
+ GROUP_SHAREE(CALENDAR_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', '46');
+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/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_46_to_47.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_46_to_47.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/oracle-dialect/upgrade_from_46_to_47.sql 2014-08-12 20:45:40 UTC (rev 13868)
@@ -0,0 +1,40 @@
+----
+-- 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 46 to 47 --
+---------------------------------------------------
+
+
+create table GROUP_DELEGATE_CHANGES_WORK (
+ "WORK_ID" integer primary key not null,
+ "JOB_ID" integer not null references JOB,
+ "DELEGATOR_UID" nvarchar2(255),
+ "READ_DELEGATE_UID" nvarchar2(255),
+ "WRITE_DELEGATE_UID" nvarchar2(255)
+);
+
+create index GROUP_DELEGATE_CHANGE_8bf9e6d8 on GROUP_DELEGATE_CHANGES_WORK (
+ JOB_ID
+);
+
+
+-- Add "unique" to GROUPS.GROUP_UID
+alter table GROUPS add unique (GROUP_UID);
+
+
+-- update the version
+update CALENDARSERVER set VALUE = '47' where NAME = 'VERSION';
Added: CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_46_to_47.sql
===================================================================
--- CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_46_to_47.sql (rev 0)
+++ CalendarServer/trunk/txdav/common/datastore/sql_schema/upgrades/postgres-dialect/upgrade_from_46_to_47.sql 2014-08-12 20:45:40 UTC (rev 13868)
@@ -0,0 +1,40 @@
+----
+-- 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 46 to 47 --
+---------------------------------------------------
+
+
+
+create table GROUP_DELEGATE_CHANGES_WORK (
+ WORK_ID integer primary key default nextval('WORKITEM_SEQ') not null, -- implicit index
+ JOB_ID integer references JOB not null,
+ DELEGATOR_UID varchar(255) not null,
+ READ_DELEGATE_UID varchar(255) not null,
+ WRITE_DELEGATE_UID varchar(255) not null
+);
+
+create index GROUP_DELEGATE_CHANGES_WORK_JOB_ID on
+ GROUP_DELEGATE_CHANGES_WORK(JOB_ID);
+
+
+-- Add "unique" to GROUPS.GROUP_UID
+alter table GROUPS add unique (GROUP_UID);
+
+
+-- update the version
+update CALENDARSERVER set VALUE = '47' where NAME = 'VERSION';
Modified: CalendarServer/trunk/txdav/dps/client.py
===================================================================
--- CalendarServer/trunk/txdav/dps/client.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/dps/client.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -41,7 +41,8 @@
RecordsMatchingTokensCommand, RecordsMatchingFieldsCommand,
MembersCommand, GroupsCommand, SetMembersCommand,
VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand,
- WikiAccessForUIDCommand, ContinuationCommand, StatsCommand
+ WikiAccessForUIDCommand, ContinuationCommand,
+ StatsCommand, ExternalDelegatesCommand, ExpandedMemberUIDsCommand
)
from txdav.who.delegates import RecordType as DelegatesRecordType
from txdav.who.directory import (
@@ -136,12 +137,12 @@
def _processMultipleRecords(self, result):
"""
- Takes a dictionary with a "fieldsList" key whose value is an iterable
+ Takes a dictionary with a "items" key whose value is an iterable
of pickled dictionaries (of records' fields), and returns a list of
records.
"""
serializedFieldsList = []
- for fields in result["fieldsList"]:
+ for fields in result["items"]:
fields = pickle.loads(fields)
serializedFieldsList.append(fields)
results = []
@@ -193,8 +194,8 @@
numResults = 0
if "fields" in results:
numResults = 1
- if "fieldsList" in results:
- numResults = len(results["fieldsList"])
+ if "items" in results:
+ numResults = len(results["items"])
log.debug(
"DPS call {command} duration={duration:.2f}ms, results={numResults}",
command=command, duration=1000.0 * duration, numResults=numResults
@@ -235,9 +236,9 @@
)
multi.append(results)
- results = {"fieldsList": []}
+ results = {"items": []}
for result in multi:
- results["fieldsList"].extend(result["fieldsList"])
+ results["items"].extend(result["items"])
self._logResultTiming(command, startTime, results)
returnValue(postProcess(results))
@@ -339,6 +340,14 @@
)
+ def recordsWithDirectoryBasedDelegates(self):
+ return self._call(
+ ExternalDelegatesCommand,
+ self._processMultipleRecords
+ )
+
+
+
def recordsFromExpression(self, expression, recordTypes=None):
raise NotImplementedError(
"This won't work until expressions are serializable to send "
@@ -426,6 +435,25 @@
)
+ def _convertUIDs(self, results):
+ uids = []
+ for uid in results["items"]:
+ uids.append(uid.decode("utf-8"))
+ return uids
+
+
+ def expandedMemberUIDs(self):
+ log.debug("DPS Client expandedMemberUIDs")
+ if self.recordType is RecordType.group:
+ return self.service._call(
+ ExpandedMemberUIDsCommand,
+ self._convertUIDs,
+ uid=self.uid.encode("utf-8")
+ )
+ else:
+ return succeed([])
+
+
def _convertAccess(self, results):
access = results["access"].decode("utf-8")
return txdav.who.wiki.WikiAccessLevel.lookupByName(access)
Modified: CalendarServer/trunk/txdav/dps/commands.py
===================================================================
--- CalendarServer/trunk/txdav/dps/commands.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/dps/commands.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -53,7 +53,7 @@
('recordType', amp.String()),
]
response = [
- ('fieldsList', amp.ListOf(amp.String())),
+ ('items', amp.ListOf(amp.String())),
('continuation', amp.String(optional=True)),
]
@@ -64,7 +64,7 @@
('emailAddress', amp.String()),
]
response = [
- ('fieldsList', amp.ListOf(amp.String())),
+ ('items', amp.ListOf(amp.String())),
('continuation', amp.String(optional=True)),
]
@@ -75,7 +75,7 @@
('continuation', amp.String(optional=True)),
]
response = [
- ('fieldsList', amp.ListOf(amp.String())),
+ ('items', amp.ListOf(amp.String())),
('continuation', amp.String(optional=True)),
]
@@ -87,7 +87,7 @@
('context', amp.String(optional=True)),
]
response = [
- ('fieldsList', amp.ListOf(amp.String())),
+ ('items', amp.ListOf(amp.String())),
('continuation', amp.String(optional=True)),
]
@@ -100,7 +100,7 @@
('recordType', amp.String(optional=True)),
]
response = [
- ('fieldsList', amp.ListOf(amp.String())),
+ ('items', amp.ListOf(amp.String())),
('continuation', amp.String(optional=True)),
]
@@ -108,7 +108,7 @@
class UpdateRecordsCommand(amp.Command):
arguments = [
- ('fieldsList', amp.ListOf(amp.String())),
+ ('items', amp.ListOf(amp.String())),
('create', amp.Boolean(optional=True)),
]
response = [
@@ -132,7 +132,7 @@
('uid', amp.String()),
]
response = [
- ('fieldsList', amp.ListOf(amp.String())),
+ ('items', amp.ListOf(amp.String())),
('continuation', amp.String(optional=True)),
]
@@ -143,7 +143,7 @@
('uid', amp.String()),
]
response = [
- ('fieldsList', amp.ListOf(amp.String())),
+ ('items', amp.ListOf(amp.String())),
('continuation', amp.String(optional=True)),
]
@@ -159,7 +159,17 @@
]
+class ExpandedMemberUIDsCommand(amp.Command):
+ arguments = [
+ ('uid', amp.String()),
+ ]
+ response = [
+ ('items', amp.ListOf(amp.String())),
+ ('continuation', amp.String(optional=True)),
+ ]
+
+
class VerifyPlaintextPasswordCommand(amp.Command):
arguments = [
('uid', amp.String()),
@@ -201,7 +211,14 @@
]
+class ExternalDelegatesCommand(amp.Command):
+ arguments = []
+ response = [
+ ('items', amp.ListOf(amp.String())),
+ ('continuation', amp.String(optional=True)),
+ ]
+
class StatsCommand(amp.Command):
arguments = []
response = [
Modified: CalendarServer/trunk/txdav/dps/json.py
===================================================================
--- CalendarServer/trunk/txdav/dps/json.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/dps/json.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -32,6 +32,7 @@
from twext.who.expression import (
CompoundExpression, Operand,
MatchExpression, MatchType, MatchFlags,
+ ExistsExpression, BooleanExpression
)
@@ -46,7 +47,21 @@
)
+def existsExpressionAsJSON(expression):
+ return dict(
+ type=expression.__class__.__name__,
+ field=expression.fieldName.name,
+ )
+
+def booleanExpressionAsJSON(expression):
+ return dict(
+ type=expression.__class__.__name__,
+ field=expression.fieldName.name,
+ )
+
+
+
def compoundExpressionAsJSON(expression):
return dict(
type=expression.__class__.__name__,
@@ -63,6 +78,12 @@
if isinstance(expression, MatchExpression):
return matchExpressionAsJSON(expression)
+ if isinstance(expression, ExistsExpression):
+ return existsExpressionAsJSON(expression)
+
+ if isinstance(expression, BooleanExpression):
+ return booleanExpressionAsJSON(expression)
+
raise TypeError(
"Unknown expression type: {!r}".format(expression)
)
@@ -116,7 +137,32 @@
)
+def existsExpressionFromJSON(service, json):
+ try:
+ jsonField = json["field"]
+ except KeyError as e:
+ raise ValueError(
+ "JSON match expression must have {!r} key.".format(e[0])
+ )
+ fieldName = service.fieldName.lookupByName(jsonField)
+
+ return ExistsExpression(fieldName)
+
+
+def booleanExpressionFromJSON(service, json):
+ try:
+ jsonField = json["field"]
+ except KeyError as e:
+ raise ValueError(
+ "JSON match expression must have {!r} key.".format(e[0])
+ )
+
+ fieldName = service.fieldName.lookupByName(jsonField)
+
+ return BooleanExpression(fieldName)
+
+
def compoundExpressionFromJSON(json):
try:
expressions_json = json["expressions"]
@@ -148,6 +194,12 @@
if json_type == "MatchExpression":
return matchExpressionFromJSON(json)
+ if json_type == "ExistsExpression":
+ return existsExpressionFromJSON(json)
+
+ if json_type == "BooleanExpression":
+ return booleanExpressionFromJSON(json)
+
raise NotImplementedError(
"Unknown expression type: {}".format(json_type)
)
Modified: CalendarServer/trunk/txdav/dps/server.py
===================================================================
--- CalendarServer/trunk/txdav/dps/server.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/dps/server.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -38,7 +38,7 @@
MembersCommand, GroupsCommand, SetMembersCommand,
VerifyPlaintextPasswordCommand, VerifyHTTPDigestCommand,
WikiAccessForUIDCommand, ContinuationCommand,
- StatsCommand,
+ ExternalDelegatesCommand, StatsCommand, ExpandedMemberUIDsCommand
# UpdateRecordsCommand, RemoveRecordsCommand
)
from txdav.who.cache import CachingDirectoryService
@@ -67,7 +67,7 @@
self._directory = directory
# How to large we let an AMP response get before breaking it up
- self._maxSize = 60000
+ self._maxSize = 55000
# The cache of results we have not fully responded with. A dictionary
# whose keys are "continuation tokens" and whose values are tuples of
@@ -78,19 +78,20 @@
self._continuations = {}
- def _storeContinuation(self, records):
+ def _storeContinuation(self, things, kind):
"""
Store an iterable of records and generate an opaque token we can
give back to the client so they can later retrieve these remaining
results that did not fit in the previous AMP response.
- @param records: an iterable of records
+ @param things: an iterable
+ @param kind: "items" or "records"
@return: a C{str} token
"""
token = str(uuid.uuid4())
# FIXME: I included a timestamp just in case we want to have code that
# looks for stale continuations to expire them.
- self._continuations[token] = (datetime.datetime.now(), records)
+ self._continuations[token] = (datetime.datetime.now(), things, kind)
return token
@@ -103,11 +104,12 @@
@return: an iterable of records, or None if the token does not exist
"""
if token in self._continuations:
- _ignore_timestamp, records = self._continuations[token]
+ _ignore_timestamp, things, kind = self._continuations[token]
del self._continuations[token]
else:
- records = None
- return records
+ things = None
+ kind = None
+ return things, kind
@ContinuationCommand.responder
@@ -120,8 +122,13 @@
in the previous response.
"""
log.debug("Continuation: {c}", c=continuation)
- records = self._retrieveContinuation(continuation)
- response = self._recordsToResponse(records)
+ things, kind = self._retrieveContinuation(continuation)
+ if kind == "records":
+ response = self._recordsToResponse(things)
+ elif kind == "items":
+ response = self._itemsToResponse(things)
+ else:
+ response = {}
# log.debug("Responding with: {response}", response=response)
return response
@@ -135,7 +142,7 @@
@param records: an iterable of records
@return: the response dictionary, with a list of pickled records
- stored in the "fieldsList" key, and if there are leftover
+ stored in the "items" key, and if there are leftover
records that did not fit, there will be a "continuation" key
containing the token the client must send via ContinuationCommand.
"""
@@ -156,14 +163,53 @@
fieldsList.append(pickled)
count += 1
- response = {"fieldsList": fieldsList}
+ response = {"items": fieldsList}
if records:
- response["continuation"] = self._storeContinuation(records)
+ response["continuation"] = self._storeContinuation(records, "records")
return response
+ def _itemsToResponse(self, items):
+ """
+ Craft an AMP response containing as many items as will fit within
+ the size limit. Remaining items are stored as a "continuation",
+ identified by a token that is returned to the client to fetch later
+ via the ContinuationCommand.
+
+ @param records: an iterable
+ @return: the response dictionary, with a list of items
+ stored in the "items" key, and if there are leftover
+ items that did not fit, there will be a "continuation" key
+ containing the token the client must send via ContinuationCommand.
+ """
+ itemsToSend = []
+ count = 0
+ if items:
+ size = 0
+ while size < self._maxSize:
+ try:
+ item = items.pop()
+ except (KeyError, IndexError):
+ # We're done.
+ # Note: because records is an iterable (list or set)
+ # we're catching both KeyError and IndexError.
+ break
+ size = size + len(item)
+ itemsToSend.append(item)
+ count += 1
+
+ response = {"items": itemsToSend}
+
+ if items:
+ response["continuation"] = self._storeContinuation(items, "items")
+
+ return response
+
+
+
+
def recordToDict(self, record):
"""
Turn a record in a dictionary of fields which can be reconstituted
@@ -173,14 +219,12 @@
if record is not None:
for field, value in record.fields.iteritems():
valueType = record.service.fieldName.valueType(field)
- # print("%s: %s (%s)" % (field.name, value, valueType))
if valueType in (unicode, bool):
fields[field.name] = value
elif valueType is uuid.UUID:
fields[field.name] = str(value)
elif issubclass(valueType, (Names, NamedConstant)):
fields[field.name] = value.name if value else None
- # print("Server side fields", fields)
return fields
@@ -380,6 +424,23 @@
returnValue(response)
+ @ExpandedMemberUIDsCommand.responder
+ @inlineCallbacks
+ def expandedMemberUIDs(self, uid):
+ uid = uid.decode("utf-8")
+ log.debug("ExpandedMemberUIDs: {u}", u=uid)
+ try:
+ record = (yield self._directory.recordWithUID(uid))
+ except Exception as e:
+ log.error("Failed in expandedMemberUIDs", error=e)
+ record = None
+
+ uids = yield record.expandedMemberUIDs()
+ response = self._itemsToResponse([u.encode("utf-8") for u in uids])
+ # log.debug("Responding with: {response}", response=response)
+ returnValue(response)
+
+
@VerifyPlaintextPasswordCommand.responder
@inlineCallbacks
def verifyPlaintextPassword(self, uid, password):
@@ -468,7 +529,17 @@
returnValue(response)
+ @ExternalDelegatesCommand.responder
+ @inlineCallbacks
+ def externalDelegates(self):
+ log.debug("ExternalDelegates")
+ records = yield self._directory.recordsWithDirectoryBasedDelegates()
+ response = self._recordsToResponse(records)
+ # log.debug("Responding with: {response}", response=response)
+ returnValue(response)
+
+
class DirectoryProxyAMPFactory(Factory):
"""
"""
Modified: CalendarServer/trunk/txdav/dps/test/test_client.py
===================================================================
--- CalendarServer/trunk/txdav/dps/test/test_client.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/dps/test/test_client.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -47,8 +47,8 @@
# Mix in the calendar-specific service methods
class CalendarXMLDirectoryService(
- XMLDirectoryService,
- CalendarDirectoryServiceMixin
+ CalendarDirectoryServiceMixin,
+ XMLDirectoryService
):
pass
@@ -60,8 +60,8 @@
# Mix in the calendar-specific service methods
class CalendarODDirectoryService(
- OpenDirectoryService,
- CalendarDirectoryServiceMixin
+ CalendarDirectoryServiceMixin,
+ OpenDirectoryService
):
pass
@@ -590,6 +590,18 @@
@inlineCallbacks
+ def test_expandedMemberUIDs(self):
+ group = yield self.client.recordWithUID(u"__top_group_1__")
+ memberUIDs = yield group.expandedMemberUIDs()
+ self.assertEquals(
+ set(memberUIDs),
+ set(
+ [u'__wsanchez1__', u'__cdaboo1__', u'__glyph1__', u'__sagen1__']
+ )
+ )
+
+
+ @inlineCallbacks
def test_groups(self):
# A group must first be "refreshed" into the DB otherwise we won't
@@ -717,8 +729,8 @@
# Connect the two services directly via an IOPump
client = AMP()
- server = DirectoryProxyAMPProtocol(remoteDirectory)
- pump = returnConnected(server, client)
+ self.server = DirectoryProxyAMPProtocol(remoteDirectory)
+ pump = returnConnected(self.server, client)
# Replace the normal _getConnection method with one that bypasses any
# actual networking
@@ -768,3 +780,9 @@
group = yield self.directory.recordWithUID(u"bigGroup")
members = yield group.members()
self.assertEquals(len(members), self.numUsers)
+
+ # force the limit small so continuations happen
+ self.server._maxSize = 500
+ # expandedMemberUIDs
+ memberUIDs = yield group.expandedMemberUIDs()
+ self.assertEquals(len(memberUIDs), self.numUsers)
Modified: CalendarServer/trunk/txdav/who/cache.py
===================================================================
--- CalendarServer/trunk/txdav/who/cache.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/who/cache.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -378,6 +378,10 @@
)
+ def recordsWithDirectoryBasedDelegates(self):
+ return self._directory.recordsWithDirectoryBasedDelegates()
+
+
def recordWithCalendarUserAddress(self, cua):
# This will get cached by the underlying recordWith... call
return CalendarDirectoryServiceMixin.recordWithCalendarUserAddress(
Modified: CalendarServer/trunk/txdav/who/directory.py
===================================================================
--- CalendarServer/trunk/txdav/who/directory.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/who/directory.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -22,7 +22,8 @@
from twext.python.log import Logger
from twext.who.expression import (
- MatchType, Operand, MatchExpression, CompoundExpression, MatchFlags
+ MatchType, Operand, MatchExpression, CompoundExpression, MatchFlags,
+ ExistsExpression, BooleanExpression
)
from twext.who.idirectory import RecordType as BaseRecordType
from twisted.cred.credentials import UsernamePassword
@@ -32,7 +33,8 @@
from txdav.caldav.datastore.scheduling.utils import normalizeCUAddr
from txdav.who.delegates import RecordType as DelegateRecordType
from txdav.who.idirectory import (
- RecordType as DAVRecordType, AutoScheduleMode
+ RecordType as DAVRecordType, AutoScheduleMode,
+ FieldName as CalFieldName
)
from txweb2.auth.digest import DigestedCredentials
@@ -257,7 +259,39 @@
return None
+ @inlineCallbacks
+ def recordsWithDirectoryBasedDelegates(self):
+ """
+ Fetch calendar-enabled locations and resources which have proxy
+ groups assigned.
+ """
+ expression = CompoundExpression(
+ (
+ BooleanExpression(CalFieldName.hasCalendars),
+ CompoundExpression(
+ (
+ ExistsExpression(CalFieldName.readOnlyProxy),
+ ExistsExpression(CalFieldName.readWriteProxy)
+ ),
+ Operand.OR
+ )
+ ),
+ Operand.AND
+ )
+
+ records = yield self.recordsFromExpression(
+ expression,
+ recordTypes=(self.recordType.location,)
+ # FIXME, commenting out resources for the moment since it's
+ # super slow:
+ # recordTypes=(self.recordType.location, self.recordType.resource)
+
+ )
+ returnValue(records)
+
+
+
class CalendarDirectoryRecordMixin(object):
"""
Calendar (and Contacts) specific logic for directory records lives in this
@@ -535,8 +569,8 @@
organizerRecord = yield service.recordWithCalendarUserAddress(organizer)
if organizerRecord is not None:
autoAcceptGroup = yield service.recordWithUID(autoAcceptGroup)
- members = yield autoAcceptGroup.expandedMembers()
- if organizerRecord.uid in ([m.uid for m in members]):
+ memberUIDs = yield autoAcceptGroup.expandedMemberUIDs()
+ if organizerRecord.uid in memberUIDs:
returnValue(True)
returnValue(False)
@@ -559,14 +593,25 @@
if self not in seen:
seen.add(self)
for member in (yield self.members()):
- if member.recordType == BaseRecordType.group:
- yield member.expandedMembers(members, seen)
- else:
- members.add(member)
+ if member is not None:
+ if member.recordType == BaseRecordType.group:
+ yield member.expandedMembers(members, seen)
+ else:
+ members.add(member)
returnValue(members)
+ @inlineCallbacks
+ def expandedMemberUIDs(self):
+ """
+ Return a L{set} containing the UIDs of the fully expanded membership
+ for this group.
+ """
+ members = yield self.expandedMembers()
+ returnValue([member.uid for member in members])
+
+
# For scheduling/freebusy
@inlineCallbacks
def isProxyFor(self, other):
Modified: CalendarServer/trunk/txdav/who/groups.py
===================================================================
--- CalendarServer/trunk/txdav/who/groups.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/who/groups.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -31,6 +31,7 @@
from txdav.caldav.datastore.sql import CalendarStoreFeatures, ComponentUpdateState
from txdav.common.datastore.sql_tables import schema, _BIND_MODE_OWN
import datetime
+import time
log = Logger()
@@ -47,7 +48,7 @@
def _enqueue(txn):
return GroupCacherPollingWork.reschedule(txn, seconds)
- if config.InboxCleanup.Enabled:
+ if config.GroupCaching.Enabled:
return store.inTransaction("GroupCacherPollingWork.initialSchedule", _enqueue)
else:
return succeed(None)
@@ -67,6 +68,7 @@
groupCacher = getattr(self.transaction, "_groupCacher", None)
if groupCacher is not None:
+ startTime = time.time()
try:
yield groupCacher.update(self.transaction)
except Exception, e:
@@ -74,6 +76,11 @@
"Failed to update new group membership cache ({error})",
error=e
)
+ endTime = time.time()
+ log.debug(
+ "GroupCacher polling took {duration:0.2f} seconds",
+ duration=(endTime - startTime)
+ )
@@ -112,6 +119,35 @@
+class GroupDelegateChangesWork(WorkItem, fromTable(schema.GROUP_DELEGATE_CHANGES_WORK)):
+
+ delegator = property(lambda self: (self.table.DELEGATOR_UID == self.delegatorUid))
+
+ @inlineCallbacks
+ def doWork(self):
+ # Delete all other work items for this delegator
+ yield Delete(
+ From=self.table,
+ Where=self.delegator,
+ ).on(self.transaction)
+
+ groupCacher = getattr(self.transaction, "_groupCacher", None)
+ if groupCacher is not None:
+
+ try:
+ yield groupCacher.applyExternalAssignments(
+ self.transaction,
+ self.delegatorUid.decode("utf-8"),
+ self.readDelegateUid.decode("utf-8"),
+ self.writeDelegateUid.decode("utf-8")
+ )
+ except Exception, e:
+ log.error(
+ "Failed to apply external delegates for {uid} {err}",
+ uid=self.delegatorUid, err=e
+ )
+
+
class GroupAttendeeReconciliationWork(
WorkItem, fromTable(schema.GROUP_ATTENDEE_RECONCILE_WORK)
):
@@ -288,30 +324,45 @@
def __init__(
self, directory,
updateSeconds=600,
- useExternalProxies=False,
- externalProxiesSource=None
+ useDirectoryBasedDelegates=False,
+ directoryBasedDelegatesSource=None
):
self.directory = directory
- self.useExternalProxies = useExternalProxies
- if useExternalProxies and externalProxiesSource is None:
- externalProxiesSource = self.directory.getExternalProxyAssignments
- self.externalProxiesSource = externalProxiesSource
+ self.useDirectoryBasedDelegates = useDirectoryBasedDelegates
+ if useDirectoryBasedDelegates and directoryBasedDelegatesSource is None:
+ directoryBasedDelegatesSource = self.directory.recordsWithDirectoryBasedDelegates
+ self.directoryBasedDelegatesSource = directoryBasedDelegatesSource
self.updateSeconds = updateSeconds
@inlineCallbacks
def update(self, txn):
- # TODO
- # Pull in external delegate assignments and stick in delegate db
- # if self.useExternalProxies:
- # externalAssignments = (yield self.externalProxiesSource())
- # yield self.applyExternalAssignments(txn, externalAssignments)
+ if self.useDirectoryBasedDelegates:
+ # Pull in delegate assignments from the directory and stick them
+ # into the delegate db
+ recordsWithDirectoryBasedDelegates = yield self.directoryBasedDelegatesSource()
+ externalAssignments = {}
+ for record in recordsWithDirectoryBasedDelegates:
+ try:
+ readWriteProxy = record.readWriteProxy
+ except AttributeError:
+ readWriteProxy = None
+ try:
+ readOnlyProxy = record.readOnlyProxy
+ except AttributeError:
+ readOnlyProxy = None
+
+ if readOnlyProxy or readWriteProxy:
+ externalAssignments[record.uid] = (readOnlyProxy, readWriteProxy)
+
+ yield self.scheduleExternalAssignments(txn, externalAssignments)
+
# Figure out which groups matter
groupUIDs = yield self.groupsToRefresh(txn)
- self.log.debug(
- "Groups to refresh: {g}", g=groupUIDs
- )
+ # self.log.debug(
+ # "Groups to refresh: {g}", g=groupUIDs
+ # )
gr = schema.GROUPS
if config.AutomaticPurging.Enabled and groupUIDs:
@@ -351,9 +402,11 @@
@inlineCallbacks
- def applyExternalAssignments(self, txn, newAssignments):
+ def scheduleExternalAssignments(
+ self, txn, newAssignments, immediately=False
+ ):
- oldAssignments = (yield txn.externalDelegates())
+ oldAssignments = yield txn.externalDelegates()
# external assignments is of the form:
# { delegatorUID: (readDelegateGroupUID, writeDelegateGroupUID),
@@ -364,33 +417,71 @@
for (
delegatorUID, (readDelegateUID, writeDelegateUID)
) in changed:
- readDelegateGroupID = writeDelegateGroupID = None
- if readDelegateUID:
- (
- readDelegateGroupID, _ignore_name, _ignore_hash,
- _ignore_modified, _ignore_extant
- ) = (
- yield txn.groupByUID(readDelegateUID)
+ self.log.debug(
+ "Scheduling external delegate assignment changes for {uid}",
+ uid=delegatorUID
+ )
+ if not readDelegateUID:
+ readDelegateUID = ""
+ if not writeDelegateUID:
+ writeDelegateUID = ""
+ if immediately:
+ yield self.applyExternalAssignments(
+ txn, delegatorUID, readDelegateUID, writeDelegateUID
)
- if writeDelegateUID:
- (
- writeDelegateGroupID, _ignore_name, _ignore_hash,
- _ignore_modified, _ignore_extant
- ) = (
- yield txn.groupByUID(writeDelegateUID)
+ else:
+ yield GroupDelegateChangesWork.reschedule(
+ txn, 0, delegatorUid=delegatorUID,
+ readDelegateUid=readDelegateUID,
+ writeDelegateUid=writeDelegateUID
)
- yield txn.assignExternalDelegates(
- delegatorUID, readDelegateGroupID, writeDelegateGroupID,
- readDelegateUID, writeDelegateUID
- )
if removed:
for delegatorUID in removed:
- yield txn.assignExternalDelegates(
- delegatorUID, None, None, None, None
+ self.log.debug(
+ "Scheduling external delegation assignment removal for {uid}",
+ uid=delegatorUID
)
+ if immediately:
+ yield self.applyExternalAssignments(
+ txn, delegatorUID, "", ""
+ )
+ else:
+ yield GroupDelegateChangesWork.reschedule(
+ txn, 0, delegatorUid=delegatorUID,
+ readDelegateUid="", writeDelegateUid=""
+ )
@inlineCallbacks
+ def applyExternalAssignments(
+ self, txn, delegatorUID, readDelegateUID, writeDelegateUID
+ ):
+ self.log.debug(
+ "External delegate assignments changed for {uid}",
+ uid=delegatorUID
+ )
+ readDelegateGroupID = writeDelegateGroupID = None
+ if readDelegateUID:
+ (
+ readDelegateGroupID, _ignore_name, _ignore_hash,
+ _ignore_modified, _ignore_extant
+ ) = (
+ yield txn.groupByUID(readDelegateUID)
+ )
+ if writeDelegateUID:
+ (
+ writeDelegateGroupID, _ignore_name, _ignore_hash,
+ _ignore_modified, _ignore_extant
+ ) = (
+ yield txn.groupByUID(writeDelegateUID)
+ )
+ yield txn.assignExternalDelegates(
+ delegatorUID, readDelegateGroupID, writeDelegateGroupID,
+ readDelegateUID, writeDelegateUID
+ )
+
+
+ @inlineCallbacks
def refreshGroup(self, txn, groupUID):
"""
Does the work of a per-group refresh work item
@@ -398,7 +489,8 @@
and updates the GROUP_MEMBERSHIP table
WorkProposal is returned for tests
"""
- self.log.debug("Faulting in group: {g}", g=groupUID)
+ self.log.debug("Refreshing group: {g}", g=groupUID)
+
record = (yield self.directory.recordWithUID(groupUID))
if record is None:
# the group has disappeared from the directory
@@ -421,9 +513,20 @@
)
if membershipChanged:
+ self.log.debug(
+ "Membership changed for group {uid} {name}",
+ uid=groupUID,
+ name=cachedName
+ )
wpsAttendee = yield self.scheduleGroupAttendeeReconciliations(txn, groupID)
wpsShareee = yield self.scheduleGroupShareeReconciliations(txn, groupID)
returnValue(wpsAttendee + wpsShareee)
+ else:
+ self.log.debug(
+ "No membership change for group {uid} {name}",
+ uid=groupUID,
+ name=cachedName
+ )
returnValue(tuple())
Modified: CalendarServer/trunk/txdav/who/idirectory.py
===================================================================
--- CalendarServer/trunk/txdav/who/idirectory.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/who/idirectory.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -156,6 +156,16 @@
autoAcceptGroup.description = u"auto-accept group"
autoAcceptGroup.valueType = BaseFieldName.valueType(BaseFieldName.uid)
+ readOnlyProxy = NamedConstant()
+ readOnlyProxy.description = u"read-only proxy group"
+ readOnlyProxy.valueType = BaseFieldName.valueType(BaseFieldName.uid)
+
+ readWriteProxy = NamedConstant()
+ readWriteProxy.description = u"read-write proxy group"
+ readWriteProxy.valueType = BaseFieldName.valueType(BaseFieldName.uid)
+
+
+
# For "locations", i.e., scheduled spaces:
associatedAddress = NamedConstant()
Modified: CalendarServer/trunk/txdav/who/test/test_groups.py
===================================================================
--- CalendarServer/trunk/txdav/who/test/test_groups.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/who/test/test_groups.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -190,7 +190,9 @@
newAssignments = {
u"__wsanchez1__": (None, u"__top_group_1__")
}
- yield self.groupCacher.applyExternalAssignments(txn, newAssignments)
+ yield self.groupCacher.scheduleExternalAssignments(
+ txn, newAssignments, immediately=True
+ )
oldExternalAssignments = (yield txn.externalDelegates())
self.assertEquals(
oldExternalAssignments,
@@ -215,7 +217,10 @@
u"__top_group_1__"
),
}
- yield self.groupCacher.applyExternalAssignments(txn, newAssignments)
+
+ yield self.groupCacher.scheduleExternalAssignments(
+ txn, newAssignments, immediately=True
+ )
oldExternalAssignments = (yield txn.externalDelegates())
self.assertEquals(
oldExternalAssignments,
@@ -290,7 +295,9 @@
None
),
}
- yield self.groupCacher.applyExternalAssignments(txn, newAssignments)
+ yield self.groupCacher.scheduleExternalAssignments(
+ txn, newAssignments, immediately=True
+ )
oldExternalAssignments = (yield txn.externalDelegates())
self.assertEquals(
oldExternalAssignments,
Modified: CalendarServer/trunk/txdav/who/util.py
===================================================================
--- CalendarServer/trunk/txdav/who/util.py 2014-08-12 19:57:18 UTC (rev 13867)
+++ CalendarServer/trunk/txdav/who/util.py 2014-08-12 20:45:40 UTC (rev 13868)
@@ -143,6 +143,9 @@
BaseFieldName.fullNames: mapping.fullNames,
BaseFieldName.emailAddresses: mapping.emailAddresses,
LDAPFieldName.memberDNs: mapping.memberDNs,
+ CalFieldName.readOnlyProxy: mapping.readOnlyProxy,
+ CalFieldName.readWriteProxy: mapping.readWriteProxy,
+ CalFieldName.hasCalendars: mapping.hasCalendars,
}),
recordTypeSchemas=MappingProxyType({
RecordType.user: RecordTypeSchema(
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140812/77c0b80f/attachment-0001.html>
More information about the calendarserver-changes
mailing list