imip-agent

Annotated imiptools/client.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@441 1
#!/usr/bin/env python
paul@441 2
paul@441 3
"""
paul@441 4
Common calendar client utilities.
paul@441 5
paul@441 6
Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk>
paul@441 7
paul@441 8
This program is free software; you can redistribute it and/or modify it under
paul@441 9
the terms of the GNU General Public License as published by the Free Software
paul@441 10
Foundation; either version 3 of the License, or (at your option) any later
paul@441 11
version.
paul@441 12
paul@441 13
This program is distributed in the hope that it will be useful, but WITHOUT
paul@441 14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@441 15
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@441 16
details.
paul@441 17
paul@441 18
You should have received a copy of the GNU General Public License along with
paul@441 19
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@441 20
"""
paul@441 21
paul@473 22
from imiptools.data import get_uri, get_window_end, uri_dict, uri_items, uri_values
paul@443 23
from imiptools.dates import get_default_timezone
paul@443 24
from imiptools.profile import Preferences
paul@441 25
paul@473 26
def update_attendees(obj, attendees, removed):
paul@441 27
paul@441 28
    """
paul@473 29
    Update the attendees in 'obj' with the given 'attendees' and 'removed'
paul@441 30
    attendee lists. A list is returned containing the attendees whose
paul@441 31
    attendance should be cancelled.
paul@441 32
    """
paul@441 33
paul@441 34
    to_cancel = []
paul@441 35
paul@473 36
    existing_attendees = uri_values(obj.get_values("ATTENDEE") or [])
paul@473 37
    added = set(attendees).difference(existing_attendees)
paul@473 38
paul@441 39
    if added or removed:
paul@441 40
        attendees = uri_items(obj.get_items("ATTENDEE") or [])
paul@460 41
        sequence = obj.get_value("SEQUENCE")
paul@441 42
paul@441 43
        if removed:
paul@441 44
            remaining = []
paul@441 45
paul@441 46
            for attendee, attendee_attr in attendees:
paul@441 47
                if attendee in removed:
paul@460 48
paul@460 49
                    # Without a sequence number, assume that the event has not
paul@460 50
                    # been published and that attendees can be silently removed.
paul@460 51
paul@460 52
                    if sequence is not None:
paul@441 53
                        to_cancel.append((attendee, attendee_attr))
paul@441 54
                else:
paul@441 55
                    remaining.append((attendee, attendee_attr))
paul@441 56
paul@441 57
            attendees = remaining
paul@441 58
paul@441 59
        if added:
paul@441 60
            for attendee in added:
paul@473 61
                attendee = attendee.strip()
paul@473 62
                if attendee:
paul@473 63
                    attendees.append((get_uri(attendee), {"PARTSTAT" : "NEEDS-ACTION", "RSVP" : "TRUE"}))
paul@441 64
paul@441 65
        obj["ATTENDEE"] = attendees
paul@441 66
paul@441 67
    return to_cancel
paul@441 68
paul@473 69
def update_participation(obj, user, partstat):
paul@473 70
paul@473 71
    "Update the participation in 'obj' of 'user' with the given 'partstat'."
paul@473 72
paul@473 73
    existing_attendees = uri_dict(obj.get_value_map("ATTENDEE"))
paul@473 74
paul@473 75
    if partstat:
paul@473 76
        if existing_attendees.has_key(user):
paul@473 77
            existing_attendees[user]["PARTSTAT"] = partstat
paul@473 78
            if existing_attendees[user].has_key("RSVP"):
paul@473 79
                del existing_attendees[user]["RSVP"]
paul@473 80
paul@443 81
class Client:
paul@443 82
paul@443 83
    "Common handler and manager methods."
paul@443 84
paul@467 85
    default_window_size = 100
paul@467 86
paul@443 87
    def __init__(self, user):
paul@443 88
        self.user = user
paul@443 89
        self.preferences = None
paul@443 90
paul@443 91
    def get_preferences(self):
paul@467 92
        if not self.preferences and self.user:
paul@443 93
            self.preferences = Preferences(self.user)
paul@443 94
        return self.preferences
paul@443 95
paul@443 96
    def get_tzid(self):
paul@443 97
        prefs = self.get_preferences()
paul@467 98
        return prefs and prefs.get("TZID") or get_default_timezone()
paul@443 99
paul@443 100
    def get_window_size(self):
paul@443 101
        prefs = self.get_preferences()
paul@443 102
        try:
paul@467 103
            return prefs and int(prefs.get("window_size")) or self.default_window_size
paul@443 104
        except (TypeError, ValueError):
paul@467 105
            return self.default_window_size
paul@443 106
paul@443 107
    def get_window_end(self):
paul@443 108
        return get_window_end(self.get_tzid(), self.get_window_size())
paul@443 109
paul@443 110
    def is_sharing(self):
paul@467 111
        prefs = self.get_preferences()
paul@467 112
        return prefs and prefs.get("freebusy_sharing") == "share" or False
paul@443 113
paul@443 114
    def is_bundling(self):
paul@467 115
        prefs = self.get_preferences()
paul@467 116
        return prefs and prefs.get("freebusy_bundling") == "always" or False
paul@467 117
paul@467 118
    def is_notifying(self):
paul@467 119
        prefs = self.get_preferences()
paul@467 120
        return prefs and prefs.get("freebusy_messages") == "notify" or False
paul@443 121
paul@441 122
# vim: tabstop=4 expandtab shiftwidth=4