mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-26 13:20:54 -05:00
Merge pull request #1277 from alphagov/send-test-page-per-thing
Show one field at a time on send yourself a test
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
$(() => $("time.timeago").timeago());
|
||||
|
||||
$(() => GOVUK.stickAtTopWhenScrolling.init());
|
||||
|
||||
$(() => GOVUK.modules.start());
|
||||
|
||||
$(() => $('.error-message').eq(0).parent('label').next('input').trigger('focus'));
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// CSS adapted from
|
||||
// https://github.com/alphagov/govuk_frontend_toolkit/blob/d9489a987086471fe30b4b925a81c12cd198c91d/docs/javascript.md#stick-at-top-when-scrolling
|
||||
|
||||
.js-stick-at-top-when-scrolling {
|
||||
|
||||
overflow: hidden;
|
||||
margin-left: -$gutter-half;
|
||||
margin-top: -10px;
|
||||
padding: 10px 0 0 $gutter-half;
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.content-fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
background: $white;
|
||||
z-index: 100;
|
||||
margin-top: 0;
|
||||
padding-right: $gutter-half;
|
||||
border-bottom: 1px solid $border-colour;
|
||||
box-shadow: 0 2px 0 0 rgba($border-colour, 0.2);
|
||||
}
|
||||
|
||||
.shim {
|
||||
display: block;
|
||||
}
|
||||
@@ -57,6 +57,7 @@ $path: '/static/images/';
|
||||
@import 'components/list-entry';
|
||||
@import 'components/letter';
|
||||
@import 'components/live-search';
|
||||
@import 'components/stick-at-top-when-scrolling';
|
||||
@import 'components/vendor/breadcrumbs';
|
||||
@import 'components/vendor/responsive-embed';
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import re
|
||||
|
||||
import pytz
|
||||
from flask_login import current_user
|
||||
|
||||
from flask_wtf import Form
|
||||
from datetime import datetime, timedelta
|
||||
from notifications_utils.recipients import (
|
||||
@@ -619,3 +618,26 @@ class ChooseTemplateType(Form):
|
||||
class SearchTemplatesForm(Form):
|
||||
|
||||
search = SearchField('Search by name')
|
||||
|
||||
|
||||
class PlaceholderForm(Form):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def get_placeholder_form_instance(
|
||||
placeholder_name,
|
||||
dict_to_populate_from,
|
||||
optional_placeholder=False
|
||||
):
|
||||
|
||||
PlaceholderForm.placeholder_value = StringField(
|
||||
placeholder_name,
|
||||
validators=[
|
||||
DataRequired(message='Can’t be empty')
|
||||
] if not optional_placeholder else []
|
||||
)
|
||||
|
||||
return PlaceholderForm(
|
||||
placeholder_value=dict_to_populate_from.get(placeholder_name, '')
|
||||
)
|
||||
|
||||
@@ -21,10 +21,20 @@ from flask import (
|
||||
from flask_login import login_required, current_user
|
||||
|
||||
from notifications_utils.columns import Columns
|
||||
from notifications_utils.recipients import RecipientCSV, first_column_headings, validate_and_format_phone_number
|
||||
from notifications_utils.recipients import (
|
||||
RecipientCSV,
|
||||
first_column_headings,
|
||||
validate_and_format_phone_number,
|
||||
optional_address_columns,
|
||||
)
|
||||
|
||||
from app.main import main
|
||||
from app.main.forms import CsvUploadForm, ChooseTimeForm, get_furthest_possible_scheduled_time
|
||||
from app.main.forms import (
|
||||
CsvUploadForm,
|
||||
ChooseTimeForm,
|
||||
get_furthest_possible_scheduled_time,
|
||||
get_placeholder_form_instance
|
||||
)
|
||||
from app.main.uploader import (
|
||||
s3upload,
|
||||
s3download
|
||||
@@ -147,63 +157,141 @@ def get_example_csv(service_id, template_id):
|
||||
}
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/send/<template_id>/test", methods=['GET', 'POST'])
|
||||
@main.route("/services/<service_id>/send/<template_id>/test")
|
||||
@login_required
|
||||
@user_has_permissions('send_texts', 'send_emails', 'send_letters')
|
||||
def send_test(service_id, template_id):
|
||||
session['send_test_values'] = dict()
|
||||
session['send_test_letter_page_count'] = None
|
||||
return redirect(url_for(
|
||||
'.send_test_step',
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
step_index=0,
|
||||
help=get_help_argument(),
|
||||
))
|
||||
|
||||
file_name = current_app.config['TEST_MESSAGE_FILENAME']
|
||||
|
||||
@main.route("/services/<service_id>/send/<template_id>/test/step-<int:step_index>", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
@user_has_permissions('send_texts', 'send_emails', 'send_letters')
|
||||
def send_test_step(service_id, template_id, step_index):
|
||||
|
||||
if 'send_test_values' not in session:
|
||||
return redirect(url_for(
|
||||
'.send_test', service_id=service_id, template_id=template_id
|
||||
))
|
||||
|
||||
template = service_api_client.get_service_template(service_id, template_id)['data']
|
||||
|
||||
if not session.get('send_test_letter_page_count'):
|
||||
session['send_test_letter_page_count'] = get_page_count_for_letter(template)
|
||||
|
||||
template = get_template(
|
||||
template,
|
||||
current_service,
|
||||
show_recipient=True,
|
||||
expand_emails=True,
|
||||
letter_preview_url=url_for(
|
||||
'.view_letter_template_preview',
|
||||
'.send_test_preview',
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
filetype='png',
|
||||
page_count=get_page_count_for_letter(template),
|
||||
),
|
||||
page_count=session['send_test_letter_page_count']
|
||||
)
|
||||
|
||||
if len(template.placeholders) == 0 or request.method == 'POST':
|
||||
upload_id = s3upload(
|
||||
service_id,
|
||||
{
|
||||
'file_name': file_name,
|
||||
'data': Spreadsheet.from_rows([
|
||||
first_column_headings[template.template_type] + list(template.placeholders),
|
||||
get_example_csv_rows(template, use_example_as_example=False, submitted_fields=request.form)
|
||||
]).as_csv_data
|
||||
},
|
||||
current_app.config['AWS_REGION']
|
||||
)
|
||||
session['upload_data'] = {
|
||||
"template_id": template_id,
|
||||
"original_file_name": file_name
|
||||
}
|
||||
placeholders = fields_to_fill_in(template)
|
||||
|
||||
if len(placeholders) == 0:
|
||||
return make_and_upload_csv_file(service_id, template)
|
||||
|
||||
try:
|
||||
current_placeholder = placeholders[step_index]
|
||||
except IndexError:
|
||||
return redirect(url_for(
|
||||
'.check_messages',
|
||||
upload_id=upload_id,
|
||||
service_id=service_id,
|
||||
template_type=template.template_type,
|
||||
from_test=True,
|
||||
help=2 if request.args.get('help') else 0
|
||||
'.send_test', service_id=service_id, template_id=template_id
|
||||
))
|
||||
optional_placeholder = (current_placeholder in optional_address_columns)
|
||||
form = get_placeholder_form_instance(
|
||||
current_placeholder,
|
||||
dict_to_populate_from=get_normalised_send_test_values_from_session(),
|
||||
optional_placeholder=optional_placeholder,
|
||||
)
|
||||
|
||||
if form.validate_on_submit():
|
||||
|
||||
session['send_test_values'][current_placeholder] = form.placeholder_value.data
|
||||
|
||||
if all(
|
||||
get_normalised_send_test_values_from_session().get(placeholder, False) not in (False, None)
|
||||
for placeholder in placeholders
|
||||
):
|
||||
return make_and_upload_csv_file(service_id, template)
|
||||
|
||||
return redirect(url_for(
|
||||
'.send_test_step',
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
step_index=step_index + 1,
|
||||
help=get_help_argument(),
|
||||
))
|
||||
|
||||
if get_help_argument():
|
||||
back_link = None
|
||||
elif step_index == 0:
|
||||
back_link = url_for(
|
||||
'.view_template',
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
)
|
||||
else:
|
||||
back_link = url_for(
|
||||
'.send_test_step',
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
step_index=step_index - 1,
|
||||
)
|
||||
|
||||
template.values = get_normalised_send_test_values_from_session()
|
||||
template.values[current_placeholder] = None
|
||||
|
||||
return render_template(
|
||||
'views/send-test.html',
|
||||
template=template,
|
||||
recipient_columns=first_column_headings[template.template_type],
|
||||
example=[get_example_csv_rows(template, use_example_as_example=False)],
|
||||
help=get_help_argument()
|
||||
form=form,
|
||||
optional_placeholder=optional_placeholder,
|
||||
help=get_help_argument(),
|
||||
back_link=back_link,
|
||||
)
|
||||
|
||||
|
||||
@main.route("/services/<service_id>/send/<template_id>/test.<filetype>", methods=['GET'])
|
||||
@login_required
|
||||
@user_has_permissions('send_texts', 'send_emails', 'send_letters')
|
||||
def send_test_preview(service_id, template_id, filetype):
|
||||
|
||||
if filetype not in ('pdf', 'png'):
|
||||
abort(404)
|
||||
|
||||
template = service_api_client.get_service_template(service_id, template_id)['data']
|
||||
|
||||
template = get_template(
|
||||
template,
|
||||
current_service,
|
||||
letter_preview_url=url_for(
|
||||
'.send_test_preview',
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
filetype='png',
|
||||
),
|
||||
)
|
||||
|
||||
template.values = get_normalised_send_test_values_from_session()
|
||||
|
||||
return TemplatePreview.from_utils_template(template, filetype, page=request.args.get('page'))
|
||||
|
||||
|
||||
def _check_messages(service_id, template_type, upload_id, letters_as_pdf=False):
|
||||
|
||||
if not session.get('upload_data'):
|
||||
@@ -380,3 +468,48 @@ def get_check_messages_back_url(service_id, template_type):
|
||||
return url_for('.send_test', service_id=service_id, template_id=templates[0]['id'], help=1)
|
||||
|
||||
return url_for('main.choose_template', service_id=service_id)
|
||||
|
||||
|
||||
def fields_to_fill_in(template):
|
||||
|
||||
recipient_columns = first_column_headings[template.template_type]
|
||||
|
||||
if 'letter' == template.template_type:
|
||||
return recipient_columns + list(template.placeholders)
|
||||
|
||||
session['send_test_values'][recipient_columns[0]] = {
|
||||
'email': current_user.email_address,
|
||||
'sms': current_user.mobile_number,
|
||||
}.get(template.template_type)
|
||||
|
||||
return list(template.placeholders)
|
||||
|
||||
|
||||
def get_normalised_send_test_values_from_session():
|
||||
return {
|
||||
key: ''.join(value or [])
|
||||
for key, value in session.get('send_test_values', {}).items()
|
||||
}
|
||||
|
||||
|
||||
def make_and_upload_csv_file(service_id, template):
|
||||
upload_id = s3upload(
|
||||
service_id,
|
||||
Spreadsheet.from_dict(
|
||||
session['send_test_values'],
|
||||
filename=current_app.config['TEST_MESSAGE_FILENAME']
|
||||
).as_dict,
|
||||
current_app.config['AWS_REGION'],
|
||||
)
|
||||
session['upload_data'] = {
|
||||
"template_id": template.id,
|
||||
"original_file_name": current_app.config['TEST_MESSAGE_FILENAME']
|
||||
}
|
||||
return redirect(url_for(
|
||||
'.check_messages',
|
||||
upload_id=upload_id,
|
||||
service_id=service_id,
|
||||
template_type=template.template_type,
|
||||
from_test=True,
|
||||
help=2 if get_help_argument() else 0
|
||||
))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{% extends "withnav_template.html" %}
|
||||
{% from "components/page-footer.html" import page_footer %}
|
||||
{% from "components/file-upload.html" import file_upload %}
|
||||
{% from "components/textbox.html" import textbox %}
|
||||
{% from "components/table.html" import list_table, field, text_field, index_field, index_field_heading %}
|
||||
|
||||
{% block service_page_title %}
|
||||
@@ -25,29 +26,14 @@
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
{{ template|string }}
|
||||
|
||||
<form method="post">
|
||||
{% call(item, row_number) list_table(
|
||||
example,
|
||||
caption="Fill in the {}".format('field' if (recipient_columns + template.placeholders|list)|length == 2 else 'fields'),
|
||||
field_headings=recipient_columns + template.placeholders|list
|
||||
) %}
|
||||
{% for column in item %}
|
||||
{% call field() %}
|
||||
{% if loop.index > 1 or template.template_type == 'letter' %}
|
||||
<label class="visuallyhidden" for="placeholder-field-{{ loop.index }}">{{ column }}</label>
|
||||
<input class="form-control form-control-1-1 " data-module="" name="{{ column }}" rows="8" type="text" value="" id="placeholder-field-{{ loop.index }}">
|
||||
{% else %}
|
||||
{{ column }}
|
||||
{% endif %}
|
||||
{% endcall %}
|
||||
{% endfor %}
|
||||
{% endcall %}
|
||||
|
||||
{{ page_footer("Preview", back_link=(
|
||||
url_for('.send_messages', service_id=current_service.id, template_id=template.id)) if not help else None
|
||||
<form method="post" class="js-stick-at-top-when-scrolling" data-module="autofocus">
|
||||
{{ textbox(
|
||||
form.placeholder_value,
|
||||
hint='Optional' if optional_placeholder else None
|
||||
) }}
|
||||
{{ page_footer('Next', back_link=back_link) }}
|
||||
</form>
|
||||
|
||||
{{ template|string }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -223,6 +223,15 @@ class Spreadsheet():
|
||||
output.writerow(row)
|
||||
return cls(converted.getvalue(), filename)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, dictionary, filename=''):
|
||||
return cls.from_rows(
|
||||
zip(
|
||||
*sorted(dictionary.items(), key=lambda pair: pair[0])
|
||||
),
|
||||
filename
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, file_content, filename=''):
|
||||
extension = cls.get_extension(filename)
|
||||
|
||||
@@ -54,6 +54,8 @@ gulp.task('copy:govuk_template:images', () => gulp.src(paths.template + 'assets/
|
||||
gulp.task('javascripts', () => gulp
|
||||
.src([
|
||||
paths.toolkit + 'javascripts/govuk/modules.js',
|
||||
paths.toolkit + 'javascripts/govuk/stop-scrolling-at-footer.js',
|
||||
paths.toolkit + 'javascripts/govuk/stick-at-top-when-scrolling.js',
|
||||
paths.src + 'javascripts/detailsPolyfill.js',
|
||||
paths.src + 'javascripts/apiKey.js',
|
||||
paths.src + 'javascripts/autofocus.js',
|
||||
|
||||
18
tests/app/main/test_placeholder_form.py
Normal file
18
tests/app/main/test_placeholder_form.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from app.main.forms import get_placeholder_form_instance
|
||||
from wtforms import Label
|
||||
|
||||
|
||||
def test_form_class_not_mutated(app_):
|
||||
|
||||
with app_.test_request_context(
|
||||
method='POST',
|
||||
data={'placeholder_value': ''}
|
||||
) as req:
|
||||
form1 = get_placeholder_form_instance('name', {}, optional_placeholder=False)
|
||||
form2 = get_placeholder_form_instance('city', {}, optional_placeholder=True)
|
||||
|
||||
assert not form1.validate_on_submit()
|
||||
assert form2.validate_on_submit()
|
||||
|
||||
assert str(form1.placeholder_value.label) == '<label for="placeholder_value">name</label>'
|
||||
assert str(form2.placeholder_value.label) == '<label for="placeholder_value">city</label>'
|
||||
@@ -8,7 +8,7 @@ from functools import partial
|
||||
import pytest
|
||||
from bs4 import BeautifulSoup
|
||||
from flask import url_for
|
||||
from notifications_utils.template import LetterPreviewTemplate
|
||||
from notifications_utils.template import LetterPreviewTemplate, LetterImageTemplate
|
||||
from notifications_utils.recipients import RecipientCSV
|
||||
|
||||
from app.main.views.send import get_check_messages_back_url
|
||||
@@ -21,6 +21,8 @@ from tests.conftest import (
|
||||
mock_get_service_letter_template,
|
||||
mock_get_service,
|
||||
mock_get_international_service,
|
||||
mock_get_service_template,
|
||||
mock_get_service_email_template,
|
||||
)
|
||||
|
||||
template_types = ['email', 'sms']
|
||||
@@ -48,19 +50,16 @@ def test_upload_files_in_different_formats(
|
||||
filename,
|
||||
acceptable_file,
|
||||
logged_in_client,
|
||||
api_user_active,
|
||||
service_one,
|
||||
mocker,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_template,
|
||||
mock_s3_upload,
|
||||
mock_has_permissions,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
with open(filename, 'rb') as uploaded:
|
||||
response = logged_in_client.post(
|
||||
url_for('main.send_messages', service_id=fake_uuid, template_id=fake_uuid),
|
||||
url_for('main.send_messages', service_id=service_one['id'], template_id=fake_uuid),
|
||||
data={'file': (BytesIO(uploaded.read()), filename)},
|
||||
content_type='multipart/form-data'
|
||||
)
|
||||
@@ -81,13 +80,10 @@ def test_upload_files_in_different_formats(
|
||||
|
||||
def test_upload_csvfile_with_errors_shows_check_page_with_errors(
|
||||
logged_in_client,
|
||||
api_user_active,
|
||||
service_one,
|
||||
mocker,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_template_with_placeholders,
|
||||
mock_s3_upload,
|
||||
mock_has_permissions,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid,
|
||||
@@ -103,13 +99,13 @@ def test_upload_csvfile_with_errors_shows_check_page_with_errors(
|
||||
)
|
||||
|
||||
initial_upload = logged_in_client.post(
|
||||
url_for('main.send_messages', service_id=fake_uuid, template_id=fake_uuid),
|
||||
url_for('main.send_messages', service_id=service_one['id'], template_id=fake_uuid),
|
||||
data={'file': (BytesIO(''.encode('utf-8')), 'invalid.csv')},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
)
|
||||
reupload = logged_in_client.post(
|
||||
url_for('main.check_messages', service_id=fake_uuid, template_type='sms', upload_id='abc123'),
|
||||
url_for('main.check_messages', service_id=service_one['id'], template_type='sms', upload_id='abc123'),
|
||||
data={'file': (BytesIO(''.encode('utf-8')), 'invalid.csv')},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
@@ -191,20 +187,14 @@ def test_upload_csvfile_with_missing_columns_shows_error(
|
||||
|
||||
def test_upload_csv_invalid_extension(
|
||||
logged_in_client,
|
||||
api_user_active,
|
||||
mocker,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
service_one,
|
||||
mock_get_service_template,
|
||||
mock_s3_upload,
|
||||
mock_has_permissions,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
resp = logged_in_client.post(
|
||||
url_for('main.send_messages', service_id=fake_uuid, template_id=fake_uuid),
|
||||
url_for('main.send_messages', service_id=service_one['id'], template_id=fake_uuid),
|
||||
data={'file': (BytesIO('contents'.encode('utf-8')), 'invalid.txt')},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
@@ -284,7 +274,7 @@ def test_upload_valid_csv_shows_file_contents(
|
||||
def test_send_test_doesnt_show_file_contents(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
mock_get_service_template_with_placeholders,
|
||||
mock_get_service_template,
|
||||
mock_s3_upload,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
@@ -293,13 +283,12 @@ def test_send_test_doesnt_show_file_contents(
|
||||
):
|
||||
|
||||
mocker.patch('app.main.views.send.s3download', return_value="""
|
||||
phone number,name,thing,thing,thing
|
||||
07700900986, Jo, foo, foo, foo
|
||||
phone number
|
||||
07700 900 986
|
||||
""")
|
||||
|
||||
response = logged_in_client.post(
|
||||
response = logged_in_client.get(
|
||||
url_for('main.send_test', service_id=service_one['id'], template_id=fake_uuid),
|
||||
data={},
|
||||
follow_redirects=True,
|
||||
)
|
||||
|
||||
@@ -313,85 +302,465 @@ def test_send_test_doesnt_show_file_contents(
|
||||
|
||||
def test_send_test_sms_message(
|
||||
logged_in_client,
|
||||
service_one,
|
||||
fake_uuid,
|
||||
mocker,
|
||||
api_user_active,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_template,
|
||||
mock_s3_upload,
|
||||
mock_has_permissions,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid
|
||||
):
|
||||
|
||||
expected_data = {'data': 'phone number\r\n07700 900762\r\n', 'file_name': 'Test message'}
|
||||
mocker.patch('app.main.views.send.s3download', return_value='phone number\r\n+4412341234')
|
||||
|
||||
response = logged_in_client.get(
|
||||
url_for('main.send_test', service_id=fake_uuid, template_id=fake_uuid),
|
||||
url_for('main.send_test', service_id=service_one['id'], template_id=fake_uuid),
|
||||
follow_redirects=True
|
||||
)
|
||||
assert response.status_code == 200
|
||||
mock_s3_upload.assert_called_with(fake_uuid, expected_data, 'eu-west-1')
|
||||
mock_s3_upload.assert_called_with(service_one['id'], expected_data, 'eu-west-1')
|
||||
|
||||
|
||||
def test_send_test_email_message(
|
||||
def test_send_test_step_redirects_if_session_not_setup(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
api_user_active,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_email_template_without_placeholders,
|
||||
service_one,
|
||||
fake_uuid,
|
||||
mock_get_service_email_template,
|
||||
):
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
assert 'send_test_values' not in session
|
||||
|
||||
response = logged_in_client.get(
|
||||
url_for('main.send_test_step', service_id=service_one['id'], template_id=fake_uuid, step_index=0),
|
||||
follow_redirects=True
|
||||
)
|
||||
assert response.status_code == 200
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
assert session['send_test_values'] == {'email address': 'test@user.gov.uk'}
|
||||
|
||||
|
||||
def test_send_test_redirects_to_end_if_step_out_of_bounds(
|
||||
logged_in_client,
|
||||
service_one,
|
||||
fake_uuid,
|
||||
mock_get_service_template,
|
||||
mock_s3_upload,
|
||||
mock_has_permissions,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid
|
||||
):
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
session['send_test_values'] = {'name': 'foo'}
|
||||
|
||||
response = logged_in_client.get(url_for(
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=999,
|
||||
))
|
||||
|
||||
assert response.status_code == 302
|
||||
expected_url = url_for(
|
||||
'main.check_messages',
|
||||
service_id=service_one['id'],
|
||||
upload_id=fake_uuid,
|
||||
template_type='sms',
|
||||
_external=True,
|
||||
)
|
||||
assert response.location in (
|
||||
expected_url + '?help=0&from_test=True',
|
||||
expected_url + '?from_test=True&help=0',
|
||||
)
|
||||
|
||||
|
||||
def test_send_test_redirects_to_start_if_you_skip_steps(
|
||||
logged_in_platform_admin_client,
|
||||
service_one,
|
||||
fake_uuid,
|
||||
mock_get_service_letter_template,
|
||||
mock_s3_upload,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
mocker,
|
||||
):
|
||||
|
||||
with logged_in_platform_admin_client.session_transaction() as session:
|
||||
session['send_test_letter_page_count'] = 1
|
||||
session['send_test_values'] = {'address_line_1': 'foo'}
|
||||
|
||||
response = logged_in_platform_admin_client.get(url_for(
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=7, # letter template has 7 placeholders – we’re at the end
|
||||
))
|
||||
assert response.status_code == 302
|
||||
assert response.location == url_for(
|
||||
'main.send_test',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
_external=True,
|
||||
)
|
||||
|
||||
|
||||
def test_send_test_redirects_to_start_if_index_out_of_bounds_and_some_placeholders_empty(
|
||||
logged_in_client,
|
||||
service_one,
|
||||
fake_uuid,
|
||||
mock_get_service_email_template,
|
||||
mock_s3_download,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
):
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
session['send_test_values'] = {'name': 'foo'}
|
||||
|
||||
response = logged_in_client.get(url_for(
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=999,
|
||||
))
|
||||
|
||||
assert response.status_code == 302
|
||||
assert response.location == url_for(
|
||||
'main.send_test',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
_external=True,
|
||||
)
|
||||
|
||||
|
||||
def test_send_test_sms_message_redirects_with_help_argument(
|
||||
logged_in_client,
|
||||
service_one,
|
||||
fake_uuid,
|
||||
):
|
||||
response = logged_in_client.get(
|
||||
url_for('main.send_test', service_id=service_one['id'], template_id=fake_uuid, help=1)
|
||||
)
|
||||
assert response.status_code == 302
|
||||
assert response.location == url_for(
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=0,
|
||||
help=1,
|
||||
_external=True,
|
||||
)
|
||||
|
||||
|
||||
def test_send_test_email_message_without_placeholders(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
service_one,
|
||||
mock_get_service_email_template_without_placeholders,
|
||||
mock_s3_upload,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
expected_data = {'data': 'email address\r\ntest@user.gov.uk\r\n', 'file_name': 'Test message'}
|
||||
mocker.patch('app.main.views.send.s3download', return_value='email address\r\ntest@user.gov.uk')
|
||||
|
||||
response = logged_in_client.get(
|
||||
url_for('main.send_test', service_id=fake_uuid, template_id=fake_uuid),
|
||||
url_for('main.send_test', service_id=service_one['id'], template_id=fake_uuid),
|
||||
follow_redirects=True
|
||||
)
|
||||
assert response.status_code == 200
|
||||
mock_s3_upload.assert_called_with(fake_uuid, expected_data, 'eu-west-1')
|
||||
mock_s3_upload.assert_called_with(service_one['id'], expected_data, 'eu-west-1')
|
||||
|
||||
|
||||
def test_send_test_sms_message_with_placeholders(
|
||||
def test_send_test_sms_message_with_placeholders_shows_first_field(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
api_user_active,
|
||||
service_one,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_template_with_placeholders,
|
||||
mock_s3_upload,
|
||||
mock_has_permissions,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
expected_data = {
|
||||
'data': 'phone number,name\r\n07700 900762,Jo\r\n',
|
||||
'file_name': 'Test message'
|
||||
}
|
||||
with logged_in_client.session_transaction() as session:
|
||||
assert 'send_test_values' not in session
|
||||
|
||||
response = logged_in_client.get(
|
||||
url_for(
|
||||
'main.send_test',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
),
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||||
|
||||
assert page.select('label')[0].text.strip() == 'name'
|
||||
assert page.select('input')[0]['name'] == 'placeholder_value'
|
||||
assert page.select('.page-footer-back-link')[0]['href'] == url_for(
|
||||
'main.view_template',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
)
|
||||
with logged_in_client.session_transaction() as session:
|
||||
assert session['send_test_values']['phone number'] == '07700 900762'
|
||||
|
||||
|
||||
def test_send_test_letter_clears_previous_page_cache(
|
||||
logged_in_platform_admin_client,
|
||||
mocker,
|
||||
service_one,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_letter_template,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
with logged_in_platform_admin_client.session_transaction() as session:
|
||||
session['send_test_letter_page_count'] = 'WRONG'
|
||||
|
||||
response = logged_in_platform_admin_client.get(url_for(
|
||||
'main.send_test',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
))
|
||||
assert response.status_code == 302
|
||||
|
||||
with logged_in_platform_admin_client.session_transaction() as session:
|
||||
assert session['send_test_letter_page_count'] is None
|
||||
|
||||
|
||||
def test_send_test_populates_field_from_session(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
service_one,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_template_with_placeholders,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
session['send_test_values'] = {}
|
||||
session['send_test_values']['name'] = 'Jo'
|
||||
|
||||
response = logged_in_client.get(url_for(
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=0,
|
||||
))
|
||||
assert response.status_code == 200
|
||||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||||
|
||||
assert page.select('input')[0]['value'] == 'Jo'
|
||||
|
||||
|
||||
def test_send_test_caches_page_count(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
service_one,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_letter_template,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=99)
|
||||
|
||||
response = logged_in_client.get(
|
||||
url_for(
|
||||
'main.send_test',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
),
|
||||
follow_redirects=True,
|
||||
)
|
||||
with logged_in_client.session_transaction() as session:
|
||||
assert session['send_test_letter_page_count'] == 99
|
||||
|
||||
|
||||
def test_send_test_indicates_optional_address_columns(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
service_one,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_letter_template,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=1)
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
session['send_test_values'] = {}
|
||||
|
||||
response = logged_in_client.get(url_for(
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=3,
|
||||
))
|
||||
assert response.status_code == 200
|
||||
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||||
|
||||
assert normalize_spaces(page.select('label')[0].text) == (
|
||||
'address line 4 '
|
||||
'Optional'
|
||||
)
|
||||
assert page.select('.page-footer-back-link')[0]['href'] == url_for(
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=2,
|
||||
)
|
||||
|
||||
|
||||
def test_send_test_allows_empty_optional_address_columns(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
service_one,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_letter_template,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=1)
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
session['send_test_values'] = {}
|
||||
|
||||
response = logged_in_client.post(
|
||||
url_for(
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=3,
|
||||
),
|
||||
# no data here
|
||||
)
|
||||
|
||||
assert response.status_code == 302
|
||||
assert response.location == url_for(
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=4,
|
||||
_external=True,
|
||||
)
|
||||
|
||||
|
||||
def test_send_test_sms_message_puts_submitted_data_in_session_and_file(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
service_one,
|
||||
mock_get_service_template_with_placeholders,
|
||||
mock_s3_upload,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
session['send_test_values'] = {}
|
||||
|
||||
mocker.patch('app.main.views.send.s3download', return_value='phone number\r\n+4412341234')
|
||||
|
||||
response = logged_in_client.post(
|
||||
url_for(
|
||||
'main.send_test',
|
||||
service_id=fake_uuid,
|
||||
template_id=fake_uuid
|
||||
'main.send_test_step',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
step_index=0,
|
||||
),
|
||||
data={'name': 'Jo'},
|
||||
follow_redirects=True
|
||||
data={'placeholder_value': 'Jo'},
|
||||
follow_redirects=True,
|
||||
)
|
||||
assert response.status_code == 200
|
||||
mock_s3_upload.assert_called_with(fake_uuid, expected_data, 'eu-west-1')
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
assert session['send_test_values']['phone number'] == '07700 900762'
|
||||
assert session['send_test_values']['name'] == 'Jo'
|
||||
|
||||
mock_s3_upload.assert_called_with(
|
||||
service_one['id'],
|
||||
{
|
||||
'data': 'name,phone number\r\nJo,07700 900762\r\n',
|
||||
'file_name': 'Test message'
|
||||
},
|
||||
'eu-west-1'
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('filetype', ['pdf', 'png'])
|
||||
def test_send_test_works_as_letter_preview(
|
||||
filetype,
|
||||
logged_in_platform_admin_client,
|
||||
mock_get_service_letter_template,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
service_one,
|
||||
fake_uuid,
|
||||
mocker,
|
||||
):
|
||||
service_one['can_send_letters'] = True
|
||||
mocker.patch('app.service_api_client.get_service', return_value={"data": service_one})
|
||||
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=1)
|
||||
mocked_preview = mocker.patch(
|
||||
'app.main.views.send.TemplatePreview.from_utils_template',
|
||||
return_value='foo'
|
||||
)
|
||||
|
||||
service_id = service_one['id']
|
||||
template_id = fake_uuid
|
||||
with logged_in_platform_admin_client.session_transaction() as session:
|
||||
session['send_test_values'] = {'address_line_1': 'Jo Lastname'}
|
||||
response = logged_in_platform_admin_client.get(
|
||||
url_for(
|
||||
'main.send_test_preview',
|
||||
service_id=service_id,
|
||||
template_id=template_id,
|
||||
filetype=filetype
|
||||
)
|
||||
)
|
||||
|
||||
mock_get_service_letter_template.assert_called_with(service_id, template_id)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.get_data(as_text=True) == 'foo'
|
||||
assert mocked_preview.call_args[0][0].id == template_id
|
||||
assert type(mocked_preview.call_args[0][0]) == LetterImageTemplate
|
||||
assert mocked_preview.call_args[0][0].values == {'address_line_1': 'Jo Lastname'}
|
||||
assert mocked_preview.call_args[0][1] == filetype
|
||||
|
||||
|
||||
def test_send_test_clears_session(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
service_one,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
session['send_test_values'] = {'foo': 'bar'}
|
||||
|
||||
response = logged_in_client.get(
|
||||
url_for(
|
||||
'main.send_test',
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
),
|
||||
)
|
||||
assert response.status_code == 302
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
assert session['send_test_values'] == {}
|
||||
|
||||
|
||||
def test_download_example_csv(
|
||||
@@ -416,16 +785,13 @@ def test_download_example_csv(
|
||||
|
||||
def test_upload_csvfile_with_valid_phone_shows_all_numbers(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
api_user_active,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
mock_get_service_template,
|
||||
mock_s3_upload,
|
||||
mock_has_permissions,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid
|
||||
service_one,
|
||||
fake_uuid,
|
||||
mock_s3_upload,
|
||||
mocker,
|
||||
):
|
||||
|
||||
mocker.patch(
|
||||
@@ -436,7 +802,7 @@ def test_upload_csvfile_with_valid_phone_shows_all_numbers(
|
||||
)
|
||||
|
||||
response = logged_in_client.post(
|
||||
url_for('main.send_messages', service_id=fake_uuid, template_id=fake_uuid),
|
||||
url_for('main.send_messages', service_id=service_one['id'], template_id=fake_uuid),
|
||||
data={'file': (BytesIO(''.encode('utf-8')), 'valid.csv')},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
@@ -453,7 +819,7 @@ def test_upload_csvfile_with_valid_phone_shows_all_numbers(
|
||||
assert '07700 900750' not in content
|
||||
assert 'Only showing the first 50 rows' in content
|
||||
|
||||
mock_get_detailed_service_for_today.assert_called_once_with(fake_uuid)
|
||||
mock_get_detailed_service_for_today.assert_called_once_with(service_one['id'])
|
||||
|
||||
|
||||
@pytest.mark.parametrize('service_mock, should_allow_international', [
|
||||
@@ -495,12 +861,9 @@ def test_upload_csvfile_with_international_validates(
|
||||
def test_test_message_can_only_be_sent_now(
|
||||
logged_in_client,
|
||||
mocker,
|
||||
api_user_active,
|
||||
mock_login,
|
||||
mock_get_service,
|
||||
service_one,
|
||||
mock_get_service_template,
|
||||
mock_s3_download,
|
||||
mock_has_permissions,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid
|
||||
@@ -515,7 +878,7 @@ def test_test_message_can_only_be_sent_now(
|
||||
}
|
||||
response = logged_in_client.get(url_for(
|
||||
'main.check_messages',
|
||||
service_id=fake_uuid,
|
||||
service_id=service_one['id'],
|
||||
upload_id=fake_uuid,
|
||||
template_type='sms',
|
||||
from_test=True
|
||||
@@ -527,15 +890,17 @@ def test_test_message_can_only_be_sent_now(
|
||||
|
||||
def test_letter_can_only_be_sent_now(
|
||||
logged_in_client,
|
||||
mock_get_service,
|
||||
mocker,
|
||||
service_one,
|
||||
mock_get_service_letter_template,
|
||||
mock_s3_download,
|
||||
mock_has_permissions,
|
||||
mock_get_users_by_service,
|
||||
mock_get_detailed_service_for_today,
|
||||
fake_uuid,
|
||||
):
|
||||
|
||||
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=1)
|
||||
|
||||
with logged_in_client.session_transaction() as session:
|
||||
session['upload_data'] = {
|
||||
'original_file_name': 'Test message',
|
||||
@@ -543,9 +908,10 @@ def test_letter_can_only_be_sent_now(
|
||||
'notification_count': 1,
|
||||
'valid': True
|
||||
}
|
||||
|
||||
response = logged_in_client.get(url_for(
|
||||
'main.check_messages',
|
||||
service_id=fake_uuid,
|
||||
service_id=service_one['id'],
|
||||
upload_id=fake_uuid,
|
||||
template_type='letter',
|
||||
from_test=True
|
||||
@@ -555,15 +921,12 @@ def test_letter_can_only_be_sent_now(
|
||||
assert 'name="scheduled_for"' not in content
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'when', [
|
||||
'', '2016-08-25T13:04:21.767198'
|
||||
]
|
||||
)
|
||||
@pytest.mark.parametrize('when', [
|
||||
'', '2016-08-25T13:04:21.767198'
|
||||
])
|
||||
def test_create_job_should_call_api(
|
||||
logged_in_client,
|
||||
service_one,
|
||||
active_user_with_permissions,
|
||||
mock_create_job,
|
||||
mock_get_job,
|
||||
mock_get_notifications,
|
||||
@@ -634,6 +997,7 @@ def test_should_show_preview_letter_message(
|
||||
):
|
||||
service_one['can_send_letters'] = True
|
||||
mocker.patch('app.service_api_client.get_service', return_value={"data": service_one})
|
||||
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=1)
|
||||
|
||||
mocker.patch(
|
||||
'app.main.views.send.s3download',
|
||||
@@ -697,13 +1061,11 @@ def test_dont_show_preview_letter_templates_for_bad_filetype(
|
||||
def test_check_messages_should_revalidate_file_when_uploading_file(
|
||||
logged_in_client,
|
||||
service_one,
|
||||
active_user_with_permissions,
|
||||
mock_create_job,
|
||||
mock_get_job,
|
||||
mock_get_service_template_with_placeholders,
|
||||
mock_s3_upload,
|
||||
mocker,
|
||||
mock_has_permissions,
|
||||
mock_get_detailed_service_for_today,
|
||||
mock_get_users_by_service,
|
||||
fake_uuid
|
||||
@@ -726,7 +1088,7 @@ def test_check_messages_should_revalidate_file_when_uploading_file(
|
||||
'notification_count': data['notification_count'],
|
||||
'valid': True}
|
||||
response = logged_in_client.post(
|
||||
url_for('main.start_job', service_id=service_id, upload_id=data['id']),
|
||||
url_for('main.start_job', service_id=service_one['id'], upload_id=data['id']),
|
||||
data={'file': (BytesIO(''.encode('utf-8')), 'invalid.csv')},
|
||||
content_type='multipart/form-data',
|
||||
follow_redirects=True
|
||||
|
||||
@@ -4,6 +4,8 @@ from csv import DictReader
|
||||
|
||||
import pytest
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from app.utils import (
|
||||
email_safe,
|
||||
generate_notifications_csv,
|
||||
@@ -105,6 +107,20 @@ def test_can_create_spreadsheet_from_large_excel_file():
|
||||
assert ret.as_csv_data
|
||||
|
||||
|
||||
def test_can_create_spreadsheet_from_dict():
|
||||
assert Spreadsheet.from_dict(OrderedDict(
|
||||
foo='bar',
|
||||
name='Jane',
|
||||
)).as_csv_data == (
|
||||
"foo,name\r\n"
|
||||
"bar,Jane\r\n"
|
||||
)
|
||||
|
||||
|
||||
def test_can_create_spreadsheet_from_dict_with_filename():
|
||||
assert Spreadsheet.from_dict({}, filename='empty.csv').as_dict['file_name'] == "empty.csv"
|
||||
|
||||
|
||||
def test_generate_notifications_csv_returns_correct_csv_file(_get_notifications_csv_mock):
|
||||
csv_content = generate_notifications_csv(service_id='1234')
|
||||
csv_file = DictReader(StringIO('\n'.join(csv_content)))
|
||||
|
||||
Reference in New Issue
Block a user