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 page = self.page 119 settings = self.get_current_preferences() 120 prefs = self.get_preferences() 121 122 # Add a hidden control to help determine whether editing has already begun. 123 124 self.control("editing", "hidden", "true") 125 126 # Show the range of preferences, getting all possible entries and using 127 # configuration defaults. 128 129 page.table(class_="profile", cellspacing=5, cellpadding=5) 130 page.thead() 131 page.tr() 132 page.th("Preferences", class_="mainheading", colspan=2) 133 page.tr.close() 134 page.thead.close() 135 page.tbody() 136 137 for name, label in self.pref_labels: 138 value = settings.get(name) 139 default = prefs.known_keys.get(name) 140 choices = prefs.known_key_choices.get(name) 141 142 page.tr() 143 page.th(class_="profileheading %s%s" % (name, errors and name in errors and " error" or "")) 144 page.label(label, for_=name) 145 page.th.close() 146 page.td() 147 148 if not choices: 149 page.input(name=name, value=(value or default), type="text", class_="preference", id_=name) 150 else: 151 choices = list(choices.items()) 152 choices.sort() 153 self.menu(name, default, choices, value is not None and [value] or None, class_="preference") 154 155 page.td.close() 156 page.tr.close() 157 158 page.tbody.close() 159 page.table.close() 160 161 def show_controls(self): 162 163 "Show controls for performing actions." 164 165 page = self.page 166 167 page.p(class_="controls") 168 page.input(name="save", type="submit", value="Save") 169 page.input(name="cancel", type="submit", value="Cancel") 170 page.p.close() 171 172 # Full page output methods. 173 174 def show(self): 175 176 "Show the preferences of a user." 177 178 page = self.page 179 errors = self.handle_request() 180 181 if not errors: 182 return True 183 184 self.new_page(title="Profile") 185 page.form(method="POST") 186 self.show_preferences(errors) 187 self.show_controls() 188 page.form.close() 189 190 return True 191 192 # vim: tabstop=4 expandtab shiftwidth=4