imip-agent

Annotated tools/make_freebusy.py

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