1.1 --- a/conf/postgresql/schema.sql Sat Jun 04 17:16:36 2016 +0200
1.2 +++ b/conf/postgresql/schema.sql Sat Jun 04 18:42:53 2016 +0200
1.3 @@ -74,7 +74,8 @@
1.4 transp varchar,
1.5 object_recurrenceid varchar,
1.6 summary varchar,
1.7 - organiser varchar
1.8 + organiser varchar,
1.9 + attendee varchar -- used by quotas
1.10 );
1.11
1.12 create index freebusy_other_start on freebusy_other(store_user, other, "start");
1.13 @@ -110,45 +111,12 @@
1.14
1.15 -- Journal store tables.
1.16
1.17 --- Journal free/busy details.
1.18 -
1.19 -create table quota_freebusy (
1.20 - quota varchar not null,
1.21 - user_group varchar not null,
1.22 - "start" varchar not null,
1.23 - "end" varchar not null,
1.24 - object_uid varchar,
1.25 - transp varchar,
1.26 - object_recurrenceid varchar,
1.27 - summary varchar,
1.28 - organiser varchar,
1.29 - attendee varchar
1.30 -);
1.31 -
1.32 -create index quota_freebusy_start on quota_freebusy(quota, user_group, "start");
1.33 -create index quota_freebusy_end on quota_freebusy(quota, user_group, "end");
1.34 -
1.35 create table quota_delegates (
1.36 quota varchar not null,
1.37 store_user varchar not null,
1.38 primary key(quota, store_user)
1.39 );
1.40
1.41 -create table user_freebusy (
1.42 - quota varchar not null,
1.43 - store_user varchar not null,
1.44 - "start" varchar not null,
1.45 - "end" varchar not null,
1.46 - object_uid varchar,
1.47 - transp varchar,
1.48 - object_recurrenceid varchar,
1.49 - summary varchar,
1.50 - organiser varchar
1.51 -);
1.52 -
1.53 -create index user_freebusy_start on user_freebusy(quota, store_user, "start");
1.54 -create index user_freebusy_end on user_freebusy(quota, store_user, "end");
1.55 -
1.56 -- Journal user groups and limits.
1.57
1.58 create table quota_limits (
2.1 --- a/docs/wiki/DatabaseStore Sat Jun 04 17:16:36 2016 +0200
2.2 +++ b/docs/wiki/DatabaseStore Sat Jun 04 18:42:53 2016 +0200
2.3 @@ -50,19 +50,15 @@
2.4 {{{#!table
2.5 '''Table''' || '''Purpose'''
2.6 ==
2.7 -`quota_freebusy`
2.8 -|| Period descriptions describing reservations for resources sharing a quota (`quota`)
2.9 -.. made by users or groups (`user_group`), structured similarly to the `freebusy` table
2.10 -.. in the data store
2.11 +`freebusy_other`
2.12 +|| Period descriptions describing reservations for resources sharing a quota
2.13 +.. (`store_user`) made by users or groups (`other`), structured similarly to the
2.14 +.. `freebusy` table in the data store; this may be the same table as the one employed
2.15 +.. by the data store to store received or deduced free/busy details
2.16 ==
2.17 `quota_limits`
2.18 || A mapping from user identities or group identifiers to quota limits
2.19 ==
2.20 -`user_freebusy`
2.21 -|| Period descriptions for reservations made in the context of a quota (`quota`) by a
2.22 -.. specific user (`store_user`), structured similarly to the `freebusy` table in the
2.23 -.. data store
2.24 -==
2.25 `user_groups`
2.26 || A mapping from user identities to group identifiers indicating the sharing of a quota
2.27 .. across a number of users
3.1 --- a/docs/wiki/FilesystemUsage Sat Jun 04 17:16:36 2016 +0200
3.2 +++ b/docs/wiki/FilesystemUsage Sat Jun 04 18:42:53 2016 +0200
3.3 @@ -43,30 +43,22 @@
3.4 {{{{#!table
3.5 '''Entry''' || '''Purpose'''
3.6 ==
3.7 -`freebusy`
3.8 -|| A directory containing files, one per user, each containing period descriptions
3.9 +`freebusy-other`
3.10 +|| A directory containing files, one per user (each containing period descriptions
3.11 .. for reservations made by that user, in chronological order, structured
3.12 -.. similarly to the `freebusy` file found in each user's own store; the record is
3.13 -.. consolidated for all resources in a quota group, but it is not consolidated for
3.14 -.. groups of users
3.15 +.. similarly to the `freebusy` file found in each user's own store) or one per
3.16 +.. group (for reservations made by users belonging to the groups defined for the
3.17 +.. quota); the record in each file is consolidated for all resources in a quota
3.18 +.. group
3.19 {{{
3.20 -freebusy/USER
3.21 +freebusy-other/GROUP
3.22 +freebusy-other/USER
3.23 }}}
3.24 ==
3.25 `groups`
3.26 || A mapping from user identities to group identifiers indicating the sharing
3.27 .. of a quota across a number of users
3.28 ==
3.29 -`journal`
3.30 -|| A directory containing consolidated schedules, one per user or user group,
3.31 -.. describing reservations for resources sharing a quota made by the indicated
3.32 -.. user or group, structured similarly to the `freebusy` file found in each
3.33 -.. resource's own store
3.34 -{{{
3.35 -journal/GROUP
3.36 -journal/USER
3.37 -}}}
3.38 -==
3.39 `limits`
3.40 || A mapping from user identities or group identifiers to quota limits
3.41 }}}}
4.1 --- a/imiptools/handlers/scheduling/quota.py Sat Jun 04 17:16:36 2016 +0200
4.2 +++ b/imiptools/handlers/scheduling/quota.py Sat Jun 04 18:42:53 2016 +0200
4.3 @@ -209,7 +209,7 @@
4.4 # organiser's reservations.
4.5
4.6 periods = handler.get_periods(handler.obj)
4.7 - freebusy = handler.get_journal().get_freebusy(quota, organiser)
4.8 + freebusy = handler.get_journal().get_entries(quota, organiser)
4.9 scheduled = handler.can_schedule(freebusy, periods)
4.10
4.11 return standard_responses(handler, scheduled and "ACCEPTED" or "DECLINED")
4.12 @@ -224,9 +224,9 @@
4.13 quota, organiser = _get_quota_and_identity(handler, args)
4.14
4.15 journal = handler.get_journal()
4.16 - freebusy = journal.get_freebusy_for_update(quota, organiser)
4.17 + freebusy = journal.get_entries_for_update(quota, organiser)
4.18 handler.update_freebusy(freebusy, organiser, True)
4.19 - journal.set_freebusy(quota, organiser, freebusy)
4.20 + journal.set_entries(quota, organiser, freebusy)
4.21
4.22 def remove_from_quota_freebusy(handler, args):
4.23
4.24 @@ -238,9 +238,9 @@
4.25 quota, organiser = _get_quota_and_identity(handler, args)
4.26
4.27 journal = handler.get_journal()
4.28 - freebusy = journal.get_freebusy_for_update(quota, organiser)
4.29 + freebusy = journal.get_entries_for_update(quota, organiser)
4.30 handler.remove_from_freebusy(freebusy)
4.31 - journal.set_freebusy(quota, organiser, freebusy)
4.32 + journal.set_entries(quota, organiser, freebusy)
4.33
4.34 def _get_quota_and_identity(handler, args):
4.35
5.1 --- a/imiptools/stores/common.py Sat Jun 04 17:16:36 2016 +0200
5.2 +++ b/imiptools/stores/common.py Sat Jun 04 18:42:53 2016 +0200
5.3 @@ -628,38 +628,6 @@
5.4
5.5 pass
5.6
5.7 - # Free/busy period access for users within quota groups.
5.8 -
5.9 - def get_freebusy_users(self, quota):
5.10 -
5.11 - """
5.12 - Return a list of users whose free/busy details are retained for the
5.13 - given 'quota'.
5.14 - """
5.15 -
5.16 - pass
5.17 -
5.18 - def get_freebusy(self, quota, user, mutable=False):
5.19 -
5.20 - "Get free/busy details for the given 'quota' and 'user'."
5.21 -
5.22 - pass
5.23 -
5.24 - def get_freebusy_for_update(self, quota, user):
5.25 -
5.26 - """
5.27 - Get free/busy details for the given 'quota' and 'user' that may be
5.28 - updated, potentially affecting the stored information directly.
5.29 - """
5.30 -
5.31 - return self.get_freebusy(quota, user, True)
5.32 -
5.33 - def set_freebusy(self, quota, user, freebusy):
5.34 -
5.35 - "For the given 'quota' and 'user', set 'freebusy' details."
5.36 -
5.37 - pass
5.38 -
5.39 # Journal entry methods.
5.40
5.41 def get_entries(self, quota, group, mutable=False):
6.1 --- a/imiptools/stores/database/common.py Sat Jun 04 17:16:36 2016 +0200
6.2 +++ b/imiptools/stores/database/common.py Sat Jun 04 18:42:53 2016 +0200
6.3 @@ -439,12 +439,13 @@
6.4 cls = cls or FreeBusyDatabaseCollection
6.5 return cls(self.cursor, table, ["store_user"], [user], mutable, self.paramstyle)
6.6
6.7 - def get_freebusy_for_other(self, user, other, mutable=False):
6.8 + def get_freebusy_for_other(self, user, other, mutable=False, cls=None):
6.9
6.10 "For the given 'user', get free/busy details for the 'other' user."
6.11
6.12 table = "freebusy_other"
6.13 - return FreeBusyDatabaseCollection(self.cursor, table, ["store_user", "other"], [user, other], mutable, self.paramstyle)
6.14 + cls = cls or FreeBusyDatabaseCollection
6.15 + return cls(self.cursor, table, ["store_user", "other"], [user, other], mutable, self.paramstyle)
6.16
6.17 def set_freebusy(self, user, freebusy, name=None, cls=None):
6.18
6.19 @@ -459,14 +460,15 @@
6.20
6.21 return True
6.22
6.23 - def set_freebusy_for_other(self, user, freebusy, other):
6.24 + def set_freebusy_for_other(self, user, freebusy, other, cls=None):
6.25
6.26 "For the given 'user', set 'freebusy' details for the 'other' user."
6.27
6.28 table = "freebusy_other"
6.29 + cls = cls or FreeBusyDatabaseCollection
6.30
6.31 - if not isinstance(freebusy, FreeBusyDatabaseCollection) or freebusy.table_name != table:
6.32 - fbc = FreeBusyDatabaseCollection(self.cursor, table, ["store_user", "other"], [user, other], True, self.paramstyle)
6.33 + if not isinstance(freebusy, cls) or freebusy.table_name != table:
6.34 + fbc = cls(self.cursor, table, ["store_user", "other"], [user, other], True, self.paramstyle)
6.35 fbc += freebusy
6.36
6.37 return True
6.38 @@ -812,7 +814,7 @@
6.39 self.cursor.execute(query, values)
6.40 return True
6.41
6.42 -class DatabaseJournal(DatabaseStoreBase, JournalBase):
6.43 +class DatabaseJournal(DatabaseStore, JournalBase):
6.44
6.45 "A journal system to support quotas."
6.46
6.47 @@ -976,46 +978,6 @@
6.48
6.49 return True
6.50
6.51 - # Free/busy period access for users within quota groups.
6.52 -
6.53 - def get_freebusy_users(self, quota):
6.54 -
6.55 - """
6.56 - Return a list of users whose free/busy details are retained for the
6.57 - given 'quota'.
6.58 - """
6.59 -
6.60 - columns = ["quota"]
6.61 - values = [quota]
6.62 -
6.63 - query, values = self.get_query(
6.64 - "select distinct store_user from user_freebusy :condition",
6.65 - columns, values)
6.66 -
6.67 - self.cursor.execute(query, values)
6.68 - return [r[0] for r in self.cursor.fetchall()]
6.69 -
6.70 - def get_freebusy(self, quota, user, mutable=False, cls=None):
6.71 -
6.72 - "Get free/busy details for the given 'quota' and 'user'."
6.73 -
6.74 - table = "user_freebusy"
6.75 - cls = cls or FreeBusyDatabaseCollection
6.76 - return cls(self.cursor, table, ["quota", "store_user"], [quota, user], mutable, self.paramstyle)
6.77 -
6.78 - def set_freebusy(self, quota, user, freebusy, cls=None):
6.79 -
6.80 - "For the given 'quota' and 'user', set 'freebusy' details."
6.81 -
6.82 - table = "user_freebusy"
6.83 - cls = cls or FreeBusyDatabaseCollection
6.84 -
6.85 - if not isinstance(freebusy, cls) or freebusy.table_name != table:
6.86 - fbc = cls(self.cursor, table, ["quota", "store_user"], [quota, user], True, self.paramstyle)
6.87 - fbc += freebusy
6.88 -
6.89 - return True
6.90 -
6.91 # Journal entry methods.
6.92
6.93 def get_entries(self, quota, group, mutable=False):
6.94 @@ -1025,8 +987,7 @@
6.95 'group'.
6.96 """
6.97
6.98 - table = "quota_freebusy"
6.99 - return FreeBusyGroupDatabaseCollection(self.cursor, table, ["quota", "user_group"], [quota, group], mutable, self.paramstyle)
6.100 + return self.get_freebusy_for_other(quota, group, mutable, cls=FreeBusyGroupDatabaseCollection)
6.101
6.102 def set_entries(self, quota, group, entries):
6.103
6.104 @@ -1035,12 +996,6 @@
6.105 'entries'.
6.106 """
6.107
6.108 - table = "quota_freebusy"
6.109 -
6.110 - if not isinstance(entries, FreeBusyGroupDatabaseCollection) or entries.table_name != table:
6.111 - fbc = FreeBusyGroupDatabaseCollection(self.cursor, table, ["quota", "user_group"], [quota, group], True, self.paramstyle)
6.112 - fbc += entries
6.113 -
6.114 - return True
6.115 + return self.set_freebusy_for_other(quota, entries, group, cls=FreeBusyGroupDatabaseCollection)
6.116
6.117 # vim: tabstop=4 expandtab shiftwidth=4
7.1 --- a/imiptools/stores/file.py Sat Jun 04 17:16:36 2016 +0200
7.2 +++ b/imiptools/stores/file.py Sat Jun 04 18:42:53 2016 +0200
7.3 @@ -471,7 +471,7 @@
7.4
7.5 return FreeBusyCollection(periods, mutable)
7.6
7.7 - def get_freebusy_for_other(self, user, other, mutable=False):
7.8 + def get_freebusy_for_other(self, user, other, mutable=False, cls=None, collection=None):
7.9
7.10 "For the given 'user', get free/busy details for the 'other' user."
7.11
7.12 @@ -480,10 +480,12 @@
7.13 if not filename or not isfile(filename):
7.14 periods = []
7.15 else:
7.16 - periods = map(lambda t: FreeBusyPeriod(*t),
7.17 + cls = cls or FreeBusyPeriod
7.18 + periods = map(lambda t: cls(*t),
7.19 self._get_table_atomic(user, filename))
7.20
7.21 - return FreeBusyCollection(periods, mutable)
7.22 + collection = collection or FreeBusyCollection
7.23 + return collection(periods, mutable)
7.24
7.25 def set_freebusy(self, user, freebusy, name=None):
7.26
7.27 @@ -779,13 +781,10 @@
7.28
7.29 return True
7.30
7.31 -class Journal(FileStoreBase, JournalBase):
7.32 +class Journal(Store, JournalBase):
7.33
7.34 "A journal system to support quotas."
7.35
7.36 - def __init__(self, store_dir=None):
7.37 - FileBase.__init__(self, store_dir or JOURNAL_DIR)
7.38 -
7.39 # Quota and user identity/group discovery.
7.40
7.41 def get_quotas(self):
7.42 @@ -877,47 +876,6 @@
7.43 self._set_table_atomic(quota, filename, limits.items())
7.44 return True
7.45
7.46 - # Free/busy period access for users within quota groups.
7.47 -
7.48 - def get_freebusy_users(self, quota):
7.49 -
7.50 - """
7.51 - Return a list of users whose free/busy details are retained for the
7.52 - given 'quota'.
7.53 - """
7.54 -
7.55 - filename = self.get_object_in_store(quota, "freebusy")
7.56 - if not filename or not isdir(filename):
7.57 - return []
7.58 -
7.59 - return listdir(filename)
7.60 -
7.61 - def get_freebusy(self, quota, user, mutable=False, cls=None):
7.62 -
7.63 - "Get free/busy details for the given 'quota' and 'user'."
7.64 -
7.65 - filename = self.get_object_in_store(quota, "freebusy", user)
7.66 -
7.67 - if not filename or not isfile(filename):
7.68 - periods = []
7.69 - else:
7.70 - cls = cls or FreeBusyPeriod
7.71 - periods = map(lambda t: cls(*t),
7.72 - self._get_table_atomic(quota, filename))
7.73 -
7.74 - return FreeBusyCollection(periods, mutable)
7.75 -
7.76 - def set_freebusy(self, quota, user, freebusy):
7.77 -
7.78 - "For the given 'quota' and 'user', set 'freebusy' details."
7.79 -
7.80 - filename = self.get_object_in_store(quota, "freebusy", user)
7.81 - if not filename:
7.82 - return False
7.83 -
7.84 - self._set_freebusy(quota, freebusy, filename)
7.85 - return True
7.86 -
7.87 # Journal entry methods.
7.88
7.89 def get_entries(self, quota, group, mutable=False):
7.90 @@ -927,15 +885,7 @@
7.91 'group'.
7.92 """
7.93
7.94 - filename = self.get_object_in_store(quota, "journal", group)
7.95 -
7.96 - if not filename or not isfile(filename):
7.97 - periods = []
7.98 - else:
7.99 - periods = map(lambda t: FreeBusyGroupPeriod(*t),
7.100 - self._get_table_atomic(quota, filename))
7.101 -
7.102 - return FreeBusyGroupCollection(periods, mutable)
7.103 + return self.get_freebusy_for_other(quota, group, mutable, cls=FreeBusyGroupPeriod, collection=FreeBusyGroupCollection)
7.104
7.105 def set_entries(self, quota, group, entries):
7.106
7.107 @@ -944,11 +894,6 @@
7.108 'entries'.
7.109 """
7.110
7.111 - filename = self.get_object_in_store(quota, "journal", group)
7.112 - if not filename:
7.113 - return False
7.114 -
7.115 - self._set_freebusy(quota, entries, filename)
7.116 - return True
7.117 + return self.set_freebusy_for_other(quota, entries, group)
7.118
7.119 # vim: tabstop=4 expandtab shiftwidth=4
8.1 --- a/tools/copy_store.py Sat Jun 04 17:16:36 2016 +0200
8.2 +++ b/tools/copy_store.py Sat Jun 04 18:42:53 2016 +0200
8.3 @@ -121,8 +121,8 @@
8.4
8.5 # Copy individual free/busy details.
8.6
8.7 - for store_user in from_journal.get_freebusy_users(quota):
8.8 - to_journal.set_freebusy(store_user, from_journal.get_freebusy(store_user))
8.9 + for other in from_journal.get_freebusy_others(quota):
8.10 + to_journal.set_freebusy_for_other(quota, other, from_journal.get_freebusy_for_other(quota, other))
8.11
8.12 # Main program.
8.13