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
This commit is contained in:
Leo Hemsted
2019-09-03 16:49:03 +01:00
parent 5cdce44e42
commit 22aff482a8
4 changed files with 62 additions and 2 deletions

View File

@@ -1547,7 +1547,7 @@ class Notification(db.Model):
elif self.status in [NOTIFICATION_DELIVERED, NOTIFICATION_RETURNED_LETTER]: elif self.status in [NOTIFICATION_DELIVERED, NOTIFICATION_RETURNED_LETTER]:
return NOTIFICATION_STATUS_LETTER_RECEIVED return NOTIFICATION_STATUS_LETTER_RECEIVED
else: else:
# Currently can only be technical-failure # Currently can only be technical-failure OR pending-virus-check OR validation-failed
return self.status return self.status
def get_created_by_name(self): def get_created_by_name(self):

View File

@@ -1,9 +1,14 @@
import base64
from flask import jsonify, request, url_for, current_app from flask import jsonify, request, url_for, current_app
from app import api_user, authenticated_service from app import api_user, authenticated_service
from app.dao import notifications_dao from app.dao import notifications_dao
from app.letters.utils import get_letter_pdf
from app.schema_validation import validate from app.schema_validation import validate
from app.v2.notifications import v2_notification_blueprint from app.v2.notifications import v2_notification_blueprint
from app.v2.notifications.notification_schemas import get_notifications_request, notification_by_id 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("/<notification_id>", methods=['GET']) @v2_notification_blueprint.route("/<notification_id>", methods=['GET'])
@@ -14,7 +19,17 @@ def get_notification_by_id(notification_id):
authenticated_service.id, notification_id, key_type=None 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']) @v2_notification_blueprint.route("", methods=['GET'])

View File

@@ -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() 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) @freeze_time(FROZEN_DATE_TIME)
def test_get_bucket_name_and_prefix_for_failed_validation(sample_precompiled_letter_notification): def test_get_bucket_name_and_prefix_for_failed_validation(sample_precompiled_letter_notification):
sample_precompiled_letter_notification.status = NOTIFICATION_VALIDATION_FAILED sample_precompiled_letter_notification.status = NOTIFICATION_VALIDATION_FAILED

View File

@@ -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)) json_response = json.loads(response.get_data(as_text=True))
assert response.status_code == 200 assert response.status_code == 200
assert json_response['status'] == expected_status 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