mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-24 16:24:08 -04:00
Add a version of the tour for live services
At the moment if you’re invited to a live broadcast service you get the training mode tour. This is misleading, and could make people think they weren’t in danger of sending a real alert. This commit adds a short, 2 step tour for users invited to a live broadcast service.
This commit is contained in:
File diff suppressed because one or more lines are too long
BIN
app/assets/images/broadcast-tour/live/1.png
Normal file
BIN
app/assets/images/broadcast-tour/live/1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
app/assets/images/broadcast-tour/live/2.png
Normal file
BIN
app/assets/images/broadcast-tour/live/2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.1 KiB |
@@ -137,7 +137,7 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
color: $white;
|
color: $white;
|
||||||
background-color: $link-hover-colour;
|
background-color: $link-hover-colour;
|
||||||
box-shadow: 0 0 0 10px solid $link-hover-colour;
|
box-shadow: 0 0 0 10px $link-hover-colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus,
|
&:focus,
|
||||||
|
|||||||
@@ -42,6 +42,17 @@ def broadcast_tour(service_id, step_index):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@main.route('/services/<uuid:service_id>/broadcast-tour/live/<int:step_index>')
|
||||||
|
@user_has_permissions()
|
||||||
|
@service_has_permission('broadcast')
|
||||||
|
def broadcast_tour_live(service_id, step_index):
|
||||||
|
if step_index not in (1, 2):
|
||||||
|
abort(404)
|
||||||
|
return render_template(
|
||||||
|
f'views/broadcast/tour/live/{step_index}.html'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@main.route('/services/<uuid:service_id>/current-alerts')
|
@main.route('/services/<uuid:service_id>/current-alerts')
|
||||||
@user_has_permissions()
|
@user_has_permissions()
|
||||||
@service_has_permission('broadcast')
|
@service_has_permission('broadcast')
|
||||||
|
|||||||
@@ -37,12 +37,14 @@ def accept_invite(token):
|
|||||||
return render_template('views/cancelled-invitation.html',
|
return render_template('views/cancelled-invitation.html',
|
||||||
from_user=invited_user.from_user.name,
|
from_user=invited_user.from_user.name,
|
||||||
service_name=service.name)
|
service_name=service.name)
|
||||||
|
|
||||||
if invited_user.status == 'accepted':
|
if invited_user.status == 'accepted':
|
||||||
session.pop('invited_user_id', None)
|
session.pop('invited_user_id', None)
|
||||||
service = Service.from_id(invited_user.service)
|
service = Service.from_id(invited_user.service)
|
||||||
if service.has_permission('broadcast'):
|
if service.has_permission('broadcast'):
|
||||||
return redirect(url_for('main.broadcast_tour', service_id=service.id, step_index=1))
|
if service.live:
|
||||||
|
return redirect(url_for('main.broadcast_tour_live', service_id=service.id, step_index=1))
|
||||||
|
else:
|
||||||
|
return redirect(url_for('main.broadcast_tour', service_id=service.id, step_index=1))
|
||||||
return redirect(url_for('main.service_dashboard', service_id=invited_user.service))
|
return redirect(url_for('main.service_dashboard', service_id=invited_user.service))
|
||||||
|
|
||||||
session['invited_user_id'] = invited_user.id
|
session['invited_user_id'] = invited_user.id
|
||||||
@@ -71,7 +73,10 @@ def accept_invite(token):
|
|||||||
invited_by_id=invited_user.from_user.id,
|
invited_by_id=invited_user.from_user.id,
|
||||||
)
|
)
|
||||||
if service.has_permission('broadcast'):
|
if service.has_permission('broadcast'):
|
||||||
return redirect(url_for('main.broadcast_tour', service_id=service.id, step_index=1))
|
if service.live:
|
||||||
|
return redirect(url_for('main.broadcast_tour_live', service_id=service.id, step_index=1))
|
||||||
|
else:
|
||||||
|
return redirect(url_for('main.broadcast_tour', service_id=service.id, step_index=1))
|
||||||
return redirect(url_for('main.service_dashboard', service_id=service.id))
|
return redirect(url_for('main.service_dashboard', service_id=service.id))
|
||||||
else:
|
else:
|
||||||
return redirect(url_for('main.register_from_invite'))
|
return redirect(url_for('main.register_from_invite'))
|
||||||
|
|||||||
31
app/templates/service_navigation.html
Normal file
31
app/templates/service_navigation.html
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<div class="navigation-service">
|
||||||
|
{% if current_service.organisation_id %}
|
||||||
|
{% if current_user.platform_admin or
|
||||||
|
(current_user.belongs_to_organisation(current_service.organisation_id) and current_service.live) %}
|
||||||
|
<a href="{{ url_for('.organisation_dashboard', org_id=current_service.organisation_id) }}" class="govuk-link govuk-link--no-visited-state navigation-organisation-link">{{ current_service.organisation_name }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
<div class="navigation-service-name govuk-!-font-weight-bold">
|
||||||
|
{{ current_service.name }}
|
||||||
|
{% if not current_service.active %}
|
||||||
|
<span class="navigation-service-type navigation-service-type--suspended">Suspended</span>
|
||||||
|
{% elif current_service.has_permission('broadcast') %}
|
||||||
|
{% if current_service.trial_mode %}
|
||||||
|
<span class="navigation-service-type navigation-service-type--training">Training
|
||||||
|
{% elif current_service.broadcast_channel == 'severe' %}
|
||||||
|
<span class="navigation-service-type navigation-service-type--live">Live
|
||||||
|
{% elif current_service.broadcast_channel == 'test' %}
|
||||||
|
<span class="navigation-service-type navigation-service-type--live">{{ current_service.broadcast_channel|title }}
|
||||||
|
{% if current_service.allowed_broadcast_provider == "all" %}
|
||||||
|
(all networks)
|
||||||
|
{% else %}
|
||||||
|
({{ current_service.allowed_broadcast_provider }})
|
||||||
|
{% endif %}
|
||||||
|
{% elif current_service.broadcast_channel == 'government' %}
|
||||||
|
<span class="navigation-service-type navigation-service-type--government">Government
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<a href="{{ url_for('main.choose_account') }}" class="govuk-link govuk-link--no-visited-state navigation-service-switch">Switch service</a>
|
||||||
|
</div>
|
||||||
37
app/templates/views/broadcast/tour/live/1.html
Normal file
37
app/templates/views/broadcast/tour/live/1.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{% from "components/banner.html" import banner_wrapper %}
|
||||||
|
|
||||||
|
{% extends "admin_template.html" %}
|
||||||
|
|
||||||
|
{% block per_page_title %}
|
||||||
|
You’ve been invited to send live emergency alerts.
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% set mainClasses = "govuk-!-padding-top-0 govuk-!-padding-bottom-0" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% include "service_navigation.html" %}
|
||||||
|
|
||||||
|
<div class="banner-tour banner-tour-no-fixed-height banner-tour-with-service-name">
|
||||||
|
<div class="govuk-grid-row">
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<h1 class="heading-medium">
|
||||||
|
You’ve been invited to send live emergency alerts.
|
||||||
|
</h1>
|
||||||
|
<p class="govuk-body heading-medium">
|
||||||
|
Members of the public will receive alerts you send from this service.
|
||||||
|
</p>
|
||||||
|
<p class="govuk-body heading-medium">
|
||||||
|
<a class="govuk-link govuk-link--no-visited-state" href='{{ url_for(".broadcast_tour_live", service_id=current_service.id, step_index=2) }}'>
|
||||||
|
Continue
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<img src="{{ asset_url('images/broadcast-tour/live/1.png') }}" alt="">
|
||||||
|
<link rel="preload" href="{{ asset_url('images/broadcast-tour/live/2.png') }}" as="image">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
33
app/templates/views/broadcast/tour/live/2.html
Normal file
33
app/templates/views/broadcast/tour/live/2.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{% from "components/banner.html" import banner_wrapper %}
|
||||||
|
|
||||||
|
{% extends "admin_template.html" %}
|
||||||
|
|
||||||
|
{% block per_page_title %}
|
||||||
|
You can always go back to training mode by clicking ‘Switch service’ in the top right.
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% set mainClasses = "govuk-!-padding-top-0 govuk-!-padding-bottom-0" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% include "service_navigation.html" %}
|
||||||
|
|
||||||
|
<div class="banner-tour banner-tour-no-fixed-height banner-tour-with-service-name">
|
||||||
|
<div class="govuk-grid-row">
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<h1 class="heading-medium">
|
||||||
|
You can always go back to training mode by clicking ‘Switch service’ in the top right.
|
||||||
|
</h1>
|
||||||
|
<p class="govuk-body heading-medium">
|
||||||
|
<a class="govuk-link govuk-link--no-visited-state" href='{{ url_for(".service_dashboard", service_id=current_service.id) }}'>
|
||||||
|
Continue
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<img src="{{ asset_url('images/broadcast-tour/live/2.png') }}" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -8,37 +8,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<div class="govuk-width-container">
|
<div class="govuk-width-container">
|
||||||
<div class="navigation-service">
|
{% include "service_navigation.html" %}
|
||||||
{% if current_service.organisation_id %}
|
|
||||||
{% if current_user.platform_admin or
|
|
||||||
(current_user.belongs_to_organisation(current_service.organisation_id) and current_service.live) %}
|
|
||||||
<a href="{{ url_for('.organisation_dashboard', org_id=current_service.organisation_id) }}" class="govuk-link govuk-link--no-visited-state navigation-organisation-link">{{ current_service.organisation_name }}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
<div class="navigation-service-name govuk-!-font-weight-bold">
|
|
||||||
{{ current_service.name }}
|
|
||||||
{% if not current_service.active %}
|
|
||||||
<span class="navigation-service-type navigation-service-type--suspended">Suspended</span>
|
|
||||||
{% elif current_service.has_permission('broadcast') %}
|
|
||||||
{% if current_service.trial_mode %}
|
|
||||||
<span class="navigation-service-type navigation-service-type--training">Training
|
|
||||||
{% elif current_service.broadcast_channel == 'severe' %}
|
|
||||||
<span class="navigation-service-type navigation-service-type--live">Live
|
|
||||||
{% elif current_service.broadcast_channel == 'test' %}
|
|
||||||
<span class="navigation-service-type navigation-service-type--live">{{ current_service.broadcast_channel|title }}
|
|
||||||
{% if current_service.allowed_broadcast_provider == "all" %}
|
|
||||||
(all networks)
|
|
||||||
{% else %}
|
|
||||||
({{ current_service.allowed_broadcast_provider }})
|
|
||||||
{% endif %}
|
|
||||||
{% elif current_service.broadcast_channel == 'government' %}
|
|
||||||
<span class="navigation-service-type navigation-service-type--government">Government
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<a href="{{ url_for('main.choose_account') }}" class="govuk-link govuk-link--no-visited-state navigation-service-switch">Switch service</a>
|
|
||||||
</div>
|
|
||||||
<div class="govuk-grid-row govuk-!-padding-bottom-12">
|
<div class="govuk-grid-row govuk-!-padding-bottom-12">
|
||||||
{% if help %}
|
{% if help %}
|
||||||
<div class="govuk-grid-column-one-third">
|
<div class="govuk-grid-column-one-third">
|
||||||
|
|||||||
@@ -55,6 +55,44 @@ def test_existing_user_accept_invite_calls_api_and_redirects_to_dashboard(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('trial_mode, expected_endpoint', (
|
||||||
|
(True, '.broadcast_tour'),
|
||||||
|
(False, '.broadcast_tour_live'),
|
||||||
|
))
|
||||||
|
def test_broadcast_service_shows_tour(
|
||||||
|
client,
|
||||||
|
service_one,
|
||||||
|
mock_check_invite_token,
|
||||||
|
mock_get_unknown_user_by_email,
|
||||||
|
mock_get_users_by_service,
|
||||||
|
mock_accept_invite,
|
||||||
|
mock_add_user_to_service,
|
||||||
|
mocker,
|
||||||
|
mock_events,
|
||||||
|
mock_get_user,
|
||||||
|
trial_mode,
|
||||||
|
expected_endpoint,
|
||||||
|
):
|
||||||
|
service_one['permissions'] = ['broadcast']
|
||||||
|
service_one['restricted'] = trial_mode
|
||||||
|
|
||||||
|
mocker.patch('app.service_api_client.get_service', return_value={
|
||||||
|
'data': service_one,
|
||||||
|
})
|
||||||
|
|
||||||
|
response = client.get(url_for(
|
||||||
|
'main.accept_invite',
|
||||||
|
token='thisisnotarealtoken'
|
||||||
|
))
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.location == url_for(
|
||||||
|
expected_endpoint,
|
||||||
|
service_id=SERVICE_ONE_ID,
|
||||||
|
step_index=1,
|
||||||
|
_external=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_existing_user_with_no_permissions_or_folder_permissions_accept_invite(
|
def test_existing_user_with_no_permissions_or_folder_permissions_accept_invite(
|
||||||
client,
|
client,
|
||||||
mocker,
|
mocker,
|
||||||
|
|||||||
@@ -236,24 +236,27 @@ def test_cancel_broadcast_page_403_for_user_without_permission(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('step_index, expected_link_text, expected_link_href', (
|
@pytest.mark.parametrize('endpoint, step_index, expected_link_text, expected_link_href', (
|
||||||
(1, 'Continue', partial(url_for, '.broadcast_tour', step_index=2)),
|
('.broadcast_tour', 1, 'Continue', partial(url_for, '.broadcast_tour', step_index=2)),
|
||||||
(2, 'Continue', partial(url_for, '.broadcast_tour', step_index=3)),
|
('.broadcast_tour', 2, 'Continue', partial(url_for, '.broadcast_tour', step_index=3)),
|
||||||
(3, 'Continue', partial(url_for, '.broadcast_tour', step_index=4)),
|
('.broadcast_tour', 3, 'Continue', partial(url_for, '.broadcast_tour', step_index=4)),
|
||||||
(4, 'Continue', partial(url_for, '.broadcast_tour', step_index=5)),
|
('.broadcast_tour', 4, 'Continue', partial(url_for, '.broadcast_tour', step_index=5)),
|
||||||
(5, 'Continue', partial(url_for, '.service_dashboard')),
|
('.broadcast_tour', 5, 'Continue', partial(url_for, '.service_dashboard')),
|
||||||
(6, 'Continue', partial(url_for, '.service_dashboard')),
|
('.broadcast_tour', 6, 'Continue', partial(url_for, '.service_dashboard')),
|
||||||
|
('.broadcast_tour_live', 1, 'Continue', partial(url_for, '.broadcast_tour_live', step_index=2)),
|
||||||
|
('.broadcast_tour_live', 2, 'Continue', partial(url_for, '.service_dashboard')),
|
||||||
))
|
))
|
||||||
def test_broadcast_tour_pages_have_continue_link(
|
def test_broadcast_tour_pages_have_continue_link(
|
||||||
client_request,
|
client_request,
|
||||||
service_one,
|
service_one,
|
||||||
|
endpoint,
|
||||||
step_index,
|
step_index,
|
||||||
expected_link_text,
|
expected_link_text,
|
||||||
expected_link_href,
|
expected_link_href,
|
||||||
):
|
):
|
||||||
service_one['permissions'] += ['broadcast']
|
service_one['permissions'] += ['broadcast']
|
||||||
page = client_request.get(
|
page = client_request.get(
|
||||||
'.broadcast_tour',
|
endpoint,
|
||||||
service_id=SERVICE_ONE_ID,
|
service_id=SERVICE_ONE_ID,
|
||||||
step_index=step_index,
|
step_index=step_index,
|
||||||
)
|
)
|
||||||
@@ -286,6 +289,28 @@ def test_broadcast_tour_page_4_shows_service_name(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('step_index', (
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
))
|
||||||
|
def test_live_broadcast_tour_shows_service_name_and_switch(
|
||||||
|
client_request,
|
||||||
|
service_one,
|
||||||
|
step_index,
|
||||||
|
):
|
||||||
|
service_one['permissions'] += ['broadcast']
|
||||||
|
service_one['restricted'] = False
|
||||||
|
service_one['allowed_broadcast_provider'] = 'all'
|
||||||
|
page = client_request.get(
|
||||||
|
'.broadcast_tour_live',
|
||||||
|
service_id=SERVICE_ONE_ID,
|
||||||
|
step_index=step_index,
|
||||||
|
)
|
||||||
|
assert normalize_spaces(page.select_one('.navigation-service').text) == (
|
||||||
|
'service one Live Switch service'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'trial_mode, channel, allowed_broadcast_provider, selector, expected_text, expected_tagged_text',
|
'trial_mode, channel, allowed_broadcast_provider, selector, expected_text, expected_tagged_text',
|
||||||
(
|
(
|
||||||
@@ -371,15 +396,21 @@ def test_broadcast_service_shows_live_or_training(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('step_index', (0, 7))
|
@pytest.mark.parametrize('endpoint, step_index', (
|
||||||
|
('.broadcast_tour', 0),
|
||||||
|
('.broadcast_tour', 7),
|
||||||
|
('.broadcast_tour_live', 0),
|
||||||
|
('.broadcast_tour_live', 3),
|
||||||
|
))
|
||||||
def test_broadcast_tour_page_404s_out_of_range(
|
def test_broadcast_tour_page_404s_out_of_range(
|
||||||
client_request,
|
client_request,
|
||||||
service_one,
|
service_one,
|
||||||
|
endpoint,
|
||||||
step_index,
|
step_index,
|
||||||
):
|
):
|
||||||
service_one['permissions'] += ['broadcast']
|
service_one['permissions'] += ['broadcast']
|
||||||
client_request.get(
|
client_request.get(
|
||||||
'.broadcast_tour',
|
endpoint,
|
||||||
service_id=SERVICE_ONE_ID,
|
service_id=SERVICE_ONE_ID,
|
||||||
step_index=step_index,
|
step_index=step_index,
|
||||||
_expected_status=404,
|
_expected_status=404,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ EXCLUDED_ENDPOINTS = tuple(map(Navigation.get_endpoint_with_blueprint, {
|
|||||||
'broadcast_dashboard_rejected',
|
'broadcast_dashboard_rejected',
|
||||||
'broadcast_dashboard_updates',
|
'broadcast_dashboard_updates',
|
||||||
'broadcast_tour',
|
'broadcast_tour',
|
||||||
|
'broadcast_tour_live',
|
||||||
'callbacks',
|
'callbacks',
|
||||||
'cancel_broadcast_message',
|
'cancel_broadcast_message',
|
||||||
'cancel_invited_org_user',
|
'cancel_invited_org_user',
|
||||||
|
|||||||
Reference in New Issue
Block a user