mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-04 10:21:14 -05:00
Validate and format postcode for the API letter sending flow.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from flask import jsonify, current_app, request
|
from flask import jsonify, current_app, request
|
||||||
from jsonschema import ValidationError
|
from jsonschema import ValidationError as JsonSchemaValidationError
|
||||||
from notifications_utils.recipients import InvalidEmailError
|
from notifications_utils.recipients import InvalidEmailError
|
||||||
from sqlalchemy.exc import DataError
|
from sqlalchemy.exc import DataError
|
||||||
from sqlalchemy.orm.exc import NoResultFound
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
@@ -57,6 +57,15 @@ class BadRequestError(InvalidRequest):
|
|||||||
self.message = message if message else self.message
|
self.message = message if message else self.message
|
||||||
|
|
||||||
|
|
||||||
|
class ValidationError(InvalidRequest):
|
||||||
|
message = "Your notification has failed validation"
|
||||||
|
|
||||||
|
def __init__(self, fields=[], message=None, status_code=400):
|
||||||
|
self.status_code = status_code
|
||||||
|
self.fields = fields
|
||||||
|
self.message = message if message else self.message
|
||||||
|
|
||||||
|
|
||||||
class PDFNotReadyError(BadRequestError):
|
class PDFNotReadyError(BadRequestError):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__(message='PDF not available yet, try again later', status_code=400)
|
super().__init__(message='PDF not available yet, try again later', status_code=400)
|
||||||
@@ -77,7 +86,7 @@ def register_errors(blueprint):
|
|||||||
response = jsonify(error.to_dict_v2()), error.status_code
|
response = jsonify(error.to_dict_v2()), error.status_code
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@blueprint.errorhandler(ValidationError)
|
@blueprint.errorhandler(JsonSchemaValidationError)
|
||||||
def validation_error(error):
|
def validation_error(error):
|
||||||
current_app.logger.info(error)
|
current_app.logger.info(error)
|
||||||
return jsonify(json.loads(error.message)), 400
|
return jsonify(json.loads(error.message)), 400
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import base64
|
|||||||
import functools
|
import functools
|
||||||
|
|
||||||
from flask import request, jsonify, current_app, abort
|
from flask import request, jsonify, current_app, abort
|
||||||
from notifications_utils.recipients import try_validate_and_format_phone_number
|
from notifications_utils.recipients import (
|
||||||
|
format_postcode_for_printing, is_a_real_uk_postcode, try_validate_and_format_phone_number
|
||||||
|
)
|
||||||
|
|
||||||
from app import api_user, authenticated_service, notify_celery, document_download_client
|
from app import api_user, authenticated_service, notify_celery, document_download_client
|
||||||
from app.celery.letters_pdf_tasks import create_letters_pdf, process_virus_scan_passed
|
from app.celery.letters_pdf_tasks import create_letters_pdf, process_virus_scan_passed
|
||||||
@@ -44,7 +46,7 @@ from app.notifications.validators import (
|
|||||||
validate_template,
|
validate_template,
|
||||||
)
|
)
|
||||||
from app.schema_validation import validate
|
from app.schema_validation import validate
|
||||||
from app.v2.errors import BadRequestError
|
from app.v2.errors import BadRequestError, ValidationError
|
||||||
from app.v2.notifications import v2_notification_blueprint
|
from app.v2.notifications import v2_notification_blueprint
|
||||||
from app.v2.notifications.create_response import (
|
from app.v2.notifications.create_response import (
|
||||||
create_post_sms_response_from_notification,
|
create_post_sms_response_from_notification,
|
||||||
@@ -267,12 +269,18 @@ def process_letter_notification(*, letter_data, api_key, template, reply_to_text
|
|||||||
template=template,
|
template=template,
|
||||||
reply_to_text=reply_to_text)
|
reply_to_text=reply_to_text)
|
||||||
|
|
||||||
|
postcode = letter_data['personalisation']['postcode']
|
||||||
|
if not is_a_real_uk_postcode(postcode):
|
||||||
|
raise ValidationError(message='A real UK postcode is required.')
|
||||||
|
|
||||||
test_key = api_key.key_type == KEY_TYPE_TEST
|
test_key = api_key.key_type == KEY_TYPE_TEST
|
||||||
|
|
||||||
# if we don't want to actually send the letter, then start it off in SENDING so we don't pick it up
|
# if we don't want to actually send the letter, then start it off in SENDING so we don't pick it up
|
||||||
status = NOTIFICATION_CREATED if not test_key else NOTIFICATION_SENDING
|
status = NOTIFICATION_CREATED if not test_key else NOTIFICATION_SENDING
|
||||||
queue = QueueNames.CREATE_LETTERS_PDF if not test_key else QueueNames.RESEARCH_MODE
|
queue = QueueNames.CREATE_LETTERS_PDF if not test_key else QueueNames.RESEARCH_MODE
|
||||||
|
|
||||||
|
letter_data['personalisation']['postcode'] = format_postcode_for_printing(postcode)
|
||||||
|
|
||||||
notification = create_letter_notification(letter_data=letter_data,
|
notification = create_letter_notification(letter_data=letter_data,
|
||||||
template=template,
|
template=template,
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
|
|||||||
@@ -118,6 +118,56 @@ def test_post_letter_notification_sets_postage(
|
|||||||
assert notification.postage == "first"
|
assert notification.postage == "first"
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_letter_notification_formats_postcode(
|
||||||
|
client, notify_db_session, mocker
|
||||||
|
):
|
||||||
|
service = create_service(service_permissions=[LETTER_TYPE])
|
||||||
|
template = create_template(service, template_type="letter")
|
||||||
|
mocker.patch('app.celery.tasks.letters_pdf_tasks.create_letters_pdf.apply_async')
|
||||||
|
data = {
|
||||||
|
'template_id': str(template.id),
|
||||||
|
'personalisation': {
|
||||||
|
'address_line_1': 'Her Royal Highness Queen Elizabeth II',
|
||||||
|
'address_line_2': 'Buckingham Palace',
|
||||||
|
'address_line_3': 'London',
|
||||||
|
'postcode': ' Sw1 1aa ',
|
||||||
|
'name': 'Lizzie'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp_json = letter_request(client, data, service_id=service.id)
|
||||||
|
|
||||||
|
assert validate(resp_json, post_letter_response) == resp_json
|
||||||
|
notification = Notification.query.one()
|
||||||
|
assert notification.personalisation["postcode"] == "SW1 1AA"
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_letter_notification_throws_error_for_bad_postcode(
|
||||||
|
client, notify_db_session, mocker
|
||||||
|
):
|
||||||
|
service = create_service(service_permissions=[LETTER_TYPE])
|
||||||
|
template = create_template(service, template_type="letter", postage="first")
|
||||||
|
mocker.patch('app.celery.tasks.letters_pdf_tasks.create_letters_pdf.apply_async')
|
||||||
|
data = {
|
||||||
|
'template_id': str(template.id),
|
||||||
|
'personalisation': {
|
||||||
|
'address_line_1': 'Her Royal Highness Queen Elizabeth II',
|
||||||
|
'address_line_2': 'Buckingham Palace',
|
||||||
|
'address_line_3': 'London',
|
||||||
|
'postcode': 'not a real postcode',
|
||||||
|
'name': 'Lizzie'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error_json = letter_request(client, data, service_id=service.id, _expected_status=400)
|
||||||
|
|
||||||
|
assert error_json['status_code'] == 400
|
||||||
|
assert error_json['errors'] == [{
|
||||||
|
'error': 'ValidationError',
|
||||||
|
'message': 'A real UK postcode is required.'
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('env', [
|
@pytest.mark.parametrize('env', [
|
||||||
'staging',
|
'staging',
|
||||||
'live',
|
'live',
|
||||||
@@ -366,7 +416,7 @@ def test_post_letter_notification_is_delivered_but_still_creates_pdf_if_in_trial
|
|||||||
|
|
||||||
data = {
|
data = {
|
||||||
"template_id": sample_trial_letter_template.id,
|
"template_id": sample_trial_letter_template.id,
|
||||||
"personalisation": {'address_line_1': 'Foo', 'address_line_2': 'Bar', 'postcode': 'Baz'}
|
"personalisation": {'address_line_1': 'Foo', 'address_line_2': 'Bar', 'postcode': 'BA5 5AB'}
|
||||||
}
|
}
|
||||||
|
|
||||||
letter_request(client, data=data, service_id=sample_trial_letter_template.service_id, key_type=KEY_TYPE_TEST)
|
letter_request(client, data=data, service_id=sample_trial_letter_template.service_id, key_type=KEY_TYPE_TEST)
|
||||||
@@ -411,7 +461,7 @@ def test_post_letter_notification_persists_notification_reply_to_text(
|
|||||||
template = create_template(service=service, template_type='letter', reply_to=letter_contact.id)
|
template = create_template(service=service, template_type='letter', reply_to=letter_contact.id)
|
||||||
data = {
|
data = {
|
||||||
"template_id": template.id,
|
"template_id": template.id,
|
||||||
"personalisation": {'address_line_1': 'Foo', 'address_line_2': 'Bar', 'postcode': 'Baz'}
|
"personalisation": {'address_line_1': 'Foo', 'address_line_2': 'Bar', 'postcode': 'BA5 5AB'}
|
||||||
}
|
}
|
||||||
letter_request(client, data=data, service_id=service.id, key_type=KEY_TYPE_NORMAL)
|
letter_request(client, data=data, service_id=service.id, key_type=KEY_TYPE_NORMAL)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user