diff --git a/app/__init__.py b/app/__init__.py index d4193822a..94d1b2657 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -27,7 +27,7 @@ from flask_wtf import CsrfProtect from functools import partial from notifications_python_client.errors import HTTPError -from notifications_utils import logging, request_id +from notifications_utils import logging, request_id, formatters from notifications_utils.clients.statsd.statsd_client import StatsdClient from notifications_utils.recipients import validate_phone_number, InvalidPhoneError from pygments import highlight @@ -134,6 +134,7 @@ def create_app(): application.add_template_filter(format_notification_status_as_field_status) application.add_template_filter(format_notification_status_as_url) application.add_template_filter(formatted_list) + application.add_template_filter(nl2br) application.after_request(useful_headers_after_request) application.after_request(save_service_after_request) @@ -375,6 +376,10 @@ def formatted_list( ).format(**locals()) +def nl2br(value): + return formatters.nl2br(value) if value else '' + + @login_manager.user_loader def load_user(user_id): return user_api_client.get_user(user_id) diff --git a/app/main/forms.py b/app/main/forms.py index ca271dc2b..3ba8894c2 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -486,10 +486,20 @@ class ServiceSmsSender(Form): ) def validate_sms_sender(form, field): - if field.data and not re.match('^[a-zA-Z0-9\s]+$', field.data): + if field.data and not re.match(r'^[a-zA-Z0-9\s]+$', field.data): raise ValidationError('Use letters and numbers only') +class ServiceLetterContactBlock(Form): + letter_contact_block = TextAreaField( + 'How should users contact you?' + ) + + def validate_letter_contact_block(form, field): + if field.data.strip().count('\n') >= 10: + raise ValidationError('Can only have 10 lines') + + class ServiceBrandingOrg(Form): def __init__(self, organisations=[], *args, **kwargs): diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 098bef06d..5c8f83ae3 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -25,6 +25,7 @@ from app.main.forms import ( RequestToGoLiveForm, ServiceReplyToEmailFrom, ServiceSmsSender, + ServiceLetterContactBlock, ServiceBrandingOrg ) from app import user_api_client, current_service, organisations_client @@ -236,6 +237,7 @@ def service_set_reply_to_email(service_id): reply_to_email_address=form.email_address.data ) return redirect(url_for('.service_settings', service_id=service_id)) + return render_template( 'views/service-settings/set-reply-to-email.html', form=form) @@ -259,6 +261,27 @@ def service_set_sms_sender(service_id): form=form) +@main.route("/services//service-settings/set-letter-contact-block", methods=['GET', 'POST']) +@login_required +@user_has_permissions('manage_settings', admin_override=True) +def service_set_letter_contact_block(service_id): + + if not current_service['can_send_letters']: + abort(403) + + form = ServiceLetterContactBlock(letter_contact_block=current_service['letter_contact_block']) + if form.validate_on_submit(): + service_api_client.update_service( + current_service['id'], + letter_contact_block=form.letter_contact_block.data.replace('\r', '') or None + ) + return redirect(url_for('.service_settings', service_id=service_id)) + return render_template( + 'views/service-settings/set-letter-contact-block.html', + form=form + ) + + @main.route("/services//service-settings/set-branding-and-org", methods=['GET', 'POST']) @login_required @user_has_permissions(admin_override=True) diff --git a/app/notify_client/service_api_client.py b/app/notify_client/service_api_client.py index 8ab6049ae..5f93f7ca0 100644 --- a/app/notify_client/service_api_client.py +++ b/app/notify_client/service_api_client.py @@ -90,7 +90,8 @@ class ServiceAPIClient(NotifyAdminAPIClient): 'sms_sender', 'created_by', 'branding', - 'organisation' + 'organisation', + 'letter_contact_block' } if disallowed_attributes: raise TypeError('Not allowed to update service attributes: {}'.format( diff --git a/app/templates/components/textbox.html b/app/templates/components/textbox.html index 450059b59..2c66c923e 100644 --- a/app/templates/components/textbox.html +++ b/app/templates/components/textbox.html @@ -30,7 +30,9 @@ {% endif %} {{ field(**{ - 'class': 'form-control form-control-{} textbox-highlight-textbox'.format(width) if highlight_tags else 'form-control form-control-{} {}'.format(width, 'textbox-right-aligned' if suffix else ''), + 'class': + 'form-control form-control-{} textbox-highlight-textbox'.format(width) if highlight_tags else + 'form-control form-control-{} {}'.format(width, 'textbox-right-aligned' if suffix else ''), 'data-module': 'highlight-tags' if highlight_tags else '', 'rows': rows|string }) }} diff --git a/app/templates/views/service-settings.html b/app/templates/views/service-settings.html index d45f3b4e7..22328e672 100644 --- a/app/templates/views/service-settings.html +++ b/app/templates/views/service-settings.html @@ -20,23 +20,35 @@ caption_visible=False ) %} {% call row() %} - {{ text_field('Service name' )}} + {{ text_field('Service name') }} {{ text_field(current_service.name) }} {{ edit_field('Change', url_for('.service_name_change', service_id=current_service.id)) }} {% endcall %} + {% call row() %} - {{ text_field('Email reply to address')}} + {{ text_field('Email reply to address') }} {{ text_field( current_service.reply_to_email_address, status='' if current_service.reply_to_email_address else 'default' ) }} {{ edit_field('Change', url_for('.service_set_reply_to_email', service_id=current_service.id)) }} {% endcall %} + {% call row() %} - {{ text_field('Text message sender')}} + {{ text_field('Text message sender') }} {{ text_field(current_service.sms_sender or '40604') }} {{ edit_field('Change', url_for('.service_set_sms_sender', service_id=current_service.id)) }} {% endcall %} + + {% if current_service.can_send_letters %} + {% call row() %} + {{ text_field('Letter contact details') }} + {% call field(status='' if current_service.letter_contact_block else 'default') %} + {{ current_service.letter_contact_block | escape | nl2br | safe }} + {% endcall %} + {{ edit_field('Change', url_for('.service_set_letter_contact_block', service_id=current_service.id)) }} + {% endcall %} + {% endif %} {% endcall %} diff --git a/app/templates/views/service-settings/set-letter-contact-block.html b/app/templates/views/service-settings/set-letter-contact-block.html new file mode 100644 index 000000000..7f9cbf1b0 --- /dev/null +++ b/app/templates/views/service-settings/set-letter-contact-block.html @@ -0,0 +1,27 @@ +{% extends "withnav_template.html" %} +{% from "components/textbox.html" import textbox %} +{% from "components/page-footer.html" import page_footer %} + +{% block service_page_title %} + Letter contact block +{% endblock %} + +{% block maincolumn_content %} + +

+ Letter contact details +

+
+ {{ textbox( + form.letter_contact_block, + width='1-1', + rows=10 + ) }} + {{ 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 816c1e702..2350fe553 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -56,7 +56,8 @@ def service_json( can_send_letters=False, organisation=None, branding='govuk', - created_at=None + created_at=None, + letter_contact_block=None ): if users is None: users = [] @@ -74,7 +75,8 @@ def service_json( 'can_send_letters': can_send_letters, 'organisation': organisation, 'branding': branding, - 'created_at': created_at or str(datetime.utcnow()) + 'created_at': created_at or str(datetime.utcnow()), + 'letter_contact_block': letter_contact_block } diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index b35c06fcd..f35eda093 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -49,6 +49,49 @@ def test_should_show_overview_for_service_with_more_things_set( assert row == " ".join(page.find_all('tr')[index + 1].text.split()) +def test_if_cant_send_letters_then_cant_see_letter_contact_block( + logged_in_client, + service_one, +): + response = logged_in_client.get(url_for( + 'main.service_settings', service_id=service_one['id'] + )) + assert 'Letter contact block' not in response.get_data(as_text=True) + + +def test_letter_contact_block_shows_None_if_not_set( + logged_in_client, + service_one, + mocker +): + service_one['can_send_letters'] = True + response = logged_in_client.get(url_for( + 'main.service_settings', service_id=service_one['id'] + )) + + page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') + div = page.find_all('tr')[4].find_all('td')[1].div + assert div.text.strip() == 'None' + assert 'default' in div.attrs['class'][0] + + +def test_escapes_letter_contact_block( + logged_in_client, + service_one, + mocker, +): + service_one['can_send_letters'] = True + service_one['letter_contact_block'] = 'foo\nbar' + response = logged_in_client.get(url_for( + 'main.service_settings', service_id=service_one['id'] + )) + + page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') + div = str(page.find_all('tr')[4].find_all('td')[1].div) + assert 'foo
bar' in div + assert '