# HG changeset patch # User Paul Boddie # Date 1508454369 -7200 # Node ID 3c7f0da08063d59c84abacd7e879605d045910b8 # Parent ed7239f61458c47693bcd5e5ebb4f101405c30ee Added conflicting period computation. Introduced ordering of suggested attendees and periods. Relaxed the attendee editing test. diff -r ed7239f61458 -r 3c7f0da08063 imiptools/editing.py --- a/imiptools/editing.py Fri Oct 20 00:51:26 2017 +0200 +++ b/imiptools/editing.py Fri Oct 20 01:06:09 2017 +0200 @@ -23,7 +23,7 @@ from copy import copy from datetime import datetime, timedelta from imiptools.client import ClientForObject -from imiptools.data import get_main_period +from imiptools.data import get_main_period, uri_items from imiptools.dates import end_date_from_calendar, end_date_to_calendar, \ format_datetime, get_datetime, \ get_datetime_attributes, get_end_of_day, \ @@ -125,12 +125,12 @@ "Reset the editing state." self.state = State({ - "attendees" : lambda: OrderedDict(self.obj.get_items("ATTENDEE") or []), - "organiser" : lambda: self.obj.get_value("ORGANIZER"), - "periods" : lambda: form_periods_from_periods(self.get_unedited_periods()), + "attendees" : lambda: OrderedDict(self.obj.get_items("ATTENDEE") or []), + "organiser" : lambda: self.obj.get_value("ORGANIZER"), + "periods" : lambda: form_periods_from_periods(self.get_unedited_periods()), "suggested_attendees" : self.get_suggested_attendees, - "suggested_periods" : self.get_suggested_periods, - "summary" : lambda: self.obj.get_value("SUMMARY"), + "suggested_periods" : self.get_suggested_periods, + "summary" : lambda: self.obj.get_value("SUMMARY"), }) # Access to stored and current information. @@ -185,11 +185,16 @@ existing = self.state.get("attendees") l = [] + for attendee, objects in self.get_counters().items(): for obj in objects: for suggested, attr in obj.get_items("ATTENDEE"): if suggested not in existing: l.append((attendee, (suggested, attr))) + + # Provide a stable ordering. + + l.sort() return l def get_suggested_periods(self): @@ -239,8 +244,60 @@ for period in removed: suggested.append((attendee, period, "remove")) + # Provide a stable ordering. + + suggested.sort() return suggested + def get_conflicting_periods(self): + periods = self.state.get("periods") + attendees = self.state.get("attendees") + conflicts = set() + + for attendee, attr in uri_items(attendees.items()): + if not attendee: + continue + + # If not attending this event, other periods cannot conflict. + + if not attr.get("PARTSTAT") in ("ACCEPTED", "TENTATIVE"): + continue + + # Obtain free/busy details for the attendee. + + if attendee == self.user: + freebusy = self.store.get_freebusy(attendee) + elif attendee: + freebusy = self.store.get_freebusy_for_other(self.user, attendee) + else: + continue + + # Without free/busy information, no conflicts can be determined for + # the user. + + if not freebusy: + continue + + # Compare the origin of each conflicting period. + + for p in freebusy.have_conflict(periods, True): + + # Ignore transparent periods. + + if p.transp == "ORG": + continue + + # Prevent conflicts with this event's own periods. + + if p.uid == self.uid and (not self.recurrenceid or + not p.recurrenceid or + self.recurrenceid == p.recurrenceid): + continue + + conflicts.add(p) + + return conflicts + # Validation methods. def get_checked_periods(self): @@ -620,7 +677,7 @@ try: attr = attendees[attendee] - if self.is_organiser() and not self.obj.is_shared() or not attr: + if self.is_organiser() or not attr: return (attendee, attr) except IndexError: pass