diff --git a/app/main/forms.py b/app/main/forms.py index 18ea30058..27146b068 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -1109,9 +1109,9 @@ class ServiceLetterBrandingDetails(StripWhitespaceForm): class PDFUploadForm(StripWhitespaceForm): file = FileField_wtf( - 'Upload a letter in PDF format to check if it fits in the printable area', + 'Upload a letter in PDF format', validators=[ - FileAllowed(['pdf'], 'PDF documents only!'), + FileAllowed(['pdf'], 'Letters must be saved as a PDF'), DataRequired(message="You need to upload a file to submit") ] ) diff --git a/app/main/views/uploads.py b/app/main/views/uploads.py index 4fe8efc36..f35ae95f9 100644 --- a/app/main/views/uploads.py +++ b/app/main/views/uploads.py @@ -1,6 +1,10 @@ -from flask import render_template +import uuid +from flask import redirect, render_template, request, url_for + +from app import current_service from app.main import main +from app.main.forms import PDFUploadForm from app.utils import user_has_permissions @@ -8,3 +12,31 @@ from app.utils import user_has_permissions @user_has_permissions('send_messages') def uploads(service_id): return render_template('views/uploads/index.html') + + +@main.route("/services//upload-letter", methods=['GET', 'POST']) +@user_has_permissions('send_messages') +def upload_letter(service_id): + form = PDFUploadForm() + + if form.validate_on_submit(): + upload_id = uuid.uuid4() + + return redirect( + url_for( + 'main.uploaded_letter_preview', + service_id=current_service.id, + file_id=upload_id, + original_filename=form.file.data.filename, + ) + ) + + return render_template('views/uploads/choose-file.html', form=form) + + +@main.route("/services//preview-letter/") +@user_has_permissions('send_messages') +def uploaded_letter_preview(service_id, file_id): + original_filename = request.args.get('original_filename') + + return render_template('views/uploads/preview.html', original_filename=original_filename) diff --git a/app/navigation.py b/app/navigation.py index fe05bcd40..39b937dd4 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -304,6 +304,8 @@ class HeaderNavigation(Navigation): 'template_history', 'template_usage', 'trial_mode', + 'upload_letter', + 'uploaded_letter_preview', 'uploads', 'usage', 'view_job', @@ -365,6 +367,8 @@ class MainNavigation(Navigation): 'view_template_versions', }, 'uploads': { + 'upload_letter', + 'uploaded_letter_preview', 'uploads', }, 'team-members': { @@ -859,6 +863,8 @@ class CaseworkNavigation(Navigation): 'two_factor_email_sent', 'update_email_branding', 'update_letter_branding', + 'upload_letter', + 'uploaded_letter_preview', 'uploads', 'usage', 'usage_for_all_services', @@ -1138,6 +1144,8 @@ class OrgNavigation(Navigation): 'two_factor_email_sent', 'update_email_branding', 'update_letter_branding', + 'upload_letter', + 'uploaded_letter_preview', 'uploads', 'usage', 'usage_for_all_services', diff --git a/app/templates/views/uploads/choose-file.html b/app/templates/views/uploads/choose-file.html new file mode 100644 index 000000000..435081ac9 --- /dev/null +++ b/app/templates/views/uploads/choose-file.html @@ -0,0 +1,28 @@ +{% extends "withnav_template.html" %} +{% from "components/file-upload.html" import file_upload %} +{% from "components/page-header.html" import page_header %} + +{% block service_page_title %} + Upload a letter +{% endblock %} + +{% block maincolumn_content %} +
+
+ {{ page_header( + 'Upload a letter', + back_link=url_for('main.uploads', service_id=current_service.id) + ) }} + +

+ {{ file_upload( + form.file, + action = url_for('main.upload_letter', service_id=current_service.id), + )}} +

+

You can upload a single letter as a PDF.

+

Your file must meet our letter specification.

+ +
+
+{% endblock %} diff --git a/app/templates/views/uploads/index.html b/app/templates/views/uploads/index.html index 9e5ff2bd7..0b2ad0480 100644 --- a/app/templates/views/uploads/index.html +++ b/app/templates/views/uploads/index.html @@ -7,10 +7,12 @@ {% block maincolumn_content %}
-
+
{{ page_header('Uploads') }}

Upload a letter and Notify will print, pack and post it for you.

+ + Upload a letter
{% endblock %} diff --git a/app/templates/views/uploads/preview.html b/app/templates/views/uploads/preview.html new file mode 100644 index 000000000..fe14c5bb6 --- /dev/null +++ b/app/templates/views/uploads/preview.html @@ -0,0 +1,14 @@ +{% extends "withnav_template.html" %} +{% from "components/page-header.html" import page_header %} + +{% block service_page_title %} + {{ original_filename }} +{% endblock %} + +{% block maincolumn_content %} + {{ page_header( + original_filename, + back_link=url_for('main.upload_letter', service_id=current_service.id) + ) }} + +{% endblock %} diff --git a/tests/app/main/views/test_platform_admin.py b/tests/app/main/views/test_platform_admin.py index 4f72fe549..114e297ce 100644 --- a/tests/app/main/views/test_platform_admin.py +++ b/tests/app/main/views/test_platform_admin.py @@ -805,7 +805,7 @@ def test_letter_validation_preview_doesnt_call_template_preview_when_file_not_pd antivirus_scan.assert_not_called() validate_letter.assert_not_called() page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') - assert page.find('span', class_='error-message').text.strip() == "PDF documents only!" + assert page.find('span', class_='error-message').text.strip() == "Letters must be saved as a PDF" def test_letter_validation_preview_doesnt_call_template_preview_when_file_doesnt_pass_virus_scan( diff --git a/tests/app/main/views/test_uploads.py b/tests/app/main/views/test_uploads.py index e33965eea..d02b65a9e 100644 --- a/tests/app/main/views/test_uploads.py +++ b/tests/app/main/views/test_uploads.py @@ -1,5 +1,70 @@ +from flask import url_for + from tests.conftest import SERVICE_ONE_ID def test_get_upload_hub_page(client_request): - client_request.get('main.uploads', service_id=SERVICE_ONE_ID) + page = client_request.get('main.uploads', service_id=SERVICE_ONE_ID) + + assert page.find('h1').text == 'Uploads' + assert page.find('a', text='Upload a letter').attrs['href'] == url_for( + 'main.upload_letter', service_id=SERVICE_ONE_ID + ) + + +def test_get_upload_letter(client_request): + page = client_request.get('main.upload_letter', service_id=SERVICE_ONE_ID) + + assert page.find('h1').text == 'Upload a letter' + assert page.find('input', class_='file-upload-field') + assert page.select('button[type=submit]') + + +def test_post_upload_letter_redirects_for_valid_file(mocker, client_request): + mocker.patch('uuid.uuid4', return_value='fake-uuid') + + 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}, + _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 + ) + ) + + +def test_post_upload_letter_shows_error_when_file_is_not_a_pdf(client_request): + with open('tests/non_spreadsheet_files/actually_a_png.csv', 'rb') as file: + page = client_request.post( + 'main.upload_letter', + service_id=SERVICE_ONE_ID, + _data={'file': file}, + _expected_status=200 + ) + assert page.find('span', class_='error-message').text.strip() == "Letters must be saved as a PDF" + + +def test_post_upload_letter_shows_error_when_no_file_uploaded(client_request): + page = client_request.post( + 'main.upload_letter', + service_id=SERVICE_ONE_ID, + _data={'file': ''}, + _expected_status=200 + ) + assert page.find('span', class_='error-message').text.strip() == "You need to upload a file to submit" + + +def test_uploaded_letter_preview(client_request): + page = client_request.get( + 'main.uploaded_letter_preview', + service_id=SERVICE_ONE_ID, + file_id='fake-uuid', + original_filename='my_letter.pdf', + ) + + assert page.find('h1').text == 'my_letter.pdf'