1.1 --- a/imipweb/event.py Mon Oct 12 17:41:06 2015 +0200
1.2 +++ b/imipweb/event.py Mon Oct 12 17:42:03 2015 +0200
1.3 @@ -52,6 +52,9 @@
1.4 (None, "Not indicated"),
1.5 ]
1.6
1.7 + def can_change_object(self):
1.8 + return self.is_organiser() or self._is_request()
1.9 +
1.10 def can_remove_recurrence(self, recurrence):
1.11
1.12 """
1.13 @@ -80,7 +83,7 @@
1.14 notification.
1.15 """
1.16
1.17 - return self.can_edit_attendee(attendee) or attendee == self.user
1.18 + return self.can_edit_attendee(attendee) or attendee == self.user and self.is_organiser()
1.19
1.20 def can_edit_attendee(self, attendee):
1.21
1.22 @@ -96,9 +99,6 @@
1.23
1.24 # Access to stored object information.
1.25
1.26 - def is_organiser(self):
1.27 - return get_uri(self.obj.get_value("ORGANIZER")) == self.user
1.28 -
1.29 def get_stored_attendees(self):
1.30 return [get_verbose_address(value, attr) for value, attr in self.obj.get_items("ATTENDEE") or []]
1.31
1.32 @@ -141,7 +141,6 @@
1.33
1.34 attendees = uri_values(self.get_current_attendees())
1.35 is_attendee = self.user in attendees
1.36 - is_request = self._have_request(self.uid, self.recurrenceid)
1.37
1.38 if not self.obj.is_shared():
1.39 page.p("This event has not been shared.")
1.40 @@ -166,7 +165,7 @@
1.41 self.control("create", "submit", "Update event")
1.42 page.add(" ")
1.43
1.44 - if self.obj.is_shared() and not is_request:
1.45 + if self.obj.is_shared() and not self._is_request():
1.46 self.control("cancel", "submit", "Cancel event")
1.47 else:
1.48 self.control("discard", "submit", "Discard event")
1.49 @@ -294,7 +293,7 @@
1.50
1.51 # Allow more attendees to be specified.
1.52
1.53 - if self.is_organiser():
1.54 + if self.can_change_object():
1.55 if not first:
1.56 page.tr()
1.57
1.58 @@ -304,6 +303,8 @@
1.59 page.td.close()
1.60 page.tr.close()
1.61
1.62 + # NOTE: Permit attendees to suggest others for counter-proposals.
1.63 +
1.64 # Handle potentially many values of other kinds.
1.65
1.66 else:
1.67 @@ -349,8 +350,9 @@
1.68 page.td(class_="objectvalue")
1.69
1.70 # Show a form control as organiser for new attendees.
1.71 + # NOTE: Permit suggested attendee editing for counter-proposals.
1.72
1.73 - if self.is_organiser() and self.can_edit_attendee(attendee_uri):
1.74 + if self.can_change_object() and self.can_edit_attendee(attendee_uri):
1.75 self.control("attendee", "value", attendee, size="40")
1.76 else:
1.77 self.control("attendee", "hidden", attendee)
1.78 @@ -376,8 +378,9 @@
1.79 page.span(dict(self.partstat_items).get(partstat, ""), class_="partstat")
1.80
1.81 # Permit organisers to remove attendees.
1.82 + # NOTE: Permit the removal of suggested attendees for counter-proposals.
1.83
1.84 - if self.is_organiser():
1.85 + if self.can_change_object() and (self.can_remove_attendee(attendee_uri) or self.is_organiser()):
1.86
1.87 # Permit the removal of newly-added attendees.
1.88
1.89 @@ -425,8 +428,9 @@
1.90 page.p("This event occurs on the following occasions within the next %d days:" % self.get_window_size())
1.91
1.92 # Show each recurrence in a separate table if editable.
1.93 + # NOTE: Allow recurrence editing for counter-proposals.
1.94
1.95 - if self.is_organiser() and recurrences:
1.96 + if self.can_change_object() and recurrences:
1.97
1.98 for index, period in enumerate(recurrences):
1.99 self.show_recurrence(index, period, self.recurrenceid, recurrenceids, errors)
1.100 @@ -732,12 +736,14 @@
1.101 # Update the object.
1.102
1.103 single_user = False
1.104 + changed = False
1.105
1.106 if reply or create or cancel or save:
1.107
1.108 # Update principal event details if organiser.
1.109 + # NOTE: Handle edited details for counter-proposals.
1.110
1.111 - if self.is_organiser():
1.112 + if self.can_change_object():
1.113
1.114 # Update time periods (main and recurring).
1.115
1.116 @@ -756,26 +762,32 @@
1.117
1.118 to_unschedule, to_exclude = self.get_removed_periods(periods)
1.119
1.120 - self.obj.set_period(period)
1.121 - self.obj.set_periods(periods)
1.122 - self.obj.update_exceptions(to_exclude)
1.123 + changed = self.obj.set_period(period) or changed
1.124 + changed = self.obj.set_periods(periods) or changed
1.125 + changed = self.obj.update_exceptions(to_exclude) or changed
1.126
1.127 - # Update summary.
1.128 + # Organiser-only changes...
1.129 +
1.130 + if self.is_organiser():
1.131 +
1.132 + # Update summary.
1.133
1.134 - if args.has_key("summary"):
1.135 - self.obj["SUMMARY"] = [(args["summary"][0], {})]
1.136 + if args.has_key("summary"):
1.137 + self.obj["SUMMARY"] = [(args["summary"][0], {})]
1.138
1.139 - # Obtain any participants and those to be removed.
1.140 + # Obtain any new participants and those to be removed.
1.141
1.142 - attendees = map(lambda s: s and get_uri(s), self.get_attendees_from_page())
1.143 - removed = [attendees[int(i)] for i in args.get("remove", [])]
1.144 - to_cancel = self.update_attendees(self.obj, attendees, removed)
1.145 - single_user = not attendees or attendees == [self.user]
1.146 + if self.can_change_object():
1.147 + attendees = self.get_attendees_from_page()
1.148 + removed = [attendees[int(i)] for i in args.get("remove", [])]
1.149 + added, to_cancel = self.update_attendees(attendees, removed)
1.150 + single_user = not attendees or attendees == [self.user]
1.151 + changed = added or changed
1.152
1.153 # Update attendee participation for the current user.
1.154
1.155 if args.has_key("partstat"):
1.156 - self.update_participation(self.obj, args["partstat"][0])
1.157 + self.update_participation(args["partstat"][0])
1.158
1.159 # Process any action.
1.160
1.161 @@ -788,7 +800,7 @@
1.162
1.163 # Process the object and remove it from the list of requests.
1.164
1.165 - if reply and self.process_received_request():
1.166 + if reply and self.process_received_request(changed):
1.167 self.remove_request()
1.168
1.169 elif self.is_organiser() and (invite or cancel):
1.170 @@ -1069,7 +1081,7 @@
1.171 on whether editing has begun or whether the object has just been loaded.
1.172 """
1.173
1.174 - if self.is_initial_load() or not self.is_organiser():
1.175 + if self.is_initial_load() or not self.can_change_object():
1.176 return self.get_stored_main_period()
1.177 else:
1.178 return self.get_main_period_from_page()
1.179 @@ -1081,7 +1093,7 @@
1.180 details where no editing is in progress, using form data otherwise.
1.181 """
1.182
1.183 - if self.is_initial_load() or not self.is_organiser():
1.184 + if self.is_initial_load() or not self.can_change_object():
1.185 return self.get_stored_recurrences()
1.186 else:
1.187 return self.get_recurrences_from_page()
1.188 @@ -1090,7 +1102,7 @@
1.189
1.190 "Return an updated collection of recurrences for the current object."
1.191
1.192 - if self.is_initial_load() or not self.is_organiser():
1.193 + if self.is_initial_load() or not self.can_change_object():
1.194 return self.get_stored_recurrences()
1.195 else:
1.196 return self.update_recurrences_from_page()
1.197 @@ -1103,7 +1115,7 @@
1.198 form.
1.199 """
1.200
1.201 - if self.is_initial_load() or not self.is_organiser():
1.202 + if self.is_initial_load() or not self.can_change_object():
1.203 return self.get_stored_attendees()
1.204 else:
1.205 return self.get_attendees_from_page()
1.206 @@ -1112,7 +1124,7 @@
1.207
1.208 "Return an updated collection of attendees for the current object."
1.209
1.210 - if self.is_initial_load() or not self.is_organiser():
1.211 + if self.is_initial_load() or not self.can_change_object():
1.212 return self.get_stored_attendees()
1.213 else:
1.214 return self.update_attendees_from_page()