# HG changeset patch # User Paul Boddie # Date 1425337522 -3600 # Node ID 5c62afb4823e1e01af9b7e7c14422a807da62daa # Parent 4d88a31c967a3958e7b1583e7e162e8f78c3f36a Consolidated attendance and free/busy handling, introducing a special organiser- only value for the transparency field in free/busy collections. diff -r 4d88a31c967a -r 5c62afb4823e imip_manager.py --- a/imip_manager.py Tue Mar 03 00:03:45 2015 +0100 +++ b/imip_manager.py Tue Mar 03 00:05:22 2015 +0100 @@ -405,10 +405,19 @@ return self.store.remove_event(self.user, uid, recurrenceid) def update_freebusy(self, uid, recurrenceid, obj): + + """ + Update stored free/busy details for the event with the given 'uid' and + 'recurrenceid' having a representation of 'obj'. + """ + + is_only_organiser = self.user not in uri_values(obj.get_values("ATTENDEE")) + freebusy = self.store.get_freebusy(self.user) update_freebusy(freebusy, obj.get_periods_for_freebusy(self.get_tzid(), self.get_window_end()), - obj.get_value("TRANSP"), uid, recurrenceid) + is_only_organiser and "ORG" or obj.get_value("TRANSP"), + uid, recurrenceid) self.store.set_freebusy(self.user, freebusy) def remove_from_freebusy(self, uid, recurrenceid=None): diff -r 4d88a31c967a -r 5c62afb4823e imiptools/content.py --- a/imiptools/content.py Tue Mar 03 00:03:45 2015 +0100 +++ b/imiptools/content.py Tue Mar 03 00:05:22 2015 +0100 @@ -25,7 +25,7 @@ from imiptools.config import MANAGER_PATH, MANAGER_URL from imiptools.data import Object, parse_object, \ get_address, get_uri, get_value, get_window_end, \ - is_new_object, uri_dict, uri_item + is_new_object, uri_dict, uri_item, uri_values from imiptools.dates import format_datetime, get_default_timezone, to_timezone from imiptools.period import can_schedule, insert_period, remove_period, \ remove_affected_period, update_freebusy @@ -172,7 +172,17 @@ remove_period(freebusy, self.uid, self.recurrenceid) - def _update_freebusy(self, freebusy, periods, recurrenceid): + def remove_freebusy_for_original_recurrence(self, freebusy): + + """ + Remove from 'freebusy' any specific recurrence from parent free/busy + details for the current object. + """ + + if self.recurrenceid: + remove_affected_period(freebusy, self.uid, self.recurrenceid) + + def _update_freebusy(self, freebusy, periods, recurrenceid, transp=None): """ Update the 'freebusy' collection with the given 'periods', indicating an @@ -180,25 +190,41 @@ event. """ - update_freebusy(freebusy, periods, self.obj.get_value("TRANSP"), + update_freebusy(freebusy, periods, transp or self.obj.get_value("TRANSP"), self.uid, recurrenceid) - def update_freebusy(self, freebusy, periods): + def update_freebusy(self, freebusy, periods, transp=None): """ Update the 'freebusy' collection for this event with the given 'periods'. """ - self._update_freebusy(freebusy, periods, self.recurrenceid) + self._update_freebusy(freebusy, periods, self.recurrenceid, transp) + + def update_freebusy_for_participant(self, freebusy, periods, attr, for_organiser=False): + + """ + Update the 'freebusy' collection using the given 'periods', subject to + the 'attr' provided for the participant, indicating whether this is + being generated 'for_organiser' or not. + """ + + # Organisers employ a special transparency. + + if for_organiser or attr.get("PARTSTAT") != "DECLINED": + self.update_freebusy(freebusy, periods, transp=(for_organiser and "ORG" or None)) + else: + self.remove_from_freebusy(freebusy) # Convenience methods for updating stored free/busy information. - def update_freebusy_from_participant(self, user, participant_item): + def update_freebusy_from_participant(self, user, participant_item, for_organiser): """ For the given 'user', record the free/busy information for the - 'participant_item' (a value plus attributes). + 'participant_item' (a value plus attributes) representing a different + identity, thus maintaining a separate record of their free/busy details. """ participant, participant_attr = participant_item @@ -209,19 +235,14 @@ freebusy = self.store.get_freebusy_for_other(user, participant) tzid = self.get_tzid(user) window_end = get_window_end(tzid) + periods = self.obj.get_periods_for_freebusy(tzid, window_end) - if participant_attr.get("PARTSTAT") != "DECLINED": - self.update_freebusy(freebusy, - self.obj.get_periods_for_freebusy(tzid, window_end) - ) - else: - self.remove_from_freebusy(freebusy) + # Record in the free/busy details unless a non-participating attendee. - # Remove any specific recurrence from parent free/busy details. + self.update_freebusy_for_participant(freebusy, periods, participant_attr, + for_organiser and self.is_not_attendee(participant, self.obj)) - if self.recurrenceid: - remove_affected_period(freebusy, self.uid, self.recurrenceid) - + self.remove_freebusy_for_original_recurrence(freebusy) self.store.set_freebusy_for_other(user, freebusy, participant) def update_freebusy_from_organiser(self, attendee, organiser_item): @@ -231,17 +252,23 @@ 'organiser_item' (a value plus attributes). """ - self.update_freebusy_from_participant(attendee, organiser_item) + self.update_freebusy_from_participant(attendee, organiser_item, True) def update_freebusy_from_attendees(self, organiser, attendees): "For the 'organiser', record free/busy information from 'attendees'." for attendee_item in attendees.items(): - self.update_freebusy_from_participant(organiser, attendee_item) + self.update_freebusy_from_participant(organiser, attendee_item, False) # Logic, filtering and access to calendar structures and other data. + def is_not_attendee(self, identity, obj): + + "Return whether 'identity' is not an attendee in 'obj'." + + return identity not in uri_values(obj.get_values("ATTENDEE")) + def can_schedule(self, freebusy, periods): return can_schedule(freebusy, periods, self.uid, self.recurrenceid) diff -r 4d88a31c967a -r 5c62afb4823e imiptools/handlers/person_outgoing.py --- a/imiptools/handlers/person_outgoing.py Tue Mar 03 00:03:45 2015 +0100 +++ b/imiptools/handlers/person_outgoing.py Tue Mar 03 00:05:22 2015 +0100 @@ -95,18 +95,10 @@ periods = obj.get_periods_for_freebusy(tzid, get_window_end(tzid)) - if attr.get("PARTSTAT") != "DECLINED": - self.update_freebusy(freebusy, periods) - else: - self.remove_from_freebusy(freebusy) + self.update_freebusy_for_participant(freebusy, periods, attr, + from_organiser and self.is_not_attendee(identity, obj)) - # For any parent object, refresh the updated periods. - - obj = self.get_parent_object(identity) - if obj: - periods = obj.get_periods_for_freebusy(tzid, get_window_end(tzid)) - self._update_freebusy(freebusy, periods, None) - + self.remove_freebusy_for_original_recurrence(freebusy) self.store.set_freebusy(identity, freebusy) if self.publisher: @@ -163,7 +155,6 @@ if update_freebusy: freebusy = self.store.get_freebusy(identity) self.remove_from_freebusy(freebusy) - self.store.set_freebusy(identity, freebusy) if self.publisher: