1.1 --- a/htdocs/styles.css Sun Oct 25 01:24:56 2015 +0200
1.2 +++ b/htdocs/styles.css Sun Oct 25 01:25:29 2015 +0200
1.3 @@ -28,6 +28,7 @@
1.4
1.5 table.conflicts,
1.6 table.counters,
1.7 +table.profile,
1.8 table.recurrence,
1.9 table.object {
1.10 border: 2px solid #000;
1.11 @@ -55,7 +56,12 @@
1.12 width: 100%;
1.13 }
1.14
1.15 +table.profile th.mainheading {
1.16 + background-color: #7bf;
1.17 +}
1.18 +
1.19 th.timeslot,
1.20 +th.profileheading,
1.21 th.objectheading {
1.22 white-space: nowrap;
1.23 }
1.24 @@ -64,6 +70,11 @@
1.25 background-color: #fca;
1.26 }
1.27
1.28 +th.profileheading {
1.29 + background-color: #bef;
1.30 + text-align: right;
1.31 +}
1.32 +
1.33 th.timeslot {
1.34 padding-top: 0;
1.35 vertical-align: top;
1.36 @@ -120,6 +131,7 @@
1.37 color: #009;
1.38 }
1.39
1.40 +th.profileheading.error,
1.41 th.objectheading.error {
1.42 background-color: #f77;
1.43 }
2.1 --- a/imip_manager.py Sun Oct 25 01:24:56 2015 +0200
2.2 +++ b/imip_manager.py Sun Oct 25 01:25:29 2015 +0200
2.3 @@ -29,6 +29,7 @@
2.4
2.5 from imipweb.calendar import CalendarPage
2.6 from imipweb.event import EventPage
2.7 +from imipweb.profile import ProfilePage
2.8 from imipweb.resource import ResourceClient
2.9
2.10 class Manager(ResourceClient):
2.11 @@ -43,6 +44,8 @@
2.12
2.13 if not path_info:
2.14 CalendarPage(self).show()
2.15 + elif path_info == "profile":
2.16 + ProfilePage(self).show()
2.17 elif EventPage(self).show(path_info):
2.18 pass
2.19 else:
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/imipweb/profile.py Sun Oct 25 01:25:29 2015 +0200
3.3 @@ -0,0 +1,112 @@
3.4 +#!/usr/bin/env python
3.5 +
3.6 +"""
3.7 +A Web interface to the user profile.
3.8 +
3.9 +Copyright (C) 2015 Paul Boddie <paul@boddie.org.uk>
3.10 +
3.11 +This program is free software; you can redistribute it and/or modify it under
3.12 +the terms of the GNU General Public License as published by the Free Software
3.13 +Foundation; either version 3 of the License, or (at your option) any later
3.14 +version.
3.15 +
3.16 +This program is distributed in the hope that it will be useful, but WITHOUT
3.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
3.19 +details.
3.20 +
3.21 +You should have received a copy of the GNU General Public License along with
3.22 +this program. If not, see <http://www.gnu.org/licenses/>.
3.23 +"""
3.24 +
3.25 +from imiptools import config
3.26 +from imipweb.resource import ResourceClient
3.27 +
3.28 +class ProfilePage(ResourceClient):
3.29 +
3.30 + "A request handler for the user profile page."
3.31 +
3.32 + # See: imiptools.profile
3.33 +
3.34 + pref_labels = {
3.35 + "CN" : "Common name",
3.36 + "LANG" : "Language",
3.37 + "TZID" : "Time zone/regime",
3.38 + "add_method_response" : "Respond to messages adding events with...",
3.39 + "event_refreshing" : "Handle event refresh requests automatically",
3.40 + "freebusy_bundling" : "Bundle free/busy details with messages",
3.41 + "freebusy_messages" : "Notify about received free/busy messages",
3.42 + "freebusy_offers" : "Reserve time periods when making counter-proposals",
3.43 + "freebusy_publishing" : "Publish free/busy details via the Web",
3.44 + "freebusy_sharing" : "Share free/busy information at all",
3.45 + "incoming" : "Incoming calendar messages presented using...",
3.46 + "organiser_replacement" : "Recognise which kinds of participants as replacement organisers...",
3.47 + "participating" : "Participate in the calendar system at all?",
3.48 + "permitted_times" : None,
3.49 + }
3.50 +
3.51 + def handle_request(self):
3.52 + args = self.env.get_args()
3.53 + save = args.has_key("save")
3.54 + cancel = args.has_key("cancel")
3.55 + action = save or cancel
3.56 +
3.57 + if not action:
3.58 + return ["action"]
3.59 +
3.60 + return None
3.61 +
3.62 + # Output fragment methods.
3.63 +
3.64 + def show_preferences(self, errors=None):
3.65 + page = self.page
3.66 +
3.67 + # Show the range of preferences, getting all possible entries and using
3.68 + # configuration defaults.
3.69 +
3.70 + prefs = self.get_preferences()
3.71 + items = prefs.items(True, None, True)
3.72 + items.sort()
3.73 +
3.74 + page.table(class_="profile", cellspacing=5, cellpadding=5)
3.75 + page.thead()
3.76 + page.tr()
3.77 + page.th("Preferences", class_="mainheading", colspan=2)
3.78 + page.tr.close()
3.79 + page.thead.close()
3.80 + page.tbody()
3.81 +
3.82 + for name, value in items:
3.83 + label = self.pref_labels.get(name)
3.84 + if not label:
3.85 + continue
3.86 +
3.87 + page.tr()
3.88 + page.th(class_="profileheading %s%s" % (name, errors and name in errors and " error" or ""))
3.89 + page.label(label)
3.90 + page.th.close()
3.91 + page.td()
3.92 + page.input(name=name, value=(value or ""), type="text", class_="preference")
3.93 + page.td.close()
3.94 + page.tr.close()
3.95 +
3.96 + page.tbody.close()
3.97 + page.table.close()
3.98 +
3.99 + # Full page output methods.
3.100 +
3.101 + def show(self):
3.102 +
3.103 + "Show the preferences of a user."
3.104 +
3.105 + errors = self.handle_request()
3.106 +
3.107 + if not errors:
3.108 + return True
3.109 +
3.110 + self.new_page(title="Profile")
3.111 + self.show_preferences(errors)
3.112 +
3.113 + return True
3.114 +
3.115 +# vim: tabstop=4 expandtab shiftwidth=4