imip-agent

tools/make_freebusy.py

528:07ab41a7f8cf
2015-05-16 Paul Boddie Made period abstractions more consistent. Indicate cancelled recurrences and make sure that they are not considered as conflicting with other event periods.
     1 #!/usr/bin/env python     2      3 from imiptools.data import get_window_end, Object     4 from imiptools.dates import format_datetime, get_default_timezone, to_recurrence_start     5 from imiptools.period import FreeBusyPeriod     6 from imiptools.profile import Preferences     7 from imip_store import FileStore, FilePublisher     8 import sys     9     10 def get_periods(fb, obj, tzid, window_end, only_organiser, recurrenceids):    11     12     # Update free/busy details with the actual periods associated with the event.    13     14     recurrenceid = format_datetime(obj.get_utc_datetime("RECURRENCE-ID")) or ""    15     recurrenceids = [to_recurrence_start(r, tzid) for r in recurrenceids]    16     17     for p in obj.get_periods_for_freebusy(tzid, window_end):    18         if recurrenceid or p.start not in recurrenceids:    19             fb.append(FreeBusyPeriod(    20                 p.start, p.end,    21                 obj.get_value("UID"),    22                 only_organiser and "ORG" or obj.get_value("TRANSP") or "OPAQUE",    23                 recurrenceid,    24                 obj.get_value("SUMMARY"),    25                 obj.get_value("ORGANIZER")    26                 ))    27     28 # Main program.    29     30 try:    31     user = sys.argv[1]    32     args = sys.argv[2:]    33     participant = args and args[0] not in ("-n", "-s", "-v") and args[0] or user    34     store_and_publish = "-s" in args    35     include_needs_action = "-n" in args    36     verbose = "-v" in args    37 except IndexError:    38     print >>sys.stderr, """\    39 Need a user and an optional participant (if different from the user),    40 along with the -s option if updating the store and the published details.    41 """    42     sys.exit(1)    43     44 preferences = Preferences(user)    45 tzid = preferences.get("TZID") or get_default_timezone()    46     47 # Get the size of the free/busy window.    48     49 try:    50     window_size = int(preferences.get("window_size"))    51 except (TypeError, ValueError):    52     window_size = 100    53 window_end = get_window_end(tzid, window_size)    54     55 store = FileStore()    56 publisher = FilePublisher()    57     58 # Get all identifiers for events.    59     60 uids = store.get_events(user)    61     62 all_events = set()    63 for uid in uids:    64     all_events.add((uid, None))    65     all_events.update([(uid, recurrenceid) for recurrenceid in store.get_recurrences(user, uid)])    66     67 # Filter out cancelled events.    68     69 cancelled = store.get_cancellations(user) or []    70 all_events.difference_update(cancelled)    71     72 # Obtain event objects.    73     74 objs = []    75 for uid, recurrenceid in all_events:    76     if verbose:    77         print >>sys.stderr, uid, recurrenceid    78     event = store.get_event(user, uid, recurrenceid)    79     if event:    80         objs.append(Object(event))    81     82 # Build a free/busy collection for the given user.    83     84 fb = []    85 for obj in objs:    86     attendees = obj.get_value_map("ATTENDEE")    87     organiser = obj.get_value("ORGANIZER")    88     recurrenceids = store.get_recurrences(user, obj.get_value("UID"))    89     90     for attendee, attendee_attr in attendees.items():    91     92         # Only consider events where the stated participant actually attends.    93     94         if attendee == participant:    95             partstat = attendee_attr.get("PARTSTAT", "NEEDS-ACTION")    96     97             if partstat not in ("DECLINED", "DELEGATED", "NEEDS-ACTION") or \    98                 include_needs_action and partstat == "NEEDS-ACTION":    99    100                 get_periods(fb, obj, tzid, window_end, False, recurrenceids)   101    102             break   103    104     # Where not attending, retain the affected periods and mark them as   105     # organising periods.   106    107     else:   108         if organiser == participant:   109             get_periods(fb, obj, tzid, window_end, True, recurrenceids)   110    111 fb.sort()   112    113 # Store and publish the free/busy collection.   114    115 if store_and_publish:   116     if user == participant:   117         store.set_freebusy(user, fb)   118         publisher.set_freebusy(user, fb)   119     else:   120         store.set_freebusy_for_other(user, fb, participant)   121 else:   122     for item in fb:   123         print "\t".join(item.as_tuple())   124    125 # vim: tabstop=4 expandtab shiftwidth=4