# HG changeset patch # User Paul Boddie # Date 1423777310 -3600 # Node ID e6d5b640b19c314cf7f47f1872665b354700e268 # Parent b7dcff0d35af30650654e2f944e230870854ef56 Expanded support for recurrences to handlers and the manager, improving and fixing support in the store, ensuring that free/busy details, requests and cancellations can employ recurrence identifiers. diff -r b7dcff0d35af -r e6d5b640b19c imip_manager.py --- a/imip_manager.py Thu Feb 12 22:35:16 2015 +0100 +++ b/imip_manager.py Thu Feb 12 22:41:50 2015 +0100 @@ -320,12 +320,12 @@ def _get_uid(self, path_info): return path_info.lstrip("/").split("/", 1)[0] - def _get_object(self, uid): - if self.objects.has_key(uid): - return self.objects[uid] + def _get_object(self, uid, recurrenceid=None): + if self.objects.has_key((uid, recurrenceid)): + return self.objects[(uid, recurrenceid)] - fragment = uid and self.store.get_event(self.user, uid) or None - obj = self.objects[uid] = fragment and Object(fragment) + fragment = uid and self.store.get_event(self.user, uid, recurrenceid) or None + obj = self.objects[(uid, recurrenceid)] = fragment and Object(fragment) return obj def _get_requests(self): @@ -337,11 +337,11 @@ def _get_request_summary(self): summary = [] - for uid in self._get_requests(): - obj = self._get_object(uid) + for uid, recurrenceid in self._get_requests(): + obj = self._get_object(uid, recurrenceid) if obj: for start, end in obj.get_periods_for_freebusy(self.get_tzid()): - summary.append((start, end, uid)) + summary.append((start, end, uid, obj.get_value("TRANSP"), recurrenceid)) return summary # Preference methods. @@ -369,21 +369,21 @@ # Data management methods. - def remove_request(self, uid): - return self.store.dequeue_request(self.user, uid) + def remove_request(self, uid, recurrenceid=None): + return self.store.dequeue_request(self.user, uid, recurrenceid) - def remove_event(self, uid): - return self.store.remove_event(self.user, uid) + def remove_event(self, uid, recurrenceid=None): + return self.store.remove_event(self.user, uid, recurrenceid) - def update_freebusy(self, uid, obj): + def update_freebusy(self, uid, recurrenceid, obj): tzid = self.get_tzid() freebusy = self.store.get_freebusy(self.user) update_freebusy(freebusy, self.user, obj.get_periods_for_freebusy(tzid), - obj.get_value("TRANSP"), uid, self.store) + obj.get_value("TRANSP"), uid, recurrenceid, self.store) - def remove_from_freebusy(self, uid): + def remove_from_freebusy(self, uid, recurrenceid=None): freebusy = self.store.get_freebusy(self.user) - remove_from_freebusy(freebusy, self.user, uid, self.store) + remove_from_freebusy(freebusy, self.user, uid, recurrenceid, self.store) # Presentation methods. @@ -509,9 +509,9 @@ participant = get_uri(participant) rwrite(("ATTENDEE", {"RSVP" : "TRUE", "PARTSTAT" : "NEEDS-ACTION"}, participant)) - obj = ("VEVENT", {}, record) + node = ("VEVENT", {}, record) - self.store.set_event(self.user, this_uid, obj) + self.store.set_event(self.user, this_uid, node=node) self.store.queue_request(self.user, this_uid) # Redirect to the object (or the first of the objects), where instead of @@ -626,8 +626,8 @@ # Save single user events. elif save: - self.store.set_event(self.user, uid, obj.to_node()) - self.update_freebusy(uid, obj) + self.store.set_event(self.user, uid, node=obj.to_node()) + self.update_freebusy(uid, None, obj=obj) self.remove_request(uid) # Remove the request and the object. @@ -707,7 +707,7 @@ attendees = uri_values((obj.get_values("ATTENDEE") or []) + args.get("attendee", [])) is_attendee = self.user in attendees - is_request = obj.get_value("UID") in self._get_requests() + is_request = (obj.get_value("UID"), obj.get_value("RECURRENCE-ID")) in self._get_requests() have_other_attendees = len(attendees) > (is_attendee and 1 or 0) @@ -1088,7 +1088,7 @@ page.tbody() for t in conflicts: - start, end, found_uid = t[:3] + start, end, found_uid, transp, found_recurrenceid = t[:5] # Provide details of any conflicting event. @@ -1101,7 +1101,7 @@ page.td() - found_obj = self._get_object(found_uid) + found_obj = self._get_object(found_uid, found_recurrenceid) if found_obj: page.a(found_obj.get_value("SUMMARY"), href=self.env.new_url(found_uid)) else: @@ -1133,11 +1133,11 @@ self.page.ul() - for request in requests: - obj = self._get_object(request) + for uid, recurrenceid in requests: + obj = self._get_object(uid, recurrenceid) if obj: self.page.li() - self.page.a(obj.get_value("SUMMARY"), href="#request-%s" % request) + self.page.a(obj.get_value("SUMMARY"), href="#request-%s-%s" % (uid, recurrenceid or "")) self.page.li.close() self.page.ul.close() @@ -1197,7 +1197,7 @@ "Show an object request using the given 'path_info' for the current user." uid = self._get_uid(path_info) - obj = self._get_object(uid) + obj = self._get_object(uid, None) if not obj: return False @@ -1559,7 +1559,7 @@ page.td.close() empty = 0 - start, end, uid, key = get_freebusy_details(t) + start, end, uid, recurrenceid, key = get_freebusy_details(t) span = spans[key] # Produce a table cell only at the start of the period @@ -1567,7 +1567,7 @@ if point == start or continuation: - obj = self._get_object(uid) + obj = self._get_object(uid, recurrenceid) has_continued = continuation and point != start will_continue = not ends_on_same_day(point, end, tzid) @@ -1581,9 +1581,11 @@ ) # Only anchor the first cell of events. + # NOTE: Need to only anchor the first period for a + # NOTE: recurring event. if point == start: - page.td(class_=css, rowspan=span, id="%s-%s" % (group_type, uid)) + page.td(class_=css, rowspan=span, id="%s-%s-%s" % (group_type, uid, recurrenceid or "")) else: page.td(class_=css, rowspan=span) @@ -1595,7 +1597,7 @@ # Only link to events if they are not being # updated by requests. - if uid in self._get_requests() and group_type != "request": + if (uid, recurrenceid) in self._get_requests() and group_type != "request": page.span(summary) else: href = "%s/%s" % (self.env.get_url().rstrip("/"), uid) diff -r b7dcff0d35af -r e6d5b640b19c imip_store.py --- a/imip_store.py Thu Feb 12 22:35:16 2015 +0100 +++ b/imip_store.py Thu Feb 12 22:41:50 2015 +0100 @@ -24,7 +24,7 @@ from imiptools.data import make_calendar, parse_object, to_stream from imiptools.filesys import fix_permissions, FileBase from os.path import exists, isfile, join -from os import listdir, remove +from os import listdir, remove, rmdir from time import sleep class FileStore(FileBase): @@ -40,6 +40,66 @@ def release_lock(self, user): FileBase.release_lock(self, user) + def _set_defaults(self, t, empty_defaults): + for i, default in empty_defaults: + if i >= len(t): + t += [None] * (i - len(t) + 1) + if not t[i]: + t[i] = default + return t + + def _get_table(self, user, filename, empty_defaults=None): + + """ + From the file for the given 'user' having the given 'filename', return + a list of tuples representing the file's contents. + + The 'empty_defaults' is a list of (index, value) tuples indicating the + default value where a column either does not exist or provides an empty + value. + """ + + self.acquire_lock(user) + try: + f = open(filename, "rb") + try: + l = [] + for line in f.readlines(): + t = line.strip().split("\t") + if empty_defaults: + t = self._set_defaults(t, empty_defaults) + l.append(tuple(t)) + return l + finally: + f.close() + finally: + self.release_lock(user) + + def _set_table(self, user, filename, items, empty_defaults=None): + + """ + For the given 'user', write to the file having the given 'filename' the + 'items'. + + The 'empty_defaults' is a list of (index, value) tuples indicating the + default value where a column either does not exist or provides an empty + value. + """ + + self.acquire_lock(user) + try: + f = open(filename, "wb") + try: + for item in items: + if empty_defaults: + item = self._set_defaults(list(item), empty_defaults) + f.write("\t".join(item) + "\n") + finally: + f.close() + fix_permissions(filename) + finally: + self.release_lock(user) + def _get_object(self, user, filename): """ @@ -88,6 +148,17 @@ return True + def _remove_collection(self, filename): + + "Remove the collection with the given 'filename'." + + try: + rmdir(filename) + except OSError: + return False + + return True + def get_events(self, user): "Return a list of event identifiers." @@ -98,7 +169,20 @@ return [name for name in listdir(filename) if isfile(join(filename, name))] - def get_event(self, user, uid): + def get_event(self, user, uid, recurrenceid=None): + + """ + Get the event for the given 'user' with the given 'uid'. If + the optional 'recurrenceid' is specified, a specific instance or + occurrence of an event is returned. + """ + + if recurrenceid: + return self.get_recurrence(user, uid, recurrenceid) + else: + return self.get_complete_event(user, uid) + + def get_complete_event(self, user, uid): "Get the event for the given 'user' with the given 'uid'." @@ -108,7 +192,20 @@ return self._get_object(user, filename) - def set_event(self, user, uid, node): + def set_event(self, user, uid, recurrenceid, node): + + """ + Set an event for 'user' having the given 'uid' and 'recurrenceid' (which + if the latter is specified, a specific instance or occurrence of an + event is referenced), using the given 'node' description. + """ + + if recurrenceid: + return self.set_recurrence(user, uid, recurrenceid, node) + else: + return self.set_complete_event(user, uid, node) + + def set_complete_event(self, user, uid, node): "Set an event for 'user' having the given 'uid' and 'node'." @@ -120,12 +217,31 @@ def remove_event(self, user, uid): + """ + Remove an event for 'user' having the given 'uid'. If the optional + 'recurrenceid' is specified, a specific instance or occurrence of an + event is removed. + """ + + if recurrenceid: + return self.remove_recurrence(user, uid, recurrenceid) + else: + for recurrenceid in self.get_recurrences(user, uid) or []: + self.remove_recurrence(user, uid, recurrenceid) + return self.remove_complete_event(user, uid) + + def remove_complete_event(self, user, uid): + "Remove an event for 'user' having the given 'uid'." filename = self.get_object_in_store(user, "objects", uid) if not filename: return False + recurrences = self.get_object_in_store(user, "recurrences", uid) + if recurrences: + self._remove_collection(recurrences) + return self._remove_object(filename) def get_recurrences(self, user, uid): @@ -168,7 +284,7 @@ "Remove an event for 'user' having the given 'uid'." - filename = self.get_object_in_store(user, "objects", uid) + filename = self.get_object_in_store(user, "recurrences", uid) if not filename: return False @@ -182,7 +298,7 @@ if not filename or not exists(filename): return [] else: - return self._get_freebusy(user, filename) + return self._get_table(user, filename, [(4, None)]) def get_freebusy_for_other(self, user, other): @@ -192,24 +308,7 @@ if not filename or not exists(filename): return [] else: - return self._get_freebusy(user, filename) - - def _get_freebusy(self, user, filename): - - "For the given 'user', get the free/busy details from 'filename'." - - self.acquire_lock(user) - try: - f = open(filename) - try: - l = [] - for line in f.readlines(): - l.append(tuple(line.strip().split("\t"))) - return l - finally: - f.close() - finally: - self.release_lock(user) + return self._get_table(user, filename, [(4, None)]) def set_freebusy(self, user, freebusy): @@ -219,7 +318,7 @@ if not filename: return False - self._set_freebusy(user, filename, freebusy) + self._set_table(user, filename, freebusy, [(3, "OPAQUE"), (4, "")]) return True def set_freebusy_for_other(self, user, freebusy, other): @@ -230,28 +329,9 @@ if not filename: return False - self._set_freebusy(user, filename, freebusy) + self._set_table(user, filename, freebusy, [(2, ""), (3, "OPAQUE"), (4, "")]) return True - def _set_freebusy(self, user, filename, freebusy): - - """ - For the given 'user', write to the file having the given 'filename' the - 'freebusy' details. - """ - - self.acquire_lock(user) - try: - f = open(filename, "w") - try: - for item in freebusy: - f.write("\t".join([(value or "OPAQUE") for value in item]) + "\n") - finally: - f.close() - fix_permissions(filename) - finally: - self.release_lock(user) - def _get_requests(self, user, queue): "Get requests for the given 'user' from the given 'queue'." @@ -260,15 +340,7 @@ if not filename or not exists(filename): return None - self.acquire_lock(user) - try: - f = open(filename) - try: - return [line.strip() for line in f.readlines()] - finally: - f.close() - finally: - self.release_lock(user) + return self._get_table(user, filename, [(1, None)]) def get_requests(self, user): @@ -298,7 +370,7 @@ f = open(filename, "w") try: for request in requests: - print >>f, request + print >>f, "\t".join([value or "" for value in request]) finally: f.close() fix_permissions(filename) @@ -319,9 +391,12 @@ return self._set_requests(user, cancellations, "cancellations") - def _set_request(self, user, request, queue): + def _set_request(self, user, uid, recurrenceid, queue): - "For the given 'user', set the queued 'request' in the given 'queue'." + """ + For the given 'user', set the queued 'uid' and 'recurrenceid' in the + given 'queue'. + """ filename = self.get_object_in_store(user, queue) if not filename: @@ -331,7 +406,7 @@ try: f = open(filename, "a") try: - print >>f, request + print >>f, "\t".join([uid, recurrenceid or ""]) finally: f.close() fix_permissions(filename) @@ -340,51 +415,63 @@ return True - def set_request(self, user, request): + def set_request(self, user, uid, recurrenceid=None): - "For the given 'user', set the queued 'request'." + "For the given 'user', set the queued 'uid' and 'recurrenceid'." - return self._set_request(user, request, "requests") + return self._set_request(user, uid, recurrenceid, "requests") - def set_cancellation(self, user, cancellation): + def set_cancellation(self, user, uid, recurrenceid=None): + + "For the given 'user', set the queued 'uid' and 'recurrenceid'." - "For the given 'user', set the queued 'cancellation'." + return self._set_request(user, uid, recurrenceid, "cancellations") - return self._set_request(user, cancellation, "cancellations") + def queue_request(self, user, uid, recurrenceid=None): - def queue_request(self, user, uid): - - "Queue a request for 'user' having the given 'uid'." + """ + Queue a request for 'user' having the given 'uid'. If the optional + 'recurrenceid' is specified, the request refers to a specific instance + or occurrence of an event. + """ requests = self.get_requests(user) or [] - if uid not in requests: - return self.set_request(user, uid) + if (uid, recurrenceid) not in requests: + return self.set_request(user, uid, recurrenceid) return False - def dequeue_request(self, user, uid): + def dequeue_request(self, user, uid, recurrenceid=None): - "Dequeue a request for 'user' having the given 'uid'." + """ + Dequeue a request for 'user' having the given 'uid'. If the optional + 'recurrenceid' is specified, the request refers to a specific instance + or occurrence of an event. + """ requests = self.get_requests(user) or [] try: - requests.remove(uid) + requests.remove((uid, recurrenceid)) self.set_requests(user, requests) except ValueError: return False else: return True - def cancel_event(self, user, uid): + def cancel_event(self, user, uid, recurrenceid=None): - "Queue an event for cancellation for 'user' having the given 'uid'." + """ + Queue an event for cancellation for 'user' having the given 'uid'. If + the optional 'recurrenceid' is specified, a specific instance or + occurrence of an event is cancelled. + """ cancellations = self.get_cancellations(user) or [] - if uid not in cancellations: - return self.set_cancellation(user, uid) + if (uid, recurrenceid) not in cancellations: + return self.set_cancellation(user, uid, recurrenceid) return False @@ -410,7 +497,7 @@ rwrite(("UID", {}, user)) rwrite(("DTSTAMP", {}, datetime.utcnow().strftime("%Y%m%dT%H%M%SZ"))) - for start, end, uid, transp in freebusy: + for start, end, uid, transp, recurrenceid in freebusy: if not transp or transp == "OPAQUE": rwrite(("FREEBUSY", {"FBTYPE" : "BUSY"}, "/".join([start, end]))) diff -r b7dcff0d35af -r e6d5b640b19c imiptools/content.py --- a/imiptools/content.py Thu Feb 12 22:35:16 2015 +0100 +++ b/imiptools/content.py Thu Feb 12 22:41:50 2015 +0100 @@ -115,6 +115,7 @@ self.obj = None self.uid = None + self.recurrenceid = None self.sequence = None self.dtstamp = None @@ -128,6 +129,7 @@ def set_object(self, obj): self.obj = obj self.uid = self.obj.get_value("UID") + self.recurrenceid = self.obj.get_value("RECURRENCE-ID") self.sequence = self.obj.get_value("SEQUENCE") self.dtstamp = self.obj.get_value("DTSTAMP") @@ -166,14 +168,14 @@ # Access to calendar structures and other data. def remove_from_freebusy(self, freebusy, attendee): - remove_from_freebusy(freebusy, attendee, self.uid, self.store) + remove_from_freebusy(freebusy, attendee, self.uid, self.recurrenceid, self.store) def remove_from_freebusy_for_other(self, freebusy, user, other): - remove_from_freebusy_for_other(freebusy, user, other, self.uid, self.store) + remove_from_freebusy_for_other(freebusy, user, other, self.uid, self.recurrenceid, self.store) def update_freebusy(self, freebusy, attendee, periods): update_freebusy(freebusy, attendee, periods, self.obj.get_value("TRANSP"), - self.uid, self.store) + self.uid, self.recurrenceid, self.store) def update_freebusy_from_participant(self, user, participant_item): @@ -192,7 +194,7 @@ update_freebusy_for_other(freebusy, user, participant, self.obj.get_periods_for_freebusy(tzid=None), self.obj.get_value("TRANSP"), - self.uid, self.store) + self.uid, self.recurrenceid, self.store) else: self.remove_from_freebusy_for_other(freebusy, user, participant) @@ -213,7 +215,7 @@ self.update_freebusy_from_participant(organiser, attendee_item) def can_schedule(self, freebusy, periods): - return can_schedule(freebusy, periods, self.uid) + return can_schedule(freebusy, periods, self.uid, self.recurrenceid) def filter_by_senders(self, mapping): @@ -335,7 +337,7 @@ given 'user' and for the given 'objtype'. """ - fragment = self.store.get_event(user, self.uid) + fragment = self.store.get_event(user, self.uid, self.recurrenceid) return fragment and Object(fragment) def have_new_object(self, attendee, obj=None): @@ -418,10 +420,7 @@ event = obj.to_node() recurrenceid = obj.get_value("RECURRENCE-ID") - if not recurrenceid: - self.store.set_event(identity, self.uid, event) - else: - self.store.set_recurrence(identity, self.uid, recurrenceid, event) + self.store.set_event(identity, self.uid, self.recurrenceid, event) return True diff -r b7dcff0d35af -r e6d5b640b19c imiptools/handlers/person.py --- a/imiptools/handlers/person.py Thu Feb 12 22:35:16 2015 +0100 +++ b/imiptools/handlers/person.py Thu Feb 12 22:41:50 2015 +0100 @@ -52,19 +52,14 @@ # Set the complete event if not an additional occurrence. event = self.obj.to_node() - recurrenceid = self.obj.get_value("RECURRENCE-ID") - - if not recurrenceid: - self.store.set_event(attendee, self.uid, event) - else: - self.store.set_recurrence(attendee, self.uid, recurrenceid, event) + self.store.set_event(attendee, self.uid, self.recurrenceid, event) # Queue any request. if queue: - self.store.queue_request(attendee, self.uid) + self.store.queue_request(attendee, self.uid, self.recurrenceid) elif cancel: - self.store.cancel_event(attendee, self.uid) + self.store.cancel_event(attendee, self.uid, self.recurrenceid) # No return message will occur to update the free/busy # information, so this is done here. diff -r b7dcff0d35af -r e6d5b640b19c imiptools/handlers/person_outgoing.py --- a/imiptools/handlers/person_outgoing.py Thu Feb 12 22:35:16 2015 +0100 +++ b/imiptools/handlers/person_outgoing.py Thu Feb 12 22:41:50 2015 +0100 @@ -62,12 +62,7 @@ # Set the complete event if not an additional occurrence. event = self.obj.to_node() - recurrenceid = self.obj.get_value("RECURRENCE-ID") - - if not recurrenceid: - self.store.set_event(identity, self.uid, event) - else: - self.store.set_recurrence(identity, self.uid, recurrenceid, event) + self.store.set_event(identity, self.uid, self.recurrenceid, event) else: organiser_item, attendees = self.require_organiser_and_attendees(from_organiser) @@ -75,7 +70,7 @@ # Remove any associated request. - self.store.dequeue_request(identity, self.uid) + self.store.dequeue_request(identity, self.uid, self.recurrenceid) # Update free/busy information. @@ -123,7 +118,7 @@ given_attendees = set(uri_values(self.obj.get_values("ATTENDEE"))) if given_attendees == all_attendees: - self.store.cancel_event(identity, self.uid) + self.store.cancel_event(identity, self.uid, self.recurrenceid) # Otherwise, remove the given attendees and update the event. @@ -141,16 +136,11 @@ # Set the complete event if not an additional occurrence. event = obj.to_node() - recurrenceid = obj.get_value("RECURRENCE-ID") - - if not recurrenceid: - self.store.set_event(identity, self.uid, event) - else: - self.store.set_recurrence(identity, self.uid, recurrenceid, event) + self.store.set_event(identity, self.uid, self.recurrenceid, event) # Remove any associated request. - self.store.dequeue_request(identity, self.uid) + self.store.dequeue_request(identity, self.uid, self.recurrenceid) # Update free/busy information. diff -r b7dcff0d35af -r e6d5b640b19c imiptools/handlers/resource.py --- a/imiptools/handlers/resource.py Thu Feb 12 22:35:16 2015 +0100 +++ b/imiptools/handlers/resource.py Thu Feb 12 22:41:50 2015 +0100 @@ -87,12 +87,7 @@ # Set the complete event if not an additional occurrence. event = self.obj.to_node() - recurrenceid = self.obj.get_value("RECURRENCE-ID") - - if not recurrenceid: - self.store.set_event(attendee, self.uid, event) - else: - self.store.set_recurrence(attendee, self.uid, recurrenceid, event) + self.store.set_event(attendee, self.uid, self.recurrenceid, event) # Only update free/busy details if the event is scheduled. @@ -108,7 +103,7 @@ def _cancel_for_attendee(self, attendee, attendee_attr): - self.store.cancel_event(attendee, self.uid) + self.store.cancel_event(attendee, self.uid, self.recurrenceid) freebusy = self.store.get_freebusy(attendee) self.remove_from_freebusy(freebusy, attendee) diff -r b7dcff0d35af -r e6d5b640b19c imiptools/period.py --- a/imiptools/period.py Thu Feb 12 22:35:16 2015 +0100 +++ b/imiptools/period.py Thu Feb 12 22:41:50 2015 +0100 @@ -25,16 +25,16 @@ # Time management with datetime strings in the UTC time zone. -def can_schedule(freebusy, periods, uid): +def can_schedule(freebusy, periods, uid, recurrenceid): """ Return whether the 'freebusy' list can accommodate the given 'periods' - employing the specified 'uid'. + employing the specified 'uid' and 'recurrenceid'. """ for conflict in have_conflict(freebusy, periods, True): - start, end, found_uid, found_transp = conflict - if found_uid != uid: + start, end, found_uid, found_transp, found_recurrenceid = conflict + if found_uid != uid and found_recurrenceid != recurrenceid: return False return True @@ -64,11 +64,11 @@ def insert_period(freebusy, period): insort_left(freebusy, period) -def remove_period(freebusy, uid): +def remove_period(freebusy, uid, recurrenceid=None): i = 0 while i < len(freebusy): t = freebusy[i] - if len(t) >= 3 and t[2] == uid: + if len(t) >= 5 and t[2] == uid and t[4] == recurrenceid: del freebusy[i] else: i += 1 @@ -332,7 +332,7 @@ for point, active in slots: for t in active: if t and len(t) >= 2: - start, end, uid, key = get_freebusy_details(t) + start, end, uid, recurrenceid, key = get_freebusy_details(t) try: start_slot = points.index(start) @@ -348,73 +348,74 @@ def get_freebusy_details(t): - "Return a tuple of the form (start, end, uid, key) from 't'." + "Return a tuple of the form (start, end, uid, recurrenceid, key) from 't'." # Handle both complete free/busy details... - if len(t) > 2: - start, end, uid = t[:3] - key = uid + if len(t) > 4: + start, end, uid, transp, recurrenceid = t[:5] + key = uid, recurrenceid # ...and published details without specific event details. else: start, end = t[:2] uid = None + recurrenceid = None key = (start, end) - return start, end, uid, key + return start, end, uid, recurrenceid, key -def remove_from_freebusy(freebusy, attendee, uid, store): +def remove_from_freebusy(freebusy, attendee, uid, recurrenceid, store): """ For the given 'attendee', remove periods from 'freebusy' that are associated - with 'uid' in the 'store'. + with 'uid' and 'recurrenceid' in the 'store'. """ - remove_period(freebusy, uid) + remove_period(freebusy, uid, recurrenceid) store.set_freebusy(attendee, freebusy) -def remove_from_freebusy_for_other(freebusy, user, other, uid, store): +def remove_from_freebusy_for_other(freebusy, user, other, uid, recurrenceid, store): """ For the given 'user', remove for the 'other' party periods from 'freebusy' - that are associated with 'uid' in the 'store'. + that are associated with 'uid' and 'recurrenceid' in the 'store'. """ - remove_period(freebusy, uid) + remove_period(freebusy, uid, recurrenceid) store.set_freebusy_for_other(user, freebusy, other) -def _update_freebusy(freebusy, periods, transp, uid): +def _update_freebusy(freebusy, periods, transp, uid, recurrenceid): """ Update the free/busy details with the given 'periods', 'transp' setting and - 'uid'. + 'uid' plus 'recurrenceid'. """ - remove_period(freebusy, uid) + remove_period(freebusy, uid, recurrenceid) for start, end in periods: - insert_period(freebusy, (start, end, uid, transp)) + insert_period(freebusy, (start, end, uid, transp, recurrenceid)) -def update_freebusy(freebusy, attendee, periods, transp, uid, store): +def update_freebusy(freebusy, attendee, periods, transp, uid, recurrenceid, store): """ For the given 'attendee', update the free/busy details with the given - 'periods', 'transp' setting and 'uid' in the 'store'. + 'periods', 'transp' setting and 'uid' plus 'recurrenceid' in the 'store'. """ - _update_freebusy(freebusy, periods, transp, uid) + _update_freebusy(freebusy, periods, transp, uid, recurrenceid) store.set_freebusy(attendee, freebusy) -def update_freebusy_for_other(freebusy, user, other, periods, transp, uid, store): +def update_freebusy_for_other(freebusy, user, other, periods, transp, uid, recurrenceid, store): """ For the given 'user', update the free/busy details of 'other' with the given - 'periods', 'transp' setting and 'uid' in the 'store'. + 'periods', 'transp' setting and 'uid' plus 'recurrenceid' in the 'store'. """ - _update_freebusy(freebusy, periods, transp, uid) + _update_freebusy(freebusy, periods, transp, uid, recurrenceid) store.set_freebusy_for_other(user, freebusy, other) # vim: tabstop=4 expandtab shiftwidth=4