# HG changeset patch # User Paul Boddie # Date 1461082626 -7200 # Node ID 313f20241312409f57c6094102b1b640f8743373 # Parent d19a1180e39b5a70d80fc3da0933b122fb45a611 Updated the mechanism for making separate occurrences (defined by attendees when replying about specific recurrence periods), updating the participant's own free/busy record so that affected periods are reassigned to such new occurrences. diff -r d19a1180e39b -r 313f20241312 imiptools/handlers/common.py --- a/imiptools/handlers/common.py Tue Apr 19 17:57:28 2016 +0200 +++ b/imiptools/handlers/common.py Tue Apr 19 18:17:06 2016 +0200 @@ -143,34 +143,49 @@ self.add_result("REFRESH", [get_address(organiser)], obj.to_part("REFRESH")) - def ensure_occurrence(self): + def is_newly_separated_occurrence(self): - """ - Ensure that the object originating from an attendee corresponds to an - existing occurrence of an event, creating or reviving a specific - recurrence if necessary. - - Return whether a valid occurrence was found. - """ + "Return whether the current object is a newly-separated occurrence." # Obtain any stored object. obj = self.get_stored_object_version() - # Handle any newly-defined occurrence. + # Handle any newly-separated, valid occurrence. + + return not obj and self.is_recurrence() + + def make_separate_occurrence(self, for_organiser=False): - if not obj: + """ + Set the current object as a separate occurrence and redefine free/busy + records in terms of this new occurrence for other participants. + """ - # Check for a valid occurrence. + parent = self.get_parent_object() + if not parent: + return False + + # Transfer attendance information from the parent. - if not self.is_recurrence(): - return False + parent_attendees = uri_dict(parent.get_value_map("ATTENDEE")) + attendee_map = uri_dict(self.obj.get_value_map("ATTENDEE")) + + for attendee, attendee_attr in parent_attendees.items(): + if not attendee_map.has_key(attendee): + attendee_map[attendee] = attendee_attr - # Set the complete event if not an additional occurrence. For any newly- - # indicated occurrence, use the received event details. + self.obj["ATTENDEE"] = attendee_map.items() + self.obj.remove_all(["RDATE", "RRULE"]) + + # Create or revive the occurrence. - self.store.remove_cancellation(self.user, self.uid, self.recurrenceid) - self.store.set_event(self.user, self.uid, self.recurrenceid, self.obj.to_node()) + self.store.remove_cancellation(self.user, self.uid, self.recurrenceid) + self.store.set_event(self.user, self.uid, self.recurrenceid, self.obj.to_node()) + + # Update free/busy details for the current object for all attendees. + + self.update_freebusy_from_attendees(attendee_map.keys()) return True diff -r d19a1180e39b -r 313f20241312 imiptools/handlers/person.py --- a/imiptools/handlers/person.py Tue Apr 19 17:57:28 2016 +0200 +++ b/imiptools/handlers/person.py Tue Apr 19 18:17:06 2016 +0200 @@ -205,15 +205,23 @@ "As organiser, update attendance from valid attendees." - if not self.ensure_occurrence(): - return False + # Occurrences that are still part of a parent object are separated, + # attendance information transferred, and the free/busy details updated. + + if self.is_newly_separated_occurrence(): + if self.make_separate_occurrence(for_organiser=True): + + # Update free/busy details for the event. + + self.update_event_in_freebusy(for_organiser=True) + return True # Merge the attendance for the received object. - if self.merge_attendance(attendees): - self.update_freebusy_from_attendees(attendees) + elif self.merge_attendance(attendees): + return self.update_freebusy_from_attendees(attendees) - return True + return False def _refresh(self, organiser, attendees): diff -r d19a1180e39b -r 313f20241312 imiptools/handlers/person_outgoing.py --- a/imiptools/handlers/person_outgoing.py Tue Apr 19 17:57:28 2016 +0200 +++ b/imiptools/handlers/person_outgoing.py Tue Apr 19 18:17:06 2016 +0200 @@ -120,14 +120,19 @@ self.store.remove_cancellation(self.user, self.uid, self.recurrenceid) else: - if not self.ensure_occurrence(): - return False + # Occurrences that are still part of a parent object are separated, + # attendance information transferred, and the free/busy details + # updated. + + if self.is_newly_separated_occurrence(): + self.make_separate_occurrence(for_organiser=not from_organiser) # Obtain valid attendees, merging their attendance with the stored # object. - attendees = self.require_attendees(from_organiser) - self.merge_attendance(attendees) + else: + attendees = self.require_attendees(from_organiser) + self.merge_attendance(attendees) # Remove any associated request.