# HG changeset patch # User Paul Boddie # Date 1413985270 -7200 # Node ID 0a93e9e289c6945edbfe84b9de441d2b6ddfabd7 # Parent e91a5a943925c721696db7d7b3050b33e63c80b6 Added the beginnings of a scheduling agent operating on behalf of people. diff -r e91a5a943925 -r 0a93e9e289c6 imip_person.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imip_person.py Wed Oct 22 15:41:10 2014 +0200 @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" +Handlers for a person for whom scheduling is performed. +""" + +from imiptools.content import Handler +from vCalendar import to_node + +class Event(Handler): + + "An event handler." + + def add(self): + pass + + def cancel(self): + pass + + def counter(self): + + "Since this handler does not send requests, it will not handle replies." + + pass + + def declinecounter(self): + + """ + Since this handler does not send counter proposals, it will not handle + replies to such proposals. + """ + + pass + + def publish(self): + pass + + def refresh(self): + pass + + def reply(self): + + "Since this handler does not send requests, it will not handle replies." + + pass + + def request(self): + + "Hold requests and notify the recipient." + + oa = self.require_organiser_and_attendees() + if not oa: + return None + + (organiser, organiser_attr), attendees = oa + + # Process each attendee separately. + + for attendee, attendee_attr in attendees.items(): + + if not self.have_new_object(attendee, "VEVENT"): + continue + + # Store the event and queue the request. + + self.store.set_event(attendee, self.uid, to_node( + {"VEVENT" : [(self.details, {})]} + )) + + self.store.queue_request(attendee, self.uid) + + # The message is now wrapped and passed on to the recipient. + +class Freebusy(Handler): + + "A free/busy handler." + + def publish(self): + pass + + def reply(self): + + "Since this handler does not send requests, it will not handle replies." + + pass + + def request(self): + + """ + Respond to a request by preparing a reply containing free/busy + information for each indicated attendee. + """ + + # NOTE: This is currently the same as the resource handler but should be + # NOTE: subject to policy/preferences. + + oa = self.require_organiser_and_attendees() + if not oa: + return None + + (organiser, organiser_attr), attendees = oa + + # Construct an appropriate fragment. + + calendar = [] + cwrite = calendar.append + + # Get the details for each attendee. + + for attendee, attendee_attr in attendees.items(): + freebusy = self.store.get_freebusy(attendee) + + if freebusy: + record = [] + rwrite = record.append + + rwrite(("ORGANIZER", organiser_attr, organiser)) + rwrite(("ATTENDEE", attendee_attr, attendee)) + rwrite(("UID", {}, self.uid)) + + for start, end, uid in freebusy: + rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, [start, end])) + + cwrite(("VFREEBUSY", {}, record)) + + # Return the reply. + + return calendar + +class Journal(Handler): + + "A journal entry handler." + + def add(self): + pass + + def cancel(self): + pass + + def publish(self): + pass + +class Todo(Handler): + + "A to-do item handler." + + def add(self): + pass + + def cancel(self): + pass + + def counter(self): + + "Since this handler does not send requests, it will not handle replies." + + pass + + def declinecounter(self): + + """ + Since this handler does not send counter proposals, it will not handle + replies to such proposals. + """ + + pass + + def publish(self): + pass + + def refresh(self): + pass + + def reply(self): + + "Since this handler does not send requests, it will not handle replies." + + pass + + def request(self): + pass + +# Handler registry. + +handlers = [ + ("VFREEBUSY", Freebusy), + ("VEVENT", Event), + ("VTODO", Todo), + ("VJOURNAL", Journal), + ] + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r e91a5a943925 -r 0a93e9e289c6 imip_store.py --- a/imip_store.py Wed Oct 22 15:40:02 2014 +0200 +++ b/imip_store.py Wed Oct 22 15:41:10 2014 +0200 @@ -119,6 +119,22 @@ return True + def queue_request(self, user, uid): + + "Queue a request for 'user' having the given 'uid'." + + filename = self.get_object_in_store(user, "requests") + if not filename: + return False + + f = open(filename, "a") + try: + print >>f, uid + finally: + f.close() + + return True + class FilePublisher(FileBase): "A publisher of objects."