1.1 --- a/imipweb/event.py Tue Sep 12 20:27:38 2017 +0200
1.2 +++ b/imipweb/event.py Tue Sep 12 21:58:33 2017 +0200
1.3 @@ -65,7 +65,8 @@
1.4 without notification.
1.5 """
1.6
1.7 - return (self.can_edit_recurrence(recurrence) or not self.is_organiser()) and \
1.8 + return (not self.is_organiser() or
1.9 + self.can_edit_recurrence(recurrence)) and \
1.10 recurrence.origin != "RRULE"
1.11
1.12 def can_edit_recurrence(self, recurrence):
1.13 @@ -87,6 +88,7 @@
1.14 notification.
1.15 """
1.16
1.17 + attendee = get_uri(attendee)
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 @@ -848,10 +850,9 @@
1.22 # modified period information.
1.23 # NOTE: Currently, rules are not updated.
1.24
1.25 - to_unschedule, to_exclude = self.get_removed_periods(periods)
1.26 + active_periods, to_unschedule, to_exclude = self.get_removed_periods(periods)
1.27 +
1.28 periods = set(periods)
1.29 - active_periods = [p for p in periods if not p.replaced]
1.30 -
1.31 changed = self.obj.set_period(period) or changed
1.32 changed = self.obj.set_periods(periods) or changed
1.33
1.34 @@ -995,6 +996,19 @@
1.35
1.36 return [p.as_event_period(i) for i, p in enumerate(self.get_recurrences_from_page())]
1.37
1.38 + def get_active_periods(self, periods):
1.39 +
1.40 + "Return a mapping of non-replaced periods to counts, given 'periods'."
1.41 +
1.42 + active_periods = {}
1.43 + for p in periods:
1.44 + if not p.replaced:
1.45 + if not active_periods.has_key(p):
1.46 + active_periods[p] = 1
1.47 + else:
1.48 + active_periods[p] += 1
1.49 + return active_periods
1.50 +
1.51 # Access to form-originating object information.
1.52
1.53 def get_main_period_from_page(self):
1.54 @@ -1042,8 +1056,12 @@
1.55 """
1.56
1.57 args = self.env.get_args()
1.58 - to_unschedule = []
1.59 - to_exclude = []
1.60 + to_unschedule = set()
1.61 + to_exclude = set()
1.62 +
1.63 + # Get all periods that are not replaced.
1.64 +
1.65 + active_periods = self.get_active_periods(periods)
1.66
1.67 for i in args.get("recur-remove", []):
1.68 try:
1.69 @@ -1051,12 +1069,26 @@
1.70 except (IndexError, ValueError):
1.71 continue
1.72
1.73 + active_periods[period] -= 1
1.74 +
1.75 if not self.can_edit_recurrence(period) and self.is_organiser():
1.76 - to_unschedule.append(period)
1.77 + l = to_unschedule
1.78 else:
1.79 - to_exclude.append(period)
1.80 + l = to_exclude
1.81 +
1.82 + l.add(period)
1.83 +
1.84 + # Determine whether some periods are both removed and added.
1.85
1.86 - return to_unschedule, to_exclude
1.87 + remaining = []
1.88 + for period, n in active_periods.items():
1.89 + if n > 0:
1.90 + remaining.append(period)
1.91 +
1.92 + to_unschedule.difference_update(remaining)
1.93 + to_exclude.difference_update(remaining)
1.94 +
1.95 + return remaining, to_unschedule, to_exclude
1.96
1.97 def get_attendees_from_page(self):
1.98
1.99 @@ -1077,6 +1109,50 @@
1.100 attendee_map = self.obj.get_value_map("ATTENDEE")
1.101 return [get_verbose_address(value, attendee_map.get(value)) for value in attendees]
1.102
1.103 + def filter_duplicates(self, l):
1.104 +
1.105 + """
1.106 + Return collection 'l' filtered for duplicate values, retaining the given
1.107 + element ordering.
1.108 + """
1.109 +
1.110 + s = set()
1.111 + f = []
1.112 +
1.113 + for value in l:
1.114 + if value not in s:
1.115 + s.add(value)
1.116 + f.append(value)
1.117 +
1.118 + return f
1.119 +
1.120 + def remove_from_collection(self, l, indexes, fn):
1.121 +
1.122 + """
1.123 + Remove from collection 'l' all values having 'indexes' where 'fn'
1.124 + applied to each referenced value returns a true value. Values where 'fn'
1.125 + returns a false value are added to a list of deferred removals which is
1.126 + returned.
1.127 + """
1.128 +
1.129 + still_to_remove = []
1.130 + correction = 0
1.131 +
1.132 + for i in indexes:
1.133 + try:
1.134 + i = int(i) - correction
1.135 + value = l[i]
1.136 + except (IndexError, ValueError):
1.137 + continue
1.138 +
1.139 + if fn(value):
1.140 + del l[i]
1.141 + correction += 1
1.142 + else:
1.143 + still_to_remove.append(str(i))
1.144 +
1.145 + return still_to_remove
1.146 +
1.147 def update_attendees_from_page(self):
1.148
1.149 "Add or remove attendees. This does not affect the stored object."
1.150 @@ -1085,7 +1161,9 @@
1.151
1.152 attendees = self.get_attendees_from_page()
1.153
1.154 - if args.has_key("add"):
1.155 + add = args.has_key("add")
1.156 +
1.157 + if add:
1.158 attendees.append("")
1.159
1.160 # Add attendees suggested in counter-proposals.
1.161 @@ -1104,24 +1182,15 @@
1.162 # Only actually remove attendees if the event is unsent, if the attendee
1.163 # is new, or if it is the current user being removed.
1.164
1.165 - if args.has_key("remove"):
1.166 - still_to_remove = []
1.167 - correction = 0
1.168 + remove = args.has_key("remove")
1.169
1.170 - for i in args["remove"]:
1.171 - try:
1.172 - i = int(i) - correction
1.173 - attendee = attendees[i]
1.174 - except (IndexError, ValueError):
1.175 - continue
1.176 + if remove:
1.177 + still_to_remove = self.remove_from_collection(attendees,
1.178 + args["remove"], self.can_remove_attendee)
1.179 + args["remove"] = still_to_remove
1.180
1.181 - if self.can_remove_attendee(get_uri(attendee)):
1.182 - del attendees[i]
1.183 - correction += 1
1.184 - else:
1.185 - still_to_remove.append(str(i))
1.186 -
1.187 - args["remove"] = still_to_remove
1.188 + if add or add_suggested or remove:
1.189 + attendees = self.filter_duplicates(attendees)
1.190
1.191 args["attendee"] = attendees
1.192 return attendees
1.193 @@ -1134,7 +1203,9 @@
1.194
1.195 recurrences = self.get_recurrences_from_page()
1.196
1.197 - if args.has_key("recur-add"):
1.198 + add = args.has_key("recur-add")
1.199 +
1.200 + if add:
1.201 period = self.get_current_main_period().as_form_period()
1.202 period.origin = "RDATE"
1.203 recurrences.append(period)
1.204 @@ -1142,24 +1213,15 @@
1.205 # Only actually remove recurrences if the event is unsent, or if the
1.206 # recurrence is new, but only for explicit recurrences.
1.207
1.208 - if args.has_key("recur-remove"):
1.209 - still_to_remove = []
1.210 - correction = 0
1.211 + remove = args.has_key("recur-remove")
1.212
1.213 - for i in args["recur-remove"]:
1.214 - try:
1.215 - i = int(i) - correction
1.216 - recurrence = recurrences[i]
1.217 - except (IndexError, ValueError):
1.218 - continue
1.219 + if remove:
1.220 + still_to_remove = self.remove_from_collection(recurrences,
1.221 + args["recur-remove"], self.can_remove_recurrence)
1.222 + args["recur-remove"] = still_to_remove
1.223
1.224 - if self.can_remove_recurrence(recurrence):
1.225 - del recurrences[i]
1.226 - correction += 1
1.227 - else:
1.228 - still_to_remove.append(str(i))
1.229 -
1.230 - args["recur-remove"] = still_to_remove
1.231 + if add or remove:
1.232 + recurrences = self.filter_duplicates(recurrences)
1.233
1.234 self.set_recurrences_in_page(recurrences)
1.235 return recurrences