diff --git a/app/main/__init__.py b/app/main/__init__.py index 29208e5cd..0521895d6 100644 --- a/app/main/__init__.py +++ b/app/main/__init__.py @@ -38,6 +38,7 @@ from app.main.views import ( # noqa isort:skip styleguide, templates, two_factor, + tour, uploads, user_profile, verify, diff --git a/app/main/views/templates.py b/app/main/views/templates.py index 232031f8f..8e6ddb164 100644 --- a/app/main/views/templates.py +++ b/app/main/views/templates.py @@ -100,6 +100,7 @@ def start_tour(service_id, template_id): show_recipient=True, ), help='1', + continue_link=url_for('.send_test', service_id=current_service.id, template_id=template['id'], help=2) ) diff --git a/app/main/views/tour.py b/app/main/views/tour.py new file mode 100644 index 000000000..98a8f5871 --- /dev/null +++ b/app/main/views/tour.py @@ -0,0 +1,38 @@ +from flask import abort, render_template + +from app import current_service, current_user, url_for +from app.main import main +from app.utils import get_template, user_has_permissions + + +@main.route("/services//tour/") +@user_has_permissions('send_messages') +def begin_tour(service_id, template_id): + db_template = current_service.get_template(template_id) + + if (db_template['template_type'] != 'sms' or not current_user.mobile_number): + abort(404) + + template = get_template( + db_template, + current_service, + show_recipient=True, + ) + + template.values = {"phone_number": current_user.mobile_number} + + return render_template( + 'views/templates/start-tour.html', + template=template, + help='1', + continue_link=url_for('.tour_step', service_id=service_id, template_id=template_id, step_index=1) + ) + + +@main.route( + "/services//tour//step-", + methods=['GET', 'POST'], +) +@user_has_permissions('send_messages', restrict_admin_usage=True) +def tour_step(service_id, template_id, step_index): + pass diff --git a/app/navigation.py b/app/navigation.py index 671320c9b..282c0ba5f 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -140,6 +140,7 @@ class HeaderNavigation(Navigation): 'api_integration', 'api_keys', 'archive_service', + 'begin_tour', 'branding_request', 'callbacks', 'cancel_invited_org_user', @@ -325,6 +326,7 @@ class HeaderNavigation(Navigation): 'submit_request_to_go_live', 'template_history', 'template_usage', + 'tour_step', 'trial_mode', 'upload_contact_list', 'check_contact_list', @@ -527,6 +529,7 @@ class MainNavigation(Navigation): 'archive_service', 'archive_user', 'bat_phone', + 'begin_tour', 'callbacks', 'cancel_invited_org_user', 'cancel_invited_user', @@ -668,6 +671,7 @@ class MainNavigation(Navigation): 'template_history', 'terms', 'thanks', + 'tour_step', 'triage', 'trial_mode', 'trial_mode_new', @@ -762,6 +766,7 @@ class CaseworkNavigation(Navigation): 'archive_service', 'archive_user', 'bat_phone', + 'begin_tour', 'branding_request', 'callbacks', 'cancel_invited_org_user', @@ -980,6 +985,7 @@ class CaseworkNavigation(Navigation): 'template_usage', 'terms', 'thanks', + 'tour_step', 'triage', 'trial_mode', 'trial_mode_new', @@ -1088,6 +1094,7 @@ class OrgNavigation(Navigation): 'archive_service', 'archive_user', 'bat_phone', + 'begin_tour', 'branding_request', 'callbacks', 'cancel_invited_org_user', @@ -1292,6 +1299,7 @@ class OrgNavigation(Navigation): 'template_usage', 'terms', 'thanks', + 'tour_step', 'triage', 'trial_mode', 'trial_mode_new', diff --git a/app/templates/views/templates/start-tour.html b/app/templates/views/templates/start-tour.html index 432312527..ba6225f45 100644 --- a/app/templates/views/templates/start-tour.html +++ b/app/templates/views/templates/start-tour.html @@ -17,7 +17,7 @@ {{ govukButton({ "element": "a", "text": "Continue", - "href": url_for('.send_test', service_id=current_service.id, template_id=template.id, help=2), + "href": continue_link, }) }} diff --git a/tests/app/main/views/test_tour.py b/tests/app/main/views/test_tour.py new file mode 100644 index 000000000..6a9decc81 --- /dev/null +++ b/tests/app/main/views/test_tour.py @@ -0,0 +1,105 @@ +import pytest +from flask import url_for + +from app import current_user +from tests import validate_route_permission +from tests.conftest import SERVICE_ONE_ID, create_template, normalize_spaces + + +def test_should_200_for_tour_start( + client_request, + mock_get_service_template_with_multiple_placeholders, + service_one, + fake_uuid, +): + page = client_request.get( + 'main.begin_tour', + service_id=SERVICE_ONE_ID, + template_id=fake_uuid, + ) + + assert normalize_spaces( + page.select('.banner-tour .heading-medium')[0].text + ) == ( + 'Try sending yourself this example' + ) + selected_hint = page.select('.banner-tour .govuk-grid-row')[0] + selected_hint_text = normalize_spaces(selected_hint.select(".govuk-body")[0].text) + assert "greyed-out-step" not in selected_hint["class"] + assert selected_hint_text == 'Every message is sent from a template' + + assert normalize_spaces( + page.select('.sms-message-recipient')[0].text + ) == ( + 'To: 07700 900762' + ) + assert normalize_spaces( + page.select('.sms-message-wrapper')[0].text + ) == ( + 'service one: ((one)) ((two)) ((three))' + ) + + assert page.select('a.govuk-button')[0]['href'] == url_for( + '.tour_step', service_id=SERVICE_ONE_ID, template_id=fake_uuid, step_index=1 + ) + + +@pytest.mark.parametrize('template_type', ['email', 'letter', 'broadcast']) +def test_should_404_if_non_sms_template_for_tour_start( + client_request, + fake_uuid, + mocker, + template_type, +): + mocker.patch( + 'app.service_api_client.get_service_template', + return_value={'data': create_template(template_type=template_type)} + ) + + client_request.get( + 'main.begin_tour', + service_id=SERVICE_ONE_ID, + template_id=fake_uuid, + _expected_status=404, + ) + + +def test_should_404_if_no_mobile_number_for_tour_start( + client_request, + mock_get_service_template_with_multiple_placeholders, + service_one, + fake_uuid, + active_user_with_permissions_no_mobile +): + client_request.login(active_user_with_permissions_no_mobile) + assert current_user.mobile_number is None + client_request.get( + 'main.begin_tour', + service_id=SERVICE_ONE_ID, + template_id=fake_uuid, + _expected_status=404, + ) + + +def test_should_403_if_user_does_not_have_send_permissions_for_tour_start( + mocker, + app_, + client, + api_user_active, + mock_get_service_template_with_multiple_placeholders, + service_one, + fake_uuid, +): + validate_route_permission( + mocker, + app_, + "GET", + 403, + url_for( + 'main.begin_tour', + service_id=SERVICE_ONE_ID, + template_id=fake_uuid, + ), + ['view_activity'], + api_user_active, + service_one) diff --git a/tests/conftest.py b/tests/conftest.py index 40b1f22b2..9015c7cf0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1169,6 +1169,33 @@ def api_user_active_email_auth(fake_uuid): return user_data +@pytest.fixture(scope='function') +def active_user_with_permissions_no_mobile(fake_uuid): + user_data = {'id': fake_uuid, + 'name': 'Test User', + 'password': 'somepassword', + 'password_changed_at': str(datetime.utcnow()), + 'email_address': 'test@user.gov.uk', + 'mobile_number': None, + 'state': 'active', + 'failed_login_count': 0, + 'permissions': {SERVICE_ONE_ID: ['send_texts', + 'send_emails', + 'send_letters', + 'manage_users', + 'manage_templates', + 'manage_settings', + 'manage_api_keys', + 'view_activity']}, + 'platform_admin': False, + 'auth_type': 'email_auth', + 'organisations': [ORGANISATION_ID], + 'services': [SERVICE_ONE_ID], + 'current_session_id': None, + } + return user_data + + @pytest.fixture(scope='function') def api_nongov_user_active(fake_uuid): user_data = {