# HG changeset patch # User Paul Boddie # Date 1428188966 -7200 # Node ID f481451fb49520ad41699ebd3dce01006892ad64 # Parent c511a0ed1bbc0c7db7fa7656ea01c54a828a9e68 Provided support for getting the current attendees of a viewed event, also introducing a convenience method for determining whether the current user is an organiser, hiding conflicting events where a user is only organising them. diff -r c511a0ed1bbc -r f481451fb495 imipweb/event.py --- a/imipweb/event.py Sun Apr 05 00:58:32 2015 +0200 +++ b/imipweb/event.py Sun Apr 05 01:09:26 2015 +0200 @@ -58,6 +58,9 @@ (None, "Not indicated"), ] + def is_organiser(self, obj): + return get_uri(obj.get_value("ORGANIZER")) == self.user + # Request logic methods. def handle_request(self, uid, recurrenceid, obj): @@ -92,14 +95,12 @@ self.redirect(self.env.get_path()) return None - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user - # Obtain the user's timezone and process datetime values. update = False periods = None - if is_organiser: + if self.is_organiser(obj): periods, errors = self.handle_all_period_controls() if errors: return errors @@ -110,7 +111,7 @@ # Update principal event details if organiser. - if is_organiser: + if self.is_organiser(obj): # Update time periods (main and recurring). @@ -147,7 +148,7 @@ if reply and handler.process_received_request(update): self.remove_request(uid, recurrenceid) - elif is_organiser and (invite or cancel): + elif self.is_organiser(obj) and (invite or cancel): if handler.process_created_request( invite and "REQUEST" or "CANCEL", update, to_cancel): @@ -407,6 +408,24 @@ dtend, dtend_attr = dtstart, dtstart_attr return (dtstart, dtstart_attr), (dtend, dtend_attr) + def get_current_attendees(self, obj): + + """ + Return attendees for 'obj' depending on whether the object is being + edited. + """ + + args = self.env.get_args() + initial_load = not args.has_key("editing") + + if initial_load or not self.is_organiser(obj): + return self.get_existing_attendees(obj) + else: + return self.get_attendees() + + def get_existing_attendees(self, obj): + return uri_values(obj.get_values("ATTENDEE") or []) + def get_attendees(self): """ @@ -421,6 +440,8 @@ ordered_attendees = [] for attendee in attendees: + if not attendee.strip(): + continue attendee = get_uri(attendee) if attendee not in unique_attendees: unique_attendees.add(attendee) @@ -455,9 +476,7 @@ page = self.page args = self.env.get_args() - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user - - attendees = uri_values((obj.get_values("ATTENDEE") or []) + filter(None, args.get("attendee", []))) + attendees = self.get_current_attendees(obj) is_attendee = self.user in attendees is_request = (obj.get_value("UID"), obj.get_value("RECURRENCE-ID")) in self._get_requests() @@ -466,7 +485,7 @@ # Show appropriate options depending on the role of the user. - if is_attendee and not is_organiser: + if is_attendee and not self.is_organiser(obj): page.p("An action is required for this request:") page.p() @@ -477,7 +496,7 @@ page.input(name="ignore", type="submit", value="Do nothing for now") page.p.close() - if is_organiser: + if self.is_organiser(obj): page.p("As organiser, you can perform the following:") if have_other_attendees: @@ -520,12 +539,12 @@ # Obtain basic event information, showing any necessary editing controls. - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user initial_load = not args.has_key("editing") - existing_attendees = uri_values(obj.get_values("ATTENDEE") or []) - attendees = is_organiser and self.update_attendees(obj) or \ - (initial_load or not is_organiser) and existing_attendees or [] + if initial_load or not self.is_organiser(obj): + attendees = self.get_existing_attendees(obj) + else: + attendees = self.update_attendees(obj) (dtstart, dtstart_attr), (dtend, dtend_attr) = self.get_event_period(obj) self.show_object_datetime_controls(dtstart, dtend) @@ -580,7 +599,7 @@ value = args.get("summary", [obj.get_value(name)])[0] page.td() - if is_organiser: + if self.is_organiser(obj): page.input(name="summary", type="text", value=value, size=80) else: page.add(value) @@ -606,7 +625,7 @@ # Allow more attendees to be specified. - if is_organiser: + if self.is_organiser(obj): i = len(attendees) if not first: @@ -653,7 +672,6 @@ page = self.page args = self.env.get_args() - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user existing = attendee_attr is not None partstat = attendee_attr and attendee_attr.get("PARTSTAT") @@ -661,7 +679,7 @@ # Show a form control as organiser for new attendees. - if is_organiser and not existing: + if self.is_organiser(obj) and not existing: page.input(name="attendee", type="value", value=attendee, size="40") else: page.input(name="attendee", type="hidden", value=attendee) @@ -677,7 +695,7 @@ # button in order to refresh the page and show a control for # the current user, if indicated. - elif is_organiser and not existing: + elif self.is_organiser(obj) and not existing: page.input(name="partstat-refresh", type="submit", value="refresh", id="partstat-%d" % i, class_="refresh") page.label(dict(self.partstat_items).get(partstat, ""), for_="partstat-%s" % i, class_="partstat") else: @@ -685,7 +703,7 @@ # Permit organisers to remove attendees. - if is_organiser: + if self.is_organiser(obj): # Permit the removal of newly-added attendees. @@ -703,7 +721,6 @@ "Show recurrences for the object having the given representation 'obj'." page = self.page - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user # Obtain any parent object if this object is a specific recurrence. @@ -725,7 +742,7 @@ if len(periods) == 1: return - if is_organiser: + if self.is_organiser(obj): page.p("This event recurs on the following occasions within the next %d days:" % self.get_window_size()) else: page.p("This event occurs on the following occasions within the next %d days:" % self.get_window_size()) @@ -737,7 +754,7 @@ # Show each recurrence in a separate table if editable. - if is_organiser and explicit_periods: + if self.is_organiser(obj) and explicit_periods: for index, p in enumerate(periods[1:]): @@ -782,11 +799,12 @@ # Show only subsequent periods if organiser, since the principal # period will be the start and end datetimes. - for index, p in enumerate(is_organiser and periods[1:] or periods): + for index, p in enumerate(self.is_organiser(obj) and periods[1:] or periods): page.tr() self.show_recurrence_controls(obj, index, p.start, p.end, p.origin, recurrenceid, recurrenceids, True) self.show_recurrence_controls(obj, index, p.start, p.end, p.origin, recurrenceid, recurrenceids, False) page.tr.close() + page.tbody.close() page.table.close() @@ -798,6 +816,7 @@ """ page = self.page + recurrenceid = format_datetime(obj.get_utc_datetime("RECURRENCE-ID")) # Obtain the user's timezone. @@ -806,55 +825,70 @@ # Indicate whether there are conflicting events. - freebusy = self.store.get_freebusy(self.user) + conflicts = [] - if freebusy: + for participant in self.get_current_attendees(obj): + if participant == self.user: + freebusy = self.store.get_freebusy(participant) + else: + freebusy = self.store.get_freebusy_for_other(self.user, participant) + + if not freebusy: + continue # Obtain any time zone details from the suggested event. _dtstart, attr = obj.get_item("DTSTART") tzid = attr.get("TZID", tzid) - # Show any conflicts. + # Show any conflicts with periods of actual attendance. - conflicts = list([p for p in have_conflict(freebusy, periods, True) if p.uid != uid]) - conflicts.sort() + for p in have_conflict(freebusy, periods, True): + if (p.uid != uid or p.recurrenceid != recurrenceid) and p.transp != "ORG": + conflicts.append(p) - if conflicts: - page.p("This event conflicts with others:") + conflicts.sort() + + # Show any conflicts with periods of actual attendance. - page.table(cellspacing=5, cellpadding=5, class_="conflicts") - page.thead() - page.tr() - page.th("Event") - page.th("Start") - page.th("End") - page.tr.close() - page.thead.close() - page.tbody() + if conflicts: + page.p("This event conflicts with others:") - for p in conflicts: + page.table(cellspacing=5, cellpadding=5, class_="conflicts") + page.thead() + page.tr() + page.th("Event") + page.th("Start") + page.th("End") + page.tr.close() + page.thead.close() + page.tbody() - # Provide details of any conflicting event. + for p in conflicts: + + # Provide details of any conflicting event. - start = self.format_datetime(to_timezone(get_datetime(p.start), tzid), "long") - end = self.format_datetime(to_timezone(get_datetime(p.end), tzid), "long") + start = self.format_datetime(to_timezone(get_datetime(p.start), tzid), "long") + end = self.format_datetime(to_timezone(get_datetime(p.end), tzid), "long") - page.tr() + page.tr() - # Show the event summary for the conflicting event. + # Show the event summary for the conflicting event. - page.td() + page.td() + if p.summary: page.a(p.summary, href=self.link_to(p.uid)) - page.td.close() + else: + page.add("(Unspecified event)") + page.td.close() - page.td(start) - page.td(end) + page.td(start) + page.td(end) - page.tr.close() + page.tr.close() - page.tbody.close() - page.table.close() + page.tbody.close() + page.table.close() # Generation of controls within page fragments. @@ -926,7 +960,6 @@ """ page = self.page - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user # Change end dates to refer to the actual dates, not the iCalendar # "next day" dates. @@ -936,7 +969,7 @@ # Show controls for editing as organiser. - if is_organiser: + if self.is_organiser(obj): page.td(class_="objectvalue dt%s" % (show_start and "start" or "end")) if show_start: @@ -981,8 +1014,6 @@ sn = self._suffixed_name ssn = self._simple_suffixed_name - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user - # Change end dates to refer to the actual dates, not the iCalendar # "next day" dates. @@ -998,7 +1029,7 @@ # Show controls for editing as organiser. - if is_organiser and not replaced and origin != "RRULE": + if self.is_organiser(obj) and not replaced and origin != "RRULE": page.td(class_="objectvalue dt%s" % (show_start and "start" or "end")) if show_start: