diff --git a/app/main/forms.py b/app/main/forms.py index e4927ea06..7856b1bc5 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -12,7 +12,8 @@ from wtforms import ( FileField, BooleanField, HiddenField, - IntegerField) + IntegerField +) from wtforms.fields.html5 import EmailField, TelField from wtforms.validators import (DataRequired, Email, Length, Regexp) @@ -318,3 +319,13 @@ class ProviderForm(Form): class ServiceReplyToEmailFrom(Form): email_address = email_address() + + +class ServiceSmsSender(Form): + sms_sender = StringField('', validators=[Length(max=11, + message="Text message sender can't be longer than 11 characters")]) + + def validate_sms_sender(form, field): + import re + if not re.match('^[a-zA-Z0-9\s]+$', field.data): + raise ValidationError('Sms text message sender can only contain alpha-numeric characters') diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index b234f923c..889e901a1 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -23,7 +23,8 @@ from app.main.forms import ( ConfirmPasswordForm, ServiceNameForm, RequestToGoLiveForm, - ServiceReplyToEmailFrom + ServiceReplyToEmailFrom, + ServiceSmsSender ) from app import user_api_client from app import current_service @@ -261,3 +262,29 @@ def service_set_reply_to_email(service_id): return render_template( 'views/service-settings/set-reply-to-email.html', form=form) + + +@main.route("/services//service-settings/set-sms-sender", methods=['GET', 'POST']) +@login_required +@user_has_permissions('manage_settings', admin_override=True) +def service_set_sms_sender(service_id): + form = ServiceSmsSender() + if request.method == 'GET': + form.sms_sender.data = current_service.get('sms_sender') + if form.validate_on_submit(): + message = 'SMS Sender set to {}'.format(form.sms_sender.data) + service_api_client.update_service( + current_service['id'], + current_service['name'], + current_service['active'], + current_service['message_limit'], + current_service['restricted'], + current_service['users'], + current_service['email_from'], + current_service['reply_to_email_address'], + sms_sender=form.sms_sender.data if form.sms_sender.data else None) + flash(message, 'default_with_tick') + return redirect(url_for('.service_settings', service_id=service_id)) + return render_template( + 'views/service-settings/set-sms-sender.html', + form=form) diff --git a/app/notify_client/api_client.py b/app/notify_client/api_client.py index a2c3af94f..a4360098f 100644 --- a/app/notify_client/api_client.py +++ b/app/notify_client/api_client.py @@ -62,7 +62,8 @@ class ServiceAPIClient(NotificationsAPIClient): restricted, users, email_from, - reply_to_email_address=None): + reply_to_email_address=None, + sms_sender=None): """ Update a service. """ @@ -74,7 +75,8 @@ class ServiceAPIClient(NotificationsAPIClient): "restricted": restricted, "users": users, "email_from": email_from, - "reply_to_email_address": reply_to_email_address + "reply_to_email_address": reply_to_email_address, + "sms_sender": sms_sender } _attach_current_user(data) endpoint = "/service/{0}".format(service_id) diff --git a/app/templates/views/service-settings.html b/app/templates/views/service-settings.html index 44bf6bda8..ca7eb6ce5 100644 --- a/app/templates/views/service-settings.html +++ b/app/templates/views/service-settings.html @@ -18,6 +18,10 @@ 'title': 'Set email reply to address', 'link': url_for('.service_set_reply_to_email', service_id=current_service.id) }, + { + 'title': 'Set text message sender name', + 'link': url_for('.service_set_sms_sender', service_id=current_service.id) + }, { 'title': 'Request to go live and turn off trial mode', 'link': url_for('.service_request_to_go_live', service_id=current_service.id), diff --git a/app/templates/views/service-settings/set-sms-sender.html b/app/templates/views/service-settings/set-sms-sender.html new file mode 100644 index 000000000..e9c39a374 --- /dev/null +++ b/app/templates/views/service-settings/set-sms-sender.html @@ -0,0 +1,28 @@ +{% extends "withnav_template.html" %} +{% from "components/textbox.html" import textbox %} +{% from "components/page-footer.html" import page_footer %} + +{% block page_title %} + Set text message sender name – GOV.UK Notify +{% endblock %} + +{% block maincolumn_content %} + +
+
+

Set text message sender name

+
+ {{ textbox( + form.sms_sender, + width='1-1', + safe_error_message=True + ) }} + {{ page_footer( + 'Save', + back_link=url_for('.service_settings', service_id=current_service.id) + ) }} +
+
+
+ +{% endblock %} diff --git a/tests/app/main/test_validators.py b/tests/app/main/test_validators.py index aa308dba8..535936eab 100644 --- a/tests/app/main/test_validators.py +++ b/tests/app/main/test_validators.py @@ -1,5 +1,5 @@ import pytest -from app.main.forms import RegisterUserForm +from app.main.forms import RegisterUserForm, ServiceSmsSender from app.main.validators import ValidEmailDomainRegex, NoCommasInPlaceHolders from wtforms import ValidationError from unittest.mock import Mock @@ -121,3 +121,20 @@ def test_for_commas_in_placeholders(app_): NoCommasInPlaceHolders()(None, _gen_mock_field('Hello ((name,date))')) assert str(error.value) == 'You can’t have commas in your fields' NoCommasInPlaceHolders()(None, _gen_mock_field('Hello ((name))')) + + +def test_sms_sender_form_validation(app_, mock_get_user_by_email): + with app_.test_request_context(): + form = ServiceSmsSender() + + form.sms_sender.data = 'elevenchars' + form.validate() + assert not form.errors + + form.sms_sender.data = 'morethanelevenchars' + form.validate() + assert "Text message sender can't be longer than 11 characters" == form.errors['sms_sender'][0] + + form.sms_sender.data = '###########' + form.validate() + assert 'Sms text message sender can only contain alpha-numeric characters' == form.errors['sms_sender'][0] diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index 9965e2922..c06931a78 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -694,3 +694,44 @@ def test_does_not_show_research_mode_indicator( page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') element = page.find('span', {"id": "research-mode"}) assert not element + + +def test_set_text_message_sender( + app_, + active_user_with_permissions, + mocker, + mock_update_service, + service_one): + with app_.test_request_context(): + with app_.test_client() as client: + client.login(active_user_with_permissions, mocker, service_one) + data = {"sms_sender": "elevenchars"} + response = client.post(url_for('main.service_set_sms_sender', service_id=service_one['id']), + data=data, + follow_redirects=True) + assert response.status_code == 200 + + mock_update_service.assert_called_with(service_one['id'], + service_one['name'], + service_one['active'], + service_one['message_limit'], + service_one['restricted'], + service_one['users'], + service_one['email_from'], + service_one['reply_to_email_address'], + "elevenchars") + + +def test_if_sms_sender_set_then_form_populated(app_, + active_user_with_permissions, + mocker, + service_one): + service_one['sms_sender'] = 'elevenchars' + with app_.test_request_context(): + with app_.test_client() as client: + client.login(active_user_with_permissions, mocker, service_one) + response = client.get(url_for('main.service_set_sms_sender', service_id=service_one['id'])) + + assert response.status_code == 200 + page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') + assert page.find(id='sms_sender')['value'] == 'elevenchars' diff --git a/tests/conftest.py b/tests/conftest.py index 81a1632b4..6df582cc8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -100,7 +100,8 @@ def mock_update_service(mocker): restricted, users, email_from, - reply_to_email_address=None): + reply_to_email_address=None, + sms_sender=None): service = service_json( service_id, service_name, users, message_limit=message_limit, active=active, restricted=restricted, email_from=email_from, reply_to_email_address=reply_to_email_address)