imip-agent

Annotated imiptools/profile.py

1067:3beb0a1b1148
2016-03-05 Paul Boddie Merged changes from the default branch. freebusy-collections
paul@147 1
#!/usr/bin/env python
paul@147 2
paul@147 3
"""
paul@147 4
User profile management.
paul@147 5
paul@1033 6
Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
paul@147 7
paul@147 8
This program is free software; you can redistribute it and/or modify it under
paul@147 9
the terms of the GNU General Public License as published by the Free Software
paul@147 10
Foundation; either version 3 of the License, or (at your option) any later
paul@147 11
version.
paul@147 12
paul@147 13
This program is distributed in the hope that it will be useful, but WITHOUT
paul@147 14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@147 15
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@147 16
details.
paul@147 17
paul@147 18
You should have received a copy of the GNU General Public License along with
paul@147 19
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@147 20
"""
paul@147 21
paul@921 22
from imiptools import config
paul@921 23
from imiptools.dates import get_default_timezone
paul@147 24
from imiptools.filesys import fix_permissions, FileBase
paul@147 25
from os.path import exists, isdir
paul@921 26
from os import listdir, makedirs
paul@1001 27
import codecs
paul@923 28
import pytz
paul@923 29
paul@1005 30
# Fake gettext method for strings to be translated later.
paul@1005 31
paul@1005 32
_ = lambda s: s
paul@1005 33
paul@923 34
def identity_dict(l):
paul@923 35
    return dict([(i, i) for i in l])
paul@147 36
paul@147 37
class Preferences(FileBase):
paul@147 38
paul@147 39
    "A simple preferences file manager."
paul@147 40
paul@1033 41
    # See: docs/wiki/Preferences
paul@921 42
paul@921 43
    known_keys = {
paul@921 44
        "CN"                    : "",
paul@921 45
        "LANG"                  : config.LANG,
paul@921 46
        "TZID"                  : get_default_timezone(),
paul@921 47
        "add_method_response"   : config.ADD_RESPONSE_DEFAULT,
paul@921 48
        "event_refreshing"      : config.REFRESHING_DEFAULT,
paul@921 49
        "freebusy_bundling"     : config.BUNDLING_DEFAULT,
paul@921 50
        "freebusy_messages"     : config.NOTIFYING_DEFAULT,
paul@921 51
        "freebusy_offers"       : config.FREEBUSY_OFFER_DEFAULT,
paul@921 52
        "freebusy_publishing"   : config.PUBLISHING_DEFAULT,
paul@921 53
        "freebusy_sharing"      : config.SHARING_DEFAULT,
paul@921 54
        "incoming"              : config.INCOMING_DEFAULT,
paul@921 55
        "organiser_replacement" : config.ORGANISER_REPLACEMENT_DEFAULT,
paul@921 56
        "participating"         : config.PARTICIPATING_DEFAULT,
paul@921 57
        "permitted_times"       : None,
paul@921 58
        }
paul@921 59
paul@923 60
    known_key_choices = {
paul@923 61
        "TZID"                  : identity_dict(pytz.all_timezones),
paul@923 62
        "add_method_response"   : {
paul@1005 63
            "add"                   : _("Add events"),
paul@1005 64
            "ignore"                : _("Ignore requests"),
paul@1005 65
            "refresh"               : _("Ask for refreshed event details"),
paul@923 66
                                  },
paul@923 67
        "event_refreshing"      : {
paul@1005 68
            "never"                 : _("Do not respond"),
paul@1005 69
            "always"                : _("Always respond"),
paul@923 70
                                  },
paul@923 71
        "freebusy_bundling"     : {
paul@1005 72
            "never"                 : _("Never"),
paul@1005 73
            "always"                : _("Always"),
paul@923 74
                                  },
paul@923 75
        "freebusy_messages"     : {
paul@1005 76
            "none"                  : _("Do not notify"),
paul@1005 77
            "notify"                : _("Notify"),
paul@923 78
                                  },
paul@923 79
        "freebusy_publishing"   : {
paul@1005 80
            "publish"               : _("Publish"),
paul@1005 81
            "no"                    : _("Do not publish"),
paul@923 82
                                  },
paul@923 83
        "freebusy_sharing"      : {
paul@1005 84
            "share"                 : _("Share"),
paul@1005 85
            "no"                    : _("Do not share"),
paul@923 86
                                  },
paul@923 87
        "incoming"              : {
paul@1005 88
            "message-only"          : _("Original message only"),
paul@1005 89
            "message-then-summary"  : _("Original message followed by a separate summary message"),
paul@1005 90
            "summary-then-message"  : _("Summary message followed by the original message"),
paul@1005 91
            "summary-only"          : _("Summary message only"),
paul@1005 92
            "summary-wraps-message" : _("Summary message wrapping the original message"),
paul@923 93
                                  },
paul@923 94
        "organiser_replacement" : {
paul@1005 95
            "any"                   : _("Anyone"),
paul@1005 96
            "attendee"              : _("Existing attendees only"),
paul@1005 97
            "never"                 : _("Never allow organiser replacement"),
paul@923 98
                                  },
paul@923 99
        "participating"         : {
paul@1005 100
            "participate"           : _("Participate"),
paul@1005 101
            "no"                    : _("Do not participate"),
paul@923 102
                                  }
paul@923 103
        }
paul@923 104
paul@639 105
    def __init__(self, user, store_dir=None):
paul@921 106
        FileBase.__init__(self, store_dir or config.PREFERENCES_DIR)
paul@147 107
        self.user = user
paul@147 108
paul@921 109
    def get(self, name, default=None, config_default=False):
paul@693 110
paul@693 111
        """
paul@693 112
        Return the value for 'name', with absent entries providing a default of
paul@921 113
        None or any indicated 'default' or, if 'config_default' is set to a true
paul@921 114
        value, the default value from the config module.
paul@693 115
        """
paul@693 116
paul@147 117
        try:
paul@147 118
            return self[name]
paul@147 119
        except KeyError:
paul@921 120
            if config_default:
paul@921 121
                return self.known_keys.get(name, default)
paul@921 122
            else:
paul@921 123
                return default
paul@147 124
paul@791 125
    def get_all(self, names):
paul@791 126
paul@791 127
        """
paul@791 128
        Return a dictionary containing values for entries having the given
paul@791 129
        'names'. Absent entries for names are omitted without error.
paul@791 130
        """
paul@791 131
paul@791 132
        d = {}
paul@791 133
        for name in names:
paul@791 134
            value = self.get(name)
paul@791 135
            if value is not None:
paul@791 136
                d[name] = value
paul@791 137
        return d
paul@791 138
paul@791 139
    def has_key(self, name):
paul@791 140
paul@791 141
        "Return whether an entry exists for 'name'."
paul@791 142
paul@791 143
        try:
paul@791 144
            self[name]
paul@791 145
            return True
paul@791 146
        except KeyError:
paul@791 147
            return False
paul@791 148
paul@921 149
    def keys(self):
paul@921 150
paul@921 151
        "Return all entry names in the preferences."
paul@921 152
paul@921 153
        filename = self.get_object_in_store(self.user)
paul@921 154
        if not filename or not isdir(filename):
paul@921 155
            return []
paul@921 156
paul@921 157
        return listdir(filename)
paul@921 158
paul@921 159
    def items(self, all_known=False, default=None, config_default=False):
paul@921 160
paul@921 161
        """
paul@921 162
        Return all entries in the preferences or all known entries if
paul@921 163
        'all_known' is set to a true value, with absent entries providing a
paul@921 164
        default of None or any indicated 'default' or, if 'config_default' is
paul@921 165
        set to a true value, the default value from the config module.
paul@923 166
paul@923 167
        Each entry will have the form (key, value).
paul@921 168
        """
paul@921 169
paul@921 170
        l = []
paul@921 171
        for key in (all_known and self.known_keys or self).keys():
paul@921 172
            l.append((key, self.get(key, default, config_default)))
paul@921 173
        return l
paul@921 174
paul@923 175
    def choices(self, all_known=False, default=None, config_default=False):
paul@923 176
paul@923 177
        """
paul@923 178
        Return all entries in the preferences or all known entries if
paul@923 179
        'all_known' is set to a true value, with absent entries providing a
paul@923 180
        default of None or any indicated 'default' or, if 'config_default' is
paul@923 181
        set to a true value, the default value from the config module.
paul@923 182
paul@923 183
        Each entry will have the form (key, value, choices).
paul@923 184
        """
paul@923 185
paul@923 186
        l = []
paul@923 187
        for key, value in self.items(all_known, default, config_default):
paul@923 188
            l.append((key, value, self.known_key_choices.get(key)))
paul@923 189
        return l
paul@923 190
paul@147 191
    def __getitem__(self, name):
paul@693 192
paul@693 193
        "Return the value for 'name', raising a KeyError if absent."
paul@693 194
paul@147 195
        filename = self.get_object_in_store(self.user, name)
paul@147 196
        if not filename or not exists(filename):
paul@147 197
            raise KeyError, name
paul@147 198
paul@1001 199
        f = codecs.open(filename, encoding="utf-8")
paul@147 200
        try:
paul@147 201
            return f.read().strip()
paul@147 202
        finally:
paul@147 203
            f.close()
paul@147 204
paul@147 205
    def __setitem__(self, name, value):
paul@693 206
paul@693 207
        "Set for 'name' the given 'value'."
paul@693 208
paul@147 209
        filename = self.get_object_in_store(self.user, name)
paul@147 210
        if not filename:
paul@147 211
            return False
paul@147 212
paul@1001 213
        f = codecs.open(filename, "w", encoding="utf-8")
paul@147 214
        try:
paul@147 215
            f.write(value)
paul@147 216
        finally:
paul@147 217
            f.close()
paul@147 218
            fix_permissions(filename)
paul@147 219
paul@147 220
        return True
paul@147 221
paul@147 222
# vim: tabstop=4 expandtab shiftwidth=4