# HG changeset patch # User Paul Boddie # Date 1465058573 -7200 # Node ID 00d37da98920957554dbd4e4159dc954cf629aca # Parent 2102cbcbadd01dd1bb9a3e032c8d5777a7a182fb Made the journal an extension of the regular store, consolidating journal entries and organiser free/busy details into a single representation employing the existing store of free/busy records defined for other calendar participants. diff -r 2102cbcbadd0 -r 00d37da98920 conf/postgresql/schema.sql --- a/conf/postgresql/schema.sql Sat Jun 04 17:16:36 2016 +0200 +++ b/conf/postgresql/schema.sql Sat Jun 04 18:42:53 2016 +0200 @@ -74,7 +74,8 @@ transp varchar, object_recurrenceid varchar, summary varchar, - organiser varchar + organiser varchar, + attendee varchar -- used by quotas ); create index freebusy_other_start on freebusy_other(store_user, other, "start"); @@ -110,45 +111,12 @@ -- Journal store tables. --- Journal free/busy details. - -create table quota_freebusy ( - quota varchar not null, - user_group varchar not null, - "start" varchar not null, - "end" varchar not null, - object_uid varchar, - transp varchar, - object_recurrenceid varchar, - summary varchar, - organiser varchar, - attendee varchar -); - -create index quota_freebusy_start on quota_freebusy(quota, user_group, "start"); -create index quota_freebusy_end on quota_freebusy(quota, user_group, "end"); - create table quota_delegates ( quota varchar not null, store_user varchar not null, primary key(quota, store_user) ); -create table user_freebusy ( - quota varchar not null, - store_user varchar not null, - "start" varchar not null, - "end" varchar not null, - object_uid varchar, - transp varchar, - object_recurrenceid varchar, - summary varchar, - organiser varchar -); - -create index user_freebusy_start on user_freebusy(quota, store_user, "start"); -create index user_freebusy_end on user_freebusy(quota, store_user, "end"); - -- Journal user groups and limits. create table quota_limits ( diff -r 2102cbcbadd0 -r 00d37da98920 docs/wiki/DatabaseStore --- a/docs/wiki/DatabaseStore Sat Jun 04 17:16:36 2016 +0200 +++ b/docs/wiki/DatabaseStore Sat Jun 04 18:42:53 2016 +0200 @@ -50,19 +50,15 @@ {{{#!table '''Table''' || '''Purpose''' == -`quota_freebusy` -|| Period descriptions describing reservations for resources sharing a quota (`quota`) -.. made by users or groups (`user_group`), structured similarly to the `freebusy` table -.. in the data store +`freebusy_other` +|| Period descriptions describing reservations for resources sharing a quota +.. (`store_user`) made by users or groups (`other`), structured similarly to the +.. `freebusy` table in the data store; this may be the same table as the one employed +.. by the data store to store received or deduced free/busy details == `quota_limits` || A mapping from user identities or group identifiers to quota limits == -`user_freebusy` -|| Period descriptions for reservations made in the context of a quota (`quota`) by a -.. specific user (`store_user`), structured similarly to the `freebusy` table in the -.. data store -== `user_groups` || A mapping from user identities to group identifiers indicating the sharing of a quota .. across a number of users diff -r 2102cbcbadd0 -r 00d37da98920 docs/wiki/FilesystemUsage --- a/docs/wiki/FilesystemUsage Sat Jun 04 17:16:36 2016 +0200 +++ b/docs/wiki/FilesystemUsage Sat Jun 04 18:42:53 2016 +0200 @@ -43,30 +43,22 @@ {{{{#!table '''Entry''' || '''Purpose''' == -`freebusy` -|| A directory containing files, one per user, each containing period descriptions +`freebusy-other` +|| A directory containing files, one per user (each containing period descriptions .. for reservations made by that user, in chronological order, structured -.. similarly to the `freebusy` file found in each user's own store; the record is -.. consolidated for all resources in a quota group, but it is not consolidated for -.. groups of users +.. similarly to the `freebusy` file found in each user's own store) or one per +.. group (for reservations made by users belonging to the groups defined for the +.. quota); the record in each file is consolidated for all resources in a quota +.. group {{{ -freebusy/USER +freebusy-other/GROUP +freebusy-other/USER }}} == `groups` || A mapping from user identities to group identifiers indicating the sharing .. of a quota across a number of users == -`journal` -|| A directory containing consolidated schedules, one per user or user group, -.. describing reservations for resources sharing a quota made by the indicated -.. user or group, structured similarly to the `freebusy` file found in each -.. resource's own store -{{{ -journal/GROUP -journal/USER -}}} -== `limits` || A mapping from user identities or group identifiers to quota limits }}}} diff -r 2102cbcbadd0 -r 00d37da98920 imiptools/handlers/scheduling/quota.py --- a/imiptools/handlers/scheduling/quota.py Sat Jun 04 17:16:36 2016 +0200 +++ b/imiptools/handlers/scheduling/quota.py Sat Jun 04 18:42:53 2016 +0200 @@ -209,7 +209,7 @@ # organiser's reservations. periods = handler.get_periods(handler.obj) - freebusy = handler.get_journal().get_freebusy(quota, organiser) + freebusy = handler.get_journal().get_entries(quota, organiser) scheduled = handler.can_schedule(freebusy, periods) return standard_responses(handler, scheduled and "ACCEPTED" or "DECLINED") @@ -224,9 +224,9 @@ quota, organiser = _get_quota_and_identity(handler, args) journal = handler.get_journal() - freebusy = journal.get_freebusy_for_update(quota, organiser) + freebusy = journal.get_entries_for_update(quota, organiser) handler.update_freebusy(freebusy, organiser, True) - journal.set_freebusy(quota, organiser, freebusy) + journal.set_entries(quota, organiser, freebusy) def remove_from_quota_freebusy(handler, args): @@ -238,9 +238,9 @@ quota, organiser = _get_quota_and_identity(handler, args) journal = handler.get_journal() - freebusy = journal.get_freebusy_for_update(quota, organiser) + freebusy = journal.get_entries_for_update(quota, organiser) handler.remove_from_freebusy(freebusy) - journal.set_freebusy(quota, organiser, freebusy) + journal.set_entries(quota, organiser, freebusy) def _get_quota_and_identity(handler, args): diff -r 2102cbcbadd0 -r 00d37da98920 imiptools/stores/common.py --- a/imiptools/stores/common.py Sat Jun 04 17:16:36 2016 +0200 +++ b/imiptools/stores/common.py Sat Jun 04 18:42:53 2016 +0200 @@ -628,38 +628,6 @@ pass - # Free/busy period access for users within quota groups. - - def get_freebusy_users(self, quota): - - """ - Return a list of users whose free/busy details are retained for the - given 'quota'. - """ - - pass - - def get_freebusy(self, quota, user, mutable=False): - - "Get free/busy details for the given 'quota' and 'user'." - - pass - - def get_freebusy_for_update(self, quota, user): - - """ - Get free/busy details for the given 'quota' and 'user' that may be - updated, potentially affecting the stored information directly. - """ - - return self.get_freebusy(quota, user, True) - - def set_freebusy(self, quota, user, freebusy): - - "For the given 'quota' and 'user', set 'freebusy' details." - - pass - # Journal entry methods. def get_entries(self, quota, group, mutable=False): diff -r 2102cbcbadd0 -r 00d37da98920 imiptools/stores/database/common.py --- a/imiptools/stores/database/common.py Sat Jun 04 17:16:36 2016 +0200 +++ b/imiptools/stores/database/common.py Sat Jun 04 18:42:53 2016 +0200 @@ -439,12 +439,13 @@ cls = cls or FreeBusyDatabaseCollection return cls(self.cursor, table, ["store_user"], [user], mutable, self.paramstyle) - def get_freebusy_for_other(self, user, other, mutable=False): + def get_freebusy_for_other(self, user, other, mutable=False, cls=None): "For the given 'user', get free/busy details for the 'other' user." table = "freebusy_other" - return FreeBusyDatabaseCollection(self.cursor, table, ["store_user", "other"], [user, other], mutable, self.paramstyle) + cls = cls or FreeBusyDatabaseCollection + return cls(self.cursor, table, ["store_user", "other"], [user, other], mutable, self.paramstyle) def set_freebusy(self, user, freebusy, name=None, cls=None): @@ -459,14 +460,15 @@ return True - def set_freebusy_for_other(self, user, freebusy, other): + def set_freebusy_for_other(self, user, freebusy, other, cls=None): "For the given 'user', set 'freebusy' details for the 'other' user." table = "freebusy_other" + cls = cls or FreeBusyDatabaseCollection - if not isinstance(freebusy, FreeBusyDatabaseCollection) or freebusy.table_name != table: - fbc = FreeBusyDatabaseCollection(self.cursor, table, ["store_user", "other"], [user, other], True, self.paramstyle) + if not isinstance(freebusy, cls) or freebusy.table_name != table: + fbc = cls(self.cursor, table, ["store_user", "other"], [user, other], True, self.paramstyle) fbc += freebusy return True @@ -812,7 +814,7 @@ self.cursor.execute(query, values) return True -class DatabaseJournal(DatabaseStoreBase, JournalBase): +class DatabaseJournal(DatabaseStore, JournalBase): "A journal system to support quotas." @@ -976,46 +978,6 @@ return True - # Free/busy period access for users within quota groups. - - def get_freebusy_users(self, quota): - - """ - Return a list of users whose free/busy details are retained for the - given 'quota'. - """ - - columns = ["quota"] - values = [quota] - - query, values = self.get_query( - "select distinct store_user from user_freebusy :condition", - columns, values) - - self.cursor.execute(query, values) - return [r[0] for r in self.cursor.fetchall()] - - def get_freebusy(self, quota, user, mutable=False, cls=None): - - "Get free/busy details for the given 'quota' and 'user'." - - table = "user_freebusy" - cls = cls or FreeBusyDatabaseCollection - return cls(self.cursor, table, ["quota", "store_user"], [quota, user], mutable, self.paramstyle) - - def set_freebusy(self, quota, user, freebusy, cls=None): - - "For the given 'quota' and 'user', set 'freebusy' details." - - table = "user_freebusy" - cls = cls or FreeBusyDatabaseCollection - - if not isinstance(freebusy, cls) or freebusy.table_name != table: - fbc = cls(self.cursor, table, ["quota", "store_user"], [quota, user], True, self.paramstyle) - fbc += freebusy - - return True - # Journal entry methods. def get_entries(self, quota, group, mutable=False): @@ -1025,8 +987,7 @@ 'group'. """ - table = "quota_freebusy" - return FreeBusyGroupDatabaseCollection(self.cursor, table, ["quota", "user_group"], [quota, group], mutable, self.paramstyle) + return self.get_freebusy_for_other(quota, group, mutable, cls=FreeBusyGroupDatabaseCollection) def set_entries(self, quota, group, entries): @@ -1035,12 +996,6 @@ 'entries'. """ - table = "quota_freebusy" - - if not isinstance(entries, FreeBusyGroupDatabaseCollection) or entries.table_name != table: - fbc = FreeBusyGroupDatabaseCollection(self.cursor, table, ["quota", "user_group"], [quota, group], True, self.paramstyle) - fbc += entries - - return True + return self.set_freebusy_for_other(quota, entries, group, cls=FreeBusyGroupDatabaseCollection) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 2102cbcbadd0 -r 00d37da98920 imiptools/stores/file.py --- a/imiptools/stores/file.py Sat Jun 04 17:16:36 2016 +0200 +++ b/imiptools/stores/file.py Sat Jun 04 18:42:53 2016 +0200 @@ -471,7 +471,7 @@ return FreeBusyCollection(periods, mutable) - def get_freebusy_for_other(self, user, other, mutable=False): + def get_freebusy_for_other(self, user, other, mutable=False, cls=None, collection=None): "For the given 'user', get free/busy details for the 'other' user." @@ -480,10 +480,12 @@ if not filename or not isfile(filename): periods = [] else: - periods = map(lambda t: FreeBusyPeriod(*t), + cls = cls or FreeBusyPeriod + periods = map(lambda t: cls(*t), self._get_table_atomic(user, filename)) - return FreeBusyCollection(periods, mutable) + collection = collection or FreeBusyCollection + return collection(periods, mutable) def set_freebusy(self, user, freebusy, name=None): @@ -779,13 +781,10 @@ return True -class Journal(FileStoreBase, JournalBase): +class Journal(Store, JournalBase): "A journal system to support quotas." - def __init__(self, store_dir=None): - FileBase.__init__(self, store_dir or JOURNAL_DIR) - # Quota and user identity/group discovery. def get_quotas(self): @@ -877,47 +876,6 @@ self._set_table_atomic(quota, filename, limits.items()) return True - # Free/busy period access for users within quota groups. - - def get_freebusy_users(self, quota): - - """ - Return a list of users whose free/busy details are retained for the - given 'quota'. - """ - - filename = self.get_object_in_store(quota, "freebusy") - if not filename or not isdir(filename): - return [] - - return listdir(filename) - - def get_freebusy(self, quota, user, mutable=False, cls=None): - - "Get free/busy details for the given 'quota' and 'user'." - - filename = self.get_object_in_store(quota, "freebusy", user) - - if not filename or not isfile(filename): - periods = [] - else: - cls = cls or FreeBusyPeriod - periods = map(lambda t: cls(*t), - self._get_table_atomic(quota, filename)) - - return FreeBusyCollection(periods, mutable) - - def set_freebusy(self, quota, user, freebusy): - - "For the given 'quota' and 'user', set 'freebusy' details." - - filename = self.get_object_in_store(quota, "freebusy", user) - if not filename: - return False - - self._set_freebusy(quota, freebusy, filename) - return True - # Journal entry methods. def get_entries(self, quota, group, mutable=False): @@ -927,15 +885,7 @@ 'group'. """ - filename = self.get_object_in_store(quota, "journal", group) - - if not filename or not isfile(filename): - periods = [] - else: - periods = map(lambda t: FreeBusyGroupPeriod(*t), - self._get_table_atomic(quota, filename)) - - return FreeBusyGroupCollection(periods, mutable) + return self.get_freebusy_for_other(quota, group, mutable, cls=FreeBusyGroupPeriod, collection=FreeBusyGroupCollection) def set_entries(self, quota, group, entries): @@ -944,11 +894,6 @@ 'entries'. """ - filename = self.get_object_in_store(quota, "journal", group) - if not filename: - return False - - self._set_freebusy(quota, entries, filename) - return True + return self.set_freebusy_for_other(quota, entries, group) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 2102cbcbadd0 -r 00d37da98920 tools/copy_store.py --- a/tools/copy_store.py Sat Jun 04 17:16:36 2016 +0200 +++ b/tools/copy_store.py Sat Jun 04 18:42:53 2016 +0200 @@ -121,8 +121,8 @@ # Copy individual free/busy details. - for store_user in from_journal.get_freebusy_users(quota): - to_journal.set_freebusy(store_user, from_journal.get_freebusy(store_user)) + for other in from_journal.get_freebusy_others(quota): + to_journal.set_freebusy_for_other(quota, other, from_journal.get_freebusy_for_other(quota, other)) # Main program.