1.1 --- a/imip_manager.py Wed Mar 25 18:15:37 2015 +0100
1.2 +++ b/imip_manager.py Wed Mar 25 18:23:37 2015 +0100
1.3 @@ -32,14 +32,12 @@
1.4 sys.path.append(LIBRARY_PATH)
1.5
1.6 from imiptools.client import Client, update_attendees
1.7 -from imiptools.data import get_address, get_uri, get_window_end, make_freebusy, \
1.8 - Object, to_part, \
1.9 - uri_dict, uri_item, uri_items, uri_values
1.10 +from imiptools.data import get_address, get_uri, get_window_end, Object, \
1.11 + uri_dict, uri_values
1.12 from imiptools.dates import format_datetime, format_time, to_date, get_datetime, \
1.13 get_datetime_item, get_end_of_day, get_period_item, \
1.14 get_start_of_day, get_start_of_next_day, get_timestamp, \
1.15 ends_on_same_day, to_timezone
1.16 -from imiptools.handlers import Handler
1.17 from imiptools.mail import Messenger
1.18 from imiptools.period import add_day_start_points, add_empty_days, add_slots, \
1.19 convert_periods, get_freebusy_details, \
1.20 @@ -47,156 +45,10 @@
1.21 partition_by_day, remove_period, remove_affected_period, \
1.22 update_freebusy
1.23 from imipweb.env import CGIEnvironment
1.24 +from imipweb.handler import ManagerHandler
1.25 import imip_store
1.26 import markup
1.27
1.28 -class ManagerHandler(Client, Handler):
1.29 -
1.30 - """
1.31 - A content handler for use by the manager, as opposed to operating within the
1.32 - mail processing pipeline.
1.33 - """
1.34 -
1.35 - def __init__(self, obj, user, messenger):
1.36 - Handler.__init__(self, messenger=messenger)
1.37 - Client.__init__(self, user)
1.38 -
1.39 - self.set_object(obj)
1.40 -
1.41 - # Communication methods.
1.42 -
1.43 - def send_message(self, method, sender, for_organiser):
1.44 -
1.45 - """
1.46 - Create a full calendar object employing the given 'method', and send it
1.47 - to the appropriate recipients, also sending a copy to the 'sender'. The
1.48 - 'for_organiser' value indicates whether the organiser is sending this
1.49 - message.
1.50 - """
1.51 -
1.52 - parts = [self.obj.to_part(method)]
1.53 -
1.54 - # As organiser, send an invitation to attendees, excluding oneself if
1.55 - # also attending. The updated event will be saved by the outgoing
1.56 - # handler.
1.57 -
1.58 - organiser = get_uri(self.obj.get_value("ORGANIZER"))
1.59 - attendees = uri_values(self.obj.get_values("ATTENDEE"))
1.60 -
1.61 - if for_organiser:
1.62 - recipients = [get_address(attendee) for attendee in attendees if attendee != self.user]
1.63 - else:
1.64 - recipients = [get_address(organiser)]
1.65 -
1.66 - # Bundle free/busy information if appropriate.
1.67 -
1.68 - if self.is_sharing() and self.is_bundling():
1.69 -
1.70 - # Invent a unique identifier.
1.71 -
1.72 - utcnow = get_timestamp()
1.73 - uid = "imip-agent-%s-%s" % (utcnow, get_address(self.user))
1.74 -
1.75 - freebusy = self.store.get_freebusy(self.user)
1.76 -
1.77 - # Replace the non-updated free/busy details for this event with
1.78 - # newer details (since the outgoing handler updates this user's
1.79 - # free/busy details).
1.80 -
1.81 - update_freebusy(freebusy,
1.82 - self.obj.get_periods_for_freebusy(self.get_tzid(), self.get_window_end()),
1.83 - self.obj.get_value("TRANSP") or "OPAQUE",
1.84 - self.uid, self.recurrenceid,
1.85 - self.obj.get_value("SUMMARY"),
1.86 - organiser)
1.87 -
1.88 - user_attr = self.messenger and self.messenger.sender != get_address(self.user) and \
1.89 - {"SENT-BY" : get_uri(self.messenger.sender)} or {}
1.90 -
1.91 - parts.append(to_part("PUBLISH", [
1.92 - make_freebusy(freebusy, uid, self.user, user_attr)
1.93 - ]))
1.94 -
1.95 - message = self.messenger.make_outgoing_message(parts, recipients, outgoing_bcc=sender)
1.96 - self.messenger.sendmail(recipients, message.as_string(), outgoing_bcc=sender)
1.97 -
1.98 - # Action methods.
1.99 -
1.100 - def process_received_request(self, update=False):
1.101 -
1.102 - """
1.103 - Process the current request for the given 'user'. Return whether any
1.104 - action was taken.
1.105 -
1.106 - If 'update' is given, the sequence number will be incremented in order
1.107 - to override any previous response.
1.108 - """
1.109 -
1.110 - # Reply only on behalf of this user.
1.111 -
1.112 - for attendee, attendee_attr in uri_items(self.obj.get_items("ATTENDEE")):
1.113 -
1.114 - if attendee == self.user:
1.115 - if attendee_attr.has_key("RSVP"):
1.116 - del attendee_attr["RSVP"]
1.117 - if self.messenger and self.messenger.sender != get_address(attendee):
1.118 - attendee_attr["SENT-BY"] = get_uri(self.messenger.sender)
1.119 - self.obj["ATTENDEE"] = [(attendee, attendee_attr)]
1.120 -
1.121 - self.update_dtstamp()
1.122 - self.set_sequence(update)
1.123 -
1.124 - self.send_message("REPLY", get_address(attendee), for_organiser=False)
1.125 -
1.126 - return True
1.127 -
1.128 - return False
1.129 -
1.130 - def process_created_request(self, method, update=False, removed=None, added=None):
1.131 -
1.132 - """
1.133 - Process the current request for the given 'user', sending a created
1.134 - request of the given 'method' to attendees. Return whether any action
1.135 - was taken.
1.136 -
1.137 - If 'update' is given, the sequence number will be incremented in order
1.138 - to override any previous message.
1.139 -
1.140 - If 'removed' is specified, a list of participants to be removed is
1.141 - provided.
1.142 -
1.143 - If 'added' is specified, a list of participants to be added is provided.
1.144 - """
1.145 -
1.146 - organiser, organiser_attr = uri_item(self.obj.get_item("ORGANIZER"))
1.147 -
1.148 - if self.messenger and self.messenger.sender != get_address(organiser):
1.149 - organiser_attr["SENT-BY"] = get_uri(self.messenger.sender)
1.150 -
1.151 - # Update the attendees in the event.
1.152 -
1.153 - to_cancel = update_attendees(self.obj, added, removed)
1.154 -
1.155 - self.update_dtstamp()
1.156 - self.set_sequence(update)
1.157 -
1.158 - self.send_message(method, get_address(organiser), for_organiser=True)
1.159 -
1.160 - # When cancelling, replace the attendees with those for whom the event
1.161 - # is now cancelled.
1.162 -
1.163 - if to_cancel:
1.164 - remaining = self.obj["ATTENDEE"]
1.165 - self.obj["ATTENDEE"] = to_cancel
1.166 - self.send_message("CANCEL", get_address(organiser), for_organiser=True)
1.167 -
1.168 - # Just in case more work is done with this event, the attendees are
1.169 - # now restored.
1.170 -
1.171 - self.obj["ATTENDEE"] = remaining
1.172 -
1.173 - return True
1.174 -
1.175 class Manager(Client):
1.176
1.177 "A simple manager application."