From e1d4181be3bd1eba9b89dcb0a3035f12693a3f37 Mon Sep 17 00:00:00 2001 From: Katie Smith Date: Tue, 5 Jun 2018 10:37:41 +0100 Subject: [PATCH] Add page to change a service's contact link Added a page which lets users with the 'manage_service' permission change the contact link for their service. There are no links to this page yet since only services using document download will need to set a contact link. --- app/main/forms.py | 10 ++- app/main/views/service_settings.py | 20 ++++++ app/navigation.py | 3 + app/notify_client/service_api_client.py | 1 + .../views/service-settings/contact_link.html | 28 +++++++++ tests/__init__.py | 1 + tests/app/main/views/test_service_settings.py | 63 +++++++++++++++++++ 7 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 app/templates/views/service-settings/contact_link.html diff --git a/app/main/forms.py b/app/main/forms.py index cffa5e513..d88fdba51 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -28,7 +28,7 @@ from wtforms import ( widgets, ) from wtforms.fields.html5 import EmailField, SearchField, TelField -from wtforms.validators import DataRequired, Length, Optional, Regexp +from wtforms.validators import URL, DataRequired, Length, Optional, Regexp from app.main.validators import ( Blacklist, @@ -572,6 +572,14 @@ class ProviderForm(StripWhitespaceForm): priority = IntegerField('Priority', [validators.NumberRange(min=1, max=100, message="Must be between 1 and 100")]) +class ServiceContactLinkForm(StripWhitespaceForm): + url = StringField( + "URL", + validators=[DataRequired(message='Can’t be empty'), + URL(message='Must be a valid URL')] + ) + + class ServiceReplyToEmailForm(StripWhitespaceForm): email_address = email_address(label='Email reply to address', gov_user=False) is_default = BooleanField("Make this email address the default") diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index d74898004..e45979324 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -34,6 +34,7 @@ from app.main.forms import ( OrganisationTypeForm, RenameServiceForm, RequestToGoLiveForm, + ServiceContactLinkForm, ServiceEditInboundNumberForm, ServiceInboundNumberForm, ServiceLetterContactBlockForm, @@ -366,6 +367,25 @@ def resume_service(service_id): return service_settings(service_id) +@main.route("/services//service-settings/contact-link", methods=['GET', 'POST']) +@login_required +@user_has_permissions('manage_service') +def service_set_contact_link(service_id): + form = ServiceContactLinkForm() + + if request.method == 'GET': + form.url.data = current_service.get('contact_link') + + if form.validate_on_submit(): + service_api_client.update_service( + current_service['id'], + contact_link=form.url.data + ) + return redirect(url_for('.service_settings', service_id=current_service['id'])) + + return render_template('views/service-settings/contact_link.html', form=form) + + @main.route("/services//service-settings/set-email", methods=['GET']) @login_required @user_has_permissions('manage_service') diff --git a/app/navigation.py b/app/navigation.py index 7f223265d..2725f50ca 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -211,6 +211,7 @@ class HeaderNavigation(Navigation): 'service_name_change', 'service_name_change_confirm', 'service_set_auth_type', + 'service_set_contact_link', 'service_set_email', 'service_set_email_branding', 'service_set_inbound_number', @@ -328,6 +329,7 @@ class MainNavigation(Navigation): 'service_name_change', 'service_name_change_confirm', 'service_set_auth_type', + 'service_set_contact_link', 'service_set_email', 'service_set_email_branding', 'service_set_inbound_number', @@ -631,6 +633,7 @@ class OrgNavigation(Navigation): 'service_name_change', 'service_name_change_confirm', 'service_set_auth_type', + 'service_set_contact_link', 'service_set_email', 'service_set_email_branding', 'service_set_inbound_number', diff --git a/app/notify_client/service_api_client.py b/app/notify_client/service_api_client.py index 454d05d2f..af8a2481a 100644 --- a/app/notify_client/service_api_client.py +++ b/app/notify_client/service_api_client.py @@ -85,6 +85,7 @@ class ServiceAPIClient(NotifyAdminAPIClient): 'organisation_type', 'free_sms_fragment_limit', 'prefix_sms', + 'contact_link', } if disallowed_attributes: raise TypeError('Not allowed to update service attributes: {}'.format( diff --git a/app/templates/views/service-settings/contact_link.html b/app/templates/views/service-settings/contact_link.html new file mode 100644 index 000000000..4b3bdb5c2 --- /dev/null +++ b/app/templates/views/service-settings/contact_link.html @@ -0,0 +1,28 @@ +{% extends "withnav_template.html" %} +{% from "components/textbox.html" import textbox %} +{% from "components/page-footer.html" import page_footer %} + +{% block service_page_title %} + Change link on ‘Download your document’ page +{% endblock %} + +{% block maincolumn_content %} +
+
+

Change link on ‘Download your document’ page

+

+ When you send users a document to download, you need to include a link to your service + on the download page. This is so users can contact you if there’s a problem (for example, + if the link to download the document has expired). +

+
+ {{ textbox(form.url, width='1-1') }} + {{ page_footer( + 'Save', + back_link=url_for('.service_settings', service_id=current_service.id), + back_link_text='Back to settings' + ) }} +
+
+
+{% endblock %} diff --git a/tests/__init__.py b/tests/__init__.py index 0885c92ad..e54aa66b2 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -145,6 +145,7 @@ def service_json( permissions=None, organisation_type='central', prefix_sms=True, + contact_link=None, ): if users is None: users = [] diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index 0ce3b0c1d..012b27207 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -2141,6 +2141,69 @@ def test_cant_resume_active_service( assert 'Resume service' not in {a.text for a in page.find_all('a', class_='button')} +def test_service_set_contact_link_displays_the_contact_link(client_request, service_one): + service_one['contact_link'] = 'http://example.com/' + + page = client_request.get( + 'main.service_set_contact_link', service_id=SERVICE_ONE_ID + ) + assert page.find('input').get('value') == 'http://example.com/' + + +def test_service_set_contact_link_updates_contact_link_and_redirects_to_settings_page( + client_request, + service_one, + mock_update_service, + mock_get_service_settings_page_common, + mock_get_service_organisation, + no_reply_to_email_addresses, + no_letter_contact_blocks, + single_sms_sender, +): + service_one['contact_link'] = 'http://example.com/' + + page = client_request.post( + 'main.service_set_contact_link', service_id=SERVICE_ONE_ID, + _data={ + 'url': 'http://new-link.com/', + }, + _follow_redirects=True + ) + + assert page.h1.text == 'Settings' + mock_update_service.assert_called_once_with( + SERVICE_ONE_ID, + contact_link='http://new-link.com/', + ) + + +@pytest.mark.parametrize('new_link', ['', 'not/a-valid/link']) +def test_service_set_contact_link_does_not_update_invalid_link( + mocker, + client_request, + service_one, + mock_get_service_settings_page_common, + mock_get_service_organisation, + no_reply_to_email_addresses, + no_letter_contact_blocks, + single_sms_sender, + new_link, +): + update_mock = mocker.patch('app.service_api_client.update_service') + service_one['contact_link'] = 'http://example.com/' + + page = client_request.post( + 'main.service_set_contact_link', service_id=SERVICE_ONE_ID, + _data={ + 'url': new_link, + }, + _follow_redirects=True + ) + + assert page.h1.text == "Change link on ‘Download your document’ page" + update_mock.assert_not_called() + + @pytest.mark.parametrize('endpoint, permissions, expected_p', [ ( 'main.service_set_inbound_sms',