1.1 --- a/imipweb/event.py Wed Jul 29 16:40:28 2015 +0200
1.2 +++ b/imipweb/event.py Wed Jul 29 18:41:11 2015 +0200
1.3 @@ -20,7 +20,6 @@
1.4 """
1.5
1.6 from datetime import date, timedelta
1.7 -from imiptools.client import update_attendees
1.8 from imiptools.data import get_uri, uri_dict, uri_values
1.9 from imiptools.dates import format_datetime, get_datetime_item, \
1.10 get_period_item, to_date, to_timezone
1.11 @@ -60,11 +59,51 @@
1.12 (None, "Not indicated"),
1.13 ]
1.14
1.15 + # Access to stored object information.
1.16 +
1.17 def is_organiser(self, obj):
1.18 return get_uri(obj.get_value("ORGANIZER")) == self.user
1.19
1.20 + def get_stored_attendees(self, obj):
1.21 + return uri_values(obj.get_values("ATTENDEE") or [])
1.22 +
1.23 + def get_stored_main_period(self, obj):
1.24 +
1.25 + """
1.26 + Return the main event period for the given 'obj'.
1.27 + """
1.28 +
1.29 + dtstart, dtstart_attr = obj.get_datetime_item("DTSTART")
1.30 +
1.31 + if obj.has_key("DTEND"):
1.32 + dtend, dtend_attr = obj.get_datetime_item("DTEND")
1.33 + elif obj.has_key("DURATION"):
1.34 + duration = obj.get_duration("DURATION")
1.35 + dtend = dtstart + duration
1.36 + dtend_attr = dtstart_attr
1.37 + else:
1.38 + dtend, dtend_attr = dtstart, dtstart_attr
1.39 +
1.40 + return EventPeriod(dtstart, dtend, self.get_tzid(), None, dtstart_attr, dtend_attr)
1.41 +
1.42 + def get_stored_recurrences(self, obj):
1.43 +
1.44 + "Return recurrences computed using the given 'obj'."
1.45 +
1.46 + recurrences = []
1.47 + for period in self.get_periods(obj):
1.48 + if period.origin != "DTSTART":
1.49 + recurrences.append(period)
1.50 + return recurrences
1.51 +
1.52 # Request logic methods.
1.53
1.54 + def is_initial_load(self):
1.55 +
1.56 + "Return whether the event is being loaded and shown for the first time."
1.57 +
1.58 + return not self.env.get_args().has_key("editing")
1.59 +
1.60 def handle_request(self, obj):
1.61
1.62 """
1.63 @@ -124,9 +163,7 @@
1.64 # Set the periods in the object, first obtaining removed and
1.65 # modified period information.
1.66
1.67 - to_unschedule = []
1.68 - for i in args.get("recur-remove", []):
1.69 - to_unschedule.append(periods[int(i)])
1.70 + to_unschedule = self.get_removed_periods()
1.71
1.72 self.set_period_in_object(obj, period)
1.73 self.set_periods_in_object(obj, periods)
1.74 @@ -138,9 +175,9 @@
1.75
1.76 # Obtain any participants and those to be removed.
1.77
1.78 - attendees = self.get_attendees()
1.79 + attendees = self.get_attendees_from_page()
1.80 removed = [attendees[int(i)] for i in args.get("remove", [])]
1.81 - to_cancel = update_attendees(obj, attendees, removed)
1.82 + to_cancel = self.update_attendees(obj, attendees, removed)
1.83 single_user = not attendees or attendees == [self.user]
1.84
1.85 # Update attendee participation for the current user.
1.86 @@ -291,29 +328,16 @@
1.87 return all_values
1.88
1.89 def get_current_main_period(self, obj):
1.90 - if self.is_initial_load() or not self.is_organiser(obj):
1.91 - return self.get_existing_main_period(obj)
1.92 - else:
1.93 - return self.get_main_period()
1.94 -
1.95 - def get_existing_main_period(self, obj):
1.96
1.97 """
1.98 - Return the main event period for the given 'obj'.
1.99 + Return the currently active main period for 'obj' depending on whether
1.100 + editing has begun or whether the object has just been loaded.
1.101 """
1.102
1.103 - dtstart, dtstart_attr = obj.get_datetime_item("DTSTART")
1.104 -
1.105 - if obj.has_key("DTEND"):
1.106 - dtend, dtend_attr = obj.get_datetime_item("DTEND")
1.107 - elif obj.has_key("DURATION"):
1.108 - duration = obj.get_duration("DURATION")
1.109 - dtend = dtstart + duration
1.110 - dtend_attr = dtstart_attr
1.111 + if self.is_initial_load() or not self.is_organiser(obj):
1.112 + return self.get_stored_main_period(obj)
1.113 else:
1.114 - dtend, dtend_attr = dtstart, dtstart_attr
1.115 -
1.116 - return EventPeriod(dtstart, dtend, self.get_tzid(), None, dtstart_attr, dtend_attr)
1.117 + return self.get_main_period()
1.118
1.119 def get_main_period(self):
1.120
1.121 @@ -336,20 +360,10 @@
1.122 """
1.123
1.124 if self.is_initial_load() or not self.is_organiser(obj):
1.125 - return self.get_existing_recurrences(obj)
1.126 + return self.get_stored_recurrences(obj)
1.127 else:
1.128 return self.get_recurrences()
1.129
1.130 - def get_existing_recurrences(self, obj):
1.131 -
1.132 - "Return recurrences computed using the given 'obj'."
1.133 -
1.134 - recurrences = []
1.135 - for period in self.get_periods(obj):
1.136 - if period.origin != "DTSTART":
1.137 - recurrences.append(period)
1.138 - return recurrences
1.139 -
1.140 def get_recurrences(self):
1.141
1.142 "Return the recurrences defined in the event form."
1.143 @@ -374,11 +388,15 @@
1.144
1.145 return periods
1.146
1.147 - def is_initial_load(self):
1.148 + def get_removed_periods(self):
1.149 +
1.150 + "Return a list of recurrence periods to remove upon updating an event."
1.151
1.152 - "Return whether the event is being loaded and shown for the first time."
1.153 -
1.154 - return not self.env.get_args().has_key("editing")
1.155 + to_unschedule = []
1.156 + args = self.env.get_args()
1.157 + for i in args.get("recur-remove", []):
1.158 + to_unschedule.append(periods[int(i)])
1.159 + return to_unschedule
1.160
1.161 def get_current_attendees(self, obj):
1.162
1.163 @@ -388,14 +406,11 @@
1.164 """
1.165
1.166 if self.is_initial_load() or not self.is_organiser(obj):
1.167 - return self.get_existing_attendees(obj)
1.168 + return self.get_stored_attendees(obj)
1.169 else:
1.170 - return self.get_attendees()
1.171 + return self.get_attendees_from_page()
1.172
1.173 - def get_existing_attendees(self, obj):
1.174 - return uri_values(obj.get_values("ATTENDEE") or [])
1.175 -
1.176 - def get_attendees(self):
1.177 + def get_attendees_from_page(self):
1.178
1.179 """
1.180 Return attendees from the request, normalised for iCalendar purposes,
1.181 @@ -418,15 +433,14 @@
1.182
1.183 return ordered_attendees
1.184
1.185 - def update_attendees(self, obj):
1.186 + def update_attendees_from_page(self, obj):
1.187
1.188 "Add or remove attendees. This does not affect the stored object."
1.189
1.190 args = self.env.get_args()
1.191
1.192 - attendees = self.get_attendees()
1.193 - existing_attendees = self.get_existing_attendees(obj)
1.194 - sequence = obj.get_value("SEQUENCE")
1.195 + attendees = self.get_attendees_from_page()
1.196 + existing_attendees = self.get_stored_attendees(obj)
1.197
1.198 if args.has_key("add"):
1.199 attendees.append("")
1.200 @@ -443,7 +457,7 @@
1.201
1.202 existing = attendee in existing_attendees
1.203
1.204 - if not existing or sequence is None or attendee == self.user:
1.205 + if not existing or not obj.is_shared() or attendee == self.user:
1.206 attendees.remove(attendee)
1.207
1.208 return attendees
1.209 @@ -460,7 +474,6 @@
1.210 attendees = self.get_current_attendees(obj)
1.211 is_attendee = self.user in attendees
1.212 is_request = (obj.get_uid(), obj.get_recurrenceid()) in self._get_requests()
1.213 - sequence = obj.get_value("SEQUENCE")
1.214
1.215 # Show appropriate options depending on the role of the user.
1.216
1.217 @@ -479,10 +492,10 @@
1.218 page.p("As organiser, you can perform the following:")
1.219
1.220 page.p()
1.221 - self._control("create", "submit", sequence is None and "Create event" or "Update event")
1.222 + self._control("create", "submit", not obj.is_shared() and "Create event" or "Update event")
1.223 page.add(" ")
1.224
1.225 - if sequence is not None and not is_request:
1.226 + if obj.is_shared() and not is_request:
1.227 self._control("cancel", "submit", "Cancel event")
1.228 else:
1.229 self._control("discard", "submit", "Discard event")
1.230 @@ -512,9 +525,9 @@
1.231 # Obtain basic event information, generating any necessary editing controls.
1.232
1.233 if self.is_initial_load() or not self.is_organiser(obj):
1.234 - attendees = self.get_existing_attendees(obj)
1.235 + attendees = self.get_stored_attendees(obj)
1.236 else:
1.237 - attendees = self.update_attendees(obj)
1.238 + attendees = self.update_attendees_from_page(obj)
1.239
1.240 p = self.get_current_main_period(obj)
1.241 self.show_object_datetime_controls(p)
1.242 @@ -650,13 +663,12 @@
1.243
1.244 existing = attendee_attr is not None
1.245 partstat = attendee_attr and attendee_attr.get("PARTSTAT")
1.246 - sequence = obj.get_value("SEQUENCE")
1.247
1.248 page.td(class_="objectvalue")
1.249
1.250 # Show a form control as organiser for new attendees.
1.251
1.252 - if self.is_organiser(obj) and (not existing or sequence is None):
1.253 + if self.is_organiser(obj) and (not existing or not obj.is_shared()):
1.254 self._control("attendee", "value", attendee, size="40")
1.255 else:
1.256 self._control("attendee", "hidden", attendee)
1.257 @@ -684,7 +696,7 @@
1.258
1.259 # Permit the removal of newly-added attendees.
1.260
1.261 - remove_type = (not existing or sequence is None or attendee == self.user) and "submit" or "checkbox"
1.262 + remove_type = (not existing or not obj.is_shared() or attendee == self.user) and "submit" or "checkbox"
1.263 self._control("remove", remove_type, str(i), str(i) in args.get("remove", []), id="remove-%d" % i, class_="remove")
1.264
1.265 page.label("Remove", for_="remove-%d" % i, class_="remove")
1.266 @@ -773,8 +785,6 @@
1.267 page = self.page
1.268 args = self.env.get_args()
1.269
1.270 - sequence = obj.get_value("SEQUENCE")
1.271 -
1.272 p = event_period_from_period(period)
1.273 replaced = not recurrenceid and self.is_replaced(p, recurrenceids)
1.274
1.275 @@ -806,7 +816,7 @@
1.276 page.th("")
1.277 page.td()
1.278
1.279 - remove_type = sequence is None or not period.origin and "submit" or "checkbox"
1.280 + remove_type = not obj.is_shared() or not period.origin and "submit" or "checkbox"
1.281 self._control("recur-remove", remove_type, str(index),
1.282 str(index) in args.get("recur-remove", []),
1.283 id="recur-remove-%d" % index, class_="remove")