# HG changeset patch # User Paul Boddie # Date 1422740052 -3600 # Node ID 7dc75bb19e9111a3289fa07dbc430c3aceaca65c # Parent 5711bd8d400db53b3a7c7ae318a73dea79a0dd7c Introduced Unicode conversion of form field values; restructured the event form and controls to enclose event details, initially handling the summary property. Made the event display more presentable. diff -r 5711bd8d400d -r 7dc75bb19e91 htdocs/styles.css --- a/htdocs/styles.css Sat Jan 31 22:28:33 2015 +0100 +++ b/htdocs/styles.css Sat Jan 31 22:34:12 2015 +0100 @@ -1,4 +1,7 @@ -table#calendar { +/* Table styling. */ + +table#calendar, +table#object { border: 2px solid #000; } @@ -18,14 +21,19 @@ background-color: #faa; } -th.dayheading { +th.dayheading, +th.mainheading { background-color: #f85; } -th.timeslot { +th.timeslot, +th.objectheading { vertical-align: top; + white-space: nowrap; +} + +th.timeslot { padding-top: 0; - white-space: nowrap; } td.event { diff -r 5711bd8d400d -r 7dc75bb19e91 imip_manager.py --- a/imip_manager.py Sat Jan 31 22:28:33 2015 +0100 +++ b/imip_manager.py Sat Jan 31 22:34:12 2015 +0100 @@ -53,7 +53,8 @@ "A CGI-compatible environment." - def __init__(self): + def __init__(self, charset=None): + self.charset = charset self.args = None self.method = None self.path = None @@ -64,7 +65,15 @@ if self.args is None: if self.get_method() != "POST": setenv("QUERY_STRING", "") - self.args = cgi.parse(keep_blank_values=True) + args = cgi.parse(keep_blank_values=True) + + if not self.charset: + self.args = args + else: + self.args = {} + for key, values in args.items(): + self.args[key] = [unicode(value, self.charset) for value in values] + return self.args def get_method(self): @@ -196,7 +205,9 @@ def __init__(self, messenger=None): self.messenger = messenger or Messenger() - self.env = CGIEnvironment() + self.encoding = "utf-8" + self.env = CGIEnvironment(self.encoding) + user = self.env.get_user() self.user = user and get_uri(user) or None self.preferences = None @@ -205,7 +216,6 @@ self.out = self.env.get_output() self.page = markup.page() - self.encoding = "utf-8" self.store = imip_store.FileStore() self.objects = {} @@ -381,10 +391,10 @@ self.redirect(self.env.new_url(uid)) - def handle_request(self, uid, request, queued): + def handle_request(self, uid, obj, queued): """ - Handle actions involving the given 'uid' and 'request' object, where + Handle actions involving the given 'uid' and 'obj' object, where 'queued' indicates that the object has not yet been handled. """ @@ -393,6 +403,14 @@ args = self.env.get_args() handled = True + # Update the object. + + if args.has_key("summary"): + details = self._get_details(obj) + details["SUMMARY"] = [(args["summary"][0], {})] + + # Process any action. + accept = args.has_key("accept") decline = args.has_key("decline") invite = args.has_key("invite") @@ -400,9 +418,9 @@ if accept or decline or invite: - handler = ManagerHandler(request, self.user, self.messenger) + handler = ManagerHandler(obj, self.user, self.messenger) - # Process the request and remove it from the list. + # Process the object and remove it from the list of requests. if (accept or decline) and handler.process_received_request(accept, update) or \ invite and handler.process_created_request(update): @@ -418,20 +436,23 @@ else: handled = False + # Upon handling an action, redirect to the main page. + if handled: self.redirect(self.env.get_path()) return handled - def show_request_form(self, obj, needs_action): + def show_request_controls(self, obj, needs_action): """ - Show a form for a request concerning 'obj', indicating whether action is - needed if 'needs_action' is specified as a true value. + Show form controls for a request concerning 'obj', indicating whether + action is needed if 'needs_action' is specified as a true value. """ + page = self.page + details = self._get_details(obj) - is_organiser = get_value(details, "ORGANIZER") == self.user if not is_organiser: @@ -441,39 +462,37 @@ if attendee_attr: partstat = attendee_attr.get("PARTSTAT") if partstat == "ACCEPTED": - self.page.p("This request has been accepted.") + page.p("This request has been accepted.") elif partstat == "DECLINED": - self.page.p("This request has been declined.") + page.p("This request has been declined.") else: - self.page.p("This request has not yet been dealt with.") + page.p("This request has not yet been dealt with.") if needs_action: - self.page.p("An action is required for this request:") + page.p("An action is required for this request:") else: - self.page.p("This request can be updated as follows:") + page.p("This request can be updated as follows:") - self.page.form(method="POST") - self.page.p() + page.p() # Show appropriate options depending on the role of the user. if is_organiser: - self.page.input(name="invite", type="submit", value="Invite") + page.input(name="invite", type="submit", value="Invite") else: - self.page.input(name="accept", type="submit", value="Accept") - self.page.add(" ") - self.page.input(name="decline", type="submit", value="Decline") + page.input(name="accept", type="submit", value="Accept") + page.add(" ") + page.input(name="decline", type="submit", value="Decline") - self.page.add(" ") - self.page.input(name="discard", type="submit", value="Discard") + page.add(" ") + page.input(name="discard", type="submit", value="Discard") # Updated objects need to have details updated upon sending. if not needs_action: - self.page.input(name="update", type="hidden", value="true") + page.input(name="update", type="hidden", value="true") - self.page.p.close() - self.page.form.close() + page.p.close() object_labels = { "SUMMARY" : "Summary", @@ -483,7 +502,7 @@ "ATTENDEE" : "Attendee", } - def show_object_on_page(self, uid, obj): + def show_object_on_page(self, uid, obj, needs_action): """ Show the calendar object with the given 'uid' and representation 'obj' @@ -491,6 +510,7 @@ """ page = self.page + page.form(method="POST") # Obtain the user's timezone. @@ -501,7 +521,13 @@ details = self._get_details(obj) - page.table(cellspacing=5, cellpadding=5) + page.table(id="object", cellspacing=5, cellpadding=5) + page.thead() + page.tr() + page.th("Event", class_="mainheading", colspan=2) + page.tr.close() + page.thead.close() + page.tbody() for name in ["SUMMARY", "DTSTART", "DTEND", "ORGANIZER", "ATTENDEE"]: page.tr() @@ -518,6 +544,16 @@ page.td(value) page.tr.close() + # Handle the summary specially. + + elif name == "SUMMARY": + value = get_value(details, name) + page.th(label, class_="objectheading") + page.td() + page.input(name="summary", type="text", value=value, size=80) + page.td.close() + page.tr.close() + # Handle potentially many values. else: @@ -543,6 +579,7 @@ page.td.close() page.tr.close() + page.tbody.close() page.table.close() dtstart = format_datetime(get_utc_datetime(details, "DTSTART")) @@ -578,6 +615,9 @@ found_details = self._get_details(found_obj) page.a(get_value(found_details, "SUMMARY"), href=self.env.new_url(found_uid)) + self.show_request_controls(obj, needs_action) + page.form.close() + def show_requests_on_page(self): "Show requests for the current user." @@ -671,10 +711,7 @@ return True self.new_page(title="Event") - - self.show_object_on_page(uid, obj) - - self.show_request_form(obj, is_request and not handled) + self.show_object_on_page(uid, obj, is_request and not handled) return True