From 9d720fd4bdb28571407db8bf2328184223666a77 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Thu, 30 Aug 2018 10:46:13 +0100 Subject: [PATCH 1/5] Add data to copy into beta partners spreadsheet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we keep track of live services in the ‘beta partners’ spreadsheet: https://docs.google.com/spreadsheets/d/1JYhE5sJaOJUVMPPDenO2eKqElC75Rygxb1_2mpRKy98/edit#gid=503930061 Every time a service goes live we need to enter some data into the spreadsheet about that service. Most of that data is copied from the request to go live ticket. This commit adds a line to the ticket with all the data needed by the spreadsheet. It’s in the same order as in the spreadsheet, and it’s tab-delimted so it should paste right on in there. --- app/main/views/service_settings.py | 21 ++++++++++++++- tests/app/main/views/test_service_settings.py | 27 ++++++++++++------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 2a82c39c8..1c4e7c0fd 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -1,3 +1,6 @@ +from datetime import datetime + +import pytz from flask import ( abort, current_app, @@ -222,6 +225,16 @@ def submit_request_to_go_live(service_id): '\nChannel: {}\nStart date: {}\nStart volume: {}' '\nPeak volume: {}' '\nFeatures: {}' + '\n' + '\n---' + '\n' + '{service_id}\t' + '{organisation}\t' + '{service_name}\t' + '{user_name}\t' + '{user_email}\t' + '-\t' + '{date}' ).format( current_service.name, url_for('main.service_dashboard', service_id=current_service.id, _external=True), @@ -239,7 +252,13 @@ def submit_request_to_go_live(service_id): 'one off' if form.method_one_off.data else None, 'file upload' if form.method_upload.data else None, 'API' if form.method_api.data else None, - )), before_each='', after_each='') + )), before_each='', after_each=''), + service_id=current_service.id, + organisation=AgreementInfo.from_current_user().owner, + service_name=current_service.name, + user_name=current_user.name, + user_email=current_user.email_address, + date=datetime.now(tz=pytz.timezone('Europe/London')).strftime('%d/%m/%Y'), ), ticket_type=zendesk_client.TYPE_QUESTION, user_email=current_user.email_address, diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index dd539d949..958636869 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -708,6 +708,7 @@ def test_should_show_request_to_go_live( ) == label +@freeze_time("2012-12-21") def test_should_redirect_after_request_to_go_live( client_request, mocker, @@ -741,16 +742,22 @@ def test_should_redirect_after_request_to_go_live( user_name=active_user_with_permissions.name, user_email=active_user_with_permissions.email_address ) - - returned_message = mock_post.call_args[1]['message'] - assert 'Service: service one' in returned_message - assert 'Organisation type: central' in returned_message - assert 'Agreement signed: Can’t tell' in returned_message - assert 'Channel: email and text messages' in returned_message - assert 'Start date: 01/01/2017' in returned_message - assert 'Start volume: 100,000' in returned_message - assert 'Peak volume: 2,000,000' in returned_message - assert 'Features: one off, file upload and API' in returned_message + assert mock_post.call_args[1]['message'] == ( + 'Service: service one\n' + 'http://localhost/services/{}\n' + '\n' + '---\n' + 'Organisation type: central\n' + 'Agreement signed: Can’t tell (domain is user.gov.uk)\n' + 'Channel: email and text messages\n' + 'Start date: 01/01/2017\n' + 'Start volume: 100,000\n' + 'Peak volume: 2,000,000\n' + 'Features: one off, file upload and API\n' + '\n' + '---\n' + '{}\tNone\tservice one\tTest User\ttest@user.gov.uk\t-\t21/12/2012' + ).format(SERVICE_ONE_ID, SERVICE_ONE_ID) assert normalize_spaces(page.select_one('.banner-default').text) == ( 'Thanks for your request to go live. We’ll get back to you within one working day.' From 80339046dfb3abacece547d1b83231a5b26d7510 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Thu, 30 Aug 2018 10:48:44 +0100 Subject: [PATCH 2/5] Remove question about which features people use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an optional question. We don’t really use the answer to it now that we have some adoption of all these features. --- app/main/forms.py | 3 --- app/main/views/service_settings.py | 6 ------ .../service-settings/submit-request-to-go-live.html | 5 ----- tests/app/main/views/test_service_settings.py | 12 ------------ 4 files changed, 26 deletions(-) diff --git a/app/main/forms.py b/app/main/forms.py index 6cec88500..794f8e322 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -584,9 +584,6 @@ class RequestToGoLiveForm(StripWhitespaceForm): 'Will the number of messages increase and when will that start?', validators=[DataRequired(message='Can’t be empty')] ) - method_one_off = BooleanField('One at a time') - method_upload = BooleanField('Upload a spreadsheet of recipients') - method_api = BooleanField('Integrate with the GOV.UK Notify API') class ProviderForm(StripWhitespaceForm): diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 1c4e7c0fd..9dd4aaee3 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -224,7 +224,6 @@ def submit_request_to_go_live(service_id): '\nAgreement signed: {}' '\nChannel: {}\nStart date: {}\nStart volume: {}' '\nPeak volume: {}' - '\nFeatures: {}' '\n' '\n---' '\n' @@ -248,11 +247,6 @@ def submit_request_to_go_live(service_id): form.start_date.data, form.start_volume.data, form.peak_volume.data, - formatted_list(filter(None, ( - 'one off' if form.method_one_off.data else None, - 'file upload' if form.method_upload.data else None, - 'API' if form.method_api.data else None, - )), before_each='', after_each=''), service_id=current_service.id, organisation=AgreementInfo.from_current_user().owner, service_name=current_service.name, diff --git a/app/templates/views/service-settings/submit-request-to-go-live.html b/app/templates/views/service-settings/submit-request-to-go-live.html index c6a352d11..495f1a0f0 100644 --- a/app/templates/views/service-settings/submit-request-to-go-live.html +++ b/app/templates/views/service-settings/submit-request-to-go-live.html @@ -28,11 +28,6 @@ {{ textbox(form.start_volume, width='1-1', hint='For example, ‘1,000 per month’.') }} {{ textbox(form.peak_volume, width='1-1', hint='For example, ‘Messages will increase to 20,000 per month in January’.') }} - {{ checkbox_group('How are you going to send messages?', [ - form.method_one_off, - form.method_upload, - form.method_api - ]) }}

By requesting to go live you’re agreeing to our terms of use.

diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index 958636869..72f2af6a1 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -698,14 +698,6 @@ def test_should_show_request_to_go_live( assert normalize_spaces( page.select_one('label[for=channel_{}]'.format(channel)).text ) == label - for feature, label in ( - ('one_off', 'One at a time'), - ('upload', 'Upload a spreadsheet of recipients'), - ('api', 'Integrate with the GOV.UK Notify API'), - ): - assert normalize_spaces( - page.select_one('label[for=method_{}]'.format(feature)).text - ) == label @freeze_time("2012-12-21") @@ -729,9 +721,6 @@ def test_should_redirect_after_request_to_go_live( 'start_date': '01/01/2017', 'start_volume': '100,000', 'peak_volume': '2,000,000', - 'method_one_off': 'y', - 'method_upload': 'y', - 'method_api': 'y', }, _follow_redirects=True ) @@ -753,7 +742,6 @@ def test_should_redirect_after_request_to_go_live( 'Start date: 01/01/2017\n' 'Start volume: 100,000\n' 'Peak volume: 2,000,000\n' - 'Features: one off, file upload and API\n' '\n' '---\n' '{}\tNone\tservice one\tTest User\ttest@user.gov.uk\t-\t21/12/2012' From 12e0e12ced8087bc4b5e3d95479b62f9aa77a39d Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Thu, 30 Aug 2018 11:00:39 +0100 Subject: [PATCH 3/5] Replace channels and volumes with volumes/channel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we’re a more mature platform we don’t care so much about the load that one service might put on our platform. We do care about intended volumes for two reasons: - modelling the benefits that services get from using Notify - managing stocks of envelopes (while our letter volumes are small enough that they could be skewed by one new service) Changing to the ‘how many per year’ question also has the benefit of mapping directly to the data we store in the ‘beta partners’ spreadsheet. --- app/main/forms.py | 15 +++---- app/main/views/service_settings.py | 39 +++++++++---------- .../submit-request-to-go-live.html | 25 ++++++------ tests/app/main/views/test_service_settings.py | 34 +++++++++------- 4 files changed, 55 insertions(+), 58 deletions(-) diff --git a/app/main/forms.py b/app/main/forms.py index 794f8e322..2d9db1e98 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -569,19 +569,16 @@ class Triage(StripWhitespaceForm): class RequestToGoLiveForm(StripWhitespaceForm): - channel_email = BooleanField('Emails') - channel_sms = BooleanField('Text messages') - channel_letter = BooleanField('Letters') - start_date = StringField( - 'When will you be ready to start sending messages?', + volume_email = StringField( + 'How many emails do you expect to send in the next year?', validators=[DataRequired(message='Can’t be empty')] ) - start_volume = StringField( - 'How many messages do you expect to send to start with?', + volume_sms = StringField( + 'How many text messages do you expect to send in the next year?', validators=[DataRequired(message='Can’t be empty')] ) - peak_volume = StringField( - 'Will the number of messages increase and when will that start?', + volume_letter = StringField( + 'How many letters do you expect to send in the next year?', validators=[DataRequired(message='Can’t be empty')] ) diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 9dd4aaee3..2cb07c1f0 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -14,7 +14,6 @@ from flask import ( from flask_login import current_user, login_required from notifications_python_client.errors import HTTPError from notifications_utils.field import Field -from notifications_utils.formatters import formatted_list from app import ( billing_api_client, @@ -217,13 +216,14 @@ def submit_request_to_go_live(service_id): zendesk_client.create_ticket( subject='Request to go live - {}'.format(current_service.name), message=( - 'Service: {}\n' - '{}\n' + 'Service: {service_name}\n' + '{service_dashboard}\n' '\n---' - '\nOrganisation type: {}' - '\nAgreement signed: {}' - '\nChannel: {}\nStart date: {}\nStart volume: {}' - '\nPeak volume: {}' + '\nOrganisation type: {organisation_type}' + '\nAgreement signed: {agreement}' + '\nEmails in next year: {volume_email}' + '\nText messages in next year: {volume_sms}' + '\nLetters in next year: {volume_letter}' '\n' '\n---' '\n' @@ -233,23 +233,20 @@ def submit_request_to_go_live(service_id): '{user_name}\t' '{user_email}\t' '-\t' - '{date}' + '{date}\t' + '{volume_sms}\t' + '{volume_email}\t' + '{volume_letter}' ).format( - current_service.name, - url_for('main.service_dashboard', service_id=current_service.id, _external=True), - current_service.organisation_type, - AgreementInfo.from_current_user().as_human_readable, - formatted_list(filter(None, ( - 'email' if form.channel_email.data else None, - 'text messages' if form.channel_sms.data else None, - 'letters' if form.channel_letter.data else None, - )), before_each='', after_each=''), - form.start_date.data, - form.start_volume.data, - form.peak_volume.data, + service_name=current_service.name, + service_dashboard=url_for('main.service_dashboard', service_id=current_service.id, _external=True), + organisation_type=current_service.organisation_type, + agreement=AgreementInfo.from_current_user().as_human_readable, + volume_email=form.volume_email.data, + volume_sms=form.volume_sms.data, + volume_letter=form.volume_letter.data, service_id=current_service.id, organisation=AgreementInfo.from_current_user().owner, - service_name=current_service.name, user_name=current_user.name, user_email=current_user.email_address, date=datetime.now(tz=pytz.timezone('Europe/London')).strftime('%d/%m/%Y'), diff --git a/app/templates/views/service-settings/submit-request-to-go-live.html b/app/templates/views/service-settings/submit-request-to-go-live.html index 495f1a0f0..fab2cf079 100644 --- a/app/templates/views/service-settings/submit-request-to-go-live.html +++ b/app/templates/views/service-settings/submit-request-to-go-live.html @@ -13,27 +13,24 @@

Request to go live

-

- Tell us how you plan to use Notify. When we receive your request we’ll make your service live within one working day. -

+
+
+

+ Tell us how you plan to use Notify. When we receive your request we’ll make your service live within one working day. +

+
+
-
- {{ checkbox_group('What kind of messages will you be sending?', [ - form.channel_email, - form.channel_sms, - form.channel_letter - ]) }} +
- {{ textbox(form.start_date, width='1-1') }} - {{ textbox(form.start_volume, width='1-1', hint='For example, ‘1,000 per month’.') }} - {{ textbox(form.peak_volume, width='1-1', hint='For example, ‘Messages will increase to 20,000 per month in January’.') }} + {{ textbox(form.volume_email, width='1-2', hint='For example, 1,000,000') }} + {{ textbox(form.volume_sms, width='1-2', hint='For example, 500,000') }} + {{ textbox(form.volume_letter, width='1-2', hint='For example, 5,000') }}

By requesting to go live you’re agreeing to our terms of use.

- {{ page_footer('Request to go live') }}
- {% endblock %} diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index 72f2af6a1..e29568672 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -691,12 +691,21 @@ def test_should_show_request_to_go_live( ) assert page.h1.text == 'Request to go live' for channel, label in ( - ('email', 'Emails'), - ('sms', 'Text messages'), - ('letter', 'Letters'), + ( + 'email', + 'How many emails do you expect to send in the next year? For example, 1,000,000' + ), + ( + 'sms', + 'How many text messages do you expect to send in the next year? For example, 500,000' + ), + ( + 'letter', + 'How many letters do you expect to send in the next year? For example, 5,000' + ), ): assert normalize_spaces( - page.select_one('label[for=channel_{}]'.format(channel)).text + page.select_one('label[for=volume_{}]'.format(channel)).text ) == label @@ -716,11 +725,9 @@ def test_should_redirect_after_request_to_go_live( 'main.submit_request_to_go_live', service_id=SERVICE_ONE_ID, _data={ - 'channel_email': 'y', - 'channel_sms': 'y', - 'start_date': '01/01/2017', - 'start_volume': '100,000', - 'peak_volume': '2,000,000', + 'volume_email': '111', + 'volume_sms': '222', + 'volume_letter': '333', }, _follow_redirects=True ) @@ -738,13 +745,12 @@ def test_should_redirect_after_request_to_go_live( '---\n' 'Organisation type: central\n' 'Agreement signed: Can’t tell (domain is user.gov.uk)\n' - 'Channel: email and text messages\n' - 'Start date: 01/01/2017\n' - 'Start volume: 100,000\n' - 'Peak volume: 2,000,000\n' + 'Emails in next year: 111\n' + 'Text messages in next year: 222\n' + 'Letters in next year: 333\n' '\n' '---\n' - '{}\tNone\tservice one\tTest User\ttest@user.gov.uk\t-\t21/12/2012' + '{}\tNone\tservice one\tTest User\ttest@user.gov.uk\t-\t21/12/2012\t222\t111\t333' ).format(SERVICE_ONE_ID, SERVICE_ONE_ID) assert normalize_spaces(page.select_one('.banner-default').text) == ( From 86ad77e54591acfb0a2a5fc13169dd8315198454 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Thu, 30 Aug 2018 11:51:34 +0100 Subject: [PATCH 4/5] Add question about research consent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since GDPR came into effect it’s less clear about whether we can contact teams for user research purposes. If we make people opt-in (or not) we know we’re safe to contact them (or not). Since we mostly care about how services are using Notify for real (ie live services) or services that are considering adopting it (ie those who have contacted us with a question) it feels like the go-live process is the most appropriate place to collect this consent. --- app/main/forms.py | 8 ++++++++ app/main/views/service_settings.py | 4 +++- app/templates/components/radios.html | 5 +++++ .../submit-request-to-go-live.html | 14 ++++++-------- tests/app/main/views/test_service_settings.py | 4 +++- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/app/main/forms.py b/app/main/forms.py index 2d9db1e98..4d5bbf3a6 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -581,6 +581,14 @@ class RequestToGoLiveForm(StripWhitespaceForm): 'How many letters do you expect to send in the next year?', validators=[DataRequired(message='Can’t be empty')] ) + research_consent = RadioField( + 'Can we contact you when we’re doing user research?', + choices=[ + ('yes', 'Yes'), + ('no', 'No'), + ], + validators=[DataRequired()] + ) class ProviderForm(StripWhitespaceForm): diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 2cb07c1f0..8d4a40cd8 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -224,6 +224,7 @@ def submit_request_to_go_live(service_id): '\nEmails in next year: {volume_email}' '\nText messages in next year: {volume_sms}' '\nLetters in next year: {volume_letter}' + '\nConsent to research: {research_consent}' '\n' '\n---' '\n' @@ -240,11 +241,12 @@ def submit_request_to_go_live(service_id): ).format( service_name=current_service.name, service_dashboard=url_for('main.service_dashboard', service_id=current_service.id, _external=True), - organisation_type=current_service.organisation_type, + organisation_type=str(current_service.organisation_type).title(), agreement=AgreementInfo.from_current_user().as_human_readable, volume_email=form.volume_email.data, volume_sms=form.volume_sms.data, volume_letter=form.volume_letter.data, + research_consent=form.research_consent.data.title(), service_id=current_service.id, organisation=AgreementInfo.from_current_user().owner, user_name=current_user.name, diff --git a/app/templates/components/radios.html b/app/templates/components/radios.html index 0604c9361..8b3ee19dc 100644 --- a/app/templates/components/radios.html +++ b/app/templates/components/radios.html @@ -21,6 +21,11 @@ {% if hide_legend %}{% endif %} {{ field.label.text|safe }} {% if hide_legend %}{% endif %} + {% if hint %} + + {{ hint }} + + {% endif %} {% if field.errors %} {{ field.errors[0] }} diff --git a/app/templates/views/service-settings/submit-request-to-go-live.html b/app/templates/views/service-settings/submit-request-to-go-live.html index fab2cf079..b5d888b3c 100644 --- a/app/templates/views/service-settings/submit-request-to-go-live.html +++ b/app/templates/views/service-settings/submit-request-to-go-live.html @@ -13,20 +13,18 @@

Request to go live

-
-
-

- Tell us how you plan to use Notify. When we receive your request we’ll make your service live within one working day. -

-
-
-
{{ textbox(form.volume_email, width='1-2', hint='For example, 1,000,000') }} {{ textbox(form.volume_sms, width='1-2', hint='For example, 500,000') }} {{ textbox(form.volume_letter, width='1-2', hint='For example, 5,000') }}
+ {{ radios(form.research_consent, hint='You don’t have to take part and you can unsubscribe at any time') }} +

+ When we receive your request we’ll get back to you within one working day. +

+ +

By requesting to go live you’re agreeing to our terms of use.

diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index e29568672..f632e20c7 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -728,6 +728,7 @@ def test_should_redirect_after_request_to_go_live( 'volume_email': '111', 'volume_sms': '222', 'volume_letter': '333', + 'research_consent': 'yes', }, _follow_redirects=True ) @@ -743,11 +744,12 @@ def test_should_redirect_after_request_to_go_live( 'http://localhost/services/{}\n' '\n' '---\n' - 'Organisation type: central\n' + 'Organisation type: Central\n' 'Agreement signed: Can’t tell (domain is user.gov.uk)\n' 'Emails in next year: 111\n' 'Text messages in next year: 222\n' 'Letters in next year: 333\n' + 'Consent to research: Yes\n' '\n' '---\n' '{}\tNone\tservice one\tTest User\ttest@user.gov.uk\t-\t21/12/2012\t222\t111\t333' From 3c563ddca61d66016471d2dee2561ffbc08ceb24 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Thu, 30 Aug 2018 14:17:32 +0100 Subject: [PATCH 5/5] Use commas not tabs to delimit service info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Zendesk strips out the tabs. Commas are the next best thing because Excel will automatically use them if you select ‘Split text into columns’. --- app/config.py | 1 - app/main/views/service_settings.py | 18 +++++++++--------- tests/app/main/views/test_service_settings.py | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/app/config.py b/app/config.py index b7ae9f2ed..e336eddeb 100644 --- a/app/config.py +++ b/app/config.py @@ -85,7 +85,6 @@ class Development(Config): API_HOST_NAME = 'http://localhost:6011' DANGEROUS_SALT = 'dev-notify-salt' SECRET_KEY = 'dev-notify-secret-key' - ZENDESK_API_KEY = "some-key" class Test(Development): diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 8d4a40cd8..50b935eee 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -228,15 +228,15 @@ def submit_request_to_go_live(service_id): '\n' '\n---' '\n' - '{service_id}\t' - '{organisation}\t' - '{service_name}\t' - '{user_name}\t' - '{user_email}\t' - '-\t' - '{date}\t' - '{volume_sms}\t' - '{volume_email}\t' + '{service_id}, ' + '{organisation}, ' + '{service_name}, ' + '{user_name}, ' + '{user_email}, ' + '-, ' + '{date}, ' + '{volume_sms}, ' + '{volume_email}, ' '{volume_letter}' ).format( service_name=current_service.name, diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index f632e20c7..7a76ee4ea 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -752,7 +752,7 @@ def test_should_redirect_after_request_to_go_live( 'Consent to research: Yes\n' '\n' '---\n' - '{}\tNone\tservice one\tTest User\ttest@user.gov.uk\t-\t21/12/2012\t222\t111\t333' + '{}, None, service one, Test User, test@user.gov.uk, -, 21/12/2012, 222, 111, 333' ).format(SERVICE_ONE_ID, SERVICE_ONE_ID) assert normalize_spaces(page.select_one('.banner-default').text) == (