# HG changeset patch # User Paul Boddie # Date 1442163615 -7200 # Node ID 2962011812c08669b9b8e55f1c5ab271dae40a4e # Parent b0501ea02be4bf71af243fde000469cdc1d42598 Added support for recording expiry times on free/busy offers, fixing testing for expired offers. diff -r b0501ea02be4 -r 2962011812c0 docs/preferences.txt --- a/docs/preferences.txt Sun Sep 13 18:23:42 2015 +0200 +++ b/docs/preferences.txt Sun Sep 13 19:00:15 2015 +0200 @@ -21,7 +21,7 @@ ------------------- Default: refresh -Alternatives (see below) +Alternatives: (see below) Indicate how ADD methods shall be responded to when received by a recipient: @@ -59,6 +59,26 @@ Indicate whether recipients are notified about received free/busy payloads. +freebusy_offers +--------------- + +Default: (none) +Alternative: (see below) + +Define the period for which free/busy offers are extended by participants +supporting this setting when counter-proposals are made during event +scheduling. + +This setting requires a value of one of the following forms: + + + d + +For example: + + 600 extend scheduling offers for 10 minutes + 1d extend offers for 1 day + freebusy_sharing ---------------- diff -r b0501ea02be4 -r 2962011812c0 imip_store.py --- a/imip_store.py Sun Sep 13 18:23:42 2015 +0200 +++ b/imip_store.py Sun Sep 13 19:00:15 2015 +0200 @@ -22,7 +22,7 @@ from datetime import datetime from imiptools.config import STORE_DIR, PUBLISH_DIR from imiptools.data import make_calendar, parse_object, to_stream -from imiptools.dates import format_datetime, get_datetime +from imiptools.dates import format_datetime, get_datetime, to_timezone from imiptools.filesys import fix_permissions, FileBase from imiptools.period import FreeBusyPeriod from os.path import exists, isfile, join @@ -597,7 +597,7 @@ offers = [] expired = [] - now = datetime.now() + now = to_timezone(datetime.now(), "UTC") # Expire old offers and save the collection if modified. diff -r b0501ea02be4 -r 2962011812c0 imiptools/client.py --- a/imiptools/client.py Sun Sep 13 18:23:42 2015 +0200 +++ b/imiptools/client.py Sun Sep 13 19:00:15 2015 +0200 @@ -19,7 +19,7 @@ this program. If not, see . """ -from datetime import datetime +from datetime import datetime, timedelta from imiptools.config import MANAGER_INTERFACE from imiptools.data import Object, get_address, get_uri, get_window_end, \ is_new_object, make_freebusy, to_part, \ @@ -115,6 +115,31 @@ prefs = self.get_preferences() return prefs and prefs.get("add_method_response", "refresh") or "refresh" + def get_offer_period(self): + + """ + Decode a specification of one of the following forms... + + + d + """ + + prefs = self.get_preferences() + duration = prefs and prefs.get("freebusy_offers") + if duration: + try: + if duration.endswith("d"): + return timedelta(days=int(duration[:-1])) + else: + return timedelta(seconds=int(duration)) + + # NOTE: Should probably report an error somehow. + + except ValueError: + return None + else: + return None + def get_organiser_replacement(self): prefs = self.get_preferences() return prefs and prefs.get("organiser_replacement", "attendee") or "attendee" @@ -268,16 +293,19 @@ return None - def update_freebusy(self, freebusy, periods, transp, uid, recurrenceid, summary, organiser): + def update_freebusy(self, freebusy, periods, transp, uid, recurrenceid, summary, organiser, expires=None): """ Update the 'freebusy' collection with the given 'periods', indicating a 'transp' status, explicit 'uid' and 'recurrenceid' to indicate either a recurrence or the parent event. The 'summary' and 'organiser' must also be provided. + + An optional 'expires' datetime string can be provided to tag a free/busy + offer. """ - update_freebusy(freebusy, periods, transp, uid, recurrenceid, summary, organiser) + update_freebusy(freebusy, periods, transp, uid, recurrenceid, summary, organiser, expires) class ClientForObject(Client): @@ -590,7 +618,7 @@ recurrenceid = self.get_recurrence_start_point(recurrenceid) remove_affected_period(freebusy, self.uid, recurrenceid) - def update_freebusy(self, freebusy, user, as_organiser): + def update_freebusy(self, freebusy, user, as_organiser, offer=False): """ Update the 'freebusy' collection for this event with the periods and @@ -598,6 +626,9 @@ identity and the attendance details provided for them, indicating whether the update is being done 'as_organiser' (for the organiser of an event) or not. + + If 'offer' is set to a true value, any free/busy updates will be tagged + with an expiry time. """ # Obtain the stored object if the current object is not issued by the @@ -619,21 +650,37 @@ obj.get_value("TRANSP") or \ "OPAQUE" + # Calculate any expiry time. If no offer period is defined, do not + # record the offer periods. + + if offer: + offer_period = self.get_offer_period() + if offer_period: + expires = format_datetime(to_timezone(datetime.utcnow(), "UTC") + offer_period) + else: + return + else: + expires = None + # Perform the low-level update. Client.update_freebusy(self, freebusy, periods, transp, self.uid, self.recurrenceid, obj.get_value("SUMMARY"), - obj.get_value("ORGANIZER")) + obj.get_value("ORGANIZER"), + expires) def update_freebusy_for_participant(self, freebusy, user, for_organiser=False, - updating_other=False): + updating_other=False, offer=False): """ Update the 'freebusy' collection for the given 'user', indicating whether the update is 'for_organiser' (being done for the organiser of an event) or not, and whether it is 'updating_other' (meaning another user's details). + + If 'offer' is set to a true value, any free/busy updates will be tagged + with an expiry time. """ # Record in the free/busy details unless a non-participating attendee. @@ -642,7 +689,8 @@ if self.is_participating(user, for_organiser and not updating_other): self.update_freebusy(freebusy, user, for_organiser and not updating_other or - not for_organiser and updating_other + not for_organiser and updating_other, + offer ) else: self.remove_from_freebusy(freebusy) diff -r b0501ea02be4 -r 2962011812c0 imiptools/handlers/common.py --- a/imiptools/handlers/common.py Sun Sep 13 18:23:42 2015 +0200 +++ b/imiptools/handlers/common.py Sun Sep 13 19:00:15 2015 +0200 @@ -167,7 +167,7 @@ # Obtain the attendance attributes for this user, if available. - self.update_freebusy_for_participant(freebusy, self.user) + self.update_freebusy_for_participant(freebusy, self.user, offer=True) # Remove original recurrence details replaced by additional # recurrences, as well as obsolete additional recurrences. diff -r b0501ea02be4 -r 2962011812c0 imiptools/period.py --- a/imiptools/period.py Sun Sep 13 18:23:42 2015 +0200 +++ b/imiptools/period.py Sun Sep 13 19:00:15 2015 +0200 @@ -757,16 +757,19 @@ return spans -def update_freebusy(freebusy, periods, transp, uid, recurrenceid, summary, organiser): +def update_freebusy(freebusy, periods, transp, uid, recurrenceid, summary, organiser, expires=None): """ Update the free/busy details with the given 'periods', 'transp' setting, 'uid' plus 'recurrenceid' and 'summary' and 'organiser' details. + + An optional 'expires' datetime string indicates the expiry time of any + free/busy offer. """ remove_period(freebusy, uid, recurrenceid) for p in periods: - insert_period(freebusy, FreeBusyPeriod(p.get_start_point(), p.get_end_point(), uid, transp, recurrenceid, summary, organiser)) + insert_period(freebusy, FreeBusyPeriod(p.get_start_point(), p.get_end_point(), uid, transp, recurrenceid, summary, organiser, expires)) # vim: tabstop=4 expandtab shiftwidth=4 diff -r b0501ea02be4 -r 2962011812c0 tests/test_resource_invitation_constraints.sh --- a/tests/test_resource_invitation_constraints.sh Sun Sep 13 18:23:42 2015 +0200 +++ b/tests/test_resource_invitation_constraints.sh Sun Sep 13 19:00:15 2015 +0200 @@ -26,6 +26,7 @@ echo 'Europe/Oslo' > "$PREFS/$USER/TZID" echo 'share' > "$PREFS/$USER/freebusy_sharing" echo '10,12,14,16,18:0,15,30,45' > "$PREFS/$USER/permitted_times" +echo '60' > "$PREFS/$USER/freebusy_offers" "$RESOURCE_SCRIPT" $ARGS < "$TEMPLATES/fb-request-sauna-all.txt" 2>> $ERROR \ | "$SHOWMAIL" \