# HG changeset patch # User Paul Boddie # Date 1439330034 -7200 # Node ID f8b21bbd82bfee1c42f9b9c67a2a91ee1f4e6011 # Parent 806c54989b5672a344b061713474505bf0ab1736 Added initial support for lists of objects providing recurrences after a given point in time, thus offering a selective, more efficient approach to computing and updating the recurrence periods when expanding a window of availability to cover a later period. Fixed the table retrieval method to not strip tabs (and thus blank columns) from the ends of lines. diff -r 806c54989b56 -r f8b21bbd82bf imip_store.py --- a/imip_store.py Sun Aug 09 23:24:29 2015 +0200 +++ b/imip_store.py Tue Aug 11 23:53:54 2015 +0200 @@ -22,7 +22,7 @@ from datetime import datetime from imiptools.config import STORE_DIR, PUBLISH_DIR from imiptools.data import make_calendar, parse_object, to_stream -from imiptools.dates import format_datetime +from imiptools.dates import format_datetime, get_datetime from imiptools.filesys import fix_permissions, FileBase from imiptools.period import FreeBusyPeriod from os.path import exists, isfile, join @@ -70,7 +70,7 @@ try: l = [] for line in f.readlines(): - t = line.strip().split("\t") + t = line.strip(" \r\n").split("\t") if empty_defaults: t = self._set_defaults(t, empty_defaults) l.append(tuple(t)) @@ -341,6 +341,40 @@ return True + # Free/busy period providers, upon extension of the free/busy records. + + def get_freebusy_providers(self, user, dt=None): + + """ + Return a set of uncancelled events of the form (uid, recurrenceid) + providing free/busy details beyond the given datetime 'dt'. + """ + + filename = self.get_object_in_store(user, "freebusy-providers") + if not filename or not exists(filename): + return None + else: + # Attempt to read providers, with a declaration of the datetime + # from which such providers are considered as still being active. + + t = self._get_table(user, filename, [(1, None)]) + try: + dt_string = t[0][0] + except IndexError: + return None + + # If the requested datetime is earlier than the stated datetime, the + # providers will need to be recomputed. + + if dt: + providers_dt = get_datetime(dt_string) + if not providers_dt or providers_dt > dt: + return None + + # Otherwise, return the providers. + + return t[1:] + # Free/busy period access. def get_freebusy(self, user): diff -r 806c54989b56 -r f8b21bbd82bf tools/make_freebusy.py --- a/tools/make_freebusy.py Sun Aug 09 23:24:29 2015 +0200 +++ b/tools/make_freebusy.py Tue Aug 11 23:53:54 2015 +0200 @@ -21,6 +21,7 @@ this program. If not, see . """ +from bisect import bisect_left from codecs import getwriter from imiptools.data import get_window_end, Object from imiptools.dates import get_default_timezone @@ -62,9 +63,23 @@ store = FileStore() publisher = FilePublisher() - # Get identifiers for uncancelled events. + # Get identifiers for uncancelled events either from a list of events + # providing free/busy periods at the end of the given time window, or from + # a list of all events. + + all_events = store.get_freebusy_providers(user, window_end) - all_events = store.get_active_events(user) + if not all_events: + all_events = store.get_active_events(user) + fb = [] + + # With providers of additional periods, append to the existing collection. + + else: + if user == participant: + fb = store.get_freebusy(user) + else: + fb = store.get_freebusy_for_other(user, participant) # Obtain event objects. @@ -78,16 +93,18 @@ # Build a free/busy collection for the given user. - fb = [] for obj in objs: partstat = obj.get_participation_status(participant) recurrenceids = not obj.get_recurrenceid() and store.get_recurrences(user, obj.get_uid()) if obj.get_participation(partstat, include_needs_action): for p in obj.get_active_periods(recurrenceids, tzid, window_end): - fb.append(obj.get_freebusy_period(p, partstat == "ORG")) - - fb.sort() + fbp = obj.get_freebusy_period(p, partstat == "ORG") + i = bisect_left(fb, fbp) + if i == len(fb): + fb.append(fbp) + elif fb[i] != fbp: + fb.insert(i, fbp) # Store and publish the free/busy collection.