1 #!/usr/bin/env python 2 3 """ 4 Handlers for a person for whom scheduling is performed, inspecting outgoing 5 messages to obtain scheduling done externally. 6 7 Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk> 8 9 This program is free software; you can redistribute it and/or modify it under 10 the terms of the GNU General Public License as published by the Free Software 11 Foundation; either version 3 of the License, or (at your option) any later 12 version. 13 14 This program is distributed in the hope that it will be useful, but WITHOUT 15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 17 details. 18 19 You should have received a copy of the GNU General Public License along with 20 this program. If not, see <http://www.gnu.org/licenses/>. 21 """ 22 23 from imiptools.data import uri_dict, uri_item, uri_values 24 from imiptools.handlers import Handler 25 from imiptools.handlers.common import Outgoing 26 27 class PersonHandler(Handler, Outgoing): 28 29 "Handling mechanisms specific to people." 30 31 def set_identity(self, from_organiser=True): 32 33 """ 34 Set the current user for the current object. It is usually set when 35 initialising the handler, using the recipient details, but outgoing 36 messages do not reference the recipient in this way. 37 """ 38 39 self.user, attr = uri_item(self.obj.get_item(from_organiser and "ORGANIZER" or "ATTENDEE")) 40 41 def _record(self, from_organiser=True): 42 43 """ 44 Record details from the current object given a message originating 45 from an organiser if 'from_organiser' is set to a true value. 46 """ 47 48 self.set_identity(from_organiser) 49 50 # Check for event using UID. 51 52 if not self.have_new_object(): 53 return False 54 55 # Update the object. 56 57 if from_organiser: 58 59 # Set the complete event or an additional occurrence. 60 61 self.store.set_event(self.user, self.uid, self.recurrenceid, self.obj.to_node()) 62 63 # Remove additional recurrences if handling a complete event. 64 65 if not self.recurrenceid: 66 self.store.remove_recurrences(self.user, self.uid) 67 68 else: 69 # Obtain valid attendees, merging their attendance with the stored 70 # object. 71 72 attendees = self.require_attendees(from_organiser) 73 self.merge_attendance(attendees) 74 75 # Remove any associated request. 76 77 self.store.dequeue_request(self.user, self.uid, self.recurrenceid) 78 79 # Update free/busy information. 80 81 self.update_event_in_freebusy(from_organiser) 82 83 return True 84 85 def _remove(self, from_organiser=True): 86 87 """ 88 Remove details from the current object given a message originating 89 from an organiser if 'from_organiser' is set to a true value. 90 """ 91 92 self.set_identity(from_organiser) 93 94 # Check for event using UID. 95 96 if not self.have_new_object(): 97 return False 98 99 # Obtain any stored object, using parent object details if a newly- 100 # indicated occurrence is referenced. 101 102 obj = self.get_object() 103 old = not obj and self.get_parent_object() or obj 104 105 if not old: 106 return False 107 108 # Only cancel the event completely if all attendees are given. 109 110 attendees = uri_dict(old.get_value_map("ATTENDEE")) 111 all_attendees = set(attendees.keys()) 112 given_attendees = set(uri_values(self.obj.get_values("ATTENDEE"))) 113 cancel_entire_event = given_attendees == all_attendees 114 115 # Keep the event for the organiser. 116 117 if cancel_entire_event: 118 self.store.cancel_event(self.user, self.uid, self.recurrenceid) 119 120 # Otherwise, remove the given attendees and update the event. 121 122 elif obj: 123 for attendee in given_attendees: 124 if attendees.has_key(attendee): 125 del attendees[attendee] 126 obj["ATTENDEE"] = attendees.items() 127 128 # Update the stored object with sequence information. 129 130 if obj: 131 obj["SEQUENCE"] = self.obj.get_items("SEQUENCE") or [] 132 obj["DTSTAMP"] = self.obj.get_items("DTSTAMP") or [] 133 134 # Set the complete event if not an additional occurrence. For any newly- 135 # indicated occurrence, use the received event details. 136 137 self.store.set_event(self.user, self.uid, self.recurrenceid, (obj or self.obj).to_node()) 138 139 # Remove any associated request. 140 141 self.store.dequeue_request(self.user, self.uid, self.recurrenceid) 142 143 # Update free/busy information. 144 145 if cancel_entire_event or self.user in given_attendees: 146 self.remove_event_from_freebusy() 147 148 return True 149 150 class Event(PersonHandler): 151 152 "An event handler." 153 154 def add(self): 155 pass 156 157 def cancel(self): 158 self._remove(True) 159 160 def counter(self): 161 pass 162 163 def declinecounter(self): 164 pass 165 166 def publish(self): 167 self._record(True) 168 169 def refresh(self): 170 pass 171 172 def reply(self): 173 self._record(False) 174 175 def request(self): 176 self._record(True) 177 178 # Handler registry. 179 180 handlers = [ 181 ("VEVENT", Event), 182 ] 183 184 # vim: tabstop=4 expandtab shiftwidth=4