1.1 --- a/imipweb/event.py Sun Apr 05 00:58:32 2015 +0200
1.2 +++ b/imipweb/event.py Sun Apr 05 01:09:26 2015 +0200
1.3 @@ -58,6 +58,9 @@
1.4 (None, "Not indicated"),
1.5 ]
1.6
1.7 + def is_organiser(self, obj):
1.8 + return get_uri(obj.get_value("ORGANIZER")) == self.user
1.9 +
1.10 # Request logic methods.
1.11
1.12 def handle_request(self, uid, recurrenceid, obj):
1.13 @@ -92,14 +95,12 @@
1.14 self.redirect(self.env.get_path())
1.15 return None
1.16
1.17 - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user
1.18 -
1.19 # Obtain the user's timezone and process datetime values.
1.20
1.21 update = False
1.22 periods = None
1.23
1.24 - if is_organiser:
1.25 + if self.is_organiser(obj):
1.26 periods, errors = self.handle_all_period_controls()
1.27 if errors:
1.28 return errors
1.29 @@ -110,7 +111,7 @@
1.30
1.31 # Update principal event details if organiser.
1.32
1.33 - if is_organiser:
1.34 + if self.is_organiser(obj):
1.35
1.36 # Update time periods (main and recurring).
1.37
1.38 @@ -147,7 +148,7 @@
1.39 if reply and handler.process_received_request(update):
1.40 self.remove_request(uid, recurrenceid)
1.41
1.42 - elif is_organiser and (invite or cancel):
1.43 + elif self.is_organiser(obj) and (invite or cancel):
1.44
1.45 if handler.process_created_request(
1.46 invite and "REQUEST" or "CANCEL", update, to_cancel):
1.47 @@ -407,6 +408,24 @@
1.48 dtend, dtend_attr = dtstart, dtstart_attr
1.49 return (dtstart, dtstart_attr), (dtend, dtend_attr)
1.50
1.51 + def get_current_attendees(self, obj):
1.52 +
1.53 + """
1.54 + Return attendees for 'obj' depending on whether the object is being
1.55 + edited.
1.56 + """
1.57 +
1.58 + args = self.env.get_args()
1.59 + initial_load = not args.has_key("editing")
1.60 +
1.61 + if initial_load or not self.is_organiser(obj):
1.62 + return self.get_existing_attendees(obj)
1.63 + else:
1.64 + return self.get_attendees()
1.65 +
1.66 + def get_existing_attendees(self, obj):
1.67 + return uri_values(obj.get_values("ATTENDEE") or [])
1.68 +
1.69 def get_attendees(self):
1.70
1.71 """
1.72 @@ -421,6 +440,8 @@
1.73 ordered_attendees = []
1.74
1.75 for attendee in attendees:
1.76 + if not attendee.strip():
1.77 + continue
1.78 attendee = get_uri(attendee)
1.79 if attendee not in unique_attendees:
1.80 unique_attendees.add(attendee)
1.81 @@ -455,9 +476,7 @@
1.82 page = self.page
1.83 args = self.env.get_args()
1.84
1.85 - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user
1.86 -
1.87 - attendees = uri_values((obj.get_values("ATTENDEE") or []) + filter(None, args.get("attendee", [])))
1.88 + attendees = self.get_current_attendees(obj)
1.89 is_attendee = self.user in attendees
1.90
1.91 is_request = (obj.get_value("UID"), obj.get_value("RECURRENCE-ID")) in self._get_requests()
1.92 @@ -466,7 +485,7 @@
1.93
1.94 # Show appropriate options depending on the role of the user.
1.95
1.96 - if is_attendee and not is_organiser:
1.97 + if is_attendee and not self.is_organiser(obj):
1.98 page.p("An action is required for this request:")
1.99
1.100 page.p()
1.101 @@ -477,7 +496,7 @@
1.102 page.input(name="ignore", type="submit", value="Do nothing for now")
1.103 page.p.close()
1.104
1.105 - if is_organiser:
1.106 + if self.is_organiser(obj):
1.107 page.p("As organiser, you can perform the following:")
1.108
1.109 if have_other_attendees:
1.110 @@ -520,12 +539,12 @@
1.111
1.112 # Obtain basic event information, showing any necessary editing controls.
1.113
1.114 - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user
1.115 initial_load = not args.has_key("editing")
1.116
1.117 - existing_attendees = uri_values(obj.get_values("ATTENDEE") or [])
1.118 - attendees = is_organiser and self.update_attendees(obj) or \
1.119 - (initial_load or not is_organiser) and existing_attendees or []
1.120 + if initial_load or not self.is_organiser(obj):
1.121 + attendees = self.get_existing_attendees(obj)
1.122 + else:
1.123 + attendees = self.update_attendees(obj)
1.124
1.125 (dtstart, dtstart_attr), (dtend, dtend_attr) = self.get_event_period(obj)
1.126 self.show_object_datetime_controls(dtstart, dtend)
1.127 @@ -580,7 +599,7 @@
1.128 value = args.get("summary", [obj.get_value(name)])[0]
1.129
1.130 page.td()
1.131 - if is_organiser:
1.132 + if self.is_organiser(obj):
1.133 page.input(name="summary", type="text", value=value, size=80)
1.134 else:
1.135 page.add(value)
1.136 @@ -606,7 +625,7 @@
1.137
1.138 # Allow more attendees to be specified.
1.139
1.140 - if is_organiser:
1.141 + if self.is_organiser(obj):
1.142 i = len(attendees)
1.143
1.144 if not first:
1.145 @@ -653,7 +672,6 @@
1.146 page = self.page
1.147 args = self.env.get_args()
1.148
1.149 - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user
1.150 existing = attendee_attr is not None
1.151 partstat = attendee_attr and attendee_attr.get("PARTSTAT")
1.152
1.153 @@ -661,7 +679,7 @@
1.154
1.155 # Show a form control as organiser for new attendees.
1.156
1.157 - if is_organiser and not existing:
1.158 + if self.is_organiser(obj) and not existing:
1.159 page.input(name="attendee", type="value", value=attendee, size="40")
1.160 else:
1.161 page.input(name="attendee", type="hidden", value=attendee)
1.162 @@ -677,7 +695,7 @@
1.163 # button in order to refresh the page and show a control for
1.164 # the current user, if indicated.
1.165
1.166 - elif is_organiser and not existing:
1.167 + elif self.is_organiser(obj) and not existing:
1.168 page.input(name="partstat-refresh", type="submit", value="refresh", id="partstat-%d" % i, class_="refresh")
1.169 page.label(dict(self.partstat_items).get(partstat, ""), for_="partstat-%s" % i, class_="partstat")
1.170 else:
1.171 @@ -685,7 +703,7 @@
1.172
1.173 # Permit organisers to remove attendees.
1.174
1.175 - if is_organiser:
1.176 + if self.is_organiser(obj):
1.177
1.178 # Permit the removal of newly-added attendees.
1.179
1.180 @@ -703,7 +721,6 @@
1.181 "Show recurrences for the object having the given representation 'obj'."
1.182
1.183 page = self.page
1.184 - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user
1.185
1.186 # Obtain any parent object if this object is a specific recurrence.
1.187
1.188 @@ -725,7 +742,7 @@
1.189 if len(periods) == 1:
1.190 return
1.191
1.192 - if is_organiser:
1.193 + if self.is_organiser(obj):
1.194 page.p("This event recurs on the following occasions within the next %d days:" % self.get_window_size())
1.195 else:
1.196 page.p("This event occurs on the following occasions within the next %d days:" % self.get_window_size())
1.197 @@ -737,7 +754,7 @@
1.198
1.199 # Show each recurrence in a separate table if editable.
1.200
1.201 - if is_organiser and explicit_periods:
1.202 + if self.is_organiser(obj) and explicit_periods:
1.203
1.204 for index, p in enumerate(periods[1:]):
1.205
1.206 @@ -782,11 +799,12 @@
1.207 # Show only subsequent periods if organiser, since the principal
1.208 # period will be the start and end datetimes.
1.209
1.210 - for index, p in enumerate(is_organiser and periods[1:] or periods):
1.211 + for index, p in enumerate(self.is_organiser(obj) and periods[1:] or periods):
1.212 page.tr()
1.213 self.show_recurrence_controls(obj, index, p.start, p.end, p.origin, recurrenceid, recurrenceids, True)
1.214 self.show_recurrence_controls(obj, index, p.start, p.end, p.origin, recurrenceid, recurrenceids, False)
1.215 page.tr.close()
1.216 +
1.217 page.tbody.close()
1.218 page.table.close()
1.219
1.220 @@ -798,6 +816,7 @@
1.221 """
1.222
1.223 page = self.page
1.224 + recurrenceid = format_datetime(obj.get_utc_datetime("RECURRENCE-ID"))
1.225
1.226 # Obtain the user's timezone.
1.227
1.228 @@ -806,55 +825,70 @@
1.229
1.230 # Indicate whether there are conflicting events.
1.231
1.232 - freebusy = self.store.get_freebusy(self.user)
1.233 + conflicts = []
1.234
1.235 - if freebusy:
1.236 + for participant in self.get_current_attendees(obj):
1.237 + if participant == self.user:
1.238 + freebusy = self.store.get_freebusy(participant)
1.239 + else:
1.240 + freebusy = self.store.get_freebusy_for_other(self.user, participant)
1.241 +
1.242 + if not freebusy:
1.243 + continue
1.244
1.245 # Obtain any time zone details from the suggested event.
1.246
1.247 _dtstart, attr = obj.get_item("DTSTART")
1.248 tzid = attr.get("TZID", tzid)
1.249
1.250 - # Show any conflicts.
1.251 + # Show any conflicts with periods of actual attendance.
1.252
1.253 - conflicts = list([p for p in have_conflict(freebusy, periods, True) if p.uid != uid])
1.254 - conflicts.sort()
1.255 + for p in have_conflict(freebusy, periods, True):
1.256 + if (p.uid != uid or p.recurrenceid != recurrenceid) and p.transp != "ORG":
1.257 + conflicts.append(p)
1.258
1.259 - if conflicts:
1.260 - page.p("This event conflicts with others:")
1.261 + conflicts.sort()
1.262 +
1.263 + # Show any conflicts with periods of actual attendance.
1.264
1.265 - page.table(cellspacing=5, cellpadding=5, class_="conflicts")
1.266 - page.thead()
1.267 - page.tr()
1.268 - page.th("Event")
1.269 - page.th("Start")
1.270 - page.th("End")
1.271 - page.tr.close()
1.272 - page.thead.close()
1.273 - page.tbody()
1.274 + if conflicts:
1.275 + page.p("This event conflicts with others:")
1.276
1.277 - for p in conflicts:
1.278 + page.table(cellspacing=5, cellpadding=5, class_="conflicts")
1.279 + page.thead()
1.280 + page.tr()
1.281 + page.th("Event")
1.282 + page.th("Start")
1.283 + page.th("End")
1.284 + page.tr.close()
1.285 + page.thead.close()
1.286 + page.tbody()
1.287
1.288 - # Provide details of any conflicting event.
1.289 + for p in conflicts:
1.290 +
1.291 + # Provide details of any conflicting event.
1.292
1.293 - start = self.format_datetime(to_timezone(get_datetime(p.start), tzid), "long")
1.294 - end = self.format_datetime(to_timezone(get_datetime(p.end), tzid), "long")
1.295 + start = self.format_datetime(to_timezone(get_datetime(p.start), tzid), "long")
1.296 + end = self.format_datetime(to_timezone(get_datetime(p.end), tzid), "long")
1.297
1.298 - page.tr()
1.299 + page.tr()
1.300
1.301 - # Show the event summary for the conflicting event.
1.302 + # Show the event summary for the conflicting event.
1.303
1.304 - page.td()
1.305 + page.td()
1.306 + if p.summary:
1.307 page.a(p.summary, href=self.link_to(p.uid))
1.308 - page.td.close()
1.309 + else:
1.310 + page.add("(Unspecified event)")
1.311 + page.td.close()
1.312
1.313 - page.td(start)
1.314 - page.td(end)
1.315 + page.td(start)
1.316 + page.td(end)
1.317
1.318 - page.tr.close()
1.319 + page.tr.close()
1.320
1.321 - page.tbody.close()
1.322 - page.table.close()
1.323 + page.tbody.close()
1.324 + page.table.close()
1.325
1.326 # Generation of controls within page fragments.
1.327
1.328 @@ -926,7 +960,6 @@
1.329 """
1.330
1.331 page = self.page
1.332 - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user
1.333
1.334 # Change end dates to refer to the actual dates, not the iCalendar
1.335 # "next day" dates.
1.336 @@ -936,7 +969,7 @@
1.337
1.338 # Show controls for editing as organiser.
1.339
1.340 - if is_organiser:
1.341 + if self.is_organiser(obj):
1.342 page.td(class_="objectvalue dt%s" % (show_start and "start" or "end"))
1.343
1.344 if show_start:
1.345 @@ -981,8 +1014,6 @@
1.346 sn = self._suffixed_name
1.347 ssn = self._simple_suffixed_name
1.348
1.349 - is_organiser = get_uri(obj.get_value("ORGANIZER")) == self.user
1.350 -
1.351 # Change end dates to refer to the actual dates, not the iCalendar
1.352 # "next day" dates.
1.353
1.354 @@ -998,7 +1029,7 @@
1.355
1.356 # Show controls for editing as organiser.
1.357
1.358 - if is_organiser and not replaced and origin != "RRULE":
1.359 + if self.is_organiser(obj) and not replaced and origin != "RRULE":
1.360 page.td(class_="objectvalue dt%s" % (show_start and "start" or "end"))
1.361
1.362 if show_start: