1 #!/usr/bin/env python 2 3 """ 4 A Web interface to the user profile. 5 6 Copyright (C) 2015, 2016 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 imipweb.resource import FormUtilities, ResourceClient 23 24 # Fake gettext method for strings to be translated later. 25 26 _ = lambda s: s 27 28 class ProfilePage(ResourceClient, FormUtilities): 29 30 "A request handler for the user profile page." 31 32 # See: imiptools.config, imiptools.profile 33 # NOTE: This could be defined in another format and generated or computed 34 # NOTE: for this class and for the documentation. 35 # See: docs/tools/profile_prefs.sh 36 37 pref_labels = [ 38 ("participating" , _("Participate in the calendar system")), 39 ("CN" , _("Your common name")), 40 ("LANG" , _("Language")), 41 ("TZID" , _("Time zone/regime")), 42 ("incoming" , _("How to present incoming calendar messages")), 43 ("freebusy_sharing" , _("Share free/busy information")), 44 ("freebusy_bundling" , _("Bundle free/busy details with messages")), 45 ("freebusy_publishing" , _("Publish free/busy details via the Web")), 46 ("freebusy_messages" , _("Deliver details of received free/busy messages")), 47 ("add_method_response" , _("How to respond to messages adding events")), 48 ("event_refreshing" , _("How to handle event refresh requests")), 49 ("organiser_replacement" , _("Recognise whom as a new organiser of an event?")), 50 ] 51 52 def handle_request(self): 53 args = self.env.get_args() 54 save = args.has_key("save") 55 cancel = args.has_key("cancel") 56 action = save or cancel 57 58 if not action: 59 return ["action"] 60 61 # Check the validation token. 62 63 if not self.check_validation_token(): 64 return ["token"] 65 66 if save: 67 errors = self.update_preferences() 68 if errors: 69 return errors 70 else: 71 self.redirect(self.link_to()) 72 73 elif cancel: 74 self.redirect(self.link_to()) 75 76 return None 77 78 def update_preferences(self): 79 80 "Update the stored preferences." 81 82 settings = self.get_current_preferences() 83 prefs = self.get_preferences() 84 errors = [] 85 86 for name, value in settings.items(): 87 choices = prefs.known_key_choices.get(name) 88 if choices and not choices.has_key(value): 89 errors.append(name) 90 91 if errors: 92 return errors 93 94 for name, value in settings.items(): 95 prefs[name] = value 96 97 # Request logic methods. 98 99 def is_initial_load(self): 100 101 "Return whether the event is being loaded and shown for the first time." 102 103 return not self.env.get_args().has_key("editing") 104 105 def get_stored_preferences(self): 106 107 "Return stored preference information for the current user." 108 109 prefs = self.get_preferences() 110 return dict(prefs.items()) 111 112 def get_current_preferences(self): 113 114 "Return the preferences currently being edited." 115 116 if self.is_initial_load(): 117 return self.get_stored_preferences() 118 else: 119 return dict([(name, values and values[0] or "") for (name, values) in self.env.get_args().items()]) 120 121 # Output fragment methods. 122 123 def show_preferences(self, errors=None): 124 125 "Show the preferences, indicating any 'errors' in the output." 126 127 _ = self.get_translator() 128 129 page = self.page 130 settings = self.get_current_preferences() 131 prefs = self.get_preferences() 132 133 # Add a hidden control to help determine whether editing has already begun. 134 135 self.control("editing", "hidden", "true") 136 137 # Show the range of preferences, getting all possible entries and using 138 # configuration defaults. 139 140 page.table(class_="profile", cellspacing=5, cellpadding=5) 141 page.thead() 142 page.tr() 143 page.th(_("Preferences"), class_="mainheading", colspan=2) 144 page.tr.close() 145 page.thead.close() 146 page.tbody() 147 148 for name, label in self.pref_labels: 149 value = settings.get(name) 150 default = prefs.known_keys.get(name) 151 choices = prefs.known_key_choices.get(name) 152 153 page.tr() 154 page.th(class_="profileheading %s%s" % (name, errors and name in errors and " error" or "")) 155 page.label(_(label), for_=name) 156 page.th.close() 157 page.td() 158 159 # For unrestricted fields, show a text field. 160 161 if not choices: 162 page.input(name=name, value=(value or default), type="text", class_="preference", id_=name) 163 164 # Otherwise, obtain the choices, localise the labels and show a 165 # menu control. 166 167 else: 168 choices = [(key, _(value_label)) for (key, value_label) in choices.items()] 169 choices.sort() 170 self.menu(name, default, choices, value is not None and [value] or None, class_="preference") 171 172 page.td.close() 173 page.tr.close() 174 175 page.tbody.close() 176 page.table.close() 177 178 def show_controls(self): 179 180 "Show controls for performing actions." 181 182 _ = self.get_translator() 183 184 page = self.page 185 186 page.p(class_="controls") 187 page.input(name="save", type="submit", value=_("Save")) 188 page.input(name="cancel", type="submit", value=_("Cancel")) 189 page.p.close() 190 191 # Full page output methods. 192 193 def show(self): 194 195 "Show the preferences of a user." 196 197 page = self.page 198 errors = self.handle_request() 199 200 if not errors: 201 return True 202 203 _ = self.get_translator() 204 205 self.new_page(title=_("Profile")) 206 page.form(method="POST") 207 self.validator() 208 self.show_preferences(errors) 209 self.show_controls() 210 page.form.close() 211 212 return True 213 214 # vim: tabstop=4 expandtab shiftwidth=4