1.1 --- a/imip_manager.py Tue Mar 03 00:03:45 2015 +0100
1.2 +++ b/imip_manager.py Tue Mar 03 00:05:22 2015 +0100
1.3 @@ -405,10 +405,19 @@
1.4 return self.store.remove_event(self.user, uid, recurrenceid)
1.5
1.6 def update_freebusy(self, uid, recurrenceid, obj):
1.7 +
1.8 + """
1.9 + Update stored free/busy details for the event with the given 'uid' and
1.10 + 'recurrenceid' having a representation of 'obj'.
1.11 + """
1.12 +
1.13 + is_only_organiser = self.user not in uri_values(obj.get_values("ATTENDEE"))
1.14 +
1.15 freebusy = self.store.get_freebusy(self.user)
1.16 update_freebusy(freebusy,
1.17 obj.get_periods_for_freebusy(self.get_tzid(), self.get_window_end()),
1.18 - obj.get_value("TRANSP"), uid, recurrenceid)
1.19 + is_only_organiser and "ORG" or obj.get_value("TRANSP"),
1.20 + uid, recurrenceid)
1.21 self.store.set_freebusy(self.user, freebusy)
1.22
1.23 def remove_from_freebusy(self, uid, recurrenceid=None):
2.1 --- a/imiptools/content.py Tue Mar 03 00:03:45 2015 +0100
2.2 +++ b/imiptools/content.py Tue Mar 03 00:05:22 2015 +0100
2.3 @@ -25,7 +25,7 @@
2.4 from imiptools.config import MANAGER_PATH, MANAGER_URL
2.5 from imiptools.data import Object, parse_object, \
2.6 get_address, get_uri, get_value, get_window_end, \
2.7 - is_new_object, uri_dict, uri_item
2.8 + is_new_object, uri_dict, uri_item, uri_values
2.9 from imiptools.dates import format_datetime, get_default_timezone, to_timezone
2.10 from imiptools.period import can_schedule, insert_period, remove_period, \
2.11 remove_affected_period, update_freebusy
2.12 @@ -172,7 +172,17 @@
2.13
2.14 remove_period(freebusy, self.uid, self.recurrenceid)
2.15
2.16 - def _update_freebusy(self, freebusy, periods, recurrenceid):
2.17 + def remove_freebusy_for_original_recurrence(self, freebusy):
2.18 +
2.19 + """
2.20 + Remove from 'freebusy' any specific recurrence from parent free/busy
2.21 + details for the current object.
2.22 + """
2.23 +
2.24 + if self.recurrenceid:
2.25 + remove_affected_period(freebusy, self.uid, self.recurrenceid)
2.26 +
2.27 + def _update_freebusy(self, freebusy, periods, recurrenceid, transp=None):
2.28
2.29 """
2.30 Update the 'freebusy' collection with the given 'periods', indicating an
2.31 @@ -180,25 +190,41 @@
2.32 event.
2.33 """
2.34
2.35 - update_freebusy(freebusy, periods, self.obj.get_value("TRANSP"),
2.36 + update_freebusy(freebusy, periods, transp or self.obj.get_value("TRANSP"),
2.37 self.uid, recurrenceid)
2.38
2.39 - def update_freebusy(self, freebusy, periods):
2.40 + def update_freebusy(self, freebusy, periods, transp=None):
2.41
2.42 """
2.43 Update the 'freebusy' collection for this event with the given
2.44 'periods'.
2.45 """
2.46
2.47 - self._update_freebusy(freebusy, periods, self.recurrenceid)
2.48 + self._update_freebusy(freebusy, periods, self.recurrenceid, transp)
2.49 +
2.50 + def update_freebusy_for_participant(self, freebusy, periods, attr, for_organiser=False):
2.51 +
2.52 + """
2.53 + Update the 'freebusy' collection using the given 'periods', subject to
2.54 + the 'attr' provided for the participant, indicating whether this is
2.55 + being generated 'for_organiser' or not.
2.56 + """
2.57 +
2.58 + # Organisers employ a special transparency.
2.59 +
2.60 + if for_organiser or attr.get("PARTSTAT") != "DECLINED":
2.61 + self.update_freebusy(freebusy, periods, transp=(for_organiser and "ORG" or None))
2.62 + else:
2.63 + self.remove_from_freebusy(freebusy)
2.64
2.65 # Convenience methods for updating stored free/busy information.
2.66
2.67 - def update_freebusy_from_participant(self, user, participant_item):
2.68 + def update_freebusy_from_participant(self, user, participant_item, for_organiser):
2.69
2.70 """
2.71 For the given 'user', record the free/busy information for the
2.72 - 'participant_item' (a value plus attributes).
2.73 + 'participant_item' (a value plus attributes) representing a different
2.74 + identity, thus maintaining a separate record of their free/busy details.
2.75 """
2.76
2.77 participant, participant_attr = participant_item
2.78 @@ -209,19 +235,14 @@
2.79 freebusy = self.store.get_freebusy_for_other(user, participant)
2.80 tzid = self.get_tzid(user)
2.81 window_end = get_window_end(tzid)
2.82 + periods = self.obj.get_periods_for_freebusy(tzid, window_end)
2.83
2.84 - if participant_attr.get("PARTSTAT") != "DECLINED":
2.85 - self.update_freebusy(freebusy,
2.86 - self.obj.get_periods_for_freebusy(tzid, window_end)
2.87 - )
2.88 - else:
2.89 - self.remove_from_freebusy(freebusy)
2.90 + # Record in the free/busy details unless a non-participating attendee.
2.91
2.92 - # Remove any specific recurrence from parent free/busy details.
2.93 + self.update_freebusy_for_participant(freebusy, periods, participant_attr,
2.94 + for_organiser and self.is_not_attendee(participant, self.obj))
2.95
2.96 - if self.recurrenceid:
2.97 - remove_affected_period(freebusy, self.uid, self.recurrenceid)
2.98 -
2.99 + self.remove_freebusy_for_original_recurrence(freebusy)
2.100 self.store.set_freebusy_for_other(user, freebusy, participant)
2.101
2.102 def update_freebusy_from_organiser(self, attendee, organiser_item):
2.103 @@ -231,17 +252,23 @@
2.104 'organiser_item' (a value plus attributes).
2.105 """
2.106
2.107 - self.update_freebusy_from_participant(attendee, organiser_item)
2.108 + self.update_freebusy_from_participant(attendee, organiser_item, True)
2.109
2.110 def update_freebusy_from_attendees(self, organiser, attendees):
2.111
2.112 "For the 'organiser', record free/busy information from 'attendees'."
2.113
2.114 for attendee_item in attendees.items():
2.115 - self.update_freebusy_from_participant(organiser, attendee_item)
2.116 + self.update_freebusy_from_participant(organiser, attendee_item, False)
2.117
2.118 # Logic, filtering and access to calendar structures and other data.
2.119
2.120 + def is_not_attendee(self, identity, obj):
2.121 +
2.122 + "Return whether 'identity' is not an attendee in 'obj'."
2.123 +
2.124 + return identity not in uri_values(obj.get_values("ATTENDEE"))
2.125 +
2.126 def can_schedule(self, freebusy, periods):
2.127 return can_schedule(freebusy, periods, self.uid, self.recurrenceid)
2.128
3.1 --- a/imiptools/handlers/person_outgoing.py Tue Mar 03 00:03:45 2015 +0100
3.2 +++ b/imiptools/handlers/person_outgoing.py Tue Mar 03 00:05:22 2015 +0100
3.3 @@ -95,18 +95,10 @@
3.4
3.5 periods = obj.get_periods_for_freebusy(tzid, get_window_end(tzid))
3.6
3.7 - if attr.get("PARTSTAT") != "DECLINED":
3.8 - self.update_freebusy(freebusy, periods)
3.9 - else:
3.10 - self.remove_from_freebusy(freebusy)
3.11 + self.update_freebusy_for_participant(freebusy, periods, attr,
3.12 + from_organiser and self.is_not_attendee(identity, obj))
3.13
3.14 - # For any parent object, refresh the updated periods.
3.15 -
3.16 - obj = self.get_parent_object(identity)
3.17 - if obj:
3.18 - periods = obj.get_periods_for_freebusy(tzid, get_window_end(tzid))
3.19 - self._update_freebusy(freebusy, periods, None)
3.20 -
3.21 + self.remove_freebusy_for_original_recurrence(freebusy)
3.22 self.store.set_freebusy(identity, freebusy)
3.23
3.24 if self.publisher:
3.25 @@ -163,7 +155,6 @@
3.26 if update_freebusy:
3.27 freebusy = self.store.get_freebusy(identity)
3.28 self.remove_from_freebusy(freebusy)
3.29 -
3.30 self.store.set_freebusy(identity, freebusy)
3.31
3.32 if self.publisher: