Sanitise uploaded letters and store in S3

This sanitises uploaded letters and stores the sanitised result in S3
with if it passes validation or the original PDF in S3 if validation
fails. A metadata value of 'status' is set to either 'valid' or
'invalid'.
This commit is contained in:
Katie Smith
2019-09-06 17:10:48 +01:00
parent 5fa9e071c7
commit 8a322b844b
8 changed files with 161 additions and 11 deletions

View File

@@ -1,4 +1,8 @@
from unittest.mock import Mock
import pytest
from flask import url_for
from requests import RequestException
from app.utils import normalize_spaces
from tests.conftest import SERVICE_ONE_ID
@@ -24,21 +28,26 @@ def test_get_upload_letter(client_request):
def test_post_upload_letter_redirects_for_valid_file(mocker, client_request):
mocker.patch('uuid.uuid4', return_value='fake-uuid')
antivirus_mock = mocker.patch('app.main.views.uploads.antivirus_client.scan', return_value=True)
mocker.patch('app.main.views.uploads.sanitise_letter', return_value=Mock(content='The sanitised content'))
mock_s3 = mocker.patch('app.main.views.uploads.upload_letter_to_s3')
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
client_request.post(
page = client_request.post(
'main.upload_letter',
service_id=SERVICE_ONE_ID,
_data={'file': file},
_expected_redirect=url_for(
'main.uploaded_letter_preview',
service_id=SERVICE_ONE_ID,
file_id='fake-uuid',
original_filename='tests/test_pdf_files/one_page_pdf.pdf',
_external=True
)
_follow_redirects=True,
)
assert antivirus_mock.called
assert antivirus_mock.called
mock_s3.assert_called_once_with(
'The sanitised content',
'service-{}/fake-uuid.pdf'.format(SERVICE_ONE_ID),
'valid',
)
assert page.find('h1').text == 'tests/test_pdf_files/one_page_pdf.pdf'
assert not page.find(id='validation-error-message')
def test_post_upload_letter_shows_error_when_file_is_not_a_pdf(client_request):
@@ -104,6 +113,57 @@ def test_post_choose_upload_file_when_file_is_malformed(mocker, client_request):
assert normalize_spaces(page.select('.banner-dangerous')[0].text) == 'Your file must be a valid PDF'
def test_post_upload_letter_with_invalid_file(mocker, client_request):
mocker.patch('uuid.uuid4', return_value='fake-uuid')
mocker.patch('app.main.views.uploads.antivirus_client.scan', return_value=True)
mock_s3 = mocker.patch('app.main.views.uploads.upload_letter_to_s3')
mock_sanitise_response = Mock()
mock_sanitise_response.raise_for_status.side_effect = RequestException(response=Mock(status_code=400))
mocker.patch('app.main.views.uploads.sanitise_letter', return_value=mock_sanitise_response)
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
file_contents = file.read()
file.seek(0)
page = client_request.post(
'main.upload_letter',
service_id=SERVICE_ONE_ID,
_data={'file': file},
_follow_redirects=True
)
mock_s3.assert_called_once_with(
file_contents,
'service-{}/fake-uuid.pdf'.format(SERVICE_ONE_ID),
'invalid',
)
assert page.find('h1').text == 'tests/test_pdf_files/one_page_pdf.pdf'
assert normalize_spaces(
page.find(id='validation-error-message').text
) == 'Validation failed'
def test_post_upload_letter_does_not_upload_to_s3_if_template_preview_raises_unknown_error(mocker, client_request):
mocker.patch('uuid.uuid4', return_value='fake-uuid')
mocker.patch('app.main.views.uploads.antivirus_client.scan', return_value=True)
mock_s3 = mocker.patch('app.main.views.uploads.upload_letter_to_s3')
mocker.patch('app.main.views.uploads.sanitise_letter', side_effect=RequestException())
with pytest.raises(RequestException):
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
client_request.post(
'main.upload_letter',
service_id=SERVICE_ONE_ID,
_data={'file': file},
_follow_redirects=True
)
assert not mock_s3.called
def test_uploaded_letter_preview(client_request):
page = client_request.get(
'main.uploaded_letter_preview',

View File

@@ -0,0 +1,17 @@
from flask import current_app
from app.s3_client.s3_letter_upload_client import upload_letter_to_s3
def test_upload_letter_to_s3(mocker):
s3_mock = mocker.patch('app.s3_client.s3_letter_upload_client.utils_s3upload')
upload_letter_to_s3('pdf_data', 'service_id/upload_id.pdf', 'valid')
s3_mock.assert_called_once_with(
bucket_name=current_app.config['TRANSIENT_UPLOADED_LETTERS'],
file_location='service_id/upload_id.pdf',
filedata='pdf_data',
metadata={'status': 'valid'},
region=current_app.config['AWS_REGION']
)

View File

@@ -4,7 +4,11 @@ from unittest.mock import Mock
import pytest
from notifications_utils.template import LetterPreviewTemplate
from app.template_previews import TemplatePreview, get_page_count_for_letter
from app.template_previews import (
TemplatePreview,
get_page_count_for_letter,
sanitise_letter,
)
@pytest.mark.parametrize('partial_call, expected_page_argument', [
@@ -119,3 +123,15 @@ def test_from_example_template_makes_request(mocker):
'filename': filename,
'letter_contact_block': None}
)
def test_sanitise_letter_calls_template_preview_sanitise_endoint_with_file(mocker):
request_mock = mocker.patch('app.template_previews.requests.post')
sanitise_letter('pdf_data')
request_mock.assert_called_once_with(
'http://localhost:9999/precompiled/sanitise',
headers={'Authorization': 'Token my-secret-key'},
data='pdf_data'
)