1.1 --- a/imip_manager.py Sun Feb 01 21:05:55 2015 +0100
1.2 +++ b/imip_manager.py Mon Feb 02 00:12:53 2015 +0100
1.3 @@ -31,10 +31,11 @@
1.4 sys.path.append(LIBRARY_PATH)
1.5
1.6 from imiptools.content import Handler
1.7 -from imiptools.data import get_address, get_uri, parse_object, Object, to_part
1.8 +from imiptools.data import get_address, get_uri, make_freebusy, parse_object, \
1.9 + Object, to_part
1.10 from imiptools.dates import format_datetime, get_datetime, get_start_of_day, \
1.11 - get_end_of_day, ends_on_same_day, to_timezone
1.12 -from imiptools.handlers.common import SupportFreebusy
1.13 + get_end_of_day, get_timestamp, ends_on_same_day, \
1.14 + to_timezone
1.15 from imiptools.mail import Messenger
1.16 from imiptools.period import add_day_start_points, add_slots, convert_periods, \
1.17 get_freebusy_details, \
1.18 @@ -106,7 +107,7 @@
1.19 path = self.get_path()
1.20 return "%s/%s" % (path.rstrip("/"), path_info.lstrip("/"))
1.21
1.22 -class ManagerHandler(Handler, SupportFreebusy):
1.23 +class ManagerHandler(Handler):
1.24
1.25 """
1.26 A content handler for use by the manager, as opposed to operating within the
1.27 @@ -131,9 +132,7 @@
1.28
1.29 parts = [self.obj.to_part(method)]
1.30
1.31 - from_organiser = self.user == self.organiser
1.32 -
1.33 - if from_organiser:
1.34 + if self.user == self.organiser:
1.35 recipients = map(get_address, self.attendees)
1.36 else:
1.37 recipients = [get_address(self.organiser)]
1.38 @@ -145,9 +144,13 @@
1.39 if preferences.get("freebusy_sharing") == "share" and \
1.40 preferences.get("freebusy_bundling") == "always":
1.41
1.42 - freebusy = self.make_freebusy(from_organiser=from_organiser, publish=True)
1.43 - if freebusy:
1.44 - parts.append(to_part("PUBLISH", freebusy))
1.45 + # Invent a unique identifier.
1.46 +
1.47 + utcnow = get_timestamp()
1.48 + uid = "imip-agent-%s-%s" % (utcnow, get_address(self.user))
1.49 +
1.50 + freebusy = self.store.get_freebusy(self.user)
1.51 + parts.append(to_part("PUBLISH", [make_freebusy(freebusy, uid, self.user)]))
1.52
1.53 message = self.messenger.make_outgoing_message(parts, recipients, outgoing_bcc=sender)
1.54 self.messenger.sendmail(recipients, message.as_string(), outgoing_bcc=sender)
1.55 @@ -361,7 +364,7 @@
1.56
1.57 # Invent a unique identifier.
1.58
1.59 - utcnow = format_datetime(to_timezone(datetime.utcnow(), "UTC"))
1.60 + utcnow = get_timestamp()
1.61 uid = "imip-agent-%s-%s" % (utcnow, get_address(self.user))
1.62
1.63 # Create a calendar object and store it as a request.
2.1 --- a/imiptools/data.py Sun Feb 01 21:05:55 2015 +0100
2.2 +++ b/imiptools/data.py Mon Feb 02 00:12:53 2015 +0100
2.3 @@ -86,6 +86,31 @@
2.4 nodes
2.5 )
2.6
2.7 +def make_freebusy(freebusy, uid, organiser, attendee=None):
2.8 +
2.9 + """
2.10 + Return a calendar node defining the free/busy details described in the given
2.11 + 'freebusy' list, employing the given 'uid', for the given 'organiser', with
2.12 + the optional 'attendee' providing recipient details.
2.13 + """
2.14 +
2.15 + record = []
2.16 + rwrite = record.append
2.17 +
2.18 + rwrite(("ORGANIZER", {}, organiser))
2.19 +
2.20 + if attendee:
2.21 + rwrite(("ATTENDEE", {}, attendee))
2.22 +
2.23 + rwrite(("UID", {}, uid))
2.24 +
2.25 + if freebusy:
2.26 + for start, end, uid, transp in freebusy:
2.27 + if transp == "OPAQUE":
2.28 + rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end])))
2.29 +
2.30 + return ("VFREEBUSY", {}, record)
2.31 +
2.32 def parse_object(f, encoding, objtype=None):
2.33
2.34 """
3.1 --- a/imiptools/dates.py Sun Feb 01 21:05:55 2015 +0100
3.2 +++ b/imiptools/dates.py Mon Feb 02 00:12:53 2015 +0100
3.3 @@ -110,4 +110,7 @@
3.4 end == get_end_of_day(dt)
3.5 )
3.6
3.7 +def get_timestamp():
3.8 + return format_datetime(to_timezone(datetime.utcnow(), "UTC"))
3.9 +
3.10 # vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/imiptools/handlers/common.py Sun Feb 01 21:05:55 2015 +0100
4.2 +++ b/imiptools/handlers/common.py Mon Feb 02 00:12:53 2015 +0100
4.3 @@ -19,38 +19,17 @@
4.4 this program. If not, see <http://www.gnu.org/licenses/>.
4.5 """
4.6
4.7 -from imiptools.data import get_address, to_part
4.8 +from imiptools.data import get_address, make_freebusy, to_part
4.9
4.10 -class SupportFreebusy:
4.11 +class CommonFreebusy:
4.12
4.13 - "Support for free/busy publishing and sharing."
4.14 + "Common free/busy mix-in."
4.15
4.16 - def make_freebusy_to_publish(self, from_organiser=True):
4.17 + def request(self):
4.18
4.19 """
4.20 - Make a freebusy object for publication for a user, providing either an
4.21 - organiser's details if 'from_organiser' is set to a true value, or an
4.22 - attendee's details otherwise.
4.23 - """
4.24 -
4.25 - calendar = self.make_freebusy(from_organiser, publish=True)
4.26 -
4.27 - # Return a published object.
4.28 -
4.29 - if calendar:
4.30 - return [(
4.31 - map(get_address,
4.32 - from_organiser and self.obj.get_values("ATTENDEE") or
4.33 - self.obj.get_values("ORGANIZER")),
4.34 - to_part("PUBLISH", calendar)
4.35 - )]
4.36 -
4.37 - def make_freebusy(self, from_organiser=True, publish=False):
4.38 -
4.39 - """
4.40 - Make a freebusy object, providing either an organiser's details if
4.41 - 'from_organiser' is set to a true value, or an attendee's details
4.42 - otherwise.
4.43 + Respond to a request by preparing a reply containing free/busy
4.44 + information for each indicated attendee.
4.45 """
4.46
4.47 oa = self.require_organiser_and_attendees()
4.48 @@ -61,63 +40,17 @@
4.49
4.50 # Get the details for each attendee.
4.51
4.52 - calendar = []
4.53 - cwrite = calendar.append
4.54 + responses = []
4.55 + rwrite = responses.append
4.56 +
4.57 + # For replies, the organiser and attendee are preserved.
4.58
4.59 for attendee, attendee_attr in attendees.items():
4.60 -
4.61 - # Construct an appropriate fragment.
4.62 -
4.63 - freebusy = self.store.get_freebusy(from_organiser and organiser or attendee)
4.64 -
4.65 - record = []
4.66 - rwrite = record.append
4.67 -
4.68 - # For replies, the organiser is preserved.
4.69 -
4.70 - if not publish or from_organiser:
4.71 - rwrite(("ORGANIZER", organiser_attr, organiser))
4.72 -
4.73 - # For published objects, the organiser is actually the user whose
4.74 - # information is being provided.
4.75 -
4.76 - else:
4.77 - rwrite(("ORGANIZER", attendee_attr, attendee))
4.78 -
4.79 - # For replies, the attendee is preserved.
4.80 - # (Published objects do not employ the attendee property.)
4.81 -
4.82 - if not publish:
4.83 - rwrite(("ATTENDEE", attendee_attr, attendee))
4.84 -
4.85 - rwrite(("UID", {}, self.uid))
4.86 -
4.87 - if freebusy:
4.88 - for start, end, uid, transp in freebusy:
4.89 - if transp == "OPAQUE":
4.90 - rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end])))
4.91 -
4.92 - cwrite(("VFREEBUSY", {}, record))
4.93 -
4.94 - # Return the object.
4.95 -
4.96 - return calendar
4.97 -
4.98 -class CommonFreebusy(SupportFreebusy):
4.99 -
4.100 - "Common free/busy mix-in."
4.101 -
4.102 - def request(self):
4.103 -
4.104 - """
4.105 - Respond to a request by preparing a reply containing free/busy
4.106 - information for each indicated attendee.
4.107 - """
4.108 -
4.109 - calendar = self.make_freebusy(from_organiser=False)
4.110 + freebusy = self.store.get_freebusy(attendee)
4.111 + rwrite(make_freebusy(freebusy, self.uid, organiser, attendee))
4.112
4.113 # Return the reply.
4.114
4.115 - return [(map(get_address, self.obj.get_values("ORGANIZER")), to_part("REPLY", calendar))]
4.116 + return [([get_address(organiser)], to_part("REPLY", responses))]
4.117
4.118 # vim: tabstop=4 expandtab shiftwidth=4