1.1 --- a/imipweb/client.py Mon Oct 05 19:47:10 2015 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,154 +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 ClientForObject
1.26 -from imiptools.data import get_address, get_uri, uri_item, uri_values
1.27 -from imiptools.dates import format_datetime
1.28 -
1.29 -class ManagerClient(ClientForObject):
1.30 -
1.31 - """
1.32 - A content client for use by the manager, as opposed to operating within the
1.33 - mail processing pipeline.
1.34 - """
1.35 -
1.36 - # Communication methods.
1.37 -
1.38 - def send_message(self, method, sender, from_organiser, parts=None):
1.39 -
1.40 - """
1.41 - Create a full calendar object employing the given 'method', and send it
1.42 - to the appropriate recipients, also sending a copy to the 'sender'. The
1.43 - 'from_organiser' value indicates whether the organiser is sending this
1.44 - message (and is thus equivalent to "as organiser").
1.45 - """
1.46 -
1.47 - parts = parts or [self.obj.to_part(method)]
1.48 -
1.49 - # As organiser, send an invitation to attendees, excluding oneself if
1.50 - # also attending. The updated event will be saved by the outgoing
1.51 - # handler.
1.52 -
1.53 - organiser = get_uri(self.obj.get_value("ORGANIZER"))
1.54 - attendees = uri_values(self.obj.get_values("ATTENDEE"))
1.55 -
1.56 - if from_organiser:
1.57 - recipients = [get_address(attendee) for attendee in attendees if attendee != self.user]
1.58 - else:
1.59 - recipients = [get_address(organiser)]
1.60 -
1.61 - # Since the outgoing handler updates this user's free/busy details,
1.62 - # the stored details will probably not have the updated details at
1.63 - # this point, so we update our copy for serialisation as the bundled
1.64 - # free/busy object.
1.65 -
1.66 - freebusy = self.store.get_freebusy(self.user)
1.67 - self.update_freebusy(freebusy, self.user, from_organiser)
1.68 -
1.69 - # Bundle free/busy information if appropriate.
1.70 -
1.71 - part = self.get_freebusy_part(freebusy)
1.72 - if part:
1.73 - parts.append(part)
1.74 -
1.75 - # Explicitly specify the outgoing BCC recipient since we are sending as
1.76 - # the generic calendar user.
1.77 -
1.78 - message = self.messenger.make_outgoing_message(parts, recipients, outgoing_bcc=sender)
1.79 - self.messenger.sendmail(recipients, message.as_string(), outgoing_bcc=sender)
1.80 -
1.81 - # Action methods.
1.82 -
1.83 - def process_received_request(self):
1.84 -
1.85 - """
1.86 - Process the current request for the current user. Return whether any
1.87 - action was taken.
1.88 - """
1.89 -
1.90 - # Reply only on behalf of this user.
1.91 -
1.92 - attendee_attr = self.update_participation(self.obj)
1.93 -
1.94 - if not attendee_attr:
1.95 - return False
1.96 -
1.97 - self.obj["ATTENDEE"] = [(self.user, attendee_attr)]
1.98 - self.update_dtstamp()
1.99 - self.set_sequence(False)
1.100 - self.send_message("REPLY", get_address(self.user), from_organiser=False)
1.101 - return True
1.102 -
1.103 - def process_created_request(self, method, to_cancel=None, to_unschedule=None):
1.104 -
1.105 - """
1.106 - Process the current request, sending a created request of the given
1.107 - 'method' to attendees. Return whether any action was taken.
1.108 -
1.109 - If 'to_cancel' is specified, a list of participants to be sent cancel
1.110 - messages is provided.
1.111 -
1.112 - If 'to_unschedule' is specified, a list of periods to be unscheduled is
1.113 - provided.
1.114 - """
1.115 -
1.116 - # Here, the organiser should be the current user.
1.117 -
1.118 - organiser, organiser_attr = uri_item(self.obj.get_item("ORGANIZER"))
1.119 -
1.120 - self.update_sender(organiser_attr)
1.121 - self.update_dtstamp()
1.122 - self.set_sequence(True)
1.123 -
1.124 - parts = [self.obj.to_part(method)]
1.125 -
1.126 - # Add message parts with cancelled occurrence information.
1.127 - # NOTE: This could probably be merged with the updated event message.
1.128 -
1.129 - if to_unschedule:
1.130 - obj = self.obj.copy()
1.131 - obj.remove_all(["RRULE", "RDATE", "DTSTART", "DTEND", "DURATION"])
1.132 -
1.133 - for p in to_unschedule:
1.134 - if not p.origin:
1.135 - continue
1.136 - obj["RECURRENCE-ID"] = [(format_datetime(p.get_start()), p.get_start_attr())]
1.137 - parts.append(obj.to_part("CANCEL"))
1.138 -
1.139 - # Send the updated event, along with a cancellation for each of the
1.140 - # unscheduled occurrences.
1.141 -
1.142 - self.send_message("CANCEL", get_address(organiser), from_organiser=True, parts=parts)
1.143 -
1.144 - # When cancelling, replace the attendees with those for whom the event
1.145 - # is now cancelled.
1.146 -
1.147 - if to_cancel:
1.148 - obj = self.obj.copy()
1.149 - obj["ATTENDEE"] = to_cancel
1.150 -
1.151 - # Send a cancellation to all uninvited attendees.
1.152 -
1.153 - self.send_message("CANCEL", get_address(organiser), from_organiser=True)
1.154 -
1.155 - return True
1.156 -
1.157 -# vim: tabstop=4 expandtab shiftwidth=4