1 #!/usr/bin/env python 2 3 """ 4 A Web interface to the user profile. 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 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 if save: 62 errors = self.update_preferences() 63 if errors: 64 return errors 65 else: 66 self.redirect(self.link_to()) 67 68 elif cancel: 69 self.redirect(self.link_to()) 70 71 return None 72 73 def update_preferences(self): 74 75 "Update the stored preferences." 76 77 settings = self.get_current_preferences() 78 prefs = self.get_preferences() 79 errors = [] 80 81 for name, value in settings.items(): 82 choices = prefs.known_key_choices.get(name) 83 if choices and not choices.has_key(value): 84 errors.append(name) 85 86 if errors: 87 return errors 88 89 for name, value in settings.items(): 90 prefs[name] = value 91 92 # Request logic methods. 93 94 def is_initial_load(self): 95 96 "Return whether the event is being loaded and shown for the first time." 97 98 return not self.env.get_args().has_key("editing") 99 100 def get_stored_preferences(self): 101 102 "Return stored preference information for the current user." 103 104 prefs = self.get_preferences() 105 return dict(prefs.items()) 106 107 def get_current_preferences(self): 108 109 "Return the preferences currently being edited." 110 111 if self.is_initial_load(): 112 return self.get_stored_preferences() 113 else: 114 return dict([(name, values and values[0] or "") for (name, values) in self.env.get_args().items()]) 115 116 # Output fragment methods. 117 118 def show_preferences(self, errors=None): 119 120 "Show the preferences, indicating any 'errors' in the output." 121 122 _ = self.get_translator() 123 124 page = self.page 125 settings = self.get_current_preferences() 126 prefs = self.get_preferences() 127 128 # Add a hidden control to help determine whether editing has already begun. 129 130 self.control("editing", "hidden", "true") 131 132 # Show the range of preferences, getting all possible entries and using 133 # configuration defaults. 134 135 page.table(class_="profile", cellspacing=5, cellpadding=5) 136 page.thead() 137 page.tr() 138 page.th("Preferences", class_="mainheading", colspan=2) 139 page.tr.close() 140 page.thead.close() 141 page.tbody() 142 143 for name, label in self.pref_labels: 144 value = settings.get(name) 145 default = prefs.known_keys.get(name) 146 choices = prefs.known_key_choices.get(name) 147 148 page.tr() 149 page.th(class_="profileheading %s%s" % (name, errors and name in errors and " error" or "")) 150 page.label(_(label), for_=name) 151 page.th.close() 152 page.td() 153 154 # For unrestricted fields, show a text field. 155 156 if not choices: 157 page.input(name=name, value=(value or default), type="text", class_="preference", id_=name) 158 159 # Otherwise, obtain the choices, localise the labels and show a 160 # menu control. 161 162 else: 163 choices = [(key, _(value_label)) for (key, value_label) in choices.items()] 164 choices.sort() 165 self.menu(name, default, choices, value is not None and [value] or None, class_="preference") 166 167 page.td.close() 168 page.tr.close() 169 170 page.tbody.close() 171 page.table.close() 172 173 def show_controls(self): 174 175 "Show controls for performing actions." 176 177 _ = self.get_translator() 178 179 page = self.page 180 181 page.p(class_="controls") 182 page.input(name="save", type="submit", value=_("Save")) 183 page.input(name="cancel", type="submit", value=_("Cancel")) 184 page.p.close() 185 186 # Full page output methods. 187 188 def show(self): 189 190 "Show the preferences of a user." 191 192 page = self.page 193 errors = self.handle_request() 194 195 if not errors: 196 return True 197 198 _ = self.get_translator() 199 200 self.new_page(title=_("Profile")) 201 page.form(method="POST") 202 self.show_preferences(errors) 203 self.show_controls() 204 page.form.close() 205 206 return True 207 208 # vim: tabstop=4 expandtab shiftwidth=4