1.1 --- a/imiptools/client.py Tue Oct 06 18:38:45 2015 +0200
1.2 +++ b/imiptools/client.py Tue Oct 06 18:43:29 2015 +0200
1.3 @@ -867,6 +867,12 @@
1.4 # Convenience methods for removing counter-proposals and updating the
1.5 # request queue.
1.6
1.7 + def remove_request(self):
1.8 + return self.store.dequeue_request(self.user, self.uid, self.recurrenceid)
1.9 +
1.10 + def remove_event(self):
1.11 + return self.store.remove_event(self.user, self.uid, self.recurrenceid)
1.12 +
1.13 def remove_counter(self, attendee):
1.14 self.remove_counters([attendee])
1.15
2.1 --- a/imipweb/event.py Tue Oct 06 18:38:45 2015 +0200
2.2 +++ b/imipweb/event.py Tue Oct 06 18:43:29 2015 +0200
2.3 @@ -574,8 +574,9 @@
2.4
2.5 if first:
2.6 page.td(rowspan=len(periods))
2.7 + self.control("accept-%d" % i, "submit", "Accept")
2.8 self.control("decline-%d" % i, "submit", "Decline")
2.9 - self.control("decline", "hidden", attendee)
2.10 + self.control("counter", "hidden", attendee)
2.11 page.td.close()
2.12
2.13 page.tr.close()
2.14 @@ -714,9 +715,10 @@
2.15 cancel = args.has_key("cancel")
2.16 ignore = args.has_key("ignore")
2.17 save = args.has_key("save")
2.18 - decline = filter(None, [(arg.startswith("decline-") and arg[len("decline-"):]) for arg in args.keys()])
2.19 + accept = self.prefixed_args("accept-", int)
2.20 + decline = self.prefixed_args("decline-", int)
2.21
2.22 - have_action = reply or discard or create or cancel or ignore or save or decline
2.23 + have_action = reply or discard or create or cancel or ignore or save or accept or decline
2.24
2.25 if not have_action:
2.26 return ["action"]
2.27 @@ -787,7 +789,7 @@
2.28 # Process the object and remove it from the list of requests.
2.29
2.30 if reply and self.process_received_request():
2.31 - self.remove_request(self.uid, self.recurrenceid)
2.32 + self.remove_request()
2.33
2.34 elif self.is_organiser() and (invite or cancel):
2.35
2.36 @@ -796,39 +798,53 @@
2.37 if self.process_created_request(
2.38 invite and "REQUEST" or "CANCEL", to_cancel, to_unschedule):
2.39
2.40 - self.remove_request(self.uid, self.recurrenceid)
2.41 + self.remove_request()
2.42
2.43 # Save single user events.
2.44
2.45 elif save:
2.46 self.store.set_event(self.user, self.uid, self.recurrenceid, node=self.obj.to_node())
2.47 self.update_event_in_freebusy()
2.48 - self.remove_request(self.uid, self.recurrenceid)
2.49 + self.remove_request()
2.50
2.51 # Remove the request and the object.
2.52
2.53 elif discard:
2.54 self.remove_event_from_freebusy()
2.55 - self.remove_event(self.uid, self.recurrenceid)
2.56 - self.remove_request(self.uid, self.recurrenceid)
2.57 + self.remove_event()
2.58 + self.remove_request()
2.59 +
2.60 + # Update counter-proposal records synchronously instead of assuming
2.61 + # that the outgoing handler will have done so before the form is
2.62 + # refreshed.
2.63 +
2.64 + # Accept a counter-proposal and decline all others, sending a new
2.65 + # request to all attendees.
2.66 +
2.67 + elif accept:
2.68
2.69 - # Decline a counter-proposal.
2.70 + # Take the first accepted proposal, although there should be only
2.71 + # one anyway.
2.72 +
2.73 + for i in accept:
2.74 + attendee_uri = get_uri(args.get("counter", [])[i])
2.75 + obj = self.get_stored_object(self.uid, self.recurrenceid, "counters", attendee_uri)
2.76 + self.obj.set_periods(self.get_periods(obj))
2.77 + break
2.78 +
2.79 + # Remove counter-proposals and issue a new invitation.
2.80 +
2.81 + attendees = uri_values(args.get("counter", []))
2.82 + self.remove_counters(attendees)
2.83 + self.process_created_request("REQUEST")
2.84 +
2.85 + # Decline a counter-proposal individually.
2.86
2.87 elif decline:
2.88 - for s in decline:
2.89 - try:
2.90 - i = int(s)
2.91 - except (IndexError, ValueError):
2.92 - pass
2.93 - else:
2.94 - attendee_uri = get_uri(args.get("decline", [])[i])
2.95 - self.process_declined_counter(attendee_uri)
2.96 -
2.97 - # Update the counter-proposals synchronously instead of
2.98 - # assuming that the outgoing handler will have done so
2.99 - # before the form is refreshed.
2.100 -
2.101 - self.remove_counter(attendee_uri)
2.102 + for i in decline:
2.103 + attendee_uri = get_uri(args.get("counter", [])[i])
2.104 + self.process_declined_counter(attendee_uri)
2.105 + self.remove_counter(attendee_uri)
2.106
2.107 # Redirect to the event.
2.108
2.109 @@ -870,7 +886,7 @@
2.110 start = self.get_date_control_values("dtstart")
2.111 end = self.get_date_control_values("dtend")
2.112
2.113 - period = FormPeriod(start, end, dtend_enabled, dttimes_enabled, self.get_tzid())
2.114 + period = FormPeriod(start, end, dtend_enabled, dttimes_enabled, self.get_tzid(), "DTSTART")
2.115
2.116 # Handle absent main period details.
2.117
3.1 --- a/imipweb/resource.py Tue Oct 06 18:38:45 2015 +0200
3.2 +++ b/imipweb/resource.py Tue Oct 06 18:43:29 2015 +0200
3.3 @@ -195,14 +195,6 @@
3.4 def _format_datetime(self, fn, dt, format):
3.5 return fn(dt, format=format, locale=self.get_user_locale())
3.6
3.7 - # Data management methods.
3.8 -
3.9 - def remove_request(self, uid, recurrenceid=None):
3.10 - return self.store.dequeue_request(self.user, uid, recurrenceid)
3.11 -
3.12 - def remove_event(self, uid, recurrenceid=None):
3.13 - return self.store.remove_event(self.user, uid, recurrenceid)
3.14 -
3.15 class ResourceClient(Resource, Client):
3.16
3.17 "A Web application resource and calendar client."
3.18 @@ -366,6 +358,29 @@
3.19
3.20 "Utility methods resource mix-in."
3.21
3.22 + def prefixed_args(self, prefix, convert=None):
3.23 +
3.24 + """
3.25 + Return values for all arguments having the given 'prefix' in their
3.26 + names, removing the prefix to obtain each value from the argument name
3.27 + itself. The 'convert' callable can be specified to perform a conversion
3.28 + (to int, for example).
3.29 + """
3.30 +
3.31 + args = self.env.get_args()
3.32 +
3.33 + values = []
3.34 + for name in args.keys():
3.35 + if name.startswith(prefix):
3.36 + value = name[len(prefix):]
3.37 + if convert:
3.38 + try:
3.39 + value = convert(value)
3.40 + except ValueError:
3.41 + pass
3.42 + values.append(value)
3.43 + return values
3.44 +
3.45 def control(self, name, type, value, selected=False, **kw):
3.46
3.47 """