# HG changeset patch # User Paul Boddie # Date 1422832373 -3600 # Node ID a24c32fa9ae1c6a3d66096a3e28074d78e5b0af2 # Parent bbe8073c82d39c18195226fee61af2c03dc9d4b2 Moved common free/busy generation functionality into the data module. Simplified the common handler module, removing the complicated SupportFreebusy class. Made a get_timestamp function in the dates module for unique identifier construction. diff -r bbe8073c82d3 -r a24c32fa9ae1 imip_manager.py --- a/imip_manager.py Sun Feb 01 21:05:55 2015 +0100 +++ b/imip_manager.py Mon Feb 02 00:12:53 2015 +0100 @@ -31,10 +31,11 @@ sys.path.append(LIBRARY_PATH) from imiptools.content import Handler -from imiptools.data import get_address, get_uri, parse_object, Object, to_part +from imiptools.data import get_address, get_uri, make_freebusy, parse_object, \ + Object, to_part from imiptools.dates import format_datetime, get_datetime, get_start_of_day, \ - get_end_of_day, ends_on_same_day, to_timezone -from imiptools.handlers.common import SupportFreebusy + get_end_of_day, get_timestamp, ends_on_same_day, \ + to_timezone from imiptools.mail import Messenger from imiptools.period import add_day_start_points, add_slots, convert_periods, \ get_freebusy_details, \ @@ -106,7 +107,7 @@ path = self.get_path() return "%s/%s" % (path.rstrip("/"), path_info.lstrip("/")) -class ManagerHandler(Handler, SupportFreebusy): +class ManagerHandler(Handler): """ A content handler for use by the manager, as opposed to operating within the @@ -131,9 +132,7 @@ parts = [self.obj.to_part(method)] - from_organiser = self.user == self.organiser - - if from_organiser: + if self.user == self.organiser: recipients = map(get_address, self.attendees) else: recipients = [get_address(self.organiser)] @@ -145,9 +144,13 @@ if preferences.get("freebusy_sharing") == "share" and \ preferences.get("freebusy_bundling") == "always": - freebusy = self.make_freebusy(from_organiser=from_organiser, publish=True) - if freebusy: - parts.append(to_part("PUBLISH", freebusy)) + # Invent a unique identifier. + + utcnow = get_timestamp() + uid = "imip-agent-%s-%s" % (utcnow, get_address(self.user)) + + freebusy = self.store.get_freebusy(self.user) + parts.append(to_part("PUBLISH", [make_freebusy(freebusy, uid, self.user)])) message = self.messenger.make_outgoing_message(parts, recipients, outgoing_bcc=sender) self.messenger.sendmail(recipients, message.as_string(), outgoing_bcc=sender) @@ -361,7 +364,7 @@ # Invent a unique identifier. - utcnow = format_datetime(to_timezone(datetime.utcnow(), "UTC")) + utcnow = get_timestamp() uid = "imip-agent-%s-%s" % (utcnow, get_address(self.user)) # Create a calendar object and store it as a request. diff -r bbe8073c82d3 -r a24c32fa9ae1 imiptools/data.py --- a/imiptools/data.py Sun Feb 01 21:05:55 2015 +0100 +++ b/imiptools/data.py Mon Feb 02 00:12:53 2015 +0100 @@ -86,6 +86,31 @@ nodes ) +def make_freebusy(freebusy, uid, organiser, attendee=None): + + """ + Return a calendar node defining the free/busy details described in the given + 'freebusy' list, employing the given 'uid', for the given 'organiser', with + the optional 'attendee' providing recipient details. + """ + + record = [] + rwrite = record.append + + rwrite(("ORGANIZER", {}, organiser)) + + if attendee: + rwrite(("ATTENDEE", {}, attendee)) + + rwrite(("UID", {}, uid)) + + if freebusy: + for start, end, uid, transp in freebusy: + if transp == "OPAQUE": + rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end]))) + + return ("VFREEBUSY", {}, record) + def parse_object(f, encoding, objtype=None): """ diff -r bbe8073c82d3 -r a24c32fa9ae1 imiptools/dates.py --- a/imiptools/dates.py Sun Feb 01 21:05:55 2015 +0100 +++ b/imiptools/dates.py Mon Feb 02 00:12:53 2015 +0100 @@ -110,4 +110,7 @@ end == get_end_of_day(dt) ) +def get_timestamp(): + return format_datetime(to_timezone(datetime.utcnow(), "UTC")) + # vim: tabstop=4 expandtab shiftwidth=4 diff -r bbe8073c82d3 -r a24c32fa9ae1 imiptools/handlers/common.py --- a/imiptools/handlers/common.py Sun Feb 01 21:05:55 2015 +0100 +++ b/imiptools/handlers/common.py Mon Feb 02 00:12:53 2015 +0100 @@ -19,38 +19,17 @@ this program. If not, see . """ -from imiptools.data import get_address, to_part +from imiptools.data import get_address, make_freebusy, to_part -class SupportFreebusy: +class CommonFreebusy: - "Support for free/busy publishing and sharing." + "Common free/busy mix-in." - def make_freebusy_to_publish(self, from_organiser=True): + def request(self): """ - Make a freebusy object for publication for a user, providing either an - organiser's details if 'from_organiser' is set to a true value, or an - attendee's details otherwise. - """ - - calendar = self.make_freebusy(from_organiser, publish=True) - - # Return a published object. - - if calendar: - return [( - map(get_address, - from_organiser and self.obj.get_values("ATTENDEE") or - self.obj.get_values("ORGANIZER")), - to_part("PUBLISH", calendar) - )] - - def make_freebusy(self, from_organiser=True, publish=False): - - """ - Make a freebusy object, providing either an organiser's details if - 'from_organiser' is set to a true value, or an attendee's details - otherwise. + Respond to a request by preparing a reply containing free/busy + information for each indicated attendee. """ oa = self.require_organiser_and_attendees() @@ -61,63 +40,17 @@ # Get the details for each attendee. - calendar = [] - cwrite = calendar.append + responses = [] + rwrite = responses.append + + # For replies, the organiser and attendee are preserved. for attendee, attendee_attr in attendees.items(): - - # Construct an appropriate fragment. - - freebusy = self.store.get_freebusy(from_organiser and organiser or attendee) - - record = [] - rwrite = record.append - - # For replies, the organiser is preserved. - - if not publish or from_organiser: - rwrite(("ORGANIZER", organiser_attr, organiser)) - - # For published objects, the organiser is actually the user whose - # information is being provided. - - else: - rwrite(("ORGANIZER", attendee_attr, attendee)) - - # For replies, the attendee is preserved. - # (Published objects do not employ the attendee property.) - - if not publish: - rwrite(("ATTENDEE", attendee_attr, attendee)) - - rwrite(("UID", {}, self.uid)) - - if freebusy: - for start, end, uid, transp in freebusy: - if transp == "OPAQUE": - rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end]))) - - cwrite(("VFREEBUSY", {}, record)) - - # Return the object. - - return calendar - -class CommonFreebusy(SupportFreebusy): - - "Common free/busy mix-in." - - def request(self): - - """ - Respond to a request by preparing a reply containing free/busy - information for each indicated attendee. - """ - - calendar = self.make_freebusy(from_organiser=False) + freebusy = self.store.get_freebusy(attendee) + rwrite(make_freebusy(freebusy, self.uid, organiser, attendee)) # Return the reply. - return [(map(get_address, self.obj.get_values("ORGANIZER")), to_part("REPLY", calendar))] + return [([get_address(organiser)], to_part("REPLY", responses))] # vim: tabstop=4 expandtab shiftwidth=4