imip-agent

Annotated imipweb/profile.py

1350:2b0d3d4eff21
2017-10-20 Paul Boddie Return the loaded object from the load_object method. client-editing-simplification
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@1120 6
Copyright (C) 2015, 2016 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@1008 24
# Fake gettext method for strings to be translated later.
paul@1008 25
paul@1008 26
_ = lambda s: s
paul@1008 27
paul@923 28
class ProfilePage(ResourceClient, FormUtilities):
paul@922 29
paul@922 30
    "A request handler for the user profile page."
paul@922 31
paul@923 32
    # See: imiptools.config, imiptools.profile
paul@999 33
    # NOTE: This could be defined in another format and generated or computed
paul@999 34
    # NOTE: for this class and for the documentation.
paul@999 35
    # See: docs/tools/profile_prefs.sh
paul@922 36
paul@923 37
    pref_labels = [
paul@1008 38
        ("participating"         , _("Participate in the calendar system")),
paul@1008 39
        ("CN"                    , _("Your common name")),
paul@1008 40
        ("LANG"                  , _("Language")),
paul@1008 41
        ("TZID"                  , _("Time zone/regime")),
paul@1008 42
        ("incoming"              , _("How to present incoming calendar messages")),
paul@1008 43
        ("freebusy_sharing"      , _("Share free/busy information")),
paul@1008 44
        ("freebusy_bundling"     , _("Bundle free/busy details with messages")),
paul@1008 45
        ("freebusy_publishing"   , _("Publish free/busy details via the Web")),
paul@1008 46
        ("freebusy_messages"     , _("Deliver details of received free/busy messages")),
paul@1008 47
        ("add_method_response"   , _("How to respond to messages adding events")),
paul@1008 48
        ("event_refreshing"      , _("How to handle event refresh requests")),
paul@1008 49
        ("organiser_replacement" , _("Recognise whom as a new organiser of an event?")),
paul@923 50
        ]
paul@922 51
paul@922 52
    def handle_request(self):
paul@922 53
        args = self.env.get_args()
paul@922 54
        save = args.has_key("save")
paul@922 55
        cancel = args.has_key("cancel")
paul@922 56
        action = save or cancel
paul@922 57
paul@922 58
        if not action:
paul@922 59
            return ["action"]
paul@922 60
paul@1162 61
        # Check the validation token.
paul@1162 62
paul@1162 63
        if not self.check_validation_token():
paul@1162 64
            return ["token"]
paul@1162 65
paul@923 66
        if save:
paul@923 67
            errors = self.update_preferences()
paul@923 68
            if errors:
paul@923 69
                return errors
paul@923 70
            else:
paul@923 71
                self.redirect(self.link_to())
paul@923 72
paul@923 73
        elif cancel:
paul@923 74
            self.redirect(self.link_to())
paul@923 75
paul@922 76
        return None
paul@922 77
paul@923 78
    def update_preferences(self):
paul@923 79
paul@923 80
        "Update the stored preferences."
paul@923 81
paul@923 82
        settings = self.get_current_preferences()
paul@923 83
        prefs = self.get_preferences()
paul@923 84
        errors = []
paul@923 85
paul@923 86
        for name, value in settings.items():
paul@923 87
            choices = prefs.known_key_choices.get(name)
paul@923 88
            if choices and not choices.has_key(value):
paul@923 89
                errors.append(name)
paul@923 90
paul@923 91
        if errors:
paul@923 92
            return errors
paul@923 93
paul@923 94
        for name, value in settings.items():
paul@923 95
            prefs[name] = value
paul@923 96
paul@923 97
    # Request logic methods.
paul@923 98
paul@923 99
    def is_initial_load(self):
paul@923 100
paul@923 101
        "Return whether the event is being loaded and shown for the first time."
paul@923 102
paul@923 103
        return not self.env.get_args().has_key("editing")
paul@923 104
paul@923 105
    def get_stored_preferences(self):
paul@923 106
paul@923 107
        "Return stored preference information for the current user."
paul@923 108
paul@923 109
        prefs = self.get_preferences()
paul@923 110
        return dict(prefs.items())
paul@923 111
paul@923 112
    def get_current_preferences(self):
paul@923 113
paul@923 114
        "Return the preferences currently being edited."
paul@923 115
paul@923 116
        if self.is_initial_load():
paul@923 117
            return self.get_stored_preferences()
paul@923 118
        else:
paul@923 119
            return dict([(name, values and values[0] or "") for (name, values) in self.env.get_args().items()])
paul@923 120
paul@922 121
    # Output fragment methods.
paul@922 122
paul@922 123
    def show_preferences(self, errors=None):
paul@923 124
paul@923 125
        "Show the preferences, indicating any 'errors' in the output."
paul@923 126
paul@1005 127
        _ = self.get_translator()
paul@1005 128
paul@922 129
        page = self.page
paul@923 130
        settings = self.get_current_preferences()
paul@923 131
        prefs = self.get_preferences()
paul@923 132
paul@923 133
        # Add a hidden control to help determine whether editing has already begun.
paul@923 134
paul@923 135
        self.control("editing", "hidden", "true")
paul@922 136
paul@922 137
        # Show the range of preferences, getting all possible entries and using
paul@922 138
        # configuration defaults.
paul@922 139
paul@922 140
        page.table(class_="profile", cellspacing=5, cellpadding=5)
paul@922 141
        page.thead()
paul@922 142
        page.tr()
paul@1120 143
        page.th(_("Preferences"), class_="mainheading", colspan=2)
paul@922 144
        page.tr.close()
paul@922 145
        page.thead.close()
paul@922 146
        page.tbody()
paul@922 147
paul@923 148
        for name, label in self.pref_labels:
paul@923 149
            value = settings.get(name)
paul@923 150
            default = prefs.known_keys.get(name)
paul@923 151
            choices = prefs.known_key_choices.get(name)
paul@922 152
paul@922 153
            page.tr()
paul@922 154
            page.th(class_="profileheading %s%s" % (name, errors and name in errors and " error" or ""))
paul@1008 155
            page.label(_(label), for_=name)
paul@922 156
            page.th.close()
paul@922 157
            page.td()
paul@923 158
paul@1005 159
            # For unrestricted fields, show a text field.
paul@1005 160
paul@923 161
            if not choices:
paul@923 162
                page.input(name=name, value=(value or default), type="text", class_="preference", id_=name)
paul@1005 163
paul@1005 164
            # Otherwise, obtain the choices, localise the labels and show a
paul@1005 165
            # menu control.
paul@1005 166
paul@923 167
            else:
paul@1008 168
                choices = [(key, _(value_label)) for (key, value_label) in choices.items()]
paul@923 169
                choices.sort()
paul@977 170
                self.menu(name, default, choices, value is not None and [value] or None, class_="preference")
paul@923 171
paul@922 172
            page.td.close()
paul@922 173
            page.tr.close()
paul@922 174
paul@922 175
        page.tbody.close()
paul@922 176
        page.table.close()
paul@922 177
paul@923 178
    def show_controls(self):
paul@923 179
paul@923 180
        "Show controls for performing actions."
paul@923 181
paul@1008 182
        _ = self.get_translator()
paul@1008 183
paul@923 184
        page = self.page
paul@923 185
paul@923 186
        page.p(class_="controls")
paul@1008 187
        page.input(name="save", type="submit", value=_("Save"))
paul@1008 188
        page.input(name="cancel", type="submit", value=_("Cancel"))
paul@923 189
        page.p.close()
paul@923 190
paul@922 191
    # Full page output methods.
paul@922 192
paul@922 193
    def show(self):
paul@922 194
paul@922 195
        "Show the preferences of a user."
paul@922 196
paul@923 197
        page = self.page
paul@922 198
        errors = self.handle_request()
paul@922 199
paul@922 200
        if not errors:
paul@922 201
            return True
paul@922 202
paul@1008 203
        _ = self.get_translator()
paul@1008 204
paul@1008 205
        self.new_page(title=_("Profile"))
paul@923 206
        page.form(method="POST")
paul@1162 207
        self.validator()
paul@922 208
        self.show_preferences(errors)
paul@923 209
        self.show_controls()
paul@923 210
        page.form.close()
paul@922 211
paul@922 212
        return True
paul@922 213
paul@922 214
# vim: tabstop=4 expandtab shiftwidth=4