From 14a1d499fa44fd7cddda9b6430bddf7423bc1534 Mon Sep 17 00:00:00 2001 From: stvnrlly Date: Wed, 7 Dec 2022 22:17:01 -0500 Subject: [PATCH] remove letters from app/template --- app/dao/templates_dao.py | 25 - app/service/send_notification.py | 91 +--- app/template/rest.py | 139 +---- app/template/template_schemas.py | 2 +- app/v2/notifications/post_notifications.py | 92 ++-- tests/app/template/test_rest.py | 584 --------------------- 6 files changed, 41 insertions(+), 892 deletions(-) diff --git a/app/dao/templates_dao.py b/app/dao/templates_dao.py index fb669565f..dc586d26a 100644 --- a/app/dao/templates_dao.py +++ b/app/dao/templates_dao.py @@ -132,28 +132,3 @@ def dao_get_template_versions(service_id, template_id): ).order_by( desc(TemplateHistory.version) ).all() - - -def get_precompiled_letter_template(service_id): - template = Template.query.filter_by( - service_id=service_id, - template_type=LETTER_TYPE, - hidden=True - ).first() - if template is not None: - return template - - template = Template( - name='Pre-compiled PDF', - created_by=get_user_by_id(current_app.config['NOTIFY_USER_ID']), - service_id=service_id, - template_type=LETTER_TYPE, - hidden=True, - subject='Pre-compiled PDF', - content='', - postage=SECOND_CLASS - ) - - dao_create_template(template) - - return template diff --git a/app/service/send_notification.py b/app/service/send_notification.py index 28208eea8..3884f9978 100644 --- a/app/service/send_notification.py +++ b/app/service/send_notification.py @@ -1,30 +1,13 @@ -import urllib - -from flask import current_app -from notifications_utils.s3 import S3ObjectNotFound -from notifications_utils.s3 import s3download as utils_s3download from sqlalchemy.orm.exc import NoResultFound from app import create_random_identifier from app.config import QueueNames -from app.dao.notifications_dao import ( - _update_notification_status, - get_notification_by_id, -) +from app.dao.notifications_dao import _update_notification_status from app.dao.service_email_reply_to_dao import dao_get_reply_to_by_id from app.dao.service_sms_sender_dao import dao_get_service_sms_senders_by_id from app.dao.services_dao import dao_fetch_service_by_id -from app.dao.templates_dao import ( - dao_get_template_by_id_and_service_id, - get_precompiled_letter_template, -) +from app.dao.templates_dao import dao_get_template_by_id_and_service_id from app.dao.users_dao import get_user_by_id -from app.letters.utils import ( - generate_letter_pdf_filename, - get_billable_units_for_letter_page_count, - get_page_count, - move_uploaded_pdf_to_letters_bucket, -) from app.models import ( EMAIL_TYPE, KEY_TYPE_NORMAL, @@ -38,7 +21,6 @@ from app.notifications.process_notifications import ( send_notification_to_queue, ) from app.notifications.validators import ( - check_service_has_permission, check_service_over_daily_message_limit, validate_address, validate_and_format_recipient, @@ -151,72 +133,3 @@ def get_reply_to_text(notification_type, sender_id, service, template): else: reply_to = template.get_reply_to_text() return reply_to - - -def send_pdf_letter_notification(service_id, post_data): - service = dao_fetch_service_by_id(service_id) - - check_service_has_permission(LETTER_TYPE, [ - p.permission for p in service.permissions - ]) - check_service_over_daily_message_limit(KEY_TYPE_NORMAL, service) - validate_created_by(service, post_data['created_by']) - validate_and_format_recipient( - send_to=post_data['recipient_address'], - key_type=KEY_TYPE_NORMAL, - service=service, - notification_type=LETTER_TYPE, - allow_guest_list_recipients=False, - ) - - # notification already exists e.g. if the user clicked send in different tabs - if get_notification_by_id(post_data['file_id']): - return {'id': str(post_data['file_id'])} - - template = get_precompiled_letter_template(service.id) - file_location = 'service-{}/{}.pdf'.format(service.id, post_data['file_id']) - - try: - letter = utils_s3download(current_app.config['TRANSIENT_UPLOADED_LETTERS'], file_location) - except S3ObjectNotFound as e: - current_app.logger.warning('Letter {}.pdf not in transient {} bucket'.format( - post_data['file_id'], current_app.config['TRANSIENT_UPLOADED_LETTERS']) - ) - - raise e - - # Getting the page count won't raise an error since admin has already checked the PDF is valid - page_count = get_page_count(letter.read()) - billable_units = get_billable_units_for_letter_page_count(page_count) - - personalisation = { - 'address_line_1': post_data['filename'] - } - - notification = persist_notification( - notification_id=post_data['file_id'], - template_id=template.id, - template_version=template.version, - recipient=urllib.parse.unquote(post_data['recipient_address']), - service=service, - personalisation=personalisation, - notification_type=LETTER_TYPE, - api_key_id=None, - key_type=KEY_TYPE_NORMAL, - reference=create_one_off_reference(LETTER_TYPE), - client_reference=post_data['filename'], - created_by_id=post_data['created_by'], - billable_units=billable_units, - postage=post_data['postage'] or template.postage, - ) - - upload_filename = generate_letter_pdf_filename( - reference=notification.reference, - created_at=notification.created_at, - ignore_folder=False, - postage=notification.postage - ) - - move_uploaded_pdf_to_letters_bucket(file_location, upload_filename) - - return {'id': str(notification.id)} diff --git a/app/template/rest.py b/app/template/rest.py index 271458f76..9280e7dc9 100644 --- a/app/template/rest.py +++ b/app/template/rest.py @@ -1,16 +1,8 @@ -import base64 -from io import BytesIO - -import botocore -from flask import Blueprint, current_app, jsonify, request +from flask import Blueprint, jsonify, request from notifications_utils import SMS_CHAR_COUNT_LIMIT -from notifications_utils.pdf import extract_page_from_pdf from notifications_utils.template import SMSMessageTemplate -from PyPDF2.errors import PdfReadError -from requests import post as requests_post from sqlalchemy.orm.exc import NoResultFound -from app.dao.notifications_dao import get_notification_by_id from app.dao.services_dao import dao_fetch_service_by_id from app.dao.template_folder_dao import ( dao_get_template_folder_by_id_and_service_id, @@ -18,17 +10,14 @@ from app.dao.template_folder_dao import ( from app.dao.templates_dao import ( dao_create_template, dao_get_all_templates_for_service, - dao_get_template_by_id, dao_get_template_by_id_and_service_id, dao_get_template_versions, dao_redact_template, dao_update_template, dao_update_template_reply_to, - get_precompiled_letter_template, ) from app.errors import InvalidRequest, register_errors -from app.letters.utils import get_letter_pdf_and_metadata -from app.models import LETTER_TYPE, SECOND_CLASS, SMS_TYPE, Template +from app.models import SMS_TYPE, Template from app.notifications.validators import check_reply_to, service_has_permission from app.schema_validation import validate from app.schemas import ( @@ -84,9 +73,6 @@ def create_template(service_id): errors = {'template_type': [message]} raise InvalidRequest(errors, 403) - if not new_template.postage and new_template.template_type == LETTER_TYPE: - new_template.postage = SECOND_CLASS - new_template.service = fetched_service over_limit = _content_count_greater_than_limit(new_template.content, new_template.template_type) @@ -151,14 +137,6 @@ def update_template(service_id, template_id): return jsonify(data=template_schema.dump(update_dict)), 200 -@template_blueprint.route('/precompiled', methods=['GET']) -def get_precompiled_template_for_service(service_id): - template = get_precompiled_letter_template(service_id) - template_dict = template_schema.dump(template) - - return jsonify(template_dict), 200 - - @template_blueprint.route('', methods=['GET']) def get_all_templates_for_service(service_id): templates = dao_get_all_templates_for_service(service_id=service_id) @@ -236,116 +214,3 @@ def redact_template(template, data): if not template.redact_personalisation: dao_redact_template(template, data['created_by']) return 'null', 200 - - -@template_blueprint.route('/preview//', methods=['GET']) -def preview_letter_template_by_notification_id(service_id, notification_id, file_type): - if file_type not in ('pdf', 'png'): - raise InvalidRequest({'content': ["file_type must be pdf or png"]}, status_code=400) - - page = request.args.get('page') - - notification = get_notification_by_id(notification_id) - template = dao_get_template_by_id(notification.template_id, notification.template_version) - metadata = {} - - if template.is_precompiled_letter: - try: - - pdf_file, metadata = get_letter_pdf_and_metadata(notification) - - except botocore.exceptions.ClientError as e: - raise InvalidRequest( - 'Error extracting requested page from PDF file for notification_id {} type {} {}'.format( - notification_id, type(e), e), - status_code=500 - ) - - page_number = page if page else "1" - content = base64.b64encode(pdf_file).decode('utf-8') - content_outside_printable_area = metadata.get("message") == "content-outside-printable-area" - page_is_in_invalid_pages = page_number in metadata.get('invalid_pages', '[]') - - if content_outside_printable_area and (file_type == "pdf" or page_is_in_invalid_pages): - path = '/precompiled/overlay.{}'.format(file_type) - query_string = '?page_number={}'.format(page_number) if file_type == 'png' else '' - content = pdf_file - elif file_type == 'png': - query_string = '?hide_notify=true' if page_number == '1' else '' - path = '/precompiled-preview.png' - else: - path = None - - if file_type == 'png': - try: - pdf_page = extract_page_from_pdf(BytesIO(pdf_file), int(page_number) - 1) - if content_outside_printable_area and page_is_in_invalid_pages: - content = pdf_page - else: - content = base64.b64encode(pdf_page).decode('utf-8') - except PdfReadError as e: - raise InvalidRequest( - 'Error extracting requested page from PDF file for notification_id {} type {} {}'.format( - notification_id, type(e), e), - status_code=500 - ) - - if path: - url = current_app.config['TEMPLATE_PREVIEW_API_HOST'] + path + query_string - response_content = _get_png_preview_or_overlaid_pdf(url, content, notification.id, json=False) - else: - response_content = content - else: - - template_for_letter_print = { - "id": str(notification.template_id), - "subject": template.subject, - "content": template.content, - "version": str(template.version), - "template_type": template.template_type - } - - service = dao_fetch_service_by_id(service_id) - letter_logo_filename = service.letter_branding and service.letter_branding.filename - data = { - 'letter_contact_block': notification.reply_to_text, - 'template': template_for_letter_print, - 'values': notification.personalisation, - 'date': notification.created_at.isoformat(), - 'filename': letter_logo_filename, - } - - url = '{}/preview.{}{}'.format( - current_app.config['TEMPLATE_PREVIEW_API_HOST'], - file_type, - '?page={}'.format(page) if page else '' - ) - response_content = _get_png_preview_or_overlaid_pdf(url, data, notification.id, json=True) - - return jsonify({"content": response_content, "metadata": metadata}) - - -def _get_png_preview_or_overlaid_pdf(url, data, notification_id, json=True): - if json: - resp = requests_post( - url, - json=data, - headers={'Authorization': 'Token {}'.format(current_app.config['TEMPLATE_PREVIEW_API_KEY'])} - ) - else: - resp = requests_post( - url, - data=data, - headers={'Authorization': 'Token {}'.format(current_app.config['TEMPLATE_PREVIEW_API_KEY'])} - ) - - if resp.status_code != 200: - raise InvalidRequest( - 'Error generating preview letter for {} Status code: {} {}'.format( - notification_id, - resp.status_code, - resp.content - ), status_code=500 - ) - - return base64.b64encode(resp.content).decode('utf-8') diff --git a/app/template/template_schemas.py b/app/template/template_schemas.py index fb38de232..72edb1cfa 100644 --- a/app/template/template_schemas.py +++ b/app/template/template_schemas.py @@ -19,7 +19,7 @@ post_create_template_schema = { }, "if": { "properties": { - "template_type": {"enum": ["email", "letter"]} + "template_type": {"enum": ["email"]} } }, "then": {"required": ["subject"]}, diff --git a/app/v2/notifications/post_notifications.py b/app/v2/notifications/post_notifications.py index f3d127baa..d41d676eb 100644 --- a/app/v2/notifications/post_notifications.py +++ b/app/v2/notifications/post_notifications.py @@ -19,7 +19,6 @@ from app.celery.tasks import save_api_email, save_api_sms from app.clients.document_download import DocumentDownloadError from app.config import QueueNames, TaskNames from app.dao.dao_utils import transaction -from app.dao.templates_dao import get_precompiled_letter_template from app.letters.utils import upload_letter_pdf from app.models import ( EMAIL_TYPE, @@ -66,7 +65,6 @@ from app.v2.notifications.create_response import ( from app.v2.notifications.notification_schemas import ( post_email_request, post_letter_request, - post_precompiled_letter_request, post_sms_request, ) from app.v2.utils import get_valid_json @@ -77,38 +75,39 @@ POST_NOTIFICATION_JSON_PARSE_DURATION_SECONDS = Histogram( ) -@v2_notification_blueprint.route('/{}'.format(LETTER_TYPE), methods=['POST']) -def post_precompiled_letter_notification(): - request_json = get_valid_json() - if 'content' not in (request_json or {}): - return post_notification(LETTER_TYPE) +# TODO: return deprecation message +# @v2_notification_blueprint.route('/{}'.format(LETTER_TYPE), methods=['POST']) +# def post_precompiled_letter_notification(): +# request_json = get_valid_json() +# if 'content' not in (request_json or {}): +# return post_notification(LETTER_TYPE) - form = validate(request_json, post_precompiled_letter_request) +# form = validate(request_json, post_precompiled_letter_request) - # Check permission to send letters - check_service_has_permission(LETTER_TYPE, authenticated_service.permissions) +# # Check permission to send letters +# check_service_has_permission(LETTER_TYPE, authenticated_service.permissions) - check_rate_limiting(authenticated_service, api_user) +# check_rate_limiting(authenticated_service, api_user) - template = get_precompiled_letter_template(authenticated_service.id) +# template = get_precompiled_letter_template(authenticated_service.id) - # For precompiled letters the to field will be set to Provided as PDF until the validation passes, - # then the address of the letter will be set as the to field - form['personalisation'] = { - 'address_line_1': 'Provided as PDF' - } +# # For precompiled letters the to field will be set to Provided as PDF until the validation passes, +# # then the address of the letter will be set as the to field +# form['personalisation'] = { +# 'address_line_1': 'Provided as PDF' +# } - notification = process_letter_notification( - letter_data=form, - api_key=api_user, - service=authenticated_service, - template=template, - template_with_content=None, # not required for precompiled - reply_to_text='', # not required for precompiled - precompiled=True - ) +# notification = process_letter_notification( +# letter_data=form, +# api_key=api_user, +# service=authenticated_service, +# template=template, +# template_with_content=None, # not required for precompiled +# reply_to_text='', # not required for precompiled +# precompiled=True +# ) - return jsonify(notification), 201 +# return jsonify(notification), 201 @v2_notification_blueprint.route('/', methods=['POST']) @@ -120,8 +119,6 @@ def post_notification(notification_type): form = validate(request_json, post_email_request) elif notification_type == SMS_TYPE: form = validate(request_json, post_sms_request) - elif notification_type == LETTER_TYPE: - form = validate(request_json, post_letter_request) else: abort(404) @@ -139,25 +136,16 @@ def post_notification(notification_type): reply_to = get_reply_to_text(notification_type, form, template) - if notification_type == LETTER_TYPE: - notification = process_letter_notification( - letter_data=form, - api_key=api_user, - service=authenticated_service, - template=template, - template_with_content=template_with_content, - reply_to_text=reply_to - ) - else: - notification = process_sms_or_email_notification( - form=form, - notification_type=notification_type, - template=template, - template_with_content=template_with_content, - template_process_type=template.process_type, - service=authenticated_service, - reply_to_text=reply_to - ) + + notification = process_sms_or_email_notification( + form=form, + notification_type=notification_type, + template=template, + template_with_content=template_with_content, + template_process_type=template.process_type, + service=authenticated_service, + reply_to_text=reply_to + ) return jsonify(notification), 201 @@ -443,9 +431,6 @@ def get_reply_to_text(notification_type, form, template): else: reply_to = template.reply_to_text - elif notification_type == LETTER_TYPE: - reply_to = template.reply_to_text - return reply_to @@ -470,11 +455,6 @@ def create_response_for_post_notification( subject=template_with_content.subject, email_from='{}@{}'.format(authenticated_service.email_from, current_app.config['NOTIFY_EMAIL_DOMAIN']), ) - elif notification_type == LETTER_TYPE: - create_resp_partial = functools.partial( - create_post_letter_response_from_notification, - subject=template_with_content.subject, - ) resp = create_resp_partial( notification_id, client_reference, template_id, template_version, service_id, url_root=request.url_root, diff --git a/tests/app/template/test_rest.py b/tests/app/template/test_rest.py index f47ca3527..c1d2d34c3 100644 --- a/tests/app/template/test_rest.py +++ b/tests/app/template/test_rest.py @@ -1131,587 +1131,3 @@ def test_update_redact_template_400s_if_no_created_by(admin_request, sample_temp assert sample_template.redact_personalisation is False assert sample_template.template_redacted.updated_at == original_updated_time - - -def test_preview_letter_template_by_id_invalid_file_type( - sample_letter_notification, - admin_request): - - resp = admin_request.get( - 'template.preview_letter_template_by_notification_id', - service_id=sample_letter_notification.service_id, - template_id=sample_letter_notification.template_id, - notification_id=sample_letter_notification.id, - file_type='doc', - _expected_status=400 - ) - - assert ['file_type must be pdf or png'] == resp['message']['content'] - - -@freeze_time('2012-12-12') -@pytest.mark.parametrize('file_type', ('png', 'pdf')) -def test_preview_letter_template_by_id_valid_file_type( - notify_api, - sample_letter_notification, - admin_request, - file_type, -): - sample_letter_notification.created_at = datetime.utcnow() - with set_config_values(notify_api, { - 'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview', - 'TEMPLATE_PREVIEW_API_KEY': 'test-key' - }): - with requests_mock.Mocker() as request_mock: - content = b'\x00\x01' - - mock_post = request_mock.post( - 'http://localhost/notifications-template-preview/preview.{}'.format(file_type), - content=content, - headers={'X-pdf-page-count': '1'}, - status_code=200 - ) - - resp = admin_request.get( - 'template.preview_letter_template_by_notification_id', - service_id=sample_letter_notification.service_id, - notification_id=sample_letter_notification.id, - file_type=file_type, - ) - - post_json = mock_post.last_request.json() - assert post_json['template']['id'] == str(sample_letter_notification.template_id) - assert post_json['values'] == { - 'address_line_1': 'A1', - 'address_line_2': 'A2', - 'address_line_3': 'A3', - 'address_line_4': 'A4', - 'address_line_5': 'A5', - 'address_line_6': 'A6', - 'postcode': 'A_POST', - } - assert post_json['date'] == '2012-12-12T00:00:00' - assert post_json['filename'] is None - assert base64.b64decode(resp['content']) == content - - -@freeze_time('2012-12-12') -def test_preview_letter_template_by_id_shows_template_version_used_by_notification( - notify_api, - sample_letter_notification, - sample_letter_template, - admin_request -): - sample_letter_notification.created_at = datetime.utcnow() - assert sample_letter_notification.template_version == 1 - - # Create a new template history to check that our preview doesn't use the newest version - # but instead the one linked with the notification - sample_letter_template.content = 'new content' - dao_update_template(sample_letter_template) - versions = dao_get_template_versions(sample_letter_notification.service.id, sample_letter_template.id) - assert len(versions) == 2 - - with set_config_values(notify_api, { - 'TEMPLATE_PREVIEW_API_HOST': 'http://localhost/notifications-template-preview', - 'TEMPLATE_PREVIEW_API_KEY': 'test-key' - }): - with requests_mock.Mocker() as request_mock: - content = b'\x00\x01' - - mock_post = request_mock.post( - 'http://localhost/notifications-template-preview/preview.png', - content=content, - headers={'X-pdf-page-count': '1'}, - status_code=200 - ) - - admin_request.get( - 'template.preview_letter_template_by_notification_id', - service_id=sample_letter_notification.service_id, - notification_id=sample_letter_notification.id, - file_type='png', - ) - - post_json = mock_post.last_request.json() - assert post_json['template']['id'] == str(sample_letter_notification.template_id) - assert post_json['template']['version'] == '1' - - -def test_preview_letter_template_by_id_template_preview_500( - notify_api, - client, - admin_request, - sample_letter_notification): - - 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: - content = b'\x00\x01' - - mock_post = request_mock.post( - 'http://localhost/notifications-template-preview/preview.pdf', - content=content, - headers={'X-pdf-page-count': '1'}, - status_code=404 - ) - - resp = admin_request.get( - 'template.preview_letter_template_by_notification_id', - service_id=sample_letter_notification.service_id, - notification_id=sample_letter_notification.id, - file_type='pdf', - _expected_status=500 - ) - - assert mock_post.last_request.json() - assert 'Status code: 404' in resp['message'] - assert 'Error generating preview letter for {}'.format(sample_letter_notification.id) in resp['message'] - - -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' - }): - with requests_mock.Mocker(): - - content = b'\x00\x01' - - mock_get_letter_pdf = mocker.patch( - 'app.template.rest.get_letter_pdf_and_metadata', - return_value=(content, { - "message": "", - "invalid_pages": "", - "page_count": "1" - }) - ) - - 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' - }): - with requests_mock.Mocker(): - - mocker.patch('app.template.rest.get_letter_pdf_and_metadata', - side_effect=botocore.exceptions.ClientError( - {'Error': {'Code': '403', 'Message': 'Unauthorized'}}, - 'GetObject' - )) - - request = admin_request.get( - 'template.preview_letter_template_by_notification_id', - service_id=notification.service_id, - notification_id=notification.id, - file_type='pdf', - _expected_status=500 - ) - - assert request['message'] == "Error extracting requested page from PDF file for notification_id {} type " \ - " An error occurred (403) " \ - "when calling the GetObject operation: Unauthorized".format(notification.id) - - -@pytest.mark.parametrize( - "requested_page, message, expected_post_url", - [ - # page defaults to 1, page is valid, no overlay shown - ("", "", 'precompiled-preview.png'), - # page is valid, no overlay shown - ("1", "", 'precompiled-preview.png'), - # page is invalid but not because content is outside printable area so no overlay - ("1", "letter-not-a4-portrait-oriented", 'precompiled-preview.png'), - # page is invalid, overlay shown - ("1", "content-outside-printable-area", 'precompiled/overlay.png?page_number=1'), - # page is valid, no overlay shown - ("2", "content-outside-printable-area", 'precompiled-preview.png'), - # page is invalid, overlay shown - ("3", "content-outside-printable-area", 'precompiled/overlay.png?page_number=3'), - ] -) -def test_preview_letter_template_precompiled_for_png_shows_overlay_on_pages_with_content_outside_printable_area( - notify_api, - client, - admin_request, - sample_service, - mocker, - requested_page, - message, - expected_post_url, -): - - 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' - }): - with requests_mock.Mocker() as request_mock: - - pdf_content = b'\x00\x01' - expected_returned_content = b'\x00\x02' - - metadata = { - "message": message, - "invalid_pages": "[1,3]", - "page_count": "4" - } - - mock_get_letter_pdf = mocker.patch( - 'app.template.rest.get_letter_pdf_and_metadata', - return_value=(pdf_content, metadata) - ) - - mocker.patch('app.template.rest.extract_page_from_pdf', return_value=pdf_content) - - mock_post = request_mock.post( - 'http://localhost/notifications-template-preview/{}'.format(expected_post_url), - content=expected_returned_content, - headers={'X-pdf-page-count': '4'}, - status_code=200 - ) - - response = admin_request.get( - 'template.preview_letter_template_by_notification_id', - page=requested_page, - service_id=notification.service_id, - notification_id=notification.id, - file_type="png", - ) - - with pytest.raises(ValueError): - mock_post.last_request.json() - assert mock_get_letter_pdf.called_once_with(notification) - assert base64.b64decode(response['content']) == expected_returned_content - assert response["metadata"] == metadata - - -@pytest.mark.parametrize( - "invalid_pages", - [ - "[1,3]", - "[2,4]", # it shouldn't make a difference if the error was on the first page or not - ] -) -def test_preview_letter_template_precompiled_for_pdf_shows_overlay_on_all_pages_if_content_outside_printable_area( - notify_api, - client, - admin_request, - sample_service, - mocker, - invalid_pages, -): - - 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' - }): - with requests_mock.Mocker() as request_mock: - - pdf_content = b'\x00\x01' - expected_returned_content = b'\x00\x02' - - metadata = { - "message": "content-outside-printable-area", - "invalid_pages": invalid_pages, - "page_count": "4" - } - - mock_get_letter_pdf = mocker.patch( - 'app.template.rest.get_letter_pdf_and_metadata', - return_value=(pdf_content, metadata) - ) - - mocker.patch('app.template.rest.extract_page_from_pdf', return_value=pdf_content) - - mock_post = request_mock.post( - 'http://localhost/notifications-template-preview/precompiled/overlay.pdf', - content=expected_returned_content, - headers={'X-pdf-page-count': '4'}, - status_code=200 - ) - - response = admin_request.get( - 'template.preview_letter_template_by_notification_id', - service_id=notification.service_id, - notification_id=notification.id, - file_type="pdf", - ) - - with pytest.raises(ValueError): - mock_post.last_request.json() - assert mock_get_letter_pdf.called_once_with(notification) - assert base64.b64decode(response['content']) == expected_returned_content - assert response["metadata"] == metadata - - -@pytest.mark.parametrize('page_number,expect_preview_url', [ - ('', 'http://localhost/notifications-template-preview/precompiled-preview.png?hide_notify=true'), - ('1', 'http://localhost/notifications-template-preview/precompiled-preview.png?hide_notify=true'), - ('2', 'http://localhost/notifications-template-preview/precompiled-preview.png') -]) -def test_preview_letter_template_precompiled_png_file_type_hide_notify_tag_only_on_first_page( - notify_api, - client, - admin_request, - sample_service, - mocker, - page_number, - expect_preview_url -): - - 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' - }): - pdf_content = b'\x00\x01' - png_content = b'\x00\x02' - encoded = base64.b64encode(png_content).decode('utf-8') - - mocker.patch( - 'app.template.rest.get_letter_pdf_and_metadata', - return_value=(pdf_content, { - "message": "", - "invalid_pages": "", - "page_count": "2" - }) - ) - mocker.patch('app.template.rest.extract_page_from_pdf', return_value=png_content) - mock_get_png_preview = mocker.patch('app.template.rest._get_png_preview_or_overlaid_pdf', return_value=encoded) - - admin_request.get( - 'template.preview_letter_template_by_notification_id', - service_id=notification.service_id, - notification_id=notification.id, - file_type='png', - page=page_number - ) - - mock_get_png_preview.assert_called_once_with( - expect_preview_url, encoded, notification.id, json=False - ) - - -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' - }): - 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_and_metadata', return_value=(pdf_content, { - "message": "", - "invalid_pages": "", - "page_count": "1" - })) - - mocker.patch('app.template.rest.extract_page_from_pdf', return_value=pdf_content) - - mock_post = 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 - - ) - - with pytest.raises(ValueError): - mock_post.last_request.json() - - -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' - }): - 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_and_metadata', return_value=(pdf_content, { - "message": "", - "invalid_pages": "", - "page_count": "1" - })) - - mocker.patch('app.template.rest.extract_page_from_pdf', return_value=pdf_content) - - mock_post = 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 - ) - - with pytest.raises(ValueError): - mock_post.last_request.json() - - -def test_preview_letter_template_precompiled_png_template_preview_pdf_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' - }): - 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_and_metadata', return_value=(pdf_content, { - "message": "", - "invalid_pages": "", - "page_count": "1" - })) - - error_message = "PDF Error message" - mocker.patch('app.template.rest.extract_page_from_pdf', side_effect=PdfReadError(error_message)) - - request_mock.post( - 'http://localhost/notifications-template-preview/precompiled-preview.png', - content=png_content, - headers={'X-pdf-page-count': '1'}, - status_code=404 - ) - - request = 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 - ) - - assert request['message'] == "Error extracting requested page from PDF file for notification_id {} type " \ - "{} {}".format(notification.id, type(PdfReadError()), error_message)