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