imip-agent

imipweb/profile.py

1039:a12150034cbd
2016-02-08 Paul Boddie Added a journal storage area, maintaining quota and collective scheduling data for scheduling decisions. Introduced confirmation and retraction functions for resource scheduling so that quotas and collective schedules can be maintained and thus queried by scheduling functions. Updated the documentation, tools and tests.
     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