Remove contact-list references from code

This commit is contained in:
Ryan Ahearn
2023-04-12 15:35:14 -04:00
parent 6587ed5223
commit de668d7aba
31 changed files with 11 additions and 2441 deletions

View File

@@ -1,714 +0,0 @@
import uuid
from io import BytesIO
from unittest.mock import ANY
import pytest
from flask import url_for
from freezegun import freeze_time
from app.formatters import normalize_spaces
from tests import contact_list_json
from tests.conftest import SERVICE_ONE_ID
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 page.select_one('form input')['accept'] == '.csv,.xlsx,.xls,.ods,.xlsm,.tsv'
assert normalize_spaces(page.select('.spreadsheet')[0].text) == (
'Example A '
'1 email address '
'2 test@example.gsa.gov'
)
assert normalize_spaces(page.select('.spreadsheet')[1].text) == (
'Example A '
'1 phone number '
'2 555-867-5309'
)
@pytest.mark.parametrize('file_contents, expected_error, expected_thead, expected_tbody,', [
(
"""
telephone,name
+12028675109
""",
(
'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.'
),
'Row in file 1 telephone name',
'2 +12028675109',
),
(
"""
phone number, email address
+12028675109, 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.'
),
'Row in file 1 phone number email address',
'2 +12028675109 test@example.com',
),
(
"""
email address
+12028675109
""",
(
'Theres a problem with invalid.csv '
'You need to fix 1 email address.'
),
'Row in file 1 email address',
'2 Not a valid email address +12028675109',
),
(
"""
phone number
test@example.com
""",
(
'Theres a problem with invalid.csv '
'You need to fix 1 phone number.'
),
'Row in file 1 phone number',
'2 The string supplied did not seem to be a phone number. test@example.com',
),
(
"""
phone number, phone number, PHONE_NUMBER
+12027900111,+12027900222,+12027900333,
""",
(
'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.'
),
'Row in file 1 phone number phone number PHONE_NUMBER',
'2 +12027900333 +12027900333 +12027900333',
),
(
"""
phone number
""",
(
'Your file is missing some rows '
'It needs at least one row of data.'
),
'Row in file 1 phone number',
'',
),
(
"+12028675109",
(
'Your file is missing some rows '
'It needs at least one row of data, in a column called '
'email address or phone number.'
),
'Row in file 1 +12028675109',
'',
),
(
"",
(
'Your file is missing some rows '
'It needs at least one row of data, in a column called '
'email address or phone number.'
),
'Row in file 1',
'',
),
(
"""
phone number
+12028675109
+12028675109
""",
(
'Theres a problem with invalid.csv '
'You need to enter missing data in 1 row.'
),
'Row in file 1 phone number',
(
'3 Missing'
)
),
(
"""
phone number
+12027900
""",
(
'Theres a problem with invalid.csv '
'You need to fix 1 phone number.'
),
'Row in file 1 phone number',
'2 Not enough digits +12027900',
),
(
"""
email address
ok@example.com
bad@example1
bad@example2
""",
(
'Theres a problem with invalid.csv '
'You need to fix 2 email addresses.'
),
'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,
notify_admin,
mock_s3_upload,
mock_get_job_doesnt_exist,
mock_get_users_by_service,
fake_uuid,
file_contents,
expected_error,
expected_thead,
expected_tbody,
):
mocker.patch('app.models.contact_list.uuid4', return_value=fake_uuid)
mock_upload = mocker.patch('app.models.contact_list.utils_s3upload')
mock_download = mocker.patch(
'app.models.contact_list.get_s3_contents',
return_value=file_contents,
)
mock_set_metadata = mocker.patch('app.models.contact_list.set_s3_metadata')
mock_get_metadata = mocker.patch(
'app.models.contact_list.get_s3_metadata',
return_value={'original_file_name': 'invalid.csv'},
)
page = client_request.post(
'main.upload_contact_list',
service_id=SERVICE_ONE_ID,
_data={'file': (BytesIO(''.encode('utf-8')), 'invalid.csv')},
_follow_redirects=True,
)
bucket_creds = notify_admin.config['CONTACT_LIST_BUCKET']
mock_upload.assert_called_once_with(
filedata='',
region=bucket_creds['region'],
bucket_name=bucket_creds['bucket'],
file_location=f"service-{SERVICE_ONE_ID}-notify/{fake_uuid}.csv",
access_key=bucket_creds['access_key_id'],
secret_key=bucket_creds['secret_access_key'],
)
mock_set_metadata.assert_called_once_with(
ANY,
original_file_name='invalid.csv'
)
mock_download.assert_called_once()
mock_get_metadata.assert_called_once()
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 page.select_one('form input')['accept'] == '.csv,.xlsx,.xls,.ods,.xlsm,.tsv'
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.utils_s3upload', return_value=fake_uuid)
mocker.patch('app.models.contact_list.set_s3_metadata')
mocker.patch('app.models.contact_list.get_s3_contents', return_value='\n'.join(
['phone number'] + (['2028675309'] * 100_001)
))
mocker.patch('app.models.contact_list.get_s3_metadata',
return_value={'original_file_name': 'invalid.csv'})
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 100,000 rows in size. '
'Your file has 100,001 rows.'
)
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_error_with_invalid_extension(
client_request,
):
page = client_request.post(
'main.upload_contact_list',
service_id=SERVICE_ONE_ID,
_data={'file': (BytesIO(''.encode('utf-8')), 'invalid.txt')},
_follow_redirects=True,
)
assert normalize_spaces(page.select_one('.banner-dangerous').text) == (
"invalid.txt is not a spreadsheet that Notify can read"
)
def test_upload_csv_file_sanitises_and_truncates_file_name_in_metadata(
client_request,
mocker,
mock_s3_upload,
mock_get_job_doesnt_exist,
mock_get_users_by_service,
fake_uuid,
):
mocker.patch('app.models.contact_list.utils_s3upload', return_value=fake_uuid)
mock_set_metadata = mocker.patch('app.models.contact_list.set_s3_metadata')
mocker.patch('app.models.contact_list.get_s3_contents', return_value='\n'.join(
['phone number'] + (['2028675309'] * 100_001)
))
filename = f"😁{'a' * 2000}.csv"
mocker.patch('app.models.contact_list.get_s3_metadata',
return_value={'original_file_name': filename})
client_request.post(
'main.upload_contact_list',
service_id=SERVICE_ONE_ID,
_data={'file': (BytesIO(''.encode('utf-8')), filename)},
_follow_redirects=False
)
assert len(
mock_set_metadata.call_args_list[0][1]['original_file_name']
) < len(filename)
assert mock_set_metadata.call_args_list[0][1]['original_file_name'].startswith('?')
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.utils_s3upload', return_value=fake_uuid)
mocker.patch('app.models.contact_list.get_s3_contents', return_value=(
'phone number\n'
'2028675209' # Not in team
))
mocker.patch('app.models.contact_list.get_s3_metadata',
return_value={'original_file_name': 'invalid.csv'})
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'
)
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.get_s3_contents', return_value='\n'.join(
['email address'] + ['test@example.com'] * 51
))
mocker.patch('app.models.contact_list.get_s3_metadata',
return_value={'original_file_name': 'good times.xlsx'})
mock_metadata_set = mocker.patch('app.models.contact_list.set_s3_metadata')
page = client_request.get(
'main.check_contact_list',
service_id=SERVICE_ONE_ID,
upload_id=fake_uuid,
_test_page_title=False,
)
mock_metadata_set.assert_called_once_with(
mocker.ANY,
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_s3_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.uploads',
service_id=SERVICE_ONE_ID,
)
)
mock_get_metadata.assert_called_once()
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_s3_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
@pytest.mark.parametrize('has_jobs, expected_empty_message', [
(False, 'Not used yet.'),
(True, 'Not used in the last 7 days.'),
])
@freeze_time('2020-06-13 16:51:56')
def test_view_contact_list(
mocker,
client_request,
mock_get_contact_list,
mock_get_no_jobs,
mock_get_service_data_retention,
fake_uuid,
has_jobs,
expected_empty_message,
):
mocker.patch(
'app.models.contact_list.contact_list_api_client.get_contact_list',
return_value=contact_list_json(
created_at='2020-03-03T17:12:12.000000Z',
service_id=SERVICE_ONE_ID,
has_jobs=has_jobs
)
)
mocker.patch('app.models.contact_list.get_s3_contents', return_value='\n'.join(
['email address'] + [
f'test-{i}@example.com' for i in range(51)
]
))
page = client_request.get(
'main.contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
)
mock_get_no_jobs.assert_called_once_with(
SERVICE_ONE_ID,
contact_list_id=fake_uuid,
limit_days=7,
statuses={
'finished',
'in progress',
'pending',
'ready to send',
'scheduled',
'sending limits exceeded',
'sent to dvla',
},
page=1,
)
assert normalize_spaces(page.select_one('h1').text) == (
'EmergencyContactList.xls'
)
assert normalize_spaces(page.select('main p')[0].text) == (
'Uploaded by Test User on 3 March at 12:12pm.'
)
assert normalize_spaces(page.select('main p')[1].text) == (
expected_empty_message
)
assert normalize_spaces(page.select_one('main h2').text) == (
'51 saved email addresses'
)
assert page.select_one('.js-stick-at-bottom-when-scrolling a[download]')['href'] == url_for(
'main.download_contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
)
assert len(page.select('tbody tr')) == 50
assert [
normalize_spaces(page.select('tbody tr')[0].text),
normalize_spaces(page.select('tbody tr')[1].text),
normalize_spaces(page.select('tbody tr')[48].text),
normalize_spaces(page.select('tbody tr')[49].text),
] == [
'test-0@example.com',
'test-1@example.com',
'test-48@example.com',
'test-49@example.com',
]
assert 'test-50@example.com' not in page.select_one('tbody').text
assert normalize_spaces(page.select_one('.table-show-more-link').text) == (
'Only showing the first 50 rows'
)
@freeze_time('2015-12-31 21:51:56')
def test_view_jobs_for_contact_list(
mocker,
client_request,
mock_get_jobs,
mock_get_service_data_retention,
fake_uuid,
):
mocker.patch(
'app.models.contact_list.contact_list_api_client.get_contact_list',
return_value={
'created_at': '2015-12-31 17:12:12',
'created_by': 'Test User',
'id': fake_uuid,
'original_file_name': 'EmergencyContactList.xls',
'row_count': 100,
'recent_job_count': 0,
'has_jobs': True,
'service_id': SERVICE_ONE_ID,
'template_type': 'email',
},
)
mocker.patch('app.models.contact_list.get_s3_contents', 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 12:12pm.'
)
assert normalize_spaces(page.select('main p')[1].text) == (
'Used 6 times in the last 7 days.'
)
assert [
normalize_spaces(row.text)
for row in page.select_one('table').select('tr')
] == [
'Template Status',
(
'Template Y '
'Sending tomorrow at 6:09pm '
'1 text message waiting to send'
),
(
'Template Z '
'Sending tomorrow at 6:09am '
'1 text message waiting to send'
),
(
'Template A '
'Sent today at 4:51pm '
'1 sending 0 delivered 0 failed'
),
(
'Template B '
'Sent today at 4:51pm '
'1 sending 0 delivered 0 failed'
),
(
'Template C '
'Sent today at 4:51pm '
'1 sending 0 delivered 0 failed'
),
(
'Template D '
'Sent today at 4:51pm '
'1 sending 0 delivered 0 failed'
),
]
assert page.select_one('table a')['href'] == url_for(
'main.view_job',
service_id=SERVICE_ONE_ID,
job_id=fake_uuid,
)
def test_view_contact_list_404s_for_non_existing_list(
client_request,
mock_get_no_contact_list,
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,
client_request,
fake_uuid,
mock_get_contact_list,
):
mocker.patch(
'app.models.contact_list.get_s3_contents',
return_value='phone number\n2028675209'
)
response = client_request.get_response(
'main.download_contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
)
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'
'2028675209'
)
def test_confirm_delete_contact_list(
mocker,
client_request,
fake_uuid,
mock_get_jobs,
mock_get_service_data_retention,
mock_get_contact_list,
):
mocker.patch(
'app.models.contact_list.get_s3_contents',
return_value='phone number\n2028675209'
)
page = client_request.get(
'main.delete_contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
)
assert normalize_spaces(page.select_one('.banner-dangerous').text) == (
'Are you sure you want to delete EmergencyContactList.xls? '
'Yes, delete'
)
assert 'action' not in page.select_one('form')
assert page.select_one('form')['method'] == 'post'
assert page.select_one('form button')['type'] == 'submit'
def test_delete_contact_list(
mocker,
client_request,
fake_uuid,
mock_get_contact_list,
):
mock_delete = mocker.patch(
'app.models.contact_list.contact_list_api_client.delete_contact_list'
)
client_request.post(
'main.delete_contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
_expected_redirect=url_for(
'main.uploads',
service_id=SERVICE_ONE_ID,
)
)
mock_delete.assert_called_once_with(
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
)

View File

@@ -1,7 +1,4 @@
import re
import pytest
from flask import url_for
from freezegun import freeze_time
from app.formatters import normalize_spaces
@@ -9,31 +6,9 @@ from tests.conftest import (
SERVICE_ONE_ID,
create_active_caseworking_user,
create_active_user_with_permissions,
create_platform_admin_user,
)
@pytest.mark.skip(reason="Not sure that TTS needs this")
@pytest.mark.parametrize('user', (
create_platform_admin_user(),
create_active_user_with_permissions(),
))
def test_all_users_have_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', (
([], (
'You have not uploaded any files recently.'
@@ -44,7 +19,6 @@ 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,
):
@@ -63,7 +37,6 @@ 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': []})
page = client_request.get('main.uploads', service_id=SERVICE_ONE_ID)
@@ -93,7 +66,6 @@ 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)
@@ -117,53 +89,3 @@ 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,
mock_get_service_data_retention,
):
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 '
'Used twice in the last 7 days '
'123 saved phone numbers'
),
(
'EmergencyContactList.xls '
'Not used in the last 7 days '
'100 saved email addresses'
),
(
'UnusedList.tsv '
'Not used yet '
'1 saved phone number'
),
(
'even_later.csv '
'Sending 1 January 2016 at 6:09pm '
'1 text message waiting to send'
),
(
'send_me_later.csv '
'Sending 1 January 2016 at 6: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',
)