mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-20 22:40:31 -04:00
Merge pull request #3366 from alphagov/upload-contact-list
Let teams upload an emergency contact list for later use
This commit is contained in:
@@ -6,12 +6,14 @@ from glob import glob
|
||||
from io import BytesIO
|
||||
from itertools import repeat
|
||||
from os import path
|
||||
from unittest.mock import ANY
|
||||
from uuid import uuid4
|
||||
from zipfile import BadZipFile
|
||||
|
||||
import pytest
|
||||
from bs4 import BeautifulSoup
|
||||
from flask import url_for
|
||||
from freezegun import freeze_time
|
||||
from notifications_python_client.errors import HTTPError
|
||||
from notifications_utils.recipients import RecipientCSV
|
||||
from notifications_utils.template import (
|
||||
@@ -36,6 +38,7 @@ from tests.conftest import (
|
||||
create_active_user_with_permissions,
|
||||
create_multiple_email_reply_to_addresses,
|
||||
create_multiple_sms_senders,
|
||||
create_platform_admin_user,
|
||||
create_template,
|
||||
mock_get_service_email_template,
|
||||
mock_get_service_letter_template,
|
||||
@@ -1308,16 +1311,17 @@ def test_send_one_off_has_skip_link(
|
||||
_follow_redirects=True,
|
||||
)
|
||||
|
||||
skip_links = page.select('a.top-gutter-4-3')
|
||||
skip_links = page.select('form a')
|
||||
|
||||
if expected_link_text and expected_link_url:
|
||||
assert skip_links[0].text.strip() == expected_link_text
|
||||
assert skip_links[0]['href'] == expected_link_url(
|
||||
assert skip_links[1].text.strip() == expected_link_text
|
||||
assert skip_links[1]['href'] == expected_link_url(
|
||||
service_id=service_one['id'],
|
||||
template_id=fake_uuid,
|
||||
)
|
||||
else:
|
||||
assert not skip_links
|
||||
with pytest.raises(IndexError):
|
||||
skip_links[1]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('template_type, expected_sticky', [
|
||||
@@ -1374,9 +1378,9 @@ def test_skip_link_will_not_show_on_sms_one_off_if_service_has_no_mobile_number(
|
||||
assert not skip_links
|
||||
|
||||
|
||||
@pytest.mark.parametrize('user, link_index', (
|
||||
(create_active_user_with_permissions(), 2),
|
||||
(create_active_caseworking_user(), 1),
|
||||
@pytest.mark.parametrize('user', (
|
||||
create_active_user_with_permissions(),
|
||||
create_active_caseworking_user(),
|
||||
))
|
||||
def test_send_one_off_offers_link_to_upload(
|
||||
client_request,
|
||||
@@ -1384,7 +1388,6 @@ def test_send_one_off_offers_link_to_upload(
|
||||
mock_get_service_template,
|
||||
mock_has_jobs,
|
||||
user,
|
||||
link_index,
|
||||
):
|
||||
client_request.login(user)
|
||||
|
||||
@@ -1396,7 +1399,7 @@ def test_send_one_off_offers_link_to_upload(
|
||||
)
|
||||
|
||||
back_link = page.select('main a')[0]
|
||||
link = page.select('main a')[link_index]
|
||||
link = page.select_one('form a')
|
||||
|
||||
assert back_link.text.strip() == 'Back'
|
||||
|
||||
@@ -1408,6 +1411,87 @@ def test_send_one_off_offers_link_to_upload(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('user', (
|
||||
pytest.param(
|
||||
create_platform_admin_user(),
|
||||
),
|
||||
pytest.param(
|
||||
create_active_user_with_permissions(),
|
||||
marks=pytest.mark.xfail(raises=AssertionError),
|
||||
),
|
||||
))
|
||||
def test_platform_admin_has_link_to_use_existing_list(
|
||||
client_request,
|
||||
mock_get_service_template,
|
||||
mock_has_jobs,
|
||||
mock_get_contact_lists,
|
||||
fake_uuid,
|
||||
user,
|
||||
):
|
||||
client_request.login(user)
|
||||
page = client_request.get(
|
||||
'main.send_one_off',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
_follow_redirects=True,
|
||||
)
|
||||
|
||||
assert [
|
||||
(link.text, link['href']) for link in page.select('form a')
|
||||
] == [
|
||||
(
|
||||
'Upload a list of phone numbers',
|
||||
url_for(
|
||||
'main.send_messages',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Use a saved list',
|
||||
url_for(
|
||||
'main.choose_from_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
),
|
||||
),
|
||||
(
|
||||
'Use my phone number',
|
||||
url_for(
|
||||
'main.send_test',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def test_no_link_to_use_existing_list_for_service_without_lists(
|
||||
mocker,
|
||||
client_request,
|
||||
mock_get_service_template,
|
||||
mock_has_jobs,
|
||||
fake_uuid,
|
||||
):
|
||||
mocker.patch(
|
||||
'app.models.contact_list.ContactLists.client_method',
|
||||
return_value=[],
|
||||
)
|
||||
client_request.login(create_platform_admin_user())
|
||||
page = client_request.get(
|
||||
'main.send_one_off',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
_follow_redirects=True,
|
||||
)
|
||||
assert [
|
||||
link.text for link in page.select('form a')
|
||||
] == [
|
||||
'Upload a list of phone numbers',
|
||||
'Use my phone number',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('user', (
|
||||
create_active_user_with_permissions(),
|
||||
create_active_caseworking_user(),
|
||||
@@ -3780,3 +3864,163 @@ def test_redirects_to_template_if_job_exists_already(
|
||||
_external=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize((
|
||||
'template_type, '
|
||||
'expected_list_id, '
|
||||
'expected_filename, '
|
||||
'expected_time, '
|
||||
'expected_count'
|
||||
), (
|
||||
(
|
||||
'email',
|
||||
'6ce466d0-fd6a-11e5-82f5-e0accb9d11a6',
|
||||
'EmergencyContactList.xls',
|
||||
'Uploaded today at 10:59am',
|
||||
'100 email addresses',
|
||||
),
|
||||
(
|
||||
'sms',
|
||||
'd7b0bd1a-d1c7-4621-be5c-3c1b4278a2ad',
|
||||
'phone number list.csv',
|
||||
'Uploaded today at 1:00pm',
|
||||
'123 phone numbers',
|
||||
),
|
||||
))
|
||||
@freeze_time('2020-03-13 13:00')
|
||||
def test_choose_from_contact_list(
|
||||
mocker,
|
||||
client_request,
|
||||
mock_get_contact_lists,
|
||||
fake_uuid,
|
||||
template_type,
|
||||
expected_list_id,
|
||||
expected_filename,
|
||||
expected_time,
|
||||
expected_count,
|
||||
):
|
||||
template = create_template(template_type=template_type)
|
||||
mocker.patch(
|
||||
'app.service_api_client.get_service_template',
|
||||
return_value={'data': template},
|
||||
)
|
||||
page = client_request.get(
|
||||
'main.choose_from_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
)
|
||||
assert len(page.select('.file-list-filename-large')) == 1
|
||||
assert normalize_spaces(page.select_one('.file-list-filename-large').text) == (
|
||||
expected_filename
|
||||
)
|
||||
assert page.select_one('a.file-list-filename-large')['href'] == url_for(
|
||||
'main.send_from_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=template['id'],
|
||||
contact_list_id=expected_list_id,
|
||||
)
|
||||
assert normalize_spaces(page.select_one('.file-list-hint-large').text) == (
|
||||
expected_time
|
||||
)
|
||||
assert normalize_spaces(page.select_one('.big-number-smallest').text) == (
|
||||
expected_count
|
||||
)
|
||||
|
||||
|
||||
def test_choose_from_contact_list_with_personalised_template(
|
||||
mocker,
|
||||
client_request,
|
||||
mock_get_contact_lists,
|
||||
fake_uuid,
|
||||
):
|
||||
template = create_template(
|
||||
content="Hey ((name)) ((thing)) is happening"
|
||||
)
|
||||
mocker.patch(
|
||||
'app.service_api_client.get_service_template',
|
||||
return_value={'data': template},
|
||||
)
|
||||
page = client_request.get(
|
||||
'main.choose_from_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
)
|
||||
assert [
|
||||
normalize_spaces(p.text) for p in page.select('main p')
|
||||
] == [
|
||||
'You cannot use a saved contact list with this template because '
|
||||
'it is personalised with ((name)) and ((thing)).',
|
||||
'Saved contact lists can only store email addresses or phone numbers.',
|
||||
]
|
||||
assert not page.select('table')
|
||||
|
||||
|
||||
def test_choose_from_contact_list_with_no_lists(
|
||||
mocker,
|
||||
client_request,
|
||||
mock_get_service_template,
|
||||
fake_uuid,
|
||||
):
|
||||
mocker.patch(
|
||||
'app.models.contact_list.ContactLists.client_method',
|
||||
return_value=[],
|
||||
)
|
||||
page = client_request.get(
|
||||
'main.choose_from_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
)
|
||||
assert [
|
||||
normalize_spaces(p.text) for p in page.select('main p')
|
||||
] == [
|
||||
'You have not saved any lists of phone numbers yet.',
|
||||
'To upload and save a new contact list, go to the uploads page.',
|
||||
]
|
||||
assert page.select_one('main p a')['href'] == url_for(
|
||||
'main.uploads',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
)
|
||||
assert not page.select('table')
|
||||
|
||||
|
||||
def test_send_from_contact_list(
|
||||
mocker,
|
||||
client_request,
|
||||
fake_uuid,
|
||||
mock_get_contact_lists,
|
||||
):
|
||||
new_uuid = uuid.uuid4()
|
||||
mock_download = mocker.patch('app.models.contact_list.s3download', return_value='contents')
|
||||
mock_get_metadata = mocker.patch('app.models.contact_list.get_csv_metadata', return_value={
|
||||
'example_key': 'example value',
|
||||
})
|
||||
mock_upload = mocker.patch('app.models.contact_list.s3upload', return_value=new_uuid)
|
||||
mock_set_metadata = mocker.patch('app.models.contact_list.set_metadata_on_csv_upload')
|
||||
client_request.get(
|
||||
'main.send_from_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
contact_list_id=fake_uuid,
|
||||
_expected_status=302,
|
||||
_expected_redirect=url_for(
|
||||
'main.check_messages',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
template_id=fake_uuid,
|
||||
upload_id=new_uuid,
|
||||
original_file_name='EmergencyContactList.xls',
|
||||
_external=True,
|
||||
)
|
||||
)
|
||||
mock_download.assert_called_once_with(
|
||||
SERVICE_ONE_ID, fake_uuid, bucket='test-contact-list'
|
||||
)
|
||||
mock_get_metadata.assert_called_once_with(
|
||||
SERVICE_ONE_ID, fake_uuid, bucket='test-contact-list'
|
||||
)
|
||||
mock_upload.assert_called_once_with(
|
||||
SERVICE_ONE_ID, {'data': 'contents'}, ANY
|
||||
)
|
||||
mock_set_metadata.assert_called_once_with(
|
||||
SERVICE_ONE_ID, new_uuid, example_key='example value'
|
||||
)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import re
|
||||
import urllib
|
||||
from unittest.mock import Mock
|
||||
import uuid
|
||||
from io import BytesIO
|
||||
from unittest.mock import ANY, Mock
|
||||
|
||||
import pytest
|
||||
from flask import make_response, url_for
|
||||
@@ -13,6 +15,7 @@ from tests.conftest import (
|
||||
SERVICE_ONE_ID,
|
||||
create_active_caseworking_user,
|
||||
create_active_user_with_permissions,
|
||||
create_platform_admin_user,
|
||||
)
|
||||
|
||||
|
||||
@@ -30,6 +33,7 @@ def test_no_upload_letters_button_without_permission(
|
||||
service_one,
|
||||
mock_get_uploads,
|
||||
mock_get_jobs,
|
||||
mock_get_no_contact_lists,
|
||||
extra_permissions,
|
||||
):
|
||||
service_one['permissions'] += extra_permissions
|
||||
@@ -37,6 +41,31 @@ def test_no_upload_letters_button_without_permission(
|
||||
assert not page.find('a', text=re.compile('Upload a letter'))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('user', (
|
||||
pytest.param(
|
||||
create_platform_admin_user(),
|
||||
),
|
||||
pytest.param(
|
||||
create_active_user_with_permissions(),
|
||||
marks=pytest.mark.xfail(raises=AssertionError),
|
||||
),
|
||||
))
|
||||
def test_platform_admin_has_upload_contact_list(
|
||||
client_request,
|
||||
mock_get_uploads,
|
||||
mock_get_jobs,
|
||||
mock_get_no_contact_lists,
|
||||
user,
|
||||
):
|
||||
client_request.login(user)
|
||||
page = client_request.get('main.uploads', service_id=SERVICE_ONE_ID)
|
||||
button = page.find('a', text=re.compile('Upload an emergency contact list'))
|
||||
assert button
|
||||
assert button['href'] == url_for(
|
||||
'main.upload_contact_list', service_id=SERVICE_ONE_ID,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('extra_permissions, expected_empty_message', (
|
||||
(['letter'], (
|
||||
'You have not uploaded any files recently. '
|
||||
@@ -53,6 +82,7 @@ def test_get_upload_hub_with_no_uploads(
|
||||
client_request,
|
||||
service_one,
|
||||
mock_get_no_uploads,
|
||||
mock_get_no_contact_lists,
|
||||
extra_permissions,
|
||||
expected_empty_message,
|
||||
):
|
||||
@@ -70,6 +100,7 @@ def test_get_upload_hub_page(
|
||||
client_request,
|
||||
service_one,
|
||||
mock_get_uploads,
|
||||
mock_get_no_contact_lists,
|
||||
):
|
||||
mocker.patch('app.job_api_client.get_jobs', return_value={'data': []})
|
||||
service_one['permissions'] += ['letter', 'upload_letters']
|
||||
@@ -97,7 +128,7 @@ def test_get_upload_hub_page(
|
||||
'123 Example Street'
|
||||
)
|
||||
assert normalize_spaces(str(uploads[1].select_one('.govuk-body'))) == (
|
||||
'<p class="govuk-body govuk-!-margin-bottom-1"> '
|
||||
'<p class="govuk-body letter-recipient-summary"> '
|
||||
'Firstname Lastname<br/> '
|
||||
'123 Example Street<br/> '
|
||||
'</p>'
|
||||
@@ -656,6 +687,7 @@ def test_uploads_page_shows_scheduled_jobs(
|
||||
client_request,
|
||||
mock_get_no_uploads,
|
||||
mock_get_jobs,
|
||||
mock_get_no_contact_lists,
|
||||
user,
|
||||
):
|
||||
client_request.login(user)
|
||||
@@ -681,11 +713,56 @@ def test_uploads_page_shows_scheduled_jobs(
|
||||
assert not page.select('.table-empty-message')
|
||||
|
||||
|
||||
@freeze_time('2020-03-15')
|
||||
def test_uploads_page_shows_contact_lists_first(
|
||||
mocker,
|
||||
client_request,
|
||||
mock_get_no_uploads,
|
||||
mock_get_jobs,
|
||||
mock_get_contact_lists,
|
||||
):
|
||||
page = client_request.get('main.uploads', service_id=SERVICE_ONE_ID)
|
||||
|
||||
assert [
|
||||
normalize_spaces(row.text) for row in page.select('tr')
|
||||
] == [
|
||||
(
|
||||
'File Status'
|
||||
),
|
||||
(
|
||||
'phone number list.csv '
|
||||
'Uploaded 13 March at 1:00pm '
|
||||
'123 saved phone numbers'
|
||||
),
|
||||
(
|
||||
'EmergencyContactList.xls '
|
||||
'Uploaded 13 March at 10:59am '
|
||||
'100 saved email addresses'
|
||||
),
|
||||
(
|
||||
'even_later.csv '
|
||||
'Sending 1 January 2016 at 11:09pm '
|
||||
'1 text message waiting to send'
|
||||
),
|
||||
(
|
||||
'send_me_later.csv '
|
||||
'Sending 1 January 2016 at 11:09am '
|
||||
'1 text message waiting to send'
|
||||
),
|
||||
]
|
||||
assert page.select_one('.file-list-filename-large')['href'] == url_for(
|
||||
'main.contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
contact_list_id='d7b0bd1a-d1c7-4621-be5c-3c1b4278a2ad',
|
||||
)
|
||||
|
||||
|
||||
def test_get_uploads_shows_pagination(
|
||||
client_request,
|
||||
active_user_with_permissions,
|
||||
mock_get_jobs,
|
||||
mock_get_uploads,
|
||||
mock_get_no_contact_lists,
|
||||
):
|
||||
page = client_request.get('main.uploads', service_id=SERVICE_ONE_ID)
|
||||
|
||||
@@ -697,3 +774,493 @@ def test_get_uploads_shows_pagination(
|
||||
'Previous page '
|
||||
'page 0'
|
||||
)
|
||||
|
||||
|
||||
def test_upload_contact_list_page(client_request):
|
||||
page = client_request.get(
|
||||
'main.upload_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
)
|
||||
assert 'action' not in page.select_one('form')
|
||||
assert page.select_one('form input')['name'] == 'file'
|
||||
assert page.select_one('form input')['type'] == 'file'
|
||||
|
||||
assert normalize_spaces(page.select('.spreadsheet')[0].text) == (
|
||||
'Example A '
|
||||
'1 email address '
|
||||
'2 test@example.gov.uk'
|
||||
)
|
||||
assert normalize_spaces(page.select('.spreadsheet')[1].text) == (
|
||||
'Example A '
|
||||
'1 phone number '
|
||||
'2 07700 900123'
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('file_contents, expected_error, expected_thead, expected_tbody,', [
|
||||
(
|
||||
"""
|
||||
telephone,name
|
||||
+447700900986
|
||||
""",
|
||||
(
|
||||
'Your file has too many columns '
|
||||
'It needs to have 1 column, called ‘email address’ or ‘phone number’. '
|
||||
'Right now it has 2 columns called ‘telephone’ and ‘name’. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 telephone name',
|
||||
'2 +447700900986',
|
||||
),
|
||||
(
|
||||
"""
|
||||
phone number, email address
|
||||
+447700900986, test@example.com
|
||||
""",
|
||||
(
|
||||
'Your file has too many columns '
|
||||
'It needs to have 1 column, called ‘email address’ or ‘phone number’. '
|
||||
'Right now it has 2 columns called ‘phone number’ and ‘email address’. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 phone number email address',
|
||||
'2 +447700900986 test@example.com',
|
||||
),
|
||||
(
|
||||
"""
|
||||
email address
|
||||
+447700900986
|
||||
""",
|
||||
(
|
||||
'There’s a problem with invalid.csv '
|
||||
'You need to fix 1 email address. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 email address',
|
||||
'2 Not a valid email address +447700900986',
|
||||
),
|
||||
(
|
||||
"""
|
||||
phone number
|
||||
test@example.com
|
||||
""",
|
||||
(
|
||||
'There’s a problem with invalid.csv '
|
||||
'You need to fix 1 phone number. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 phone number',
|
||||
'2 Must not contain letters or symbols test@example.com',
|
||||
),
|
||||
(
|
||||
"""
|
||||
phone number, phone number, PHONE_NUMBER
|
||||
+447700900111,+447700900222,+447700900333,
|
||||
""",
|
||||
(
|
||||
'Your file has too many columns '
|
||||
'It needs to have 1 column, called ‘email address’ or ‘phone number’. '
|
||||
'Right now it has 3 columns called ‘phone number’, ‘phone number’ and ‘PHONE_NUMBER’. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 phone number phone number PHONE_NUMBER',
|
||||
'2 +447700900333 +447700900333 +447700900333',
|
||||
),
|
||||
(
|
||||
"""
|
||||
phone number
|
||||
""",
|
||||
(
|
||||
'Your file is missing some rows '
|
||||
'It needs at least one row of data. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 phone number',
|
||||
'',
|
||||
),
|
||||
(
|
||||
"+447700900986",
|
||||
(
|
||||
'Your file is missing some rows '
|
||||
'It needs at least one row of data, in a column called '
|
||||
'‘email address’ or ‘phone number’. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 +447700900986',
|
||||
'',
|
||||
),
|
||||
(
|
||||
"",
|
||||
(
|
||||
'Your file is missing some rows '
|
||||
'It needs at least one row of data, in a column called '
|
||||
'‘email address’ or ‘phone number’. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1',
|
||||
'',
|
||||
),
|
||||
(
|
||||
"""
|
||||
phone number
|
||||
+447700900986
|
||||
|
||||
+447700900986
|
||||
""",
|
||||
(
|
||||
'There’s a problem with invalid.csv '
|
||||
'You need to enter missing data in 1 row. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 phone number',
|
||||
(
|
||||
'3 Missing'
|
||||
)
|
||||
),
|
||||
(
|
||||
"""
|
||||
phone number
|
||||
+447700900
|
||||
""",
|
||||
(
|
||||
'There’s a problem with invalid.csv '
|
||||
'You need to fix 1 phone number. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 phone number',
|
||||
'2 Not enough digits +447700900',
|
||||
),
|
||||
(
|
||||
"""
|
||||
email address
|
||||
ok@example.com
|
||||
bad@example1
|
||||
bad@example2
|
||||
""",
|
||||
(
|
||||
'There’s a problem with invalid.csv '
|
||||
'You need to fix 2 email addresses. '
|
||||
'Skip to file contents'
|
||||
),
|
||||
'Row in file 1 email address',
|
||||
(
|
||||
'3 Not a valid email address bad@example1 '
|
||||
'4 Not a valid email address bad@example2'
|
||||
),
|
||||
),
|
||||
])
|
||||
def test_upload_csv_file_shows_error_banner(
|
||||
client_request,
|
||||
mocker,
|
||||
mock_s3_upload,
|
||||
mock_get_job_doesnt_exist,
|
||||
mock_get_users_by_service,
|
||||
fake_uuid,
|
||||
file_contents,
|
||||
expected_error,
|
||||
expected_thead,
|
||||
expected_tbody,
|
||||
):
|
||||
mock_upload = mocker.patch(
|
||||
'app.models.contact_list.s3upload',
|
||||
return_value=fake_uuid,
|
||||
)
|
||||
mock_download = mocker.patch(
|
||||
'app.models.contact_list.s3download',
|
||||
return_value=file_contents,
|
||||
)
|
||||
|
||||
page = client_request.post(
|
||||
'main.upload_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
_data={'file': (BytesIO(''.encode('utf-8')), 'invalid.csv')},
|
||||
_follow_redirects=True,
|
||||
)
|
||||
mock_upload.assert_called_once_with(
|
||||
SERVICE_ONE_ID,
|
||||
{'data': '', 'file_name': 'invalid.csv'},
|
||||
ANY,
|
||||
bucket='test-contact-list',
|
||||
)
|
||||
mock_download.assert_called_once_with(
|
||||
SERVICE_ONE_ID,
|
||||
fake_uuid,
|
||||
bucket='test-contact-list',
|
||||
)
|
||||
|
||||
assert normalize_spaces(page.select_one('.banner-dangerous').text) == expected_error
|
||||
|
||||
assert page.select_one('form')['action'] == url_for(
|
||||
'main.upload_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
)
|
||||
assert page.select_one('form input')['type'] == 'file'
|
||||
|
||||
assert normalize_spaces(page.select_one('thead').text) == expected_thead
|
||||
assert normalize_spaces(page.select_one('tbody').text) == expected_tbody
|
||||
|
||||
|
||||
def test_upload_csv_file_shows_error_banner_for_too_many_rows(
|
||||
client_request,
|
||||
mocker,
|
||||
mock_s3_upload,
|
||||
mock_get_job_doesnt_exist,
|
||||
mock_get_users_by_service,
|
||||
fake_uuid,
|
||||
):
|
||||
mocker.patch('app.models.contact_list.s3upload', return_value=fake_uuid)
|
||||
mocker.patch('app.models.contact_list.s3download', return_value='\n'.join(
|
||||
['phone number'] + (['07700900986'] * 50001)
|
||||
))
|
||||
|
||||
page = client_request.post(
|
||||
'main.upload_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
_data={'file': (BytesIO(''.encode('utf-8')), 'invalid.csv')},
|
||||
_follow_redirects=True,
|
||||
)
|
||||
|
||||
assert normalize_spaces(page.select_one('.banner-dangerous').text) == (
|
||||
'Your file has too many rows '
|
||||
'Notify can store files up to 50,000 rows in size. '
|
||||
'Your file has 50,001 rows. '
|
||||
'Skip to file contents'
|
||||
)
|
||||
assert len(page.select('tbody tr')) == 50
|
||||
assert normalize_spaces(page.select_one('.table-show-more-link').text) == (
|
||||
'Only showing the first 50 rows'
|
||||
)
|
||||
|
||||
|
||||
def test_upload_csv_shows_trial_mode_error(
|
||||
client_request,
|
||||
mock_get_users_by_service,
|
||||
mock_get_job_doesnt_exist,
|
||||
fake_uuid,
|
||||
mocker
|
||||
):
|
||||
mocker.patch('app.models.contact_list.s3upload', return_value=fake_uuid)
|
||||
mocker.patch('app.models.contact_list.s3download', return_value=(
|
||||
'phone number\n'
|
||||
'07900900321' # Not in team
|
||||
))
|
||||
|
||||
page = client_request.get(
|
||||
'main.check_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
upload_id=fake_uuid,
|
||||
_test_page_title=False,
|
||||
)
|
||||
|
||||
assert normalize_spaces(page.select_one('.banner-dangerous').text) == (
|
||||
'You cannot save this phone number '
|
||||
'In trial mode you can only send to yourself and members of your team '
|
||||
'Skip to file contents'
|
||||
)
|
||||
assert page.select_one('.banner-dangerous a')['href'] == url_for(
|
||||
'main.trial_mode_new'
|
||||
)
|
||||
|
||||
|
||||
def test_upload_csv_shows_ok_page(
|
||||
client_request,
|
||||
mock_get_live_service,
|
||||
mock_get_users_by_service,
|
||||
mock_get_job_doesnt_exist,
|
||||
fake_uuid,
|
||||
mocker
|
||||
):
|
||||
mocker.patch('app.models.contact_list.s3download', return_value='\n'.join(
|
||||
['email address'] + ['test@example.com'] * 51
|
||||
))
|
||||
mock_metadata_set = mocker.patch('app.models.contact_list.set_metadata_on_csv_upload')
|
||||
|
||||
page = client_request.get(
|
||||
'main.check_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
upload_id=fake_uuid,
|
||||
original_file_name='good times.xlsx',
|
||||
_test_page_title=False,
|
||||
)
|
||||
|
||||
mock_metadata_set.assert_called_once_with(
|
||||
SERVICE_ONE_ID,
|
||||
fake_uuid,
|
||||
bucket='test-contact-list',
|
||||
row_count=51,
|
||||
original_file_name='good times.xlsx',
|
||||
template_type='email',
|
||||
valid=True,
|
||||
)
|
||||
|
||||
assert normalize_spaces(page.select_one('h1').text) == (
|
||||
'good times.xlsx'
|
||||
)
|
||||
assert normalize_spaces(page.select_one('main p').text) == (
|
||||
'51 email addresses found'
|
||||
)
|
||||
assert page.select_one('form')['action'] == url_for(
|
||||
'main.save_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
upload_id=fake_uuid,
|
||||
)
|
||||
|
||||
assert normalize_spaces(page.select_one('form [type=submit]').text) == (
|
||||
'Save contact list'
|
||||
)
|
||||
assert normalize_spaces(page.select_one('thead').text) == (
|
||||
'Row in file 1 email address'
|
||||
)
|
||||
assert len(page.select('tbody tr')) == 50
|
||||
assert normalize_spaces(page.select_one('tbody tr').text) == (
|
||||
'2 test@example.com'
|
||||
)
|
||||
assert normalize_spaces(page.select_one('.table-show-more-link').text) == (
|
||||
'Only showing the first 50 rows'
|
||||
)
|
||||
|
||||
|
||||
def test_save_contact_list(
|
||||
mocker,
|
||||
client_request,
|
||||
fake_uuid,
|
||||
mock_create_contact_list,
|
||||
):
|
||||
mock_get_metadata = mocker.patch('app.models.contact_list.get_csv_metadata', return_value={
|
||||
'row_count': 999,
|
||||
'valid': True,
|
||||
'original_file_name': 'example.csv',
|
||||
'template_type': 'email'
|
||||
})
|
||||
client_request.post(
|
||||
'main.save_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
upload_id=fake_uuid,
|
||||
_expected_status=302,
|
||||
_expected_redirect=url_for(
|
||||
'main.contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
contact_list_id=fake_uuid,
|
||||
_external=True,
|
||||
)
|
||||
)
|
||||
mock_get_metadata.assert_called_once_with(
|
||||
SERVICE_ONE_ID,
|
||||
fake_uuid,
|
||||
bucket='test-contact-list',
|
||||
)
|
||||
mock_create_contact_list.assert_called_once_with(
|
||||
service_id=SERVICE_ONE_ID,
|
||||
upload_id=fake_uuid,
|
||||
original_file_name='example.csv',
|
||||
row_count=999,
|
||||
template_type='email',
|
||||
)
|
||||
|
||||
|
||||
def test_cant_save_bad_contact_list(
|
||||
mocker,
|
||||
client_request,
|
||||
fake_uuid,
|
||||
mock_create_contact_list,
|
||||
):
|
||||
mocker.patch('app.models.contact_list.get_csv_metadata', return_value={
|
||||
'row_count': 999,
|
||||
'valid': False,
|
||||
'original_file_name': 'example.csv',
|
||||
'template_type': 'email'
|
||||
})
|
||||
client_request.post(
|
||||
'main.save_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
upload_id=fake_uuid,
|
||||
_expected_status=403,
|
||||
)
|
||||
assert mock_create_contact_list.called is False
|
||||
|
||||
|
||||
@freeze_time('2020-03-13 16:51:56')
|
||||
def test_view_contact_list(
|
||||
mocker,
|
||||
client_request,
|
||||
mock_get_contact_lists,
|
||||
fake_uuid,
|
||||
):
|
||||
mocker.patch('app.models.contact_list.s3download', return_value='\n'.join(
|
||||
['email address'] + ['test@example.com'] * 51
|
||||
))
|
||||
page = client_request.get(
|
||||
'main.contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
contact_list_id=fake_uuid,
|
||||
)
|
||||
assert normalize_spaces(page.select_one('h1').text) == (
|
||||
'EmergencyContactList.xls'
|
||||
)
|
||||
assert normalize_spaces(page.select('main p')[0].text) == (
|
||||
'Uploaded by Test User today at 10:59am'
|
||||
)
|
||||
assert normalize_spaces(page.select('main p')[1].text) == (
|
||||
'Download this list 51 email addresses'
|
||||
)
|
||||
assert page.select_one('a[download]')['href'] == url_for(
|
||||
'main.download_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
contact_list_id=fake_uuid,
|
||||
)
|
||||
assert normalize_spaces(page.select_one('table').text).startswith(
|
||||
'Email addresses '
|
||||
'1 email address '
|
||||
'2 test@example.com '
|
||||
'3 test@example.com '
|
||||
)
|
||||
assert normalize_spaces(page.select_one('table').text).endswith(
|
||||
'50 test@example.com '
|
||||
'51 test@example.com'
|
||||
)
|
||||
assert normalize_spaces(page.select_one('.table-show-more-link').text) == (
|
||||
'Only showing the first 50 rows'
|
||||
)
|
||||
|
||||
|
||||
def test_view_contact_list_404s_for_non_existing_list(
|
||||
client_request,
|
||||
mock_get_contact_lists,
|
||||
fake_uuid,
|
||||
):
|
||||
client_request.get(
|
||||
'main.contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
contact_list_id=uuid.uuid4(),
|
||||
_expected_status=404,
|
||||
)
|
||||
|
||||
|
||||
def test_download_contact_list(
|
||||
mocker,
|
||||
logged_in_client,
|
||||
fake_uuid,
|
||||
mock_get_contact_lists,
|
||||
):
|
||||
mocker.patch(
|
||||
'app.models.contact_list.s3download',
|
||||
return_value='phone number\n07900900321'
|
||||
)
|
||||
response = logged_in_client.get(url_for(
|
||||
'main.download_contact_list',
|
||||
service_id=SERVICE_ONE_ID,
|
||||
contact_list_id=fake_uuid,
|
||||
))
|
||||
assert response.status_code == 200
|
||||
assert response.headers['Content-Type'] == (
|
||||
'text/csv; '
|
||||
'charset=utf-8'
|
||||
)
|
||||
assert response.headers['Content-Disposition'] == (
|
||||
'attachment; '
|
||||
'filename=EmergencyContactList.csv'
|
||||
)
|
||||
assert response.get_data(as_text=True) == (
|
||||
'phone number\n'
|
||||
'07900900321'
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user