1.1 --- a/imip_manager.py Wed Jan 28 14:29:24 2015 +0100
1.2 +++ b/imip_manager.py Wed Jan 28 16:43:04 2015 +0100
1.3 @@ -36,6 +36,7 @@
1.4 to_timezone
1.5 from imiptools.mail import Messenger
1.6 from imiptools.period import add_day_start_points, add_slots, convert_periods, \
1.7 + get_freebusy_details, \
1.8 get_scale, have_conflict, get_slots, get_spans, \
1.9 partition_by_day
1.10 from imiptools.profile import Preferences
1.11 @@ -441,6 +442,8 @@
1.12
1.13 requests = self._get_requests()
1.14
1.15 + self.page.div(id="pending-requests")
1.16 +
1.17 if requests:
1.18 self.page.p("Pending requests:")
1.19
1.20 @@ -459,6 +462,55 @@
1.21 else:
1.22 self.page.p("There are no pending requests.")
1.23
1.24 + self.page.div.close()
1.25 +
1.26 + def show_participants_on_page(self):
1.27 +
1.28 + "Show participants for scheduling purposes."
1.29 +
1.30 + args = self.env.get_args()
1.31 + participants = args.get("participants", [])
1.32 +
1.33 + try:
1.34 + for name, value in args.items():
1.35 + if name.startswith("remove-participant-"):
1.36 + i = int(name[len("remove-participant-"):])
1.37 + del participants[i]
1.38 + break
1.39 + except ValueError:
1.40 + pass
1.41 +
1.42 + # Trim empty participants.
1.43 +
1.44 + while participants and not participants[-1].strip():
1.45 + participants.pop()
1.46 +
1.47 + # Show any specified participants together with controls to remove and
1.48 + # add participants.
1.49 +
1.50 + self.page.div(id="participants")
1.51 +
1.52 + self.page.form(method="POST")
1.53 +
1.54 + self.page.p("Participants for scheduling:")
1.55 +
1.56 + for i, participant in enumerate(participants):
1.57 + self.page.p()
1.58 + self.page.input(name="participants", type="text", value=participant)
1.59 + self.page.input(name="remove-participant-%d" % i, type="submit", value="Remove")
1.60 + self.page.p.close()
1.61 +
1.62 + self.page.p()
1.63 + self.page.input(name="participants", type="text")
1.64 + self.page.input(name="add-participant", type="submit", value="Add")
1.65 + self.page.p.close()
1.66 +
1.67 + self.page.form.close()
1.68 +
1.69 + self.page.div.close()
1.70 +
1.71 + return participants
1.72 +
1.73 # Full page output methods.
1.74
1.75 def show_object(self, path_info):
1.76 @@ -493,8 +545,8 @@
1.77 page = self.page
1.78
1.79 self.show_requests_on_page()
1.80 + participants = self.show_participants_on_page()
1.81
1.82 - request_summary = self._get_request_summary()
1.83 freebusy = self.store.get_freebusy(self.user)
1.84
1.85 if not freebusy:
1.86 @@ -516,17 +568,29 @@
1.87 # Details of users to invite to new events could be superimposed on the
1.88 # calendar.
1.89
1.90 - # Requests could be listed and linked to their tentative positions in
1.91 - # the calendar.
1.92 + # Requests are listed and linked to their tentative positions in the
1.93 + # calendar. Other participants are also shown.
1.94 +
1.95 + request_summary = self._get_request_summary()
1.96 +
1.97 + period_groups = [request_summary, freebusy]
1.98 + period_group_types = ["request", "freebusy"]
1.99 + period_group_sources = ["Pending requests", "Your schedule"]
1.100 +
1.101 + for participant in participants:
1.102 + period_groups.append(self.store.get_freebusy_for_other(self.user, get_uri(participant)))
1.103 + period_group_types.append("freebusy")
1.104 + period_group_sources.append(participant)
1.105
1.106 groups = []
1.107 group_columns = []
1.108 - group_types = []
1.109 + group_types = period_group_types
1.110 + group_sources = period_group_sources
1.111 all_points = set()
1.112
1.113 # Obtain time point information for each group of periods.
1.114
1.115 - for periods, group_type in zip([request_summary, freebusy], ["request", "freebusy"]):
1.116 + for periods in period_groups:
1.117 periods = convert_periods(periods, tzid)
1.118
1.119 # Get the time scale with start and end points.
1.120 @@ -544,7 +608,6 @@
1.121 # Record the slots and all time points employed.
1.122
1.123 groups.append(slots)
1.124 - group_types.append(group_type)
1.125 all_points.update([point for point, slot in slots])
1.126
1.127 # Partition the groups into days.
1.128 @@ -552,8 +615,9 @@
1.129 days = {}
1.130 partitioned_groups = []
1.131 partitioned_group_types = []
1.132 + partitioned_group_sources = []
1.133
1.134 - for slots, group_type in zip(groups, group_types):
1.135 + for slots, group_type, group_source in zip(groups, group_types, group_sources):
1.136
1.137 # Propagate time points to all groups of time slots.
1.138
1.139 @@ -584,11 +648,26 @@
1.140 group_columns.append(columns)
1.141 partitioned_groups.append(partitioned)
1.142 partitioned_group_types.append(group_type)
1.143 + partitioned_group_sources.append(group_source)
1.144
1.145 page.table(border=1, cellspacing=0, cellpadding=5)
1.146 + self.show_calendar_participant_headings(partitioned_group_sources, group_columns)
1.147 self.show_calendar_days(days, partitioned_groups, partitioned_group_types, group_columns)
1.148 page.table.close()
1.149
1.150 + def show_calendar_participant_headings(self, partitioned_group_sources, group_columns):
1.151 + page = self.page
1.152 +
1.153 + page.thead()
1.154 + page.tr()
1.155 + page.th("", class_="emptyheading")
1.156 +
1.157 + for source, columns in zip(partitioned_group_sources, group_columns):
1.158 + page.th(source, class_="participantheading", colspan=columns)
1.159 +
1.160 + page.tr.close()
1.161 + page.thead.close()
1.162 +
1.163 def show_calendar_days(self, days, partitioned_groups, partitioned_group_types, group_columns):
1.164 page = self.page
1.165
1.166 @@ -599,6 +678,8 @@
1.167 all_days = days.items()
1.168 all_days.sort()
1.169
1.170 + page.tbody()
1.171 +
1.172 # Produce a heading and time points for each day.
1.173
1.174 for day, points in all_days:
1.175 @@ -612,6 +693,8 @@
1.176
1.177 self.show_calendar_points(points, groups_for_day, partitioned_group_types, group_columns)
1.178
1.179 + page.tbody.close()
1.180 +
1.181 def show_calendar_points(self, points, groups, group_types, group_columns):
1.182 page = self.page
1.183
1.184 @@ -645,9 +728,9 @@
1.185 # Show a column for each active period.
1.186
1.187 for t in active:
1.188 - if t:
1.189 - start, end, uid = t[:3]
1.190 - span = spans[uid]
1.191 + if t and len(t) >= 2:
1.192 + start, end, uid, key = get_freebusy_details(t)
1.193 + span = spans[key]
1.194
1.195 # Produce a table cell only at the start of the period
1.196 # or when continued at the start of a day.
1.197 @@ -657,7 +740,10 @@
1.198 page.td(class_="event", rowspan=span)
1.199
1.200 obj = self._get_object(uid)
1.201 - if obj:
1.202 +
1.203 + if not obj:
1.204 + page.span("")
1.205 + else:
1.206 details = self._get_details(obj)
1.207 summary = get_value(details, "SUMMARY")
1.208
2.1 --- a/imiptools/period.py Wed Jan 28 14:29:24 2015 +0100
2.2 +++ b/imiptools/period.py Wed Jan 28 16:43:04 2015 +0100
2.3 @@ -267,8 +267,9 @@
2.4
2.5 for point, active in slots:
2.6 for t in active:
2.7 - if t:
2.8 - start, end, uid = t[:3]
2.9 + if t and len(t) >= 2:
2.10 + start, end, uid, key = get_freebusy_details(t)
2.11 +
2.12 try:
2.13 start_slot = points.index(start)
2.14 except ValueError:
2.15 @@ -277,8 +278,27 @@
2.16 end_slot = points.index(end)
2.17 except ValueError:
2.18 end_slot = len(slots)
2.19 - spans[uid] = end_slot - start_slot
2.20 + spans[key] = end_slot - start_slot
2.21
2.22 return spans
2.23
2.24 +def get_freebusy_details(t):
2.25 +
2.26 + "Return a tuple of the form (start, end, uid, key) from 't'."
2.27 +
2.28 + # Handle both complete free/busy details...
2.29 +
2.30 + if len(t) > 2:
2.31 + start, end, uid = t[:3]
2.32 + key = uid
2.33 +
2.34 + # ...and published details without specific event details.
2.35 +
2.36 + else:
2.37 + start, end = t[:2]
2.38 + uid = None
2.39 + key = (start, end)
2.40 +
2.41 + return start, end, uid, key
2.42 +
2.43 # vim: tabstop=4 expandtab shiftwidth=4