paul@922 | 1 | #!/usr/bin/env python |
paul@922 | 2 | |
paul@922 | 3 | """ |
paul@922 | 4 | A Web interface to the user profile. |
paul@922 | 5 | |
paul@922 | 6 | Copyright (C) 2015 Paul Boddie <paul@boddie.org.uk> |
paul@922 | 7 | |
paul@922 | 8 | This program is free software; you can redistribute it and/or modify it under |
paul@922 | 9 | the terms of the GNU General Public License as published by the Free Software |
paul@922 | 10 | Foundation; either version 3 of the License, or (at your option) any later |
paul@922 | 11 | version. |
paul@922 | 12 | |
paul@922 | 13 | This program is distributed in the hope that it will be useful, but WITHOUT |
paul@922 | 14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@922 | 15 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
paul@922 | 16 | details. |
paul@922 | 17 | |
paul@922 | 18 | You should have received a copy of the GNU General Public License along with |
paul@922 | 19 | this program. If not, see <http://www.gnu.org/licenses/>. |
paul@922 | 20 | """ |
paul@922 | 21 | |
paul@923 | 22 | from imipweb.resource import FormUtilities, ResourceClient |
paul@922 | 23 | |
paul@923 | 24 | class ProfilePage(ResourceClient, FormUtilities): |
paul@922 | 25 | |
paul@922 | 26 | "A request handler for the user profile page." |
paul@922 | 27 | |
paul@923 | 28 | # See: imiptools.config, imiptools.profile |
paul@922 | 29 | |
paul@923 | 30 | pref_labels = [ |
paul@923 | 31 | ("participating" , "Participate in the calendar system"), |
paul@923 | 32 | ("CN" , "Your common name"), |
paul@923 | 33 | ("LANG" , "Language"), |
paul@923 | 34 | ("TZID" , "Time zone/regime"), |
paul@923 | 35 | ("incoming" , "How to present incoming calendar messages"), |
paul@923 | 36 | ("freebusy_sharing" , "Share free/busy information"), |
paul@923 | 37 | ("freebusy_bundling" , "Bundle free/busy details with messages"), |
paul@923 | 38 | ("freebusy_publishing" , "Publish free/busy details via the Web"), |
paul@923 | 39 | ("freebusy_messages" , "Deliver details of received free/busy messages"), |
paul@923 | 40 | ("add_method_response" , "How to respond to messages adding events"), |
paul@923 | 41 | ("event_refreshing" , "How to handle event refresh requests"), |
paul@923 | 42 | ("organiser_replacement" , "Recognise whom as a new organiser of an event?"), |
paul@923 | 43 | ] |
paul@922 | 44 | |
paul@922 | 45 | def handle_request(self): |
paul@922 | 46 | args = self.env.get_args() |
paul@922 | 47 | save = args.has_key("save") |
paul@922 | 48 | cancel = args.has_key("cancel") |
paul@922 | 49 | action = save or cancel |
paul@922 | 50 | |
paul@922 | 51 | if not action: |
paul@922 | 52 | return ["action"] |
paul@922 | 53 | |
paul@923 | 54 | if save: |
paul@923 | 55 | errors = self.update_preferences() |
paul@923 | 56 | if errors: |
paul@923 | 57 | return errors |
paul@923 | 58 | else: |
paul@923 | 59 | self.redirect(self.link_to()) |
paul@923 | 60 | |
paul@923 | 61 | elif cancel: |
paul@923 | 62 | self.redirect(self.link_to()) |
paul@923 | 63 | |
paul@922 | 64 | return None |
paul@922 | 65 | |
paul@923 | 66 | def update_preferences(self): |
paul@923 | 67 | |
paul@923 | 68 | "Update the stored preferences." |
paul@923 | 69 | |
paul@923 | 70 | settings = self.get_current_preferences() |
paul@923 | 71 | prefs = self.get_preferences() |
paul@923 | 72 | errors = [] |
paul@923 | 73 | |
paul@923 | 74 | for name, value in settings.items(): |
paul@923 | 75 | choices = prefs.known_key_choices.get(name) |
paul@923 | 76 | if choices and not choices.has_key(value): |
paul@923 | 77 | errors.append(name) |
paul@923 | 78 | |
paul@923 | 79 | if errors: |
paul@923 | 80 | return errors |
paul@923 | 81 | |
paul@923 | 82 | for name, value in settings.items(): |
paul@923 | 83 | prefs[name] = value |
paul@923 | 84 | |
paul@923 | 85 | # Request logic methods. |
paul@923 | 86 | |
paul@923 | 87 | def is_initial_load(self): |
paul@923 | 88 | |
paul@923 | 89 | "Return whether the event is being loaded and shown for the first time." |
paul@923 | 90 | |
paul@923 | 91 | return not self.env.get_args().has_key("editing") |
paul@923 | 92 | |
paul@923 | 93 | def get_stored_preferences(self): |
paul@923 | 94 | |
paul@923 | 95 | "Return stored preference information for the current user." |
paul@923 | 96 | |
paul@923 | 97 | prefs = self.get_preferences() |
paul@923 | 98 | return dict(prefs.items()) |
paul@923 | 99 | |
paul@923 | 100 | def get_current_preferences(self): |
paul@923 | 101 | |
paul@923 | 102 | "Return the preferences currently being edited." |
paul@923 | 103 | |
paul@923 | 104 | if self.is_initial_load(): |
paul@923 | 105 | return self.get_stored_preferences() |
paul@923 | 106 | else: |
paul@923 | 107 | return dict([(name, values and values[0] or "") for (name, values) in self.env.get_args().items()]) |
paul@923 | 108 | |
paul@922 | 109 | # Output fragment methods. |
paul@922 | 110 | |
paul@922 | 111 | def show_preferences(self, errors=None): |
paul@923 | 112 | |
paul@923 | 113 | "Show the preferences, indicating any 'errors' in the output." |
paul@923 | 114 | |
paul@922 | 115 | page = self.page |
paul@923 | 116 | settings = self.get_current_preferences() |
paul@923 | 117 | prefs = self.get_preferences() |
paul@923 | 118 | |
paul@923 | 119 | # Add a hidden control to help determine whether editing has already begun. |
paul@923 | 120 | |
paul@923 | 121 | self.control("editing", "hidden", "true") |
paul@922 | 122 | |
paul@922 | 123 | # Show the range of preferences, getting all possible entries and using |
paul@922 | 124 | # configuration defaults. |
paul@922 | 125 | |
paul@922 | 126 | page.table(class_="profile", cellspacing=5, cellpadding=5) |
paul@922 | 127 | page.thead() |
paul@922 | 128 | page.tr() |
paul@922 | 129 | page.th("Preferences", class_="mainheading", colspan=2) |
paul@922 | 130 | page.tr.close() |
paul@922 | 131 | page.thead.close() |
paul@922 | 132 | page.tbody() |
paul@922 | 133 | |
paul@923 | 134 | for name, label in self.pref_labels: |
paul@923 | 135 | value = settings.get(name) |
paul@923 | 136 | default = prefs.known_keys.get(name) |
paul@923 | 137 | choices = prefs.known_key_choices.get(name) |
paul@922 | 138 | |
paul@922 | 139 | page.tr() |
paul@922 | 140 | page.th(class_="profileheading %s%s" % (name, errors and name in errors and " error" or "")) |
paul@923 | 141 | page.label(label, for_=name) |
paul@922 | 142 | page.th.close() |
paul@922 | 143 | page.td() |
paul@923 | 144 | |
paul@923 | 145 | if not choices: |
paul@923 | 146 | page.input(name=name, value=(value or default), type="text", class_="preference", id_=name) |
paul@923 | 147 | else: |
paul@923 | 148 | choices = list(choices.items()) |
paul@923 | 149 | choices.sort() |
paul@977 | 150 | self.menu(name, default, choices, value is not None and [value] or None, class_="preference") |
paul@923 | 151 | |
paul@922 | 152 | page.td.close() |
paul@922 | 153 | page.tr.close() |
paul@922 | 154 | |
paul@922 | 155 | page.tbody.close() |
paul@922 | 156 | page.table.close() |
paul@922 | 157 | |
paul@923 | 158 | def show_controls(self): |
paul@923 | 159 | |
paul@923 | 160 | "Show controls for performing actions." |
paul@923 | 161 | |
paul@923 | 162 | page = self.page |
paul@923 | 163 | |
paul@923 | 164 | page.p(class_="controls") |
paul@923 | 165 | page.input(name="save", type="submit", value="Save") |
paul@923 | 166 | page.input(name="cancel", type="submit", value="Cancel") |
paul@923 | 167 | page.p.close() |
paul@923 | 168 | |
paul@922 | 169 | # Full page output methods. |
paul@922 | 170 | |
paul@922 | 171 | def show(self): |
paul@922 | 172 | |
paul@922 | 173 | "Show the preferences of a user." |
paul@922 | 174 | |
paul@923 | 175 | page = self.page |
paul@922 | 176 | errors = self.handle_request() |
paul@922 | 177 | |
paul@922 | 178 | if not errors: |
paul@922 | 179 | return True |
paul@922 | 180 | |
paul@922 | 181 | self.new_page(title="Profile") |
paul@923 | 182 | page.form(method="POST") |
paul@922 | 183 | self.show_preferences(errors) |
paul@923 | 184 | self.show_controls() |
paul@923 | 185 | page.form.close() |
paul@922 | 186 | |
paul@922 | 187 | return True |
paul@922 | 188 | |
paul@922 | 189 | # vim: tabstop=4 expandtab shiftwidth=4 |