From 22aff482a88a2c4336b3260a55acb11b2e2bb712 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Tue, 3 Sep 2019 16:49:03 +0100 Subject: [PATCH] add flag to return pdf content via api this is only applicable when getting a single notification by id. it's also ignored if the notification isn't a letter. Otherwise, it overwrites the 'body' field in the response. If the notification's pdf is available, it returns that, base64 encoded. If the pdf is not available, it returns an empty string. The pdf won't be available if the notification's status is: * pending-virus-scan * virus-scan-failed * validation-failed * technical-failure The pdf will be retrieved from the correct s3 bucket based on its type --- app/models.py | 2 +- app/v2/notifications/get_notifications.py | 17 ++++++++- tests/app/letters/test_letter_utils.py | 10 ++++++ .../notifications/test_get_notifications.py | 35 +++++++++++++++++++ 4 files changed, 62 insertions(+), 2 deletions(-) diff --git a/app/models.py b/app/models.py index 62c8c36c1..c98cce026 100644 --- a/app/models.py +++ b/app/models.py @@ -1547,7 +1547,7 @@ class Notification(db.Model): elif self.status in [NOTIFICATION_DELIVERED, NOTIFICATION_RETURNED_LETTER]: return NOTIFICATION_STATUS_LETTER_RECEIVED else: - # Currently can only be technical-failure + # Currently can only be technical-failure OR pending-virus-check OR validation-failed return self.status def get_created_by_name(self): diff --git a/app/v2/notifications/get_notifications.py b/app/v2/notifications/get_notifications.py index d54df58cb..00e2adff0 100644 --- a/app/v2/notifications/get_notifications.py +++ b/app/v2/notifications/get_notifications.py @@ -1,9 +1,14 @@ +import base64 + from flask import jsonify, request, url_for, current_app + from app import api_user, authenticated_service from app.dao import notifications_dao +from app.letters.utils import get_letter_pdf from app.schema_validation import validate from app.v2.notifications import v2_notification_blueprint from app.v2.notifications.notification_schemas import get_notifications_request, notification_by_id +from app.models import NOTIFICATION_CREATED, NOTIFICATION_STATUS_TYPES_BILLABLE_FOR_LETTERS, LETTER_TYPE @v2_notification_blueprint.route("/", methods=['GET']) @@ -14,7 +19,17 @@ def get_notification_by_id(notification_id): authenticated_service.id, notification_id, key_type=None ) - return jsonify(notification.serialize()), 200 + response = notification.serialize() + + if request.args.get('return_pdf_content') and notification.notification_type == LETTER_TYPE: + if notification.status in (NOTIFICATION_CREATED, *NOTIFICATION_STATUS_TYPES_BILLABLE_FOR_LETTERS): + pdf_data = get_letter_pdf(notification) + else: + # precompiled letters that are still being virus scanned, or that failed validation/virus scan + pdf_data = b'' + response['body'] = base64.b64encode(pdf_data).decode('utf-8') + + return jsonify(response), 200 @v2_notification_blueprint.route("", methods=['GET']) diff --git a/tests/app/letters/test_letter_utils.py b/tests/app/letters/test_letter_utils.py index 1d3c427c8..504403a40 100644 --- a/tests/app/letters/test_letter_utils.py +++ b/tests/app/letters/test_letter_utils.py @@ -80,6 +80,16 @@ def test_get_bucket_name_and_prefix_for_notification_precompiled_letter_using_te sample_precompiled_letter_notification_using_test_key.reference).upper() +@freeze_time(FROZEN_DATE_TIME) +def test_get_bucket_name_and_prefix_for_notification_templated_letter_using_test_key(sample_letter_notification): + sample_letter_notification.key_type = KEY_TYPE_TEST + + bucket, bucket_prefix = get_bucket_name_and_prefix_for_notification(sample_letter_notification) + + assert bucket == current_app.config['TEST_LETTERS_BUCKET_NAME'] + assert bucket_prefix == 'NOTIFY.{}'.format(sample_letter_notification.reference).upper() + + @freeze_time(FROZEN_DATE_TIME) def test_get_bucket_name_and_prefix_for_failed_validation(sample_precompiled_letter_notification): sample_precompiled_letter_notification.status = NOTIFICATION_VALIDATION_FAILED diff --git a/tests/app/v2/notifications/test_get_notifications.py b/tests/app/v2/notifications/test_get_notifications.py index 8bbe13db5..699f0fb0b 100644 --- a/tests/app/v2/notifications/test_get_notifications.py +++ b/tests/app/v2/notifications/test_get_notifications.py @@ -649,3 +649,38 @@ def test_get_notifications_renames_letter_statuses(client, sample_letter_templat json_response = json.loads(response.get_data(as_text=True)) assert response.status_code == 200 assert json_response['status'] == expected_status + + +@pytest.mark.parametrize('status,expected_body,mock_called', [ + ('created', 'Zm9v', True), + ('sending', 'Zm9v', True), + ('pending-virus-check', '', False), + ('virus-scan-failed', '', False), + ('validation-failed', '', False), + ('technical-failure', '', False), +]) +def test_get_notification_only_returns_pdf_content_if_right_status( + client, + sample_letter_notification, + mocker, + status, + expected_body, + mock_called +): + mock_get_letter_pdf = mocker.patch('app.v2.notifications.get_notifications.get_letter_pdf', return_value=b'foo') + sample_letter_notification.status = status + + auth_header = create_authorization_header(service_id=sample_letter_notification.service_id) + response = client.get( + path=url_for( + 'v2_notifications.get_notification_by_id', + notification_id=sample_letter_notification.id, + return_pdf_content='true' + ), + headers=[('Content-Type', 'application/json'), auth_header] + ) + + json_response = json.loads(response.get_data(as_text=True)) + assert response.status_code == 200 + assert json_response['body'] == expected_body + assert mock_get_letter_pdf.called == mock_called