From 324e1f9ef400f0129940c5c217d6b76eb4c38342 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Tue, 11 Oct 2016 14:11:10 +0100 Subject: [PATCH] Allow a job to be scheduled any time in next 96hrs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If you want to send a job on Monday morning, you should be able to schedule it on Friday. You shouldn’t need to work on the weekend. 96 hours is a full 4 days, so you can schedule a job at any time on Friday for any time on Monday. We’ve checked with the information assurance people, and they’re OK with us holding the data for this extra amount of time. This commit changes the choose time form from showing one radio button for each of the next 24 hours to one for each of the next 96 hours. It changes the labels from ‘9am’ to ‘Monday at 9am’ so it’s clear which day you’re choosing. --- app/main/forms.py | 40 +++++++++++++++++++++---- app/main/views/send.py | 2 +- tests/app/main/test_choose_time_form.py | 22 ++++++++++++-- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/app/main/forms.py b/app/main/forms.py index 650f72891..ccd9fc14a 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -27,27 +27,55 @@ from app.main.validators import (Blacklist, CsvFileValidator, ValidGovEmail, NoC def get_time_value_and_label(future_time): return ( future_time.replace(tzinfo=None).isoformat(), - get_human_time(future_time.astimezone(pytz.timezone('Europe/London'))) + '{} at {}'.format( + get_human_day(future_time.astimezone(pytz.timezone('Europe/London'))), + get_human_time(future_time.astimezone(pytz.timezone('Europe/London'))) + ) ) def get_human_time(time): return { - '0': 'Midnight', - '12': 'Midday' + '0': 'midnight', + '12': 'midday' }.get( time.strftime('%-H'), time.strftime('%-I%p').lower() ) -def get_next_hours_from(now, hours=23): +def get_human_day(time): + # Add 1 hour to get ‘midnight today’ instead of ‘midnight tomorrow’ + time = (time - timedelta(hours=1)).strftime('%A') + if time == datetime.utcnow().strftime('%A'): + return 'Today' + if time == (datetime.utcnow() + timedelta(days=1)).strftime('%A'): + return 'Tomorrow' + return time + + +def get_furthest_possible_scheduled_time(): + return (datetime.utcnow() + timedelta(days=4)).replace(hour=0) + + +def get_next_hours_until(until): + now = datetime.utcnow() + hours = int((until - now).total_seconds() / (60 * 60)) return [ (now + timedelta(hours=i)).replace(minute=0, second=0).replace(tzinfo=pytz.utc) for i in range(1, hours + 1) ] +def get_next_days_until(until): + now = datetime.utcnow() + days = int((until - now).total_seconds() / (60 * 60 * 24)) + return [ + get_human_day((now + timedelta(days=i)).replace(tzinfo=pytz.utc)) + for i in range(0, days + 1) + ] + + def email_address(label='Email address', gov_user=True): validators = [ Length(min=5, max=255), @@ -310,7 +338,9 @@ class ChooseTimeForm(Form): def __init__(self, *args, **kwargs): super(ChooseTimeForm, self).__init__(*args, **kwargs) self.scheduled_for.choices = [('', 'Now')] + [ - get_time_value_and_label(hour) for hour in get_next_hours_from(datetime.utcnow()) + get_time_value_and_label(hour) for hour in get_next_hours_until( + get_furthest_possible_scheduled_time() + ) ] scheduled_for = RadioField( diff --git a/app/main/views/send.py b/app/main/views/send.py index 2ef85dd24..9766e7c7c 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -23,7 +23,7 @@ from notifications_utils.template import Template from notifications_utils.recipients import RecipientCSV, first_column_heading, validate_and_format_phone_number from app.main import main -from app.main.forms import CsvUploadForm, ChooseTimeForm +from app.main.forms import CsvUploadForm, ChooseTimeForm, get_next_days_until, get_furthest_possible_scheduled_time from app.main.uploader import ( s3upload, s3download diff --git a/tests/app/main/test_choose_time_form.py b/tests/app/main/test_choose_time_form.py index 70977908f..82b858ccb 100644 --- a/tests/app/main/test_choose_time_form.py +++ b/tests/app/main/test_choose_time_form.py @@ -9,12 +9,28 @@ def test_form_contains_next_24h(app_): choices = ChooseTimeForm().scheduled_for.choices + # Friday assert choices[0] == ('', 'Now') - assert choices[1] == ('2016-01-01T12:00:00.061258', 'Midday') - assert choices[23] == ('2016-01-02T10:00:00.061258', '10am') + assert choices[1] == ('2016-01-01T12:00:00.061258', 'Today at midday') + assert choices[13] == ('2016-01-02T00:00:00.061258', 'Today at midnight') + + # Saturday + assert choices[14] == ('2016-01-02T01:00:00.061258', 'Tomorrow at 1am') + assert choices[37] == ('2016-01-03T00:00:00.061258', 'Tomorrow at midnight') + + # Sunday + assert choices[38] == ('2016-01-03T01:00:00.061258', 'Sunday at 1am') + + # Monday + assert choices[84] == ('2016-01-04T23:00:00.061258', 'Monday at 11pm') + assert choices[85] == ('2016-01-05T00:00:00.061258', 'Monday at midnight') with pytest.raises(IndexError): - assert choices[24] + assert choices[ + 12 + # hours left in the day + (3 * 24) + # 3 days + 2 # magic number + ] @freeze_time("2016-01-01 11:09:00.061258")