mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-23 15:57:23 -04:00
Merge pull request #3140 from alphagov/store-upload-details-in-metadata
Store all data about uploaded letters in the S3 metadata
This commit is contained in:
@@ -20,6 +20,7 @@ from app.extensions import antivirus_client
|
|||||||
from app.main import main
|
from app.main import main
|
||||||
from app.main.forms import PDFUploadForm
|
from app.main.forms import PDFUploadForm
|
||||||
from app.s3_client.s3_letter_upload_client import (
|
from app.s3_client.s3_letter_upload_client import (
|
||||||
|
get_letter_metadata,
|
||||||
get_letter_pdf_and_metadata,
|
get_letter_pdf_and_metadata,
|
||||||
get_transient_letter_file_location,
|
get_transient_letter_file_location,
|
||||||
upload_letter_to_s3,
|
upload_letter_to_s3,
|
||||||
@@ -43,6 +44,7 @@ def upload_letter(service_id):
|
|||||||
|
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
pdf_file_bytes = form.file.data.read()
|
pdf_file_bytes = form.file.data.read()
|
||||||
|
original_filename = form.file.data.filename
|
||||||
|
|
||||||
virus_free = antivirus_client.scan(BytesIO(pdf_file_bytes))
|
virus_free = antivirus_client.scan(BytesIO(pdf_file_bytes))
|
||||||
if not virus_free:
|
if not virus_free:
|
||||||
@@ -67,22 +69,29 @@ def upload_letter(service_id):
|
|||||||
except RequestException as ex:
|
except RequestException as ex:
|
||||||
if ex.response is not None and ex.response.status_code == 400:
|
if ex.response is not None and ex.response.status_code == 400:
|
||||||
status = 'invalid'
|
status = 'invalid'
|
||||||
upload_letter_to_s3(pdf_file_bytes, file_location, status)
|
upload_letter_to_s3(
|
||||||
|
pdf_file_bytes,
|
||||||
|
file_location=file_location,
|
||||||
|
status=status,
|
||||||
|
page_count=page_count,
|
||||||
|
filename=original_filename)
|
||||||
else:
|
else:
|
||||||
raise ex
|
raise ex
|
||||||
else:
|
else:
|
||||||
status = 'valid'
|
status = 'valid'
|
||||||
file_contents = base64.b64decode(response.json()['file'].encode())
|
file_contents = base64.b64decode(response.json()['file'].encode())
|
||||||
upload_letter_to_s3(file_contents, file_location, status)
|
upload_letter_to_s3(
|
||||||
|
file_contents,
|
||||||
|
file_location=file_location,
|
||||||
|
status=status,
|
||||||
|
page_count=page_count,
|
||||||
|
filename=original_filename)
|
||||||
|
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for(
|
url_for(
|
||||||
'main.uploaded_letter_preview',
|
'main.uploaded_letter_preview',
|
||||||
service_id=current_service.id,
|
service_id=current_service.id,
|
||||||
file_id=upload_id,
|
file_id=upload_id,
|
||||||
original_filename=form.file.data.filename,
|
|
||||||
page_count=page_count,
|
|
||||||
status=status,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -97,9 +106,10 @@ def invalid_upload_error(message):
|
|||||||
@main.route("/services/<service_id>/preview-letter/<file_id>")
|
@main.route("/services/<service_id>/preview-letter/<file_id>")
|
||||||
@user_has_permissions('send_messages')
|
@user_has_permissions('send_messages')
|
||||||
def uploaded_letter_preview(service_id, file_id):
|
def uploaded_letter_preview(service_id, file_id):
|
||||||
original_filename = request.args.get('original_filename')
|
metadata = get_letter_metadata(service_id, file_id)
|
||||||
page_count = request.args.get('page_count')
|
original_filename = metadata.get('filename')
|
||||||
status = request.args.get('status')
|
page_count = metadata.get('page_count')
|
||||||
|
status = metadata.get('status')
|
||||||
|
|
||||||
template_dict = service_api_client.get_precompiled_template(service_id)
|
template_dict = service_api_client.get_precompiled_template(service_id)
|
||||||
|
|
||||||
@@ -126,8 +136,7 @@ def uploaded_letter_preview(service_id, file_id):
|
|||||||
@main.route("/services/<service_id>/preview-letter-image/<file_id>")
|
@main.route("/services/<service_id>/preview-letter-image/<file_id>")
|
||||||
@user_has_permissions('send_messages')
|
@user_has_permissions('send_messages')
|
||||||
def view_letter_upload_as_preview(service_id, file_id):
|
def view_letter_upload_as_preview(service_id, file_id):
|
||||||
file_location = get_transient_letter_file_location(service_id, file_id)
|
pdf_file, metadata = get_letter_pdf_and_metadata(service_id, file_id)
|
||||||
pdf_file, metadata = get_letter_pdf_and_metadata(file_location)
|
|
||||||
|
|
||||||
page = request.args.get('page')
|
page = request.args.get('page')
|
||||||
|
|
||||||
@@ -140,14 +149,12 @@ def view_letter_upload_as_preview(service_id, file_id):
|
|||||||
@main.route("/services/<service_id>/upload-letter/send", methods=['POST'])
|
@main.route("/services/<service_id>/upload-letter/send", methods=['POST'])
|
||||||
@user_has_permissions('send_messages', restrict_admin_usage=True)
|
@user_has_permissions('send_messages', restrict_admin_usage=True)
|
||||||
def send_uploaded_letter(service_id):
|
def send_uploaded_letter(service_id):
|
||||||
filename = request.form['filename']
|
|
||||||
file_id = request.form['file_id']
|
|
||||||
|
|
||||||
if not (current_service.has_permission('letter') and current_service.has_permission('upload_letters')):
|
if not (current_service.has_permission('letter') and current_service.has_permission('upload_letters')):
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
file_location = get_transient_letter_file_location(service_id, file_id)
|
file_id = request.form['file_id']
|
||||||
_, metadata = get_letter_pdf_and_metadata(file_location)
|
metadata = get_letter_metadata(service_id, file_id)
|
||||||
|
filename = metadata.get('filename')
|
||||||
|
|
||||||
if metadata.get('status') != 'valid':
|
if metadata.get('status') != 'valid':
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|||||||
@@ -7,17 +7,22 @@ def get_transient_letter_file_location(service_id, upload_id):
|
|||||||
return 'service-{}/{}.pdf'.format(service_id, upload_id)
|
return 'service-{}/{}.pdf'.format(service_id, upload_id)
|
||||||
|
|
||||||
|
|
||||||
def upload_letter_to_s3(data, file_location, status):
|
def upload_letter_to_s3(data, *, file_location, status, page_count, filename):
|
||||||
utils_s3upload(
|
utils_s3upload(
|
||||||
filedata=data,
|
filedata=data,
|
||||||
region=current_app.config['AWS_REGION'],
|
region=current_app.config['AWS_REGION'],
|
||||||
bucket_name=current_app.config['TRANSIENT_UPLOADED_LETTERS'],
|
bucket_name=current_app.config['TRANSIENT_UPLOADED_LETTERS'],
|
||||||
file_location=file_location,
|
file_location=file_location,
|
||||||
metadata={'status': status}
|
metadata={
|
||||||
|
'status': status,
|
||||||
|
'page_count': str(page_count),
|
||||||
|
'filename': filename,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_letter_pdf_and_metadata(file_location):
|
def get_letter_pdf_and_metadata(service_id, file_id):
|
||||||
|
file_location = get_transient_letter_file_location(service_id, file_id)
|
||||||
s3 = resource('s3')
|
s3 = resource('s3')
|
||||||
s3_object = s3.Object(current_app.config['TRANSIENT_UPLOADED_LETTERS'], file_location).get()
|
s3_object = s3.Object(current_app.config['TRANSIENT_UPLOADED_LETTERS'], file_location).get()
|
||||||
|
|
||||||
@@ -25,3 +30,11 @@ def get_letter_pdf_and_metadata(file_location):
|
|||||||
metadata = s3_object['Metadata']
|
metadata = s3_object['Metadata']
|
||||||
|
|
||||||
return pdf, metadata
|
return pdf, metadata
|
||||||
|
|
||||||
|
|
||||||
|
def get_letter_metadata(service_id, file_id):
|
||||||
|
file_location = get_transient_letter_file_location(service_id, file_id)
|
||||||
|
s3 = resource('s3')
|
||||||
|
s3_object = s3.Object(current_app.config['TRANSIENT_UPLOADED_LETTERS'], file_location).get()
|
||||||
|
|
||||||
|
return s3_object['Metadata']
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
service_id=current_service.id,
|
service_id=current_service.id,
|
||||||
)}}" class='page-footer'>
|
)}}" class='page-footer'>
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||||
<input type="hidden" name="filename" value="{{ original_filename }}" />
|
|
||||||
<input type="hidden" name="file_id" value="{{ file_id }}" />
|
<input type="hidden" name="file_id" value="{{ file_id }}" />
|
||||||
<button type="submit" class="button">Send 1 letter</button>
|
<button type="submit" class="button">Send 1 letter</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ def test_post_upload_letter_redirects_for_valid_file(mocker, client_request):
|
|||||||
return_value=Mock(content='The sanitised content', json=lambda: {'file': 'VGhlIHNhbml0aXNlZCBjb250ZW50'})
|
return_value=Mock(content='The sanitised content', json=lambda: {'file': 'VGhlIHNhbml0aXNlZCBjb250ZW50'})
|
||||||
)
|
)
|
||||||
mock_s3 = mocker.patch('app.main.views.uploads.upload_letter_to_s3')
|
mock_s3 = mocker.patch('app.main.views.uploads.upload_letter_to_s3')
|
||||||
|
mocker.patch('app.main.views.uploads.get_letter_metadata', return_value={
|
||||||
|
'filename': 'tests/test_pdf_files/one_page_pdf.pdf', 'page_count': '1', 'status': 'valid'})
|
||||||
mocker.patch('app.main.views.uploads.service_api_client.get_precompiled_template')
|
mocker.patch('app.main.views.uploads.service_api_client.get_precompiled_template')
|
||||||
|
|
||||||
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
|
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
|
||||||
@@ -46,14 +48,15 @@ def test_post_upload_letter_redirects_for_valid_file(mocker, client_request):
|
|||||||
|
|
||||||
mock_s3.assert_called_once_with(
|
mock_s3.assert_called_once_with(
|
||||||
b'The sanitised content',
|
b'The sanitised content',
|
||||||
'service-{}/fake-uuid.pdf'.format(SERVICE_ONE_ID),
|
file_location='service-{}/fake-uuid.pdf'.format(SERVICE_ONE_ID),
|
||||||
'valid',
|
status='valid',
|
||||||
|
page_count=1,
|
||||||
|
filename='tests/test_pdf_files/one_page_pdf.pdf'
|
||||||
)
|
)
|
||||||
|
|
||||||
assert page.find('h1').text == 'tests/test_pdf_files/one_page_pdf.pdf'
|
assert page.find('h1').text == 'tests/test_pdf_files/one_page_pdf.pdf'
|
||||||
assert not page.find(id='validation-error-message')
|
assert not page.find(id='validation-error-message')
|
||||||
|
|
||||||
assert page.find('input', {'type': 'hidden', 'name': 'filename', 'value': 'tests/test_pdf_files/one_page_pdf.pdf'})
|
|
||||||
assert page.find('input', {'type': 'hidden', 'name': 'file_id', 'value': 'fake-uuid'})
|
assert page.find('input', {'type': 'hidden', 'name': 'file_id', 'value': 'fake-uuid'})
|
||||||
assert page.find('button', {'type': 'submit'}).text == 'Send 1 letter'
|
assert page.find('button', {'type': 'submit'}).text == 'Send 1 letter'
|
||||||
|
|
||||||
@@ -73,6 +76,8 @@ def test_post_upload_letter_shows_letter_preview_for_valid_file(mocker, client_r
|
|||||||
)
|
)
|
||||||
mocker.patch('app.main.views.uploads.upload_letter_to_s3')
|
mocker.patch('app.main.views.uploads.upload_letter_to_s3')
|
||||||
mocker.patch('app.main.views.uploads.pdf_page_count', return_value=3)
|
mocker.patch('app.main.views.uploads.pdf_page_count', return_value=3)
|
||||||
|
mocker.patch('app.main.views.uploads.get_letter_metadata', return_value={
|
||||||
|
'filename': 'tests/test_pdf_files/one_page_pdf.pdf', 'page_count': '3', 'status': 'valid'})
|
||||||
mocker.patch('app.main.views.uploads.service_api_client.get_precompiled_template', return_value=letter_template)
|
mocker.patch('app.main.views.uploads.service_api_client.get_precompiled_template', return_value=letter_template)
|
||||||
|
|
||||||
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
|
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
|
||||||
@@ -170,6 +175,8 @@ def test_post_upload_letter_with_invalid_file(mocker, client_request):
|
|||||||
mock_sanitise_response.raise_for_status.side_effect = RequestException(response=Mock(status_code=400))
|
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)
|
mocker.patch('app.main.views.uploads.sanitise_letter', return_value=mock_sanitise_response)
|
||||||
mocker.patch('app.main.views.uploads.service_api_client.get_precompiled_template')
|
mocker.patch('app.main.views.uploads.service_api_client.get_precompiled_template')
|
||||||
|
mocker.patch('app.main.views.uploads.get_letter_metadata', return_value={
|
||||||
|
'filename': 'tests/test_pdf_files/one_page_pdf.pdf', 'page_count': '1', 'status': 'invalid'})
|
||||||
|
|
||||||
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
|
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
|
||||||
file_contents = file.read()
|
file_contents = file.read()
|
||||||
@@ -184,8 +191,10 @@ def test_post_upload_letter_with_invalid_file(mocker, client_request):
|
|||||||
|
|
||||||
mock_s3.assert_called_once_with(
|
mock_s3.assert_called_once_with(
|
||||||
file_contents,
|
file_contents,
|
||||||
'service-{}/fake-uuid.pdf'.format(SERVICE_ONE_ID),
|
file_location='service-{}/fake-uuid.pdf'.format(SERVICE_ONE_ID),
|
||||||
'invalid',
|
status='invalid',
|
||||||
|
page_count=1,
|
||||||
|
filename='tests/test_pdf_files/one_page_pdf.pdf'
|
||||||
)
|
)
|
||||||
|
|
||||||
assert page.find('h1').text == 'tests/test_pdf_files/one_page_pdf.pdf'
|
assert page.find('h1').text == 'tests/test_pdf_files/one_page_pdf.pdf'
|
||||||
@@ -209,6 +218,8 @@ def test_post_upload_letter_shows_letter_preview_for_invalid_file(mocker, client
|
|||||||
mock_sanitise_response.raise_for_status.side_effect = RequestException(response=Mock(status_code=400))
|
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)
|
mocker.patch('app.main.views.uploads.sanitise_letter', return_value=mock_sanitise_response)
|
||||||
mocker.patch('app.main.views.uploads.service_api_client.get_precompiled_template', return_value=letter_template)
|
mocker.patch('app.main.views.uploads.service_api_client.get_precompiled_template', return_value=letter_template)
|
||||||
|
mocker.patch('app.main.views.uploads.get_letter_metadata', return_value={
|
||||||
|
'filename': 'tests/test_pdf_files/one_page_pdf.pdf', 'page_count': '1', 'status': 'invalid'})
|
||||||
|
|
||||||
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
|
with open('tests/test_pdf_files/one_page_pdf.pdf', 'rb') as file:
|
||||||
page = client_request.post(
|
page = client_request.post(
|
||||||
@@ -253,6 +264,8 @@ def test_post_upload_letter_does_not_upload_to_s3_if_template_preview_raises_unk
|
|||||||
|
|
||||||
def test_uploaded_letter_preview(mocker, client_request):
|
def test_uploaded_letter_preview(mocker, client_request):
|
||||||
mocker.patch('app.main.views.uploads.service_api_client')
|
mocker.patch('app.main.views.uploads.service_api_client')
|
||||||
|
mocker.patch('app.main.views.uploads.get_letter_metadata', return_value={
|
||||||
|
'filename': 'my_letter.pdf', 'page_count': '1', 'status': 'valid'})
|
||||||
|
|
||||||
page = client_request.get(
|
page = client_request.get(
|
||||||
'main.uploaded_letter_preview',
|
'main.uploaded_letter_preview',
|
||||||
@@ -268,8 +281,11 @@ def test_uploaded_letter_preview(mocker, client_request):
|
|||||||
|
|
||||||
|
|
||||||
def test_send_uploaded_letter_sends_letter_and_redirects_to_notification_page(mocker, service_one, client_request):
|
def test_send_uploaded_letter_sends_letter_and_redirects_to_notification_page(mocker, service_one, client_request):
|
||||||
mocker.patch('app.main.views.uploads.get_letter_pdf_and_metadata', return_value=('file', {'status': 'valid'}))
|
metadata = {'filename': 'my_file.pdf', 'page_count': '1', 'status': 'valid'}
|
||||||
|
|
||||||
|
mocker.patch('app.main.views.uploads.get_letter_pdf_and_metadata', return_value=('file', metadata))
|
||||||
mock_send = mocker.patch('app.main.views.uploads.notification_api_client.send_precompiled_letter')
|
mock_send = mocker.patch('app.main.views.uploads.notification_api_client.send_precompiled_letter')
|
||||||
|
mocker.patch('app.main.views.uploads.get_letter_metadata', return_value=metadata)
|
||||||
|
|
||||||
service_one['permissions'] = ['letter', 'upload_letters']
|
service_one['permissions'] = ['letter', 'upload_letters']
|
||||||
file_id = 'abcd-1234'
|
file_id = 'abcd-1234'
|
||||||
@@ -315,8 +331,11 @@ def test_send_uploaded_letter_when_service_does_not_have_correct_permissions(
|
|||||||
|
|
||||||
|
|
||||||
def test_send_uploaded_letter_when_metadata_states_pdf_is_invalid(mocker, service_one, client_request):
|
def test_send_uploaded_letter_when_metadata_states_pdf_is_invalid(mocker, service_one, client_request):
|
||||||
mocker.patch('app.main.views.uploads.get_letter_pdf_and_metadata', return_value=('file', {'status': 'invalid'}))
|
|
||||||
mock_send = mocker.patch('app.main.views.uploads.notification_api_client.send_precompiled_letter')
|
mock_send = mocker.patch('app.main.views.uploads.notification_api_client.send_precompiled_letter')
|
||||||
|
mocker.patch(
|
||||||
|
'app.main.views.uploads.get_letter_metadata',
|
||||||
|
return_value={'filename': 'my_file.pdf', 'page_count': '3', 'status': 'invalid'}
|
||||||
|
)
|
||||||
|
|
||||||
service_one['permissions'] = ['letter', 'upload_letters']
|
service_one['permissions'] = ['letter', 'upload_letters']
|
||||||
file_id = 'abcd-1234'
|
file_id = 'abcd-1234'
|
||||||
|
|||||||
@@ -6,12 +6,17 @@ from app.s3_client.s3_letter_upload_client import upload_letter_to_s3
|
|||||||
def test_upload_letter_to_s3(mocker):
|
def test_upload_letter_to_s3(mocker):
|
||||||
s3_mock = mocker.patch('app.s3_client.s3_letter_upload_client.utils_s3upload')
|
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')
|
upload_letter_to_s3(
|
||||||
|
'pdf_data',
|
||||||
|
file_location='service_id/upload_id.pdf',
|
||||||
|
status='valid',
|
||||||
|
page_count=3,
|
||||||
|
filename='my_doc')
|
||||||
|
|
||||||
s3_mock.assert_called_once_with(
|
s3_mock.assert_called_once_with(
|
||||||
bucket_name=current_app.config['TRANSIENT_UPLOADED_LETTERS'],
|
bucket_name=current_app.config['TRANSIENT_UPLOADED_LETTERS'],
|
||||||
file_location='service_id/upload_id.pdf',
|
file_location='service_id/upload_id.pdf',
|
||||||
filedata='pdf_data',
|
filedata='pdf_data',
|
||||||
metadata={'status': 'valid'},
|
metadata={'status': 'valid', 'page_count': '3', 'filename': 'my_doc'},
|
||||||
region=current_app.config['AWS_REGION']
|
region=current_app.config['AWS_REGION']
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user