diff --git a/app/config.py b/app/config.py index 65dee5bc3..d38039647 100644 --- a/app/config.py +++ b/app/config.py @@ -150,6 +150,7 @@ class Config(object): CHANGE_EMAIL_CONFIRMATION_TEMPLATE_ID = 'eb4d9930-87ab-4aef-9bce-786762687884' SERVICE_NOW_LIVE_TEMPLATE_ID = '618185c6-3636-49cd-b7d2-6f6f5eb3bdde' ORGANISATION_INVITATION_EMAIL_TEMPLATE_ID = '203566f0-d835-47c5-aa06-932439c86573' + PRECOMPILED_TEMPLATE_NAME = 'Pre-compiled PDF' BROKER_URL = 'sqs://' BROKER_TRANSPORT_OPTIONS = { diff --git a/app/letters/utils.py b/app/letters/utils.py index a7f05c00f..5e7730882 100644 --- a/app/letters/utils.py +++ b/app/letters/utils.py @@ -76,3 +76,7 @@ def get_letter_pdf(notification): file_content = obj.get()["Body"].read() return file_content + + +def is_precompiled_letter(template): + return template.hidden and template.name == current_app.config['PRECOMPILED_TEMPLATE_NAME'] diff --git a/app/template/rest.py b/app/template/rest.py index c0e91c69b..5f36557e0 100644 --- a/app/template/rest.py +++ b/app/template/rest.py @@ -1,10 +1,14 @@ import base64 + +import botocore from flask import ( Blueprint, current_app, jsonify, request) from requests import post as requests_post +from werkzeug.exceptions import abort + from app.dao.notifications_dao import get_notification_by_id from app.dao.templates_dao import ( @@ -18,7 +22,7 @@ from app.dao.templates_dao import ( dao_get_template_by_id) from notifications_utils.template import SMSMessageTemplate from app.dao.services_dao import dao_fetch_service_by_id -from app.letters.utils import get_letter_pdf +from app.letters.utils import get_letter_pdf, is_precompiled_letter from app.models import SMS_TYPE from app.notifications.validators import service_has_permission, check_reply_to from app.schemas import (template_schema, template_history_schema) @@ -196,18 +200,23 @@ def preview_letter_template_by_notification_id(service_id, notification_id, file template = dao_get_template_by_id(notification.template_id) - if template.hidden and template.name == 'Pre-compiled PDF': + if is_precompiled_letter(template): - pdf_file = get_letter_pdf(notification) + try: + + pdf_file = get_letter_pdf(notification) + + except botocore.exceptions.ClientError: + abort(404) content = base64.b64encode(pdf_file).decode('utf-8') if file_type == 'png': - url = '{}//precompiled-preview.png{}'.format( - current_app.config['TEMPLATE_PREVIEW_API_HOST'], - '?page={}'.format(page) if page else '' - ) + url = '{}/precompiled-preview.png{}'.format( + current_app.config['TEMPLATE_PREVIEW_API_HOST'], + '?page={}'.format(page) if page else '' + ) resp = requests_post( url, diff --git a/tests/app/db.py b/tests/app/db.py index 16ff29910..6a09413a8 100644 --- a/tests/app/db.py +++ b/tests/app/db.py @@ -125,12 +125,13 @@ def create_service_with_defined_sms_sender( def create_template( - service, - template_type=SMS_TYPE, - template_name=None, - subject='Template subject', - content='Dear Sir/Madam, Hello. Yours Truly, The Government.', - reply_to=None + service, + template_type=SMS_TYPE, + template_name=None, + subject='Template subject', + content='Dear Sir/Madam, Hello. Yours Truly, The Government.', + reply_to=None, + hidden=False ): data = { 'name': template_name or '{} Template Name'.format(template_type), @@ -139,6 +140,7 @@ def create_template( 'service': service, 'created_by': service.created_by, 'reply_to': reply_to, + 'hidden': hidden } if template_type != SMS_TYPE: data['subject'] = subject diff --git a/tests/app/letters/test_letter_utils.py b/tests/app/letters/test_letter_utils.py new file mode 100644 index 000000000..758c35021 --- /dev/null +++ b/tests/app/letters/test_letter_utils.py @@ -0,0 +1,29 @@ +import pytest +from flask import current_app + +from app.letters.utils import get_bucket_prefix_for_notification, is_precompiled_letter + + +def test_get_bucket_prefix_for_notification_valid_notification(sample_notification): + + bucket_prefix = get_bucket_prefix_for_notification(sample_notification) + + assert bucket_prefix == '{folder}/NOTIFY.{reference}'.format( + folder=sample_notification.created_at.date(), + reference=sample_notification.reference + ).upper() + + +def test_get_bucket_prefix_for_notification_invalid_notification(): + with pytest.raises(AttributeError): + get_bucket_prefix_for_notification(None) + + +def test_is_precompiled_letter_false(sample_letter_template): + assert not is_precompiled_letter(sample_letter_template) + + +def test_is_precompiled_letter_true(sample_letter_template): + sample_letter_template.hidden = True + sample_letter_template.name = current_app.config['PRECOMPILED_TEMPLATE_NAME'] + assert is_precompiled_letter(sample_letter_template) diff --git a/tests/app/template/test_rest.py b/tests/app/template/test_rest.py index db87bb1fb..34192148d 100644 --- a/tests/app/template/test_rest.py +++ b/tests/app/template/test_rest.py @@ -4,6 +4,7 @@ import random import string from datetime import datetime, timedelta +import botocore import pytest from freezegun import freeze_time @@ -16,7 +17,7 @@ from tests.app.conftest import ( sample_template_without_email_permission, sample_template_without_letter_permission, sample_template_without_sms_permission) -from tests.app.db import create_service, create_letter_contact, create_template +from tests.app.db import create_service, create_letter_contact, create_template, create_notification from tests.conftest import set_config_values @@ -874,3 +875,215 @@ def test_preview_letter_template_by_id_template_preview_500( ) assert resp['message'] == 'Error generating preview for {}'.format(sample_letter_notification.id) + + +def test_preview_letter_template_precompiled_pdf_file_type( + notify_api, + client, + admin_request, + sample_service, + mocker +): + + template = create_template(sample_service, + template_type='letter', + template_name='Pre-compiled PDF', + subject='Pre-compiled PDF', + hidden=True) + + notification = create_notification(template) + + with set_config_values(notify_api, { + 'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview', + 'TEMPLATE_PREVIEW_API_KEY': 'test-key' + }): + import requests_mock + with requests_mock.Mocker(): + + content = b'\x00\x01' + + mock_get_letter_pdf = mocker.patch('app.template.rest.get_letter_pdf', return_value=content) + + resp = admin_request.get( + 'template.preview_letter_template_by_notification_id', + service_id=notification.service_id, + notification_id=notification.id, + file_type='pdf' + ) + + assert mock_get_letter_pdf.called_once_with(notification) + assert base64.b64decode(resp['content']) == content + + +def test_preview_letter_template_precompiled_s3_error( + notify_api, + client, + admin_request, + sample_service, + mocker +): + + template = create_template(sample_service, + template_type='letter', + template_name='Pre-compiled PDF', + subject='Pre-compiled PDF', + hidden=True) + + notification = create_notification(template) + + with set_config_values(notify_api, { + 'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview', + 'TEMPLATE_PREVIEW_API_KEY': 'test-key' + }): + import requests_mock + with requests_mock.Mocker(): + + mocker.patch('app.template.rest.get_letter_pdf', + side_effect=botocore.exceptions.ClientError( + {'Error': {'Code': '403', 'Message': 'Unauthorized'}}, + 'GetObject' + )) + + admin_request.get( + 'template.preview_letter_template_by_notification_id', + service_id=notification.service_id, + notification_id=notification.id, + file_type='pdf', + _expected_status=404 + ) + + +def test_preview_letter_template_precompiled_png_file_type( + notify_api, + client, + admin_request, + sample_service, + mocker +): + + template = create_template(sample_service, + template_type='letter', + template_name='Pre-compiled PDF', + subject='Pre-compiled PDF', + hidden=True) + + notification = create_notification(template) + + with set_config_values(notify_api, { + 'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview', + 'TEMPLATE_PREVIEW_API_KEY': 'test-key' + }): + import requests_mock + with requests_mock.Mocker() as request_mock: + + pdf_content = b'\x00\x01' + png_content = b'\x00\x02' + + mock_get_letter_pdf = mocker.patch('app.template.rest.get_letter_pdf', return_value=pdf_content) + + request_mock.post( + 'http://localhost/notifications-template-preview/precompiled-preview.png', + content=png_content, + headers={'X-pdf-page-count': '1'}, + status_code=200 + ) + + resp = admin_request.get( + 'template.preview_letter_template_by_notification_id', + service_id=notification.service_id, + notification_id=notification.id, + file_type='png' + ) + + assert mock_get_letter_pdf.called_once_with(notification) + assert base64.b64decode(resp['content']) == png_content + + +def test_preview_letter_template_precompiled_png_template_preview_500_error( + notify_api, + client, + admin_request, + sample_service, + mocker +): + + template = create_template(sample_service, + template_type='letter', + template_name='Pre-compiled PDF', + subject='Pre-compiled PDF', + hidden=True) + + notification = create_notification(template) + + with set_config_values(notify_api, { + 'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview', + 'TEMPLATE_PREVIEW_API_KEY': 'test-key' + }): + import requests_mock + with requests_mock.Mocker() as request_mock: + + pdf_content = b'\x00\x01' + png_content = b'\x00\x02' + + mocker.patch('app.template.rest.get_letter_pdf', return_value=pdf_content) + + request_mock.post( + 'http://localhost/notifications-template-preview/precompiled-preview.png', + content=png_content, + headers={'X-pdf-page-count': '1'}, + status_code=500 + ) + + admin_request.get( + 'template.preview_letter_template_by_notification_id', + service_id=notification.service_id, + notification_id=notification.id, + file_type='png', + _expected_status=500 + + ) + + +def test_preview_letter_template_precompiled_png_template_preview_400_error( + notify_api, + client, + admin_request, + sample_service, + mocker +): + + template = create_template(sample_service, + template_type='letter', + template_name='Pre-compiled PDF', + subject='Pre-compiled PDF', + hidden=True) + + notification = create_notification(template) + + with set_config_values(notify_api, { + 'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview', + 'TEMPLATE_PREVIEW_API_KEY': 'test-key' + }): + import requests_mock + with requests_mock.Mocker() as request_mock: + + pdf_content = b'\x00\x01' + png_content = b'\x00\x02' + + mocker.patch('app.template.rest.get_letter_pdf', return_value=pdf_content) + + request_mock.post( + 'http://localhost/notifications-template-preview/precompiled-preview.png', + content=png_content, + headers={'X-pdf-page-count': '1'}, + status_code=404 + ) + + admin_request.get( + 'template.preview_letter_template_by_notification_id', + service_id=notification.service_id, + notification_id=notification.id, + file_type='png', + _expected_status=500 + + )