imip-agent

imipweb/profile.py

1031:fc1efc973849
2016-01-31 Paul Boddie Introduced the access control list scheduling function plus argument support. Moved scheduling function lookup into the scheduling module as part of the revised function invocation parsing activity, employing a new text processing module in imiptools. Added tests of the access control list functionality.
     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