1.1 --- a/imiptools/data.py Wed Feb 11 17:06:21 2015 +0100
1.2 +++ b/imiptools/data.py Wed Feb 11 17:07:32 2015 +0100
1.3 @@ -23,6 +23,7 @@
1.4 from email.mime.text import MIMEText
1.5 from imiptools.dates import format_datetime, get_datetime, get_freebusy_period, \
1.6 to_timezone, to_utc_datetime
1.7 +from imiptools.period import period_overlaps
1.8 from pytz import timezone
1.9 from vCalendar import iterwrite, parse, ParseError, to_dict, to_node
1.10 from vRecurrence import get_parameters, get_rule
1.11 @@ -106,13 +107,17 @@
1.12 nodes
1.13 )
1.14
1.15 -def make_freebusy(freebusy, uid, organiser, organiser_attr=None, attendee=None, attendee_attr=None):
1.16 +def make_freebusy(freebusy, uid, organiser, organiser_attr=None, attendee=None,
1.17 + attendee_attr=None, dtstart=None, dtend=None):
1.18
1.19 """
1.20 Return a calendar node defining the free/busy details described in the given
1.21 'freebusy' list, employing the given 'uid', for the given 'organiser' and
1.22 optional 'organiser_attr', with the optional 'attendee' providing recipient
1.23 details together with the optional 'attendee_attr'.
1.24 +
1.25 + The result will be constrained to the 'dtstart' and 'dtend' period if these
1.26 + parameters are given.
1.27 """
1.28
1.29 record = []
1.30 @@ -126,7 +131,17 @@
1.31 rwrite(("UID", {}, uid))
1.32
1.33 if freebusy:
1.34 - for start, end, uid, transp in freebusy:
1.35 +
1.36 + # Get a constrained view if start and end limits are specified.
1.37 +
1.38 + periods = dtstart and dtend and period_overlaps(freebusy, (dtstart, dtend), True) or freebusy
1.39 +
1.40 + # Write the limits of the resource.
1.41 +
1.42 + rwrite(("DTSTART", {"VALUE" : "DATE-TIME"}, periods[0][0]))
1.43 + rwrite(("DTEND", {"VALUE" : "DATE-TIME"}, periods[-1][1]))
1.44 +
1.45 + for start, end, uid, transp in periods:
1.46 if transp == "OPAQUE":
1.47 rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end])))
1.48
2.1 --- a/imiptools/handlers/common.py Wed Feb 11 17:06:21 2015 +0100
2.2 +++ b/imiptools/handlers/common.py Wed Feb 11 17:07:32 2015 +0100
2.3 @@ -20,6 +20,7 @@
2.4 """
2.5
2.6 from imiptools.data import get_address, get_uri, make_freebusy, to_part
2.7 +from imiptools.dates import format_datetime
2.8
2.9 class CommonFreebusy:
2.10
2.11 @@ -53,7 +54,10 @@
2.12 if self.messenger:
2.13 attendee_attr["SENT-BY"] = get_uri(self.messenger.sender)
2.14
2.15 - rwrite(make_freebusy(freebusy, self.uid, organiser, organiser_attr, attendee, attendee_attr))
2.16 + dtstart = format_datetime(self.obj.get_utc_datetime("DTSTART"))
2.17 + dtend = format_datetime(self.obj.get_utc_datetime("DTEND"))
2.18 +
2.19 + rwrite(make_freebusy(freebusy, self.uid, organiser, organiser_attr, attendee, attendee_attr, dtstart, dtend))
2.20
2.21 # Return the reply.
2.22
3.1 --- a/imiptools/handlers/person.py Wed Feb 11 17:06:21 2015 +0100
3.2 +++ b/imiptools/handlers/person.py Wed Feb 11 17:07:32 2015 +0100
3.3 @@ -21,7 +21,9 @@
3.4
3.5 from imiptools.content import Handler
3.6 from imiptools.data import get_uri
3.7 +from imiptools.dates import format_datetime
3.8 from imiptools.handlers.common import CommonFreebusy
3.9 +from imiptools.period import replace_overlapping
3.10 from imiptools.profile import Preferences
3.11
3.12 class PersonHandler(Handler):
3.13 @@ -108,8 +110,14 @@
3.14 except ValueError:
3.15 pass
3.16
3.17 + dtstart = format_datetime(self.obj.get_utc_datetime("DTSTART"))
3.18 + dtend = format_datetime(self.obj.get_utc_datetime("DTEND"))
3.19 + user = get_uri(self.recipient)
3.20 +
3.21 for sender, sender_attr in senders:
3.22 - self.store.set_freebusy_for_other(get_uri(self.recipient), freebusy, sender)
3.23 + stored_freebusy = self.store.get_freebusy_for_other(user, other)
3.24 + replace_overlapping(stored_freebusy, (dtstart, dtend), freebusy)
3.25 + self.store.set_freebusy_for_other(user, other, stored_freebusy, sender)
3.26
3.27 class Event(PersonHandler):
3.28
4.1 --- a/imiptools/period.py Wed Feb 11 17:06:21 2015 +0100
4.2 +++ b/imiptools/period.py Wed Feb 11 17:07:32 2015 +0100
4.3 @@ -73,6 +73,32 @@
4.4 else:
4.5 i += 1
4.6
4.7 +def get_overlapping(freebusy, period):
4.8 +
4.9 + """
4.10 + Return the indexes in 'freebusy' providing periods overlapping with
4.11 + 'period'.
4.12 + """
4.13 +
4.14 + dtstart, dtend = period[:2]
4.15 + found = bisect_left(freebusy, (dtstart, dtend))
4.16 +
4.17 + # Find earlier overlapping periods.
4.18 +
4.19 + start = found
4.20 +
4.21 + while start > 0 and freebusy[start - 1][1] > dtstart:
4.22 + start -= 1
4.23 +
4.24 + # Find later overlapping periods.
4.25 +
4.26 + end = found
4.27 +
4.28 + while end < len(freebusy) and (dtend is None or freebusy[end][0] < dtend):
4.29 + end += 1
4.30 +
4.31 + return start, end
4.32 +
4.33 def period_overlaps(freebusy, period, get_periods=False):
4.34
4.35 """
4.36 @@ -81,37 +107,32 @@
4.37 true value.
4.38 """
4.39
4.40 - dtstart, dtend = period[:2]
4.41 - found = bisect_left(freebusy, (dtstart, dtend, None, None))
4.42 -
4.43 - overlapping = []
4.44 -
4.45 - # Find earlier overlapping periods.
4.46 -
4.47 - i = found
4.48 -
4.49 - while i > 0 and freebusy[i - 1][1] > dtstart:
4.50 - if get_periods:
4.51 - overlapping.insert(0, freebusy[i - 1])
4.52 - else:
4.53 - return True
4.54 - i -= 1
4.55 -
4.56 - # Find later overlapping periods.
4.57 -
4.58 - i = found
4.59 -
4.60 - while i < len(freebusy) and (dtend is None or freebusy[i][0] < dtend):
4.61 - if get_periods:
4.62 - overlapping.append(freebusy[i])
4.63 - else:
4.64 - return True
4.65 - i += 1
4.66 + start, end = get_overlapping(freebusy, period)
4.67
4.68 if get_periods:
4.69 - return overlapping
4.70 + return freebusy[start:end]
4.71 else:
4.72 - return False
4.73 + return start != end
4.74 +
4.75 +def remove_overlapping(freebusy, period):
4.76 +
4.77 + "Remove from 'freebusy' all periods overlapping with 'period'."
4.78 +
4.79 + start, end = get_overlapping(freebusy, period)
4.80 +
4.81 + if start != end:
4.82 + del freebusy[start:end]
4.83 +
4.84 +def replace_overlapping(freebusy, period, replacements):
4.85 +
4.86 + """
4.87 + Replace existing periods in 'freebusy' within the given 'period', using the
4.88 + given 'replacements'.
4.89 + """
4.90 +
4.91 + remove_overlapping(freebusy, period)
4.92 + for replacement in replacements:
4.93 + insert_period(freebusy, replacement)
4.94
4.95 # Period layout mostly with datetime objects.
4.96