1.1 --- a/imipweb/handler.py Sat Jul 25 19:29:44 2015 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,171 +0,0 @@
1.4 -#!/usr/bin/env python
1.5 -
1.6 -"""
1.7 -Interaction with the mail system for the manager interface.
1.8 -
1.9 -Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk>
1.10 -
1.11 -This program is free software; you can redistribute it and/or modify it under
1.12 -the terms of the GNU General Public License as published by the Free Software
1.13 -Foundation; either version 3 of the License, or (at your option) any later
1.14 -version.
1.15 -
1.16 -This program is distributed in the hope that it will be useful, but WITHOUT
1.17 -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.18 -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.19 -details.
1.20 -
1.21 -You should have received a copy of the GNU General Public License along with
1.22 -this program. If not, see <http://www.gnu.org/licenses/>.
1.23 -"""
1.24 -
1.25 -from imiptools.client import Client
1.26 -from imiptools.data import get_address, get_uri, make_freebusy, \
1.27 - to_part, uri_item, uri_values
1.28 -from imiptools.dates import format_datetime, get_timestamp
1.29 -from imiptools.handlers import Handler
1.30 -
1.31 -class ManagerHandler(Handler):
1.32 -
1.33 - """
1.34 - A content handler for use by the manager, as opposed to operating within the
1.35 - mail processing pipeline.
1.36 - """
1.37 -
1.38 - def __init__(self, obj, user, messenger):
1.39 - Handler.__init__(self, messenger=messenger)
1.40 - Client.__init__(self, user) # this redefines the Handler initialisation
1.41 -
1.42 - self.set_object(obj)
1.43 -
1.44 - # Communication methods.
1.45 -
1.46 - def send_message(self, method, sender, from_organiser, parts=None):
1.47 -
1.48 - """
1.49 - Create a full calendar object employing the given 'method', and send it
1.50 - to the appropriate recipients, also sending a copy to the 'sender'. The
1.51 - 'from_organiser' value indicates whether the organiser is sending this
1.52 - message.
1.53 - """
1.54 -
1.55 - parts = parts or [self.obj.to_part(method)]
1.56 -
1.57 - # As organiser, send an invitation to attendees, excluding oneself if
1.58 - # also attending. The updated event will be saved by the outgoing
1.59 - # handler.
1.60 -
1.61 - organiser = get_uri(self.obj.get_value("ORGANIZER"))
1.62 - attendees = uri_values(self.obj.get_values("ATTENDEE"))
1.63 -
1.64 - if from_organiser:
1.65 - recipients = [get_address(attendee) for attendee in attendees if attendee != self.user]
1.66 - else:
1.67 - recipients = [get_address(organiser)]
1.68 -
1.69 - # Bundle free/busy information if appropriate.
1.70 -
1.71 - if self.is_sharing() and self.is_bundling():
1.72 -
1.73 - # Invent a unique identifier.
1.74 -
1.75 - utcnow = get_timestamp()
1.76 - uid = "imip-agent-%s-%s" % (utcnow, get_address(self.user))
1.77 -
1.78 - freebusy = self.store.get_freebusy(self.user)
1.79 -
1.80 - # Since the outgoing handler updates this user's free/busy details,
1.81 - # the stored details will probably not have the updated details at
1.82 - # this point, so we update our copy for serialisation as the bundled
1.83 - # free/busy object.
1.84 -
1.85 - self.update_freebusy(freebusy,
1.86 - self.obj.get_periods(self.get_tzid(), self.get_window_end()))
1.87 -
1.88 - user_attr = {}
1.89 - self.update_sender(user_attr)
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 - # Explicitly specify the outgoing BCC recipient since we are sending as
1.96 - # the generic calendar user.
1.97 -
1.98 - message = self.messenger.make_outgoing_message(parts, recipients, outgoing_bcc=sender)
1.99 - self.messenger.sendmail(recipients, message.as_string(), outgoing_bcc=sender)
1.100 -
1.101 - # Action methods.
1.102 -
1.103 - def process_received_request(self):
1.104 -
1.105 - """
1.106 - Process the current request for the current user. Return whether any
1.107 - action was taken.
1.108 - """
1.109 -
1.110 - # Reply only on behalf of this user.
1.111 -
1.112 - attendee_attr = self.update_participation(self.obj)
1.113 -
1.114 - if not attendee_attr:
1.115 - return False
1.116 -
1.117 - self.obj["ATTENDEE"] = [(self.user, attendee_attr)]
1.118 - self.update_dtstamp()
1.119 - self.set_sequence(False)
1.120 - self.send_message("REPLY", get_address(self.user), from_organiser=False)
1.121 - return True
1.122 -
1.123 - def process_created_request(self, method, to_cancel=None, to_unschedule=None):
1.124 -
1.125 - """
1.126 - Process the current request, sending a created request of the given
1.127 - 'method' to attendees. Return whether any action was taken.
1.128 -
1.129 - If 'to_cancel' is specified, a list of participants to be sent cancel
1.130 - messages is provided.
1.131 - """
1.132 -
1.133 - # Here, the organiser should be the current user.
1.134 -
1.135 - organiser, organiser_attr = uri_item(self.obj.get_item("ORGANIZER"))
1.136 -
1.137 - self.update_sender(organiser_attr)
1.138 - self.update_dtstamp()
1.139 - self.set_sequence(True)
1.140 -
1.141 - parts = [self.obj.to_part(method)]
1.142 -
1.143 - # Add message parts with cancelled occurrence information.
1.144 - # NOTE: This could probably be merged with the updated event message.
1.145 -
1.146 - if to_unschedule:
1.147 - obj = self.obj.copy()
1.148 - obj.remove_all(["RRULE", "RDATE", "DTSTART", "DTEND", "DURATION"])
1.149 -
1.150 - for p in to_unschedule:
1.151 - if not p.origin:
1.152 - continue
1.153 - obj["RECURRENCE-ID"] = [(format_datetime(p.get_start()), {})]
1.154 - parts.append(obj.to_part("CANCEL"))
1.155 -
1.156 - # Send the updated event, along with a cancellation for each of the
1.157 - # unscheduled occurrences.
1.158 -
1.159 - self.send_message("CANCEL", get_address(organiser), from_organiser=True, parts=parts)
1.160 -
1.161 - # When cancelling, replace the attendees with those for whom the event
1.162 - # is now cancelled.
1.163 -
1.164 - if to_cancel:
1.165 - obj = self.obj.copy()
1.166 - obj["ATTENDEE"] = to_cancel
1.167 -
1.168 - # Send a cancellation to all uninvited attendees.
1.169 -
1.170 - self.send_message("CANCEL", get_address(organiser), from_organiser=True)
1.171 -
1.172 - return True
1.173 -
1.174 -# vim: tabstop=4 expandtab shiftwidth=4