mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-01 15:46:07 -05:00
Add function to send PDF letter
This function checks various permissions, downloads the PDF from the transient bucket, creates the notification then moves the letter to the 'normal' bucket.
This commit is contained in:
@@ -137,6 +137,15 @@ def move_scan_to_invalid_pdf_bucket(source_filename):
|
|||||||
_move_s3_object(scan_bucket, source_filename, invalid_pdf_bucket, source_filename)
|
_move_s3_object(scan_bucket, source_filename, invalid_pdf_bucket, source_filename)
|
||||||
|
|
||||||
|
|
||||||
|
def move_uploaded_pdf_to_letters_bucket(source_filename, upload_filename):
|
||||||
|
_move_s3_object(
|
||||||
|
source_bucket=current_app.config['TRANSIENT_UPLOADED_LETTERS'],
|
||||||
|
source_filename=source_filename,
|
||||||
|
target_bucket=current_app.config['LETTERS_PDF_BUCKET_NAME'],
|
||||||
|
target_filename=upload_filename
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_file_names_from_error_bucket():
|
def get_file_names_from_error_bucket():
|
||||||
s3 = boto3.resource('s3')
|
s3 = boto3.resource('s3')
|
||||||
scan_bucket = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
scan_bucket = current_app.config['LETTERS_SCAN_BUCKET_NAME']
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from flask import current_app
|
||||||
|
from notifications_utils.s3 import S3ObjectNotFound, s3download as utils_s3download
|
||||||
from sqlalchemy.orm.exc import NoResultFound
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
|
|
||||||
from app import create_random_identifier
|
from app import create_random_identifier
|
||||||
@@ -6,6 +8,7 @@ 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_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.service_sms_sender_dao import dao_get_service_sms_senders_by_id
|
||||||
from app.notifications.validators import (
|
from app.notifications.validators import (
|
||||||
|
check_service_has_permission,
|
||||||
check_service_over_daily_message_limit,
|
check_service_over_daily_message_limit,
|
||||||
validate_and_format_recipient,
|
validate_and_format_recipient,
|
||||||
validate_template
|
validate_template
|
||||||
@@ -21,10 +24,16 @@ from app.models import (
|
|||||||
EMAIL_TYPE,
|
EMAIL_TYPE,
|
||||||
LETTER_TYPE,
|
LETTER_TYPE,
|
||||||
NOTIFICATION_DELIVERED,
|
NOTIFICATION_DELIVERED,
|
||||||
|
UPLOAD_LETTERS,
|
||||||
)
|
)
|
||||||
from app.dao.services_dao import dao_fetch_service_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
|
from app.dao.templates_dao import dao_get_template_by_id_and_service_id, get_precompiled_letter_template
|
||||||
from app.dao.users_dao import get_user_by_id
|
from app.dao.users_dao import get_user_by_id
|
||||||
|
from app.letters.utils import (
|
||||||
|
get_letter_pdf_filename,
|
||||||
|
get_page_count,
|
||||||
|
move_uploaded_pdf_to_letters_bucket,
|
||||||
|
)
|
||||||
from app.v2.errors import BadRequestError
|
from app.v2.errors import BadRequestError
|
||||||
|
|
||||||
|
|
||||||
@@ -121,3 +130,60 @@ def get_reply_to_text(notification_type, sender_id, service, template):
|
|||||||
else:
|
else:
|
||||||
reply_to = template.get_reply_to_text()
|
reply_to = template.get_reply_to_text()
|
||||||
return reply_to
|
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, service.permissions)
|
||||||
|
check_service_has_permission(UPLOAD_LETTERS, service.permissions)
|
||||||
|
check_service_over_daily_message_limit(KEY_TYPE_NORMAL, service)
|
||||||
|
validate_created_by(service, post_data['created_by'])
|
||||||
|
|
||||||
|
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.exception('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
|
||||||
|
billable_units = get_page_count(letter.read())
|
||||||
|
|
||||||
|
personalisation = {
|
||||||
|
'address_line_1': post_data['filename']
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: stop hard-coding postage as 'second' once we get postage from the admin
|
||||||
|
notification = persist_notification(
|
||||||
|
notification_id=post_data['file_id'],
|
||||||
|
template_id=template.id,
|
||||||
|
template_version=template.version,
|
||||||
|
template_postage=template.postage,
|
||||||
|
recipient=post_data['filename'],
|
||||||
|
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='second',
|
||||||
|
)
|
||||||
|
|
||||||
|
upload_filename = get_letter_pdf_filename(
|
||||||
|
notification.reference,
|
||||||
|
notification.service.crown,
|
||||||
|
is_scan_letter=False,
|
||||||
|
postage=notification.postage
|
||||||
|
)
|
||||||
|
|
||||||
|
move_uploaded_pdf_to_letters_bucket(file_location, upload_filename)
|
||||||
|
|
||||||
|
return {'id': str(notification.id)}
|
||||||
|
|||||||
102
tests/app/service/test_send_pdf_letter_notification.py
Normal file
102
tests/app/service/test_send_pdf_letter_notification.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import uuid
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from freezegun import freeze_time
|
||||||
|
|
||||||
|
from app.dao.notifications_dao import get_notification_by_id
|
||||||
|
from app.models import EMAIL_TYPE, LETTER_TYPE, UPLOAD_LETTERS
|
||||||
|
from app.service.send_notification import send_pdf_letter_notification
|
||||||
|
from app.v2.errors import BadRequestError, TooManyRequestsError
|
||||||
|
from notifications_utils.s3 import S3ObjectNotFound
|
||||||
|
from tests.app.db import create_service
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('permissions', [
|
||||||
|
[EMAIL_TYPE],
|
||||||
|
[LETTER_TYPE],
|
||||||
|
[UPLOAD_LETTERS],
|
||||||
|
])
|
||||||
|
def test_send_pdf_letter_notification_raises_error_if_service_does_not_have_permission(
|
||||||
|
notify_db_session,
|
||||||
|
fake_uuid,
|
||||||
|
permissions,
|
||||||
|
):
|
||||||
|
service = create_service(service_permissions=permissions)
|
||||||
|
post_data = {'filename': 'valid.pdf', 'created_by': fake_uuid, 'file_id': fake_uuid}
|
||||||
|
|
||||||
|
with pytest.raises(BadRequestError):
|
||||||
|
send_pdf_letter_notification(service.id, post_data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_pdf_letter_notification_raises_error_if_service_is_over_daily_message_limit(
|
||||||
|
mocker,
|
||||||
|
sample_service_full_permissions,
|
||||||
|
fake_uuid,
|
||||||
|
):
|
||||||
|
mocker.patch(
|
||||||
|
'app.service.send_notification.check_service_over_daily_message_limit',
|
||||||
|
side_effect=TooManyRequestsError(10))
|
||||||
|
post_data = {'filename': 'valid.pdf', 'created_by': fake_uuid, 'file_id': fake_uuid}
|
||||||
|
|
||||||
|
with pytest.raises(TooManyRequestsError):
|
||||||
|
send_pdf_letter_notification(sample_service_full_permissions.id, post_data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_pdf_letter_notification_validates_created_by(
|
||||||
|
sample_service_full_permissions, fake_uuid, sample_user
|
||||||
|
):
|
||||||
|
post_data = {'filename': 'valid.pdf', 'created_by': sample_user.id, 'file_id': fake_uuid}
|
||||||
|
|
||||||
|
with pytest.raises(BadRequestError):
|
||||||
|
send_pdf_letter_notification(sample_service_full_permissions.id, post_data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_pdf_letter_notification_raises_error_when_pdf_is_not_in_transient_letter_bucket(
|
||||||
|
mocker,
|
||||||
|
sample_service_full_permissions,
|
||||||
|
fake_uuid,
|
||||||
|
notify_user,
|
||||||
|
):
|
||||||
|
user = sample_service_full_permissions.users[0]
|
||||||
|
post_data = {'filename': 'valid.pdf', 'created_by': user.id, 'file_id': fake_uuid}
|
||||||
|
mocker.patch('app.service.send_notification.utils_s3download', side_effect=S3ObjectNotFound({}, ''))
|
||||||
|
|
||||||
|
with pytest.raises(S3ObjectNotFound):
|
||||||
|
send_pdf_letter_notification(sample_service_full_permissions.id, post_data)
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time("2019-08-02 11:00:00")
|
||||||
|
def test_send_pdf_letter_notification_creates_notification_and_moves_letter(
|
||||||
|
mocker,
|
||||||
|
sample_service_full_permissions,
|
||||||
|
notify_user,
|
||||||
|
):
|
||||||
|
user = sample_service_full_permissions.users[0]
|
||||||
|
filename = 'valid.pdf'
|
||||||
|
file_id = uuid.uuid4()
|
||||||
|
post_data = {'filename': filename, 'created_by': user.id, 'file_id': file_id}
|
||||||
|
|
||||||
|
mocker.patch('app.service.send_notification.utils_s3download')
|
||||||
|
mocker.patch('app.service.send_notification.get_page_count', return_value=1)
|
||||||
|
s3_mock = mocker.patch('app.service.send_notification.move_uploaded_pdf_to_letters_bucket')
|
||||||
|
|
||||||
|
result = send_pdf_letter_notification(sample_service_full_permissions.id, post_data)
|
||||||
|
|
||||||
|
notification = get_notification_by_id(file_id)
|
||||||
|
|
||||||
|
assert notification.id == file_id
|
||||||
|
assert notification.api_key_id is None
|
||||||
|
assert notification.client_reference == filename
|
||||||
|
assert notification.created_by_id == user.id
|
||||||
|
assert notification.postage == 'second'
|
||||||
|
assert notification.notification_type == LETTER_TYPE
|
||||||
|
assert notification.billable_units == 1
|
||||||
|
assert notification.to == filename
|
||||||
|
assert notification.service_id == sample_service_full_permissions.id
|
||||||
|
|
||||||
|
assert result == {'id': str(notification.id)}
|
||||||
|
|
||||||
|
s3_mock.assert_called_once_with(
|
||||||
|
'service-{}/{}.pdf'.format(sample_service_full_permissions.id, file_id),
|
||||||
|
'2019-08-02/NOTIFY.{}.D.2.C.C.20190802110000.PDF'.format(notification.reference)
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user