imip-agent

imipweb/profile.py

1258:0b18f5594278
2017-09-12 Paul Boddie Merged changes from concurrent branch.
     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