mirror of
https://github.com/GSA/notifications-api.git
synced 2026-02-04 02:11:11 -05:00
Merge pull request #3461 from alphagov/be-more-robust-around-references-to-cancel
Be more robust in handling ambiguous references to cancel an alert
This commit is contained in:
@@ -26,6 +26,10 @@ def dao_get_broadcast_message_by_id_and_service_id(broadcast_message_id, service
|
|||||||
|
|
||||||
def dao_get_broadcast_message_by_references_and_service_id(references_to_original_broadcast, service_id):
|
def dao_get_broadcast_message_by_references_and_service_id(references_to_original_broadcast, service_id):
|
||||||
return BroadcastMessage.query.filter(
|
return BroadcastMessage.query.filter(
|
||||||
|
BroadcastMessage.status.in_((
|
||||||
|
BroadcastStatusType.PENDING_APPROVAL,
|
||||||
|
BroadcastStatusType.BROADCASTING,
|
||||||
|
)),
|
||||||
BroadcastMessage.reference.in_(references_to_original_broadcast),
|
BroadcastMessage.reference.in_(references_to_original_broadcast),
|
||||||
BroadcastMessage.service_id == service_id
|
BroadcastMessage.service_id == service_id
|
||||||
).one()
|
).one()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from itertools import chain
|
|||||||
from flask import current_app, jsonify, request
|
from flask import current_app, jsonify, request
|
||||||
from notifications_utils.polygons import Polygons
|
from notifications_utils.polygons import Polygons
|
||||||
from notifications_utils.template import BroadcastMessageTemplate
|
from notifications_utils.template import BroadcastMessageTemplate
|
||||||
|
from sqlalchemy.orm.exc import MultipleResultsFound
|
||||||
|
|
||||||
from app import api_user, authenticated_service
|
from app import api_user, authenticated_service
|
||||||
from app.broadcast_message.translators import cap_xml_to_dict
|
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):
|
def _cancel_or_reject_broadcast(references_to_original_broadcast, service_id):
|
||||||
|
try:
|
||||||
broadcast_message = dao_get_broadcast_message_by_references_and_service_id(
|
broadcast_message = dao_get_broadcast_message_by_references_and_service_id(
|
||||||
references_to_original_broadcast,
|
references_to_original_broadcast,
|
||||||
service_id
|
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:
|
if broadcast_message.status == BroadcastStatusType.PENDING_APPROVAL:
|
||||||
new_status = BroadcastStatusType.REJECTED
|
new_status = BroadcastStatusType.REJECTED
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -79,6 +79,15 @@ WAINFLEET_CANCEL_WITH_EMPTY_REFERENCES = WAINFLEET_CANCEL.format(
|
|||||||
"<references></references>"
|
"<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 = """
|
UPDATE = """
|
||||||
<alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
|
<alert xmlns="urn:oasis:names:tc:emergency:cap:1.2">
|
||||||
<identifier>PAAQ-4-mg5a94</identifier>
|
<identifier>PAAQ-4-mg5a94</identifier>
|
||||||
|
|||||||
@@ -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
|
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(
|
def test_cancel_request_does_not_cancel_broadcast_if_service_id_does_not_match(
|
||||||
client,
|
client,
|
||||||
sample_broadcast_service,
|
sample_broadcast_service,
|
||||||
@@ -253,6 +285,56 @@ def test_cancel_request_does_not_cancel_broadcast_if_service_id_does_not_match(
|
|||||||
assert response_for_cancel.status_code == 404
|
assert response_for_cancel.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("is_approved, expected_cancel_tasks", (
|
||||||
|
(True, 1),
|
||||||
|
(False, 0),
|
||||||
|
))
|
||||||
|
def test_same_broadcast_cant_be_cancelled_twice(
|
||||||
|
mocker,
|
||||||
|
client,
|
||||||
|
sample_broadcast_service,
|
||||||
|
is_approved,
|
||||||
|
expected_cancel_tasks,
|
||||||
|
):
|
||||||
|
mock_send_broadcast_event_task = mocker.patch(
|
||||||
|
'app.celery.broadcast_message_tasks.send_broadcast_event.apply_async'
|
||||||
|
)
|
||||||
|
auth_header = create_service_authorization_header(service_id=sample_broadcast_service.id)
|
||||||
|
|
||||||
|
# create a broadcast
|
||||||
|
response_for_create = client.post(
|
||||||
|
path='/v2/broadcast',
|
||||||
|
data=sample_cap_xml_documents.WAINFLEET,
|
||||||
|
headers=[('Content-Type', 'application/cap+xml'), auth_header],
|
||||||
|
)
|
||||||
|
assert response_for_create.status_code == 201
|
||||||
|
|
||||||
|
response_json_for_create = json.loads(response_for_create.get_data(as_text=True))
|
||||||
|
|
||||||
|
broadcast_message = dao_get_broadcast_message_by_id_and_service_id(
|
||||||
|
response_json_for_create["id"], response_json_for_create["service_id"]
|
||||||
|
)
|
||||||
|
# approve broadcast
|
||||||
|
if is_approved:
|
||||||
|
broadcast_message.status = 'broadcasting'
|
||||||
|
|
||||||
|
first_response_for_cancel = client.post(
|
||||||
|
path='/v2/broadcast',
|
||||||
|
data=sample_cap_xml_documents.WAINFLEET_CANCEL_WITH_REFERENCES,
|
||||||
|
headers=[('Content-Type', 'application/cap+xml'), auth_header],
|
||||||
|
)
|
||||||
|
assert first_response_for_cancel.status_code == 201
|
||||||
|
|
||||||
|
second_response_for_cancel = client.post(
|
||||||
|
path='/v2/broadcast',
|
||||||
|
data=sample_cap_xml_documents.WAINFLEET_CANCEL_WITH_REFERENCES,
|
||||||
|
headers=[('Content-Type', 'application/cap+xml'), auth_header],
|
||||||
|
)
|
||||||
|
assert second_response_for_cancel.status_code == 404
|
||||||
|
|
||||||
|
assert len(mock_send_broadcast_event_task.call_args_list) == expected_cancel_tasks
|
||||||
|
|
||||||
|
|
||||||
def test_large_polygon_is_simplified(
|
def test_large_polygon_is_simplified(
|
||||||
client,
|
client,
|
||||||
sample_broadcast_service,
|
sample_broadcast_service,
|
||||||
|
|||||||
Reference in New Issue
Block a user