# HG changeset patch # User Paul Boddie # Date 1418249960 -3600 # Node ID e7da6ceb1a9902d6d105b52cf073e0015b4cbc1e # Parent 4a7f257f384674ad778b796fa1e5bd1087628eef Added initial support for cancelling attendance, reorganising the handler code. diff -r 4a7f257f3846 -r e7da6ceb1a99 imiptools/handlers/resource.py --- a/imiptools/handlers/resource.py Wed Dec 10 21:41:56 2014 +0100 +++ b/imiptools/handlers/resource.py Wed Dec 10 23:19:20 2014 +0100 @@ -8,7 +8,85 @@ from imiptools.handlers.common import CommonFreebusy from vCalendar import to_node -class Event(Handler): +class ResourceHandler(Handler): + + "Handling mechanisms specific to resources." + + def _record_and_respond(self, handle_for_attendee): + + oa = self.require_organiser_and_attendees() + if not oa: + return None + + organiser_item, attendees = oa + + # Validate the organiser, ignoring spoofed requests. + + if not self.validate_identities([organiser_item]): + return None + + # Process each attendee separately. + + calendar = [] + + for attendee, attendee_attr in attendees.items(): + + # Check for event using UID. + + if not self.have_new_object(attendee, "VEVENT"): + continue + + # Collect response objects produced when handling the request. + + response = handle_for_attendee(attendee, attendee_attr) + if response: + calendar.append(response) + + return calendar + + def _schedule_for_attendee(self, attendee, attendee_attr): + + # If newer than any old version, discard old details from the + # free/busy record and check for suitability. + + periods = self.get_periods() + freebusy = self.store.get_freebusy(attendee) or [] + scheduled = self.can_schedule(freebusy, periods) + + attendee_attr["PARTSTAT"] = scheduled and "ACCEPTED" or "DECLINED" + if self.messenger and self.messenger.sender != get_address(attendee): + attendee_attr["SENT-BY"] = get_uri(self.messenger.sender) + + # Make a version of the request with just this attendee. + + self.details["ATTENDEE"] = [(attendee, attendee_attr)] + + event = to_node({"VEVENT" : [(self.details, {})]}) + self.store.set_event(attendee, self.uid, event) + + # Only update free/busy details if the event is scheduled. + + if scheduled: + self.update_freebusy(freebusy, attendee, periods) + else: + self.remove_from_freebusy(freebusy, attendee) + + if self.publisher: + self.publisher.set_freebusy(attendee, freebusy) + + return event + + def _cancel_for_attendee(self, attendee, attendee_attr): + + freebusy = self.store.get_freebusy(attendee) or [] + self.remove_from_freebusy(freebusy, attendee) + + if self.publisher: + self.publisher.set_freebusy(attendee, freebusy) + + return None + +class Event(ResourceHandler): "An event handler." @@ -16,7 +94,11 @@ pass def cancel(self): - pass + + "Cancel attendance for attendees." + + self._record_and_respond(self._cancel_for_attendee) + return None def counter(self): @@ -54,57 +136,13 @@ No support for countering requests is implemented. """ - oa = self.require_organiser_and_attendees() - if not oa: - return None - - organiser_item, attendees = oa - - # Validate the organiser, ignoring spoofed requests. - - if not self.validate_identities([organiser_item]): + response = self._record_and_respond(self._schedule_for_attendee) + if response: + return "REPLY", to_part("REPLY", response) + else: return None - # Process each attendee separately. - - calendar = [] - - for attendee, attendee_attr in attendees.items(): - - # Check for event using UID. - - if not self.have_new_object(attendee, "VEVENT"): - continue - - # If newer than any old version, discard old details from the - # free/busy record and check for suitability. - - periods = self.get_periods() - freebusy = self.store.get_freebusy(attendee) or [] - scheduled = self.can_schedule(freebusy, periods) - - attendee_attr["PARTSTAT"] = scheduled and "ACCEPTED" or "DECLINED" - if self.messenger and self.messenger.sender != get_address(attendee): - attendee_attr["SENT-BY"] = get_uri(self.messenger.sender) - self.details["ATTENDEE"] = [(attendee, attendee_attr)] - - event = to_node({"VEVENT" : [(self.details, {})]}) - calendar.append(event) - self.store.set_event(attendee, self.uid, event) - - # Only update free/busy details if the event is scheduled. - - if scheduled: - self.update_freebusy(freebusy, attendee, periods) - else: - self.remove_from_freebusy(freebusy, attendee) - - if self.publisher: - self.publisher.set_freebusy(attendee, freebusy) - - return "REPLY", to_part("REPLY", calendar) - -class Freebusy(Handler, CommonFreebusy): +class Freebusy(ResourceHandler, CommonFreebusy): "A free/busy handler." @@ -119,7 +157,7 @@ # request provided by CommonFreeBusy.request -class Journal(Handler): +class Journal(ResourceHandler): "A journal entry handler." @@ -132,7 +170,7 @@ def publish(self): pass -class Todo(Handler): +class Todo(ResourceHandler): "A to-do item handler."