Raise error if multiple broadcasts found for reference

Because the `<reference>` field of a `cancel` message can contain an
arbitrary number of items it’s possible for it to reference more than
one current alert.

In this case it is ambiguous which alert should be cancelled, so we
should raise a custom error.

This will help people know that they have to manually go into Notify and
figure out which alert(s) to cancel there.
This commit is contained in:
Chris Hill-Scott
2022-02-17 11:46:24 +00:00
parent f691bc2a92
commit cc207ac11f
3 changed files with 53 additions and 4 deletions

View File

@@ -3,6 +3,7 @@ from itertools import chain
from flask import current_app, jsonify, request
from notifications_utils.polygons import Polygons
from notifications_utils.template import BroadcastMessageTemplate
from sqlalchemy.orm.exc import MultipleResultsFound
from app import api_user, authenticated_service
from app.broadcast_message.translators import cap_xml_to_dict
@@ -105,10 +106,17 @@ def create_broadcast():
def _cancel_or_reject_broadcast(references_to_original_broadcast, service_id):
broadcast_message = dao_get_broadcast_message_by_references_and_service_id(
references_to_original_broadcast,
service_id
)
try:
broadcast_message = dao_get_broadcast_message_by_references_and_service_id(
references_to_original_broadcast,
service_id
)
except MultipleResultsFound:
raise BadRequestError(
message='Multiple alerts found - unclear which one to cancel',
status_code=400,
)
if broadcast_message.status == BroadcastStatusType.PENDING_APPROVAL:
new_status = BroadcastStatusType.REJECTED
else:

View File

@@ -79,6 +79,15 @@ WAINFLEET_CANCEL_WITH_EMPTY_REFERENCES = WAINFLEET_CANCEL.format(
"<references></references>"
)
WAINFLEET_CANCEL_WITH_WINDMERE_REFERENCES = WAINFLEET_CANCEL.format(
"<references>"
# Wainfleet
"www.gov.uk/environment-agency,50385fcb0ab7aa447bbd46d848ce8466E,2020-02-16T23:01:13-00:00,"
# Windemere
"www.gov.uk/environment-agency,4f6d28b10ab7aa447bbd46d85f1e9effE,2020-02-16T19:20:03+00:00"
"</references>"
)
UPDATE = """
<alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
<identifier>PAAQ-4-mg5a94</identifier>

View File

@@ -220,6 +220,38 @@ def test_cancel_request_does_not_cancel_broadcast_if_reference_does_not_match(
assert response_for_cancel_json["errors"] == expected_error
def test_cancel_raises_error_if_multiple_broadcasts_referenced(
client,
sample_broadcast_service,
):
auth_header = create_service_authorization_header(service_id=sample_broadcast_service.id)
for cap_document in (
sample_cap_xml_documents.WAINFLEET,
sample_cap_xml_documents.WINDEMERE,
):
response_for_create = client.post(
path='/v2/broadcast',
data=cap_document,
headers=[('Content-Type', 'application/cap+xml'), auth_header],
)
assert response_for_create.status_code == 201
# try to cancel two broadcasts with one request
response_for_cancel = client.post(
path='/v2/broadcast',
data=sample_cap_xml_documents.WAINFLEET_CANCEL_WITH_WINDMERE_REFERENCES,
headers=[('Content-Type', 'application/cap+xml'), auth_header],
)
response_for_cancel_json = json.loads(response_for_cancel.get_data(as_text=True))
assert response_for_cancel.status_code == 400
assert response_for_cancel_json["errors"] == [{
'error': 'BadRequestError',
'message': 'Multiple alerts found - unclear which one to cancel',
}]
def test_cancel_request_does_not_cancel_broadcast_if_service_id_does_not_match(
client,
sample_broadcast_service,