diff --git a/app/main/views/broadcast.py b/app/main/views/broadcast.py index 0ae193919..8cf079752 100644 --- a/app/main/views/broadcast.py +++ b/app/main/views/broadcast.py @@ -83,6 +83,7 @@ def choose_broadcast_area(service_id, broadcast_message_id, library_slug): search_form=SearchByNameForm(), show_search_form=(len(form.areas.choices) > 7), page_title=library.name, + broadcast_message=broadcast_message, ) @@ -124,3 +125,17 @@ def preview_broadcast_message(service_id, broadcast_message_id): 'views/broadcast/preview-message.html', broadcast_message=broadcast_message, ) + + +@main.route('/services//broadcast//cancel') +@user_has_permissions('send_messages') +@service_has_permission('broadcast') +def cancel_broadcast_message(service_id, broadcast_message_id): + BroadcastMessage.from_id( + broadcast_message_id, + service_id=current_service.id, + ).cancel_broadcast() + return redirect(url_for( + '.broadcast_dashboard', + service_id=current_service.id, + )) diff --git a/app/models/broadcast_message.py b/app/models/broadcast_message.py index bdc4c37bf..c3efd2ed1 100644 --- a/app/models/broadcast_message.py +++ b/app/models/broadcast_message.py @@ -36,6 +36,13 @@ class BroadcastMessage(JSONModel): libraries = broadcast_area_libraries + def __lt__(self, other): + return ( + self.cancelled_at or self.finishes_at + ) < ( + other.cancelled_at or other.finishes_at + ) + @classmethod def create(cls, *, service_id, template_id): return cls(broadcast_message_api_client.create_broadcast_message( @@ -125,6 +132,13 @@ class BroadcastMessage(JSONModel): service_id=self.service_id, ) + def cancel_broadcast(self): + broadcast_message_api_client.update_broadcast_message_status( + 'cancelled', + broadcast_message_id=self.id, + service_id=self.service_id, + ) + class BroadcastMessages(ModelList): diff --git a/app/navigation.py b/app/navigation.py index d5c90b836..a2a5137cd 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -358,6 +358,7 @@ class HeaderNavigation(Navigation): 'choose_broadcast_area', 'remove_broadcast_area', 'preview_broadcast_message', + 'cancel_broadcast_message', } # header HTML now comes from GOVUK Frontend so requires a boolean, not an attribute @@ -413,6 +414,7 @@ class MainNavigation(Navigation): 'choose_broadcast_area', 'remove_broadcast_area', 'preview_broadcast_message', + 'cancel_broadcast_message', }, 'uploads': { 'upload_contact_list', @@ -1001,6 +1003,7 @@ class CaseworkNavigation(Navigation): 'choose_broadcast_area', 'remove_broadcast_area', 'preview_broadcast_message', + 'cancel_broadcast_message', } @@ -1318,4 +1321,5 @@ class OrgNavigation(Navigation): 'choose_broadcast_area', 'remove_broadcast_area', 'preview_broadcast_message', + 'cancel_broadcast_message', } diff --git a/app/templates/views/broadcast/areas.html b/app/templates/views/broadcast/areas.html index dd63b4d26..5020b587c 100644 --- a/app/templates/views/broadcast/areas.html +++ b/app/templates/views/broadcast/areas.html @@ -14,7 +14,7 @@ {{ page_header( page_title, - back_link=url_for('.choose_broadcast_library', service_id=current_service.id, broadcast_message_id=broadcast_message_id), + back_link=url_for('.choose_broadcast_library', service_id=current_service.id, broadcast_message_id=broadcast_message.id), )}} {{ live_search(target_selector='.multiple-choice', show=show_search_form, form=search_form, label='Search by name') }} diff --git a/app/templates/views/broadcast/dashboard.html b/app/templates/views/broadcast/dashboard.html index 64672943e..24d78a94b 100644 --- a/app/templates/views/broadcast/dashboard.html +++ b/app/templates/views/broadcast/dashboard.html @@ -5,7 +5,7 @@ {% macro broadcast_table(broadcasts, empty_message) %}
{% call(item, row_number) list_table( - broadcasts, + broadcasts|sort|reverse|list, caption="Live broadcasts", caption_visible=False, empty_message=empty_message, @@ -24,15 +24,20 @@
{% endcall %} {% call field(align='right') %} -

- {% if item.status == 'broadcasting' %} + {% if item.status == 'broadcasting' %} +

Live until {{ item.finishes_at|format_datetime_relative }} - {% elif item.status == 'cancelled' %} + Stop broadcasting +

+ {% elif item.status == 'cancelled' %} +

Stopped {{ item.cancelled_at|format_datetime_relative }} - {% else %} +

+ {% else %} +

Finished {{ item.finishes_at|format_datetime_relative }} - {% endif %} -

+

+ {% endif %} {% endcall %} {% endcall %} diff --git a/tests/app/main/views/test_broadcast.py b/tests/app/main/views/test_broadcast.py index 13a933f2e..4b24d74b2 100644 --- a/tests/app/main/views/test_broadcast.py +++ b/tests/app/main/views/test_broadcast.py @@ -78,13 +78,13 @@ def test_broadcast_dashboard( assert [ normalize_spaces(row.text) for row in page.select('table')[0].select('tbody tr') ] == [ - 'Example template To England and Scotland Live until tomorrow at 2:20am', + 'Example template To England and Scotland Live until tomorrow at 2:20am Stop broadcasting', ] assert [ normalize_spaces(row.text) for row in page.select('table')[1].select('tbody tr') ] == [ - 'Example template To England and Scotland Finished yesterday at 8:20pm', 'Example template To England and Scotland Stopped 10 February at 2:20am', + 'Example template To England and Scotland Finished yesterday at 8:20pm', ] @@ -275,3 +275,28 @@ def test_start_broadcasting( service_id=SERVICE_ONE_ID, broadcast_message_id=fake_uuid, ) + + +def test_cancel_broadcast( + client_request, + service_one, + mock_get_draft_broadcast_message, + mock_update_broadcast_message_status, + fake_uuid, +): + service_one['permissions'] += ['broadcast'] + client_request.get( + '.cancel_broadcast_message', + service_id=SERVICE_ONE_ID, + broadcast_message_id=fake_uuid, + _expected_redirect=url_for( + '.broadcast_dashboard', + service_id=SERVICE_ONE_ID, + _external=True, + ), + ), + mock_update_broadcast_message_status.assert_called_once_with( + 'cancelled', + service_id=SERVICE_ONE_ID, + broadcast_message_id=fake_uuid, + )