1.1 --- a/docs/preferences.txt Sun Sep 13 18:23:42 2015 +0200
1.2 +++ b/docs/preferences.txt Sun Sep 13 19:00:15 2015 +0200
1.3 @@ -21,7 +21,7 @@
1.4 -------------------
1.5
1.6 Default: refresh
1.7 -Alternatives (see below)
1.8 +Alternatives: (see below)
1.9
1.10 Indicate how ADD methods shall be responded to when received by a recipient:
1.11
1.12 @@ -59,6 +59,26 @@
1.13
1.14 Indicate whether recipients are notified about received free/busy payloads.
1.15
1.16 +freebusy_offers
1.17 +---------------
1.18 +
1.19 +Default: (none)
1.20 +Alternative: (see below)
1.21 +
1.22 +Define the period for which free/busy offers are extended by participants
1.23 +supporting this setting when counter-proposals are made during event
1.24 +scheduling.
1.25 +
1.26 +This setting requires a value of one of the following forms:
1.27 +
1.28 + <number of seconds>
1.29 + <number of days>d
1.30 +
1.31 +For example:
1.32 +
1.33 + 600 extend scheduling offers for 10 minutes
1.34 + 1d extend offers for 1 day
1.35 +
1.36 freebusy_sharing
1.37 ----------------
1.38
2.1 --- a/imip_store.py Sun Sep 13 18:23:42 2015 +0200
2.2 +++ b/imip_store.py Sun Sep 13 19:00:15 2015 +0200
2.3 @@ -22,7 +22,7 @@
2.4 from datetime import datetime
2.5 from imiptools.config import STORE_DIR, PUBLISH_DIR
2.6 from imiptools.data import make_calendar, parse_object, to_stream
2.7 -from imiptools.dates import format_datetime, get_datetime
2.8 +from imiptools.dates import format_datetime, get_datetime, to_timezone
2.9 from imiptools.filesys import fix_permissions, FileBase
2.10 from imiptools.period import FreeBusyPeriod
2.11 from os.path import exists, isfile, join
2.12 @@ -597,7 +597,7 @@
2.13
2.14 offers = []
2.15 expired = []
2.16 - now = datetime.now()
2.17 + now = to_timezone(datetime.now(), "UTC")
2.18
2.19 # Expire old offers and save the collection if modified.
2.20
3.1 --- a/imiptools/client.py Sun Sep 13 18:23:42 2015 +0200
3.2 +++ b/imiptools/client.py Sun Sep 13 19:00:15 2015 +0200
3.3 @@ -19,7 +19,7 @@
3.4 this program. If not, see <http://www.gnu.org/licenses/>.
3.5 """
3.6
3.7 -from datetime import datetime
3.8 +from datetime import datetime, timedelta
3.9 from imiptools.config import MANAGER_INTERFACE
3.10 from imiptools.data import Object, get_address, get_uri, get_window_end, \
3.11 is_new_object, make_freebusy, to_part, \
3.12 @@ -115,6 +115,31 @@
3.13 prefs = self.get_preferences()
3.14 return prefs and prefs.get("add_method_response", "refresh") or "refresh"
3.15
3.16 + def get_offer_period(self):
3.17 +
3.18 + """
3.19 + Decode a specification of one of the following forms...
3.20 +
3.21 + <number of seconds>
3.22 + <number of days>d
3.23 + """
3.24 +
3.25 + prefs = self.get_preferences()
3.26 + duration = prefs and prefs.get("freebusy_offers")
3.27 + if duration:
3.28 + try:
3.29 + if duration.endswith("d"):
3.30 + return timedelta(days=int(duration[:-1]))
3.31 + else:
3.32 + return timedelta(seconds=int(duration))
3.33 +
3.34 + # NOTE: Should probably report an error somehow.
3.35 +
3.36 + except ValueError:
3.37 + return None
3.38 + else:
3.39 + return None
3.40 +
3.41 def get_organiser_replacement(self):
3.42 prefs = self.get_preferences()
3.43 return prefs and prefs.get("organiser_replacement", "attendee") or "attendee"
3.44 @@ -268,16 +293,19 @@
3.45
3.46 return None
3.47
3.48 - def update_freebusy(self, freebusy, periods, transp, uid, recurrenceid, summary, organiser):
3.49 + def update_freebusy(self, freebusy, periods, transp, uid, recurrenceid, summary, organiser, expires=None):
3.50
3.51 """
3.52 Update the 'freebusy' collection with the given 'periods', indicating a
3.53 'transp' status, explicit 'uid' and 'recurrenceid' to indicate either a
3.54 recurrence or the parent event. The 'summary' and 'organiser' must also
3.55 be provided.
3.56 +
3.57 + An optional 'expires' datetime string can be provided to tag a free/busy
3.58 + offer.
3.59 """
3.60
3.61 - update_freebusy(freebusy, periods, transp, uid, recurrenceid, summary, organiser)
3.62 + update_freebusy(freebusy, periods, transp, uid, recurrenceid, summary, organiser, expires)
3.63
3.64 class ClientForObject(Client):
3.65
3.66 @@ -590,7 +618,7 @@
3.67 recurrenceid = self.get_recurrence_start_point(recurrenceid)
3.68 remove_affected_period(freebusy, self.uid, recurrenceid)
3.69
3.70 - def update_freebusy(self, freebusy, user, as_organiser):
3.71 + def update_freebusy(self, freebusy, user, as_organiser, offer=False):
3.72
3.73 """
3.74 Update the 'freebusy' collection for this event with the periods and
3.75 @@ -598,6 +626,9 @@
3.76 identity and the attendance details provided for them, indicating
3.77 whether the update is being done 'as_organiser' (for the organiser of
3.78 an event) or not.
3.79 +
3.80 + If 'offer' is set to a true value, any free/busy updates will be tagged
3.81 + with an expiry time.
3.82 """
3.83
3.84 # Obtain the stored object if the current object is not issued by the
3.85 @@ -619,21 +650,37 @@
3.86 obj.get_value("TRANSP") or \
3.87 "OPAQUE"
3.88
3.89 + # Calculate any expiry time. If no offer period is defined, do not
3.90 + # record the offer periods.
3.91 +
3.92 + if offer:
3.93 + offer_period = self.get_offer_period()
3.94 + if offer_period:
3.95 + expires = format_datetime(to_timezone(datetime.utcnow(), "UTC") + offer_period)
3.96 + else:
3.97 + return
3.98 + else:
3.99 + expires = None
3.100 +
3.101 # Perform the low-level update.
3.102
3.103 Client.update_freebusy(self, freebusy, periods, transp,
3.104 self.uid, self.recurrenceid,
3.105 obj.get_value("SUMMARY"),
3.106 - obj.get_value("ORGANIZER"))
3.107 + obj.get_value("ORGANIZER"),
3.108 + expires)
3.109
3.110 def update_freebusy_for_participant(self, freebusy, user, for_organiser=False,
3.111 - updating_other=False):
3.112 + updating_other=False, offer=False):
3.113
3.114 """
3.115 Update the 'freebusy' collection for the given 'user', indicating
3.116 whether the update is 'for_organiser' (being done for the organiser of
3.117 an event) or not, and whether it is 'updating_other' (meaning another
3.118 user's details).
3.119 +
3.120 + If 'offer' is set to a true value, any free/busy updates will be tagged
3.121 + with an expiry time.
3.122 """
3.123
3.124 # Record in the free/busy details unless a non-participating attendee.
3.125 @@ -642,7 +689,8 @@
3.126 if self.is_participating(user, for_organiser and not updating_other):
3.127 self.update_freebusy(freebusy, user,
3.128 for_organiser and not updating_other or
3.129 - not for_organiser and updating_other
3.130 + not for_organiser and updating_other,
3.131 + offer
3.132 )
3.133 else:
3.134 self.remove_from_freebusy(freebusy)
4.1 --- a/imiptools/handlers/common.py Sun Sep 13 18:23:42 2015 +0200
4.2 +++ b/imiptools/handlers/common.py Sun Sep 13 19:00:15 2015 +0200
4.3 @@ -167,7 +167,7 @@
4.4
4.5 # Obtain the attendance attributes for this user, if available.
4.6
4.7 - self.update_freebusy_for_participant(freebusy, self.user)
4.8 + self.update_freebusy_for_participant(freebusy, self.user, offer=True)
4.9
4.10 # Remove original recurrence details replaced by additional
4.11 # recurrences, as well as obsolete additional recurrences.
5.1 --- a/imiptools/period.py Sun Sep 13 18:23:42 2015 +0200
5.2 +++ b/imiptools/period.py Sun Sep 13 19:00:15 2015 +0200
5.3 @@ -757,16 +757,19 @@
5.4
5.5 return spans
5.6
5.7 -def update_freebusy(freebusy, periods, transp, uid, recurrenceid, summary, organiser):
5.8 +def update_freebusy(freebusy, periods, transp, uid, recurrenceid, summary, organiser, expires=None):
5.9
5.10 """
5.11 Update the free/busy details with the given 'periods', 'transp' setting,
5.12 'uid' plus 'recurrenceid' and 'summary' and 'organiser' details.
5.13 +
5.14 + An optional 'expires' datetime string indicates the expiry time of any
5.15 + free/busy offer.
5.16 """
5.17
5.18 remove_period(freebusy, uid, recurrenceid)
5.19
5.20 for p in periods:
5.21 - insert_period(freebusy, FreeBusyPeriod(p.get_start_point(), p.get_end_point(), uid, transp, recurrenceid, summary, organiser))
5.22 + insert_period(freebusy, FreeBusyPeriod(p.get_start_point(), p.get_end_point(), uid, transp, recurrenceid, summary, organiser, expires))
5.23
5.24 # vim: tabstop=4 expandtab shiftwidth=4
6.1 --- a/tests/test_resource_invitation_constraints.sh Sun Sep 13 18:23:42 2015 +0200
6.2 +++ b/tests/test_resource_invitation_constraints.sh Sun Sep 13 19:00:15 2015 +0200
6.3 @@ -26,6 +26,7 @@
6.4 echo 'Europe/Oslo' > "$PREFS/$USER/TZID"
6.5 echo 'share' > "$PREFS/$USER/freebusy_sharing"
6.6 echo '10,12,14,16,18:0,15,30,45' > "$PREFS/$USER/permitted_times"
6.7 +echo '60' > "$PREFS/$USER/freebusy_offers"
6.8
6.9 "$RESOURCE_SCRIPT" $ARGS < "$TEMPLATES/fb-request-sauna-all.txt" 2>> $ERROR \
6.10 | "$SHOWMAIL" \