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