1.1 --- a/imiptools/handlers/scheduling/quota.py Fri May 13 22:41:17 2016 +0200
1.2 +++ b/imiptools/handlers/scheduling/quota.py Fri May 13 22:48:45 2016 +0200
1.3 @@ -21,6 +21,8 @@
1.4
1.5 from imiptools.dates import get_duration, to_utc_datetime
1.6 from imiptools.data import get_uri, uri_dict
1.7 +from imiptools.handlers.scheduling.common import get_scheduling_conflicts, \
1.8 + standard_responses
1.9 from imiptools.period import Endless
1.10 from datetime import timedelta
1.11
1.12 @@ -50,6 +52,15 @@
1.13 if not limit:
1.14 return "DECLINED", _("You have no quota allocation for the recipient.")
1.15
1.16 + # Decline endless events even for unlimited quotas.
1.17 + # NOTE: Such events could be supported in a similar way to those supported
1.18 + # NOTE: for each user.
1.19 +
1.20 + total = _get_duration(handler)
1.21 +
1.22 + if total == Endless():
1.23 + return "DECLINED", _("The event period exceeds your quota allocation for the recipient.")
1.24 +
1.25 # Where the quota is unlimited, accept the invitation.
1.26
1.27 if limit == "*":
1.28 @@ -57,11 +68,6 @@
1.29
1.30 # Decline events whose durations exceed the balance.
1.31
1.32 - total = _get_duration(handler)
1.33 -
1.34 - if total == Endless():
1.35 - return "DECLINED", _("The event period exceeds your quota allocation for the recipient.")
1.36 -
1.37 balance = get_duration(limit) - _get_usage(entries)
1.38
1.39 if total > balance:
1.40 @@ -81,7 +87,7 @@
1.41 total = _get_duration(handler)
1.42 expiry = _get_expiry_time(handler)
1.43
1.44 - # Reject indefinitely recurring events.
1.45 + # Ignore indefinitely recurring events.
1.46
1.47 if total == Endless() or not expiry:
1.48 return
1.49 @@ -103,11 +109,12 @@
1.50 quota, group = _get_quota_and_group(handler, args)
1.51
1.52 total = _get_duration(handler)
1.53 -
1.54 - # Allow indefinitely recurring events.
1.55 + expiry = _get_expiry_time(handler)
1.56
1.57 - if total == Endless():
1.58 - total = None
1.59 + # Ignore indefinitely recurring events.
1.60 +
1.61 + if total == Endless() or not expiry:
1.62 + return
1.63
1.64 # Update the journal entries.
1.65
1.66 @@ -196,8 +203,6 @@
1.67 nor are the quotas themselves.
1.68 """
1.69
1.70 - _ = handler.get_translator()
1.71 -
1.72 quota, organiser = _get_quota_and_identity(handler, args)
1.73
1.74 # Check the event periods against the quota's consolidated record of the
1.75 @@ -207,10 +212,7 @@
1.76 freebusy = handler.get_journal().get_freebusy(quota, organiser)
1.77 scheduled = handler.can_schedule(freebusy, periods)
1.78
1.79 - if scheduled:
1.80 - return "ACCEPTED", _("The recipient has scheduled the requested period.")
1.81 - else:
1.82 - return "DECLINED", _("The requested period cannot be scheduled.")
1.83 + return standard_responses(handler, scheduled and "ACCEPTED" or "DECLINED")
1.84
1.85 def add_to_quota_freebusy(handler, args):
1.86
1.87 @@ -263,11 +265,9 @@
1.88 """
1.89 Check the current object of the given 'handler' against the schedules
1.90 managed by the quota, delegating to a specific recipient according to the
1.91 - given policy.
1.92 + given policies.
1.93 """
1.94
1.95 - _ = handler.get_translator()
1.96 -
1.97 # First check the quota and decline any request that would exceed the quota.
1.98
1.99 scheduled = check_quota(handler, args)
1.100 @@ -279,7 +279,7 @@
1.101 # Obtain the quota and organiser group details to evaluate delegation.
1.102
1.103 quota, group = _get_quota_and_group(handler, args)
1.104 - policy = args and (args[1:] or ["arbitrary"])[0]
1.105 + policies = args and args[1:] or ["available"]
1.106
1.107 # Determine the status of the recipient.
1.108
1.109 @@ -305,26 +305,29 @@
1.110 # unavailable delegates.
1.111
1.112 entries = handler.get_journal().get_entries(quota, group)
1.113 - unavailable = set()
1.114 + conflicts = get_scheduling_conflicts(handler, entries, delegates, attendee=True)
1.115
1.116 - for period in handler.get_periods(handler.obj):
1.117 - overlapping = entries.get_overlapping(period)
1.118 + # Get the delegates in order of increasing unavailability (or decreasing
1.119 + # availability).
1.120
1.121 - # Where scheduling cannot occur, find the busy potential delegates.
1.122 + unavailability = conflicts.items()
1.123 +
1.124 + # Apply the policies to choose a suitable delegate.
1.125
1.126 - if overlapping:
1.127 - for p in overlapping:
1.128 - unavailable.add(p.attendee)
1.129 + if "most-available" in policies:
1.130 + unavailability.sort(key=lambda t: t[1])
1.131 + available = [delegate for (delegate, commitments) in unavailability]
1.132 + delegate = available and available[0]
1.133
1.134 - # Get the remaining, available delegates.
1.135 + # The default is to select completely available delegates.
1.136
1.137 - available = delegates.difference(unavailable)
1.138 + else:
1.139 + available = [delegate for (delegate, commitments) in unavailability if not commitments]
1.140 + delegate = available and (handler.user in available and handler.user or available[0])
1.141
1.142 - # Apply the policy to choose an available delegate.
1.143 - # NOTE: Currently an arbitrary delegate is chosen if not the recipient.
1.144 + # Only accept or delegate if a suitably available delegate is found.
1.145
1.146 - if available:
1.147 - delegate = handler.user in available and handler.user or list(available)[0]
1.148 + if delegate:
1.149
1.150 # Add attendee for delegate, obtaining the original attendee dictionary.
1.151 # Modify this user's status to refer to the delegate.
1.152 @@ -335,11 +338,13 @@
1.153 attendee_attr["DELEGATED-TO"] = [delegate]
1.154 handler.obj["ATTENDEE"] = attendee_map.items()
1.155
1.156 - return "DELEGATED", _("The recipient has delegated the requested period.")
1.157 + response = "DELEGATED"
1.158 else:
1.159 - return "ACCEPTED", _("The recipient has scheduled the requested period.")
1.160 + response = "ACCEPTED"
1.161 else:
1.162 - return "DECLINED", _("The requested period cannot be scheduled.")
1.163 + response = "DECLINED"
1.164 +
1.165 + return standard_responses(handler, response)
1.166
1.167 # Locking and unlocking.
1.168