# HG changeset patch # User Paul Boddie # Date 1414447615 -3600 # Node ID 269d1507b5143d9824710aeacce5e7e7a92c432f # Parent 2d5d4b71ab4ee44a12f30ad78a2dc08fc4b38275 Introduced a manager-specific handler to use various convenience methods. diff -r 2d5d4b71ab4e -r 269d1507b514 imip_manager.py --- a/imip_manager.py Mon Oct 27 17:59:35 2014 +0100 +++ b/imip_manager.py Mon Oct 27 23:06:55 2014 +0100 @@ -5,11 +5,10 @@ sys.path.append("/var/lib/imip-agent") from imiptools import make_message, sendmail -from imiptools.content import format_datetime, get_address, get_datetime, \ - get_item, get_items, get_periods, get_uri, \ - get_utc_datetime, get_value, get_values, \ - parse_object, to_part, to_timezone, \ - update_freebusy +from imiptools.content import Handler, \ + format_datetime, get_address, get_datetime, \ + get_item, get_uri, get_utc_datetime, get_values, \ + parse_object, to_part, to_timezone from imiptools.period import have_conflict from vCalendar import to_node import markup @@ -64,6 +63,67 @@ path_info = self.get_path_info() return "%s%s" % (path.rstrip("/"), path_info) +class ManagerHandler(Handler): + + "A content handler for use by the manager." + + def __init__(self, details, objtype, user): + Handler.__init__(self, details) + self.objtype = objtype + self.user = user + self.organisers = map(get_address, self.get_values("ORGANIZER")) + + # Communication methods. + + def send_message(self, sender): + + """ + Create a full calendar object and send it to the organisers from the + given 'sender'. + """ + + # NOTE: Should parameterise the subject and body text. + + node = to_node({self.objtype : [(self.details, {})]}) + part = to_part("REPLY", [node]) + message = make_message([part], self.organisers, sender, "Response to request", "Response to a calendar request") + sendmail(sender, self.organisers, message.as_string()) + + # Action methods. + + def process_request(self, accept): + + """ + Process the current request for the given 'user', accepting any request + when 'accept' is true, declining requests otherwise. Return whether any + action was taken. + """ + + # When accepting or declining, do so only on behalf of this user, + # preserving any other attributes set as an attendee. + + for attendee, attendee_attr in self.get_items("ATTENDEE"): + + if attendee == self.user: + freebusy = self.store.get_freebusy(attendee) + + attendee_attr["PARTSTAT"] = accept and "ACCEPTED" or "DECLINED" + self.details["ATTENDEE"] = [(attendee, attendee_attr)] + self.send_message(get_address(attendee)) + + # Update the free/busy information. + + if accept: + periods = self.get_periods() + self.update_freebusy(freebusy, attendee, periods) + + if self.publisher: + self.publisher.set_freebusy(attendee, freebusy) + + return True + + return False + class Manager: "A simple manager application." @@ -83,18 +143,6 @@ except OSError: self.publisher = None - # Communication methods. - - def send_message(self, objtype, obj, sender, recipients): - - # Create a full calendar object and send it. - # NOTE: Should parameterise the subject and body text. - - node = to_node({objtype : [(obj, {})]}) - part = to_part("REPLY", [node]) - message = make_message([part], recipients, sender, "Response to request", "Response to a calendar request") - sendmail(sender, recipients, message.as_string()) - # Data management methods. def remove_request(self, uid): @@ -163,37 +211,18 @@ args = self.env.get_args() show_form = False - organisers = map(get_address, get_values(request, "ORGANIZER")) - freebusy = self.store.get_freebusy(self.user) - accept = args.has_key("accept") decline = args.has_key("decline") if accept or decline: - # When accepting or declining, do so only on behalf of this user, - # preserving any other attributes set as an attendee. + handler = ManagerHandler(request, objtype, self.user) - for attendee, attendee_attr in get_items(request, "ATTENDEE"): - if attendee == self.user: - attendee_attr["PARTSTAT"] = accept and "ACCEPTED" or "DECLINED" - request["ATTENDEE"] = [(attendee, attendee_attr)] - self.send_message(objtype, request, get_address(attendee), organisers) - - # Remove the request from the list. + if handler.process_request(accept): - self.remove_request(uid) - - # Update the free/busy information. + # Remove the request from the list. - if accept: - periods = get_periods(request) - update_freebusy(freebusy, attendee, periods, get_value(request, "TRANSP"), uid, self.store) - - if self.publisher: - self.publisher.set_freebusy(attendee, freebusy) - - break + self.remove_request(uid) elif args.has_key("ignore"): @@ -223,6 +252,8 @@ # Indicate whether there are conflicting events. + freebusy = self.store.get_freebusy(self.user) + if freebusy: # Obtain any time zone details from the suggested event. diff -r 2d5d4b71ab4e -r 269d1507b514 imiptools/content.py --- a/imiptools/content.py Mon Oct 27 17:59:35 2014 +0100 +++ b/imiptools/content.py Mon Oct 27 23:06:55 2014 +0100 @@ -318,15 +318,15 @@ "General handler support." - def __init__(self, details, recipients): + def __init__(self, details, recipients=None): """ Initialise the handler with the 'details' of a calendar object and the - 'recipients' of the object. + 'recipients' of the object (if specifically indicated). """ self.details = details - self.recipients = set(recipients) + self.recipients = recipients and set(recipients) self.uid = get_value(details, "UID") self.sequence = get_value(details, "SEQUENCE") @@ -369,7 +369,8 @@ return can_schedule(freebusy, periods, self.uid) def filter_by_recipients(self, values): - return self.recipients.intersection(map(get_address, values)) + addresses = map(get_address, values) + return self.recipients and self.recipients.intersection(addresses) or addresses def require_organiser_and_attendees(self):