imip-agent

imiptools/handlers/person.py

339:9e2d17bc9986
2015-02-12 Paul Boddie Properly fix the parameters!
     1 #!/usr/bin/env python     2      3 """     4 Handlers for a person for whom scheduling is performed.     5      6 Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 from imiptools.content import Handler    23 from imiptools.data import get_uri    24 from imiptools.dates import format_datetime    25 from imiptools.handlers.common import CommonFreebusy    26 from imiptools.period import replace_overlapping    27 from imiptools.profile import Preferences    28     29 class PersonHandler(Handler):    30     31     "Handling mechanisms specific to people."    32     33     def _record(self, from_organiser=True, queue=False, cancel=False):    34     35         oa = self.require_organiser_and_attendees(from_organiser)    36         if not oa:    37             return False    38     39         (organiser, organiser_attr), attendees = organiser_item, attendees = oa    40     41         # Handle notifications and invitations.    42     43         if from_organiser:    44     45             # Process each attendee separately.    46     47             for attendee, attendee_attr in attendees.items():    48     49                 if not self.have_new_object(attendee):    50                     continue    51     52                 # Store the object and queue any request.    53     54                 self.store.set_event(attendee, self.uid, self.obj.to_node())    55     56                 if queue:    57                     self.store.queue_request(attendee, self.uid)    58                 elif cancel:    59                     self.store.cancel_event(attendee, self.uid)    60     61                     # No return message will occur to update the free/busy    62                     # information, so this is done here.    63     64                     freebusy = self.store.get_freebusy(attendee)    65                     self.remove_from_freebusy(freebusy, attendee)    66     67                     if self.publisher:    68                         self.publisher.set_freebusy(attendee, freebusy)    69     70                 self.update_freebusy_from_organiser(attendee, organiser_item)    71     72         # As organiser, update attendance.    73     74         else:    75             if self.merge_attendance(attendees, organiser):    76                 self.update_freebusy_from_attendees(organiser, attendees)    77     78         return True    79     80     def _record_freebusy(self, from_organiser=True):    81     82         "Record free/busy information for the received information."    83     84         if from_organiser:    85             organiser_item = self.require_organiser(from_organiser)    86             if not organiser_item:    87                 return    88     89             senders = [organiser_item]    90         else:    91             oa = self.require_organiser_and_attendees(from_organiser)    92             if not oa:    93                 return    94     95             organiser_item, attendees = oa    96             senders = attendees.items()    97     98             if not senders:    99                 return   100    101         freebusy = []   102    103         for value in self.obj.get_values("FREEBUSY") or []:   104             if not isinstance(value, list):   105                 value = [value]   106             for v in value:   107                 try:   108                     start, end = v.split("/", 1)   109                     freebusy.append((start, end))   110                 except ValueError:   111                     pass   112    113         dtstart = format_datetime(self.obj.get_utc_datetime("DTSTART"))   114         dtend = format_datetime(self.obj.get_utc_datetime("DTEND"))   115         user = get_uri(self.recipient)   116    117         for sender, sender_attr in senders:   118             stored_freebusy = self.store.get_freebusy_for_other(user, sender)   119             replace_overlapping(stored_freebusy, (dtstart, dtend), freebusy)   120             self.store.set_freebusy_for_other(user, stored_freebusy, sender)   121    122 class Event(PersonHandler):   123    124     "An event handler."   125    126     def add(self):   127    128         # NOTE: Queue a suggested modification to any active event.   129    130         return self.wrap("An addition to an event has been received.", link=False)   131    132     def cancel(self):   133    134         "Queue a cancellation of any active event."   135    136         self._record(from_organiser=True, queue=False, cancel=True)   137         return self.wrap("A cancellation has been received.", link=False)   138    139     def counter(self):   140    141         # NOTE: Queue a suggested modification to any active event.   142    143         return self.wrap("A counter proposal has been received.", link=False)   144    145     def declinecounter(self):   146    147         # NOTE: Queue a suggested modification to any active event.   148    149         return self.wrap("A declining counter proposal has been received.", link=False)   150    151     def publish(self):   152    153         "Register details of any relevant event."   154    155         self._record(from_organiser=True, queue=False)   156         return self.wrap("Details of an event have been received.")   157    158     def refresh(self):   159    160         "Update details of any active event."   161    162         self._record(from_organiser=True, queue=False)   163         return self.wrap("An event update has been received.")   164    165     def reply(self):   166    167         "Record replies and notify the recipient."   168    169         self._record(from_organiser=False, queue=False)   170         return self.wrap("A reply has been received.")   171    172     def request(self):   173    174         "Hold requests and notify the recipient."   175    176         self._record(from_organiser=True, queue=True)   177         return self.wrap("A request has been received.")   178    179 class Freebusy(PersonHandler, CommonFreebusy):   180    181     "A free/busy handler."   182    183     def publish(self):   184    185         "Register free/busy information."   186    187         self._record_freebusy(from_organiser=True)   188    189         # Produce a message if configured to do so.   190    191         preferences = Preferences(get_uri(self.recipient))   192         if preferences.get("freebusy_messages") == "notify":   193             return self.wrap("A free/busy update has been received.", link=False)   194    195     def reply(self):   196    197         "Record replies and notify the recipient."   198    199         self._record_freebusy(from_organiser=False)   200    201         # Produce a message if configured to do so.   202    203         preferences = Preferences(get_uri(self.recipient))   204         if preferences.get("freebusy_messages") == "notify":   205             return self.wrap("A reply to a free/busy request has been received.", link=False)   206    207     def request(self):   208    209         """   210         Respond to a request by preparing a reply containing free/busy   211         information for each indicated attendee.   212         """   213    214         # Produce a reply if configured to do so.   215    216         preferences = Preferences(get_uri(self.recipient))   217         if preferences.get("freebusy_sharing") == "share":   218             return CommonFreebusy.request(self)   219    220 class Journal(PersonHandler):   221    222     "A journal entry handler."   223    224     def add(self):   225    226         # NOTE: Queue a suggested modification to any active entry.   227    228         return self.wrap("An addition to a journal entry has been received.", link=False)   229    230     def cancel(self):   231    232         # NOTE: Queue a suggested modification to any active entry.   233    234         return self.wrap("A cancellation has been received.", link=False)   235    236     def publish(self):   237    238         # NOTE: Register details of any relevant entry.   239    240         self._record(from_organiser=True, queue=False)   241         return self.wrap("Details of a journal entry have been received.")   242    243 class Todo(PersonHandler):   244    245     "A to-do item handler."   246    247     def add(self):   248    249         # NOTE: Queue a suggested modification to any active item.   250    251         return self.wrap("An addition to an item has been received.", link=False)   252    253     def cancel(self):   254    255         # NOTE: Queue a suggested modification to any active item.   256    257         return self.wrap("A cancellation has been received.", link=False)   258    259     def counter(self):   260    261         # NOTE: Queue a suggested modification to any active item.   262    263         return self.wrap("A counter proposal has been received.", link=False)   264    265     def declinecounter(self):   266    267         # NOTE: Queue a suggested modification to any active item.   268    269         return self.wrap("A declining counter proposal has been received.", link=False)   270    271     def publish(self):   272    273         "Register details of any relevant item."   274    275         self._record(from_organiser=True, queue=False)   276         return self.wrap("Details of an item have been received.")   277    278     def refresh(self):   279    280         "Update details of any active item."   281    282         self._record(from_organiser=True, queue=False)   283         return self.wrap("An item update has been received.")   284    285     def reply(self):   286    287         "Record replies and notify the recipient."   288    289         self._record(from_organiser=False, queue=False)   290         return self.wrap("A reply has been received.")   291    292     def request(self):   293    294         "Hold requests and notify the recipient."   295    296         self._record(from_organiser=True, queue=True)   297         return self.wrap("A request has been received.")   298    299 # Handler registry.   300    301 handlers = [   302     ("VFREEBUSY",   Freebusy),   303     ("VEVENT",      Event),   304     ("VTODO",       Todo),   305     ("VJOURNAL",    Journal),   306     ]   307    308 # vim: tabstop=4 expandtab shiftwidth=4