mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-23 07:46:23 -04:00
Merge pull request #3547 from alphagov/broadcast-tour
Add a tour for users new to broadcast services
This commit is contained in:
BIN
app/assets/images/broadcast-tour/1.png
Normal file
BIN
app/assets/images/broadcast-tour/1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
BIN
app/assets/images/broadcast-tour/2.png
Normal file
BIN
app/assets/images/broadcast-tour/2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 117 KiB |
BIN
app/assets/images/broadcast-tour/3.png
Normal file
BIN
app/assets/images/broadcast-tour/3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
3214
app/assets/images/broadcast-tour/artwork.ai
Normal file
3214
app/assets/images/broadcast-tour/artwork.ai
Normal file
File diff suppressed because one or more lines are too long
@@ -78,6 +78,11 @@
|
|||||||
box-shadow: inset 0 -1em 1.6em 0 rgba(0, 0, 0, 0.05);
|
box-shadow: inset 0 -1em 1.6em 0 rgba(0, 0, 0, 0.05);
|
||||||
border: 0;
|
border: 0;
|
||||||
|
|
||||||
|
&-no-fixed-height {
|
||||||
|
height: auto;
|
||||||
|
min-height: 425px;
|
||||||
|
}
|
||||||
|
|
||||||
.heading-medium {
|
.heading-medium {
|
||||||
@include core-24;
|
@include core-24;
|
||||||
}
|
}
|
||||||
@@ -98,6 +103,18 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@include core-24;
|
||||||
|
color: $white;
|
||||||
|
margin-bottom: govuk-spacing(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: govuk-spacing(3);
|
||||||
|
list-style-type: disc;
|
||||||
|
margin-left: govuk-spacing(6);
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -123,6 +140,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.greyed-out-step {
|
.greyed-out-step {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
|
|||||||
@@ -19,6 +19,17 @@ from app.models.broadcast_message import BroadcastMessage, BroadcastMessages
|
|||||||
from app.utils import service_has_permission, user_has_permissions
|
from app.utils import service_has_permission, user_has_permissions
|
||||||
|
|
||||||
|
|
||||||
|
@main.route('/services/<uuid:service_id>/broadcast-tour/<int:step_index>')
|
||||||
|
@user_has_permissions()
|
||||||
|
@service_has_permission('broadcast')
|
||||||
|
def broadcast_tour(service_id, step_index):
|
||||||
|
if step_index not in (1, 2, 3):
|
||||||
|
abort(404)
|
||||||
|
return render_template(
|
||||||
|
f'views/broadcast/tour/{step_index}.html'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@main.route('/services/<uuid:service_id>/broadcast-dashboard')
|
@main.route('/services/<uuid:service_id>/broadcast-dashboard')
|
||||||
@user_has_permissions()
|
@user_has_permissions()
|
||||||
@service_has_permission('broadcast')
|
@service_has_permission('broadcast')
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ def accept_invite(token):
|
|||||||
|
|
||||||
if invited_user.status == 'accepted':
|
if invited_user.status == 'accepted':
|
||||||
session.pop('invited_user', None)
|
session.pop('invited_user', None)
|
||||||
|
service = Service.from_id(invited_user.service)
|
||||||
|
if service.has_permission('broadcast'):
|
||||||
|
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'] = invited_user.serialize()
|
session['invited_user'] = invited_user.serialize()
|
||||||
@@ -66,6 +69,8 @@ def accept_invite(token):
|
|||||||
permissions=invited_user.permissions,
|
permissions=invited_user.permissions,
|
||||||
folder_permissions=invited_user.folder_permissions,
|
folder_permissions=invited_user.folder_permissions,
|
||||||
)
|
)
|
||||||
|
if service.has_permission('broadcast'):
|
||||||
|
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'))
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from notifications_utils.url_safe_token import check_token
|
|||||||
from app import user_api_client
|
from app import user_api_client
|
||||||
from app.main import main
|
from app.main import main
|
||||||
from app.main.forms import TwoFactorForm
|
from app.main.forms import TwoFactorForm
|
||||||
|
from app.models.service import Service
|
||||||
from app.models.user import InvitedUser, User
|
from app.models.user import InvitedUser, User
|
||||||
from app.utils import redirect_to_sign_in
|
from app.utils import redirect_to_sign_in
|
||||||
|
|
||||||
@@ -77,6 +78,9 @@ def activate_user(user_id):
|
|||||||
invited_user = session.get('invited_user')
|
invited_user = session.get('invited_user')
|
||||||
if invited_user:
|
if invited_user:
|
||||||
service_id = _add_invited_user_to_service(invited_user)
|
service_id = _add_invited_user_to_service(invited_user)
|
||||||
|
service = Service.from_id(service_id)
|
||||||
|
if service.has_permission('broadcast'):
|
||||||
|
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))
|
||||||
|
|
||||||
invited_org_user = session.get('invited_org_user')
|
invited_org_user = session.get('invited_org_user')
|
||||||
|
|||||||
@@ -352,6 +352,7 @@ class HeaderNavigation(Navigation):
|
|||||||
'old_guest_list',
|
'old_guest_list',
|
||||||
'who_can_use_notify',
|
'who_can_use_notify',
|
||||||
'who_its_for',
|
'who_its_for',
|
||||||
|
'broadcast_tour',
|
||||||
'broadcast_dashboard',
|
'broadcast_dashboard',
|
||||||
'broadcast_dashboard_updates',
|
'broadcast_dashboard_updates',
|
||||||
'broadcast',
|
'broadcast',
|
||||||
@@ -375,6 +376,7 @@ class MainNavigation(Navigation):
|
|||||||
|
|
||||||
mapping = {
|
mapping = {
|
||||||
'dashboard': {
|
'dashboard': {
|
||||||
|
'broadcast_tour',
|
||||||
'broadcast_dashboard',
|
'broadcast_dashboard',
|
||||||
'broadcast_dashboard_updates',
|
'broadcast_dashboard_updates',
|
||||||
'conversation',
|
'conversation',
|
||||||
@@ -702,6 +704,7 @@ class CaseworkNavigation(Navigation):
|
|||||||
|
|
||||||
mapping = {
|
mapping = {
|
||||||
'dashboard': {
|
'dashboard': {
|
||||||
|
'broadcast_tour',
|
||||||
'broadcast_dashboard',
|
'broadcast_dashboard',
|
||||||
'broadcast_dashboard_updates',
|
'broadcast_dashboard_updates',
|
||||||
},
|
},
|
||||||
@@ -1330,6 +1333,7 @@ class OrgNavigation(Navigation):
|
|||||||
'old_guest_list',
|
'old_guest_list',
|
||||||
'who_can_use_notify',
|
'who_can_use_notify',
|
||||||
'who_its_for',
|
'who_its_for',
|
||||||
|
'broadcast_tour',
|
||||||
'broadcast_dashboard',
|
'broadcast_dashboard',
|
||||||
'broadcast_dashboard_updates',
|
'broadcast_dashboard_updates',
|
||||||
'broadcast',
|
'broadcast',
|
||||||
|
|||||||
@@ -10,6 +10,14 @@
|
|||||||
|
|
||||||
<h1 class="govuk-visually-hidden">Dashboard</h1>
|
<h1 class="govuk-visually-hidden">Dashboard</h1>
|
||||||
|
|
||||||
|
{% if current_user.has_permissions('manage_templates') and not current_service.all_templates %}
|
||||||
|
<nav class="govuk-!-margin-top-2 govuk-!-margin-bottom-6">
|
||||||
|
<a class="govuk-link govuk-link--no-visited-state pill-separate-item govuk-!-padding-top-4 govuk-!-padding-bottom-4 govuk-!-font-weight-bold" href="{{ url_for('.choose_template', service_id=current_service.id) }}">
|
||||||
|
Start by creating a template
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<h2 class="heading-medium govuk-!-margin-bottom-2">Live broadcasts</h2>
|
<h2 class="heading-medium govuk-!-margin-bottom-2">Live broadcasts</h2>
|
||||||
|
|
||||||
{{ ajax_block(
|
{{ ajax_block(
|
||||||
|
|||||||
41
app/templates/views/broadcast/tour/1.html
Normal file
41
app/templates/views/broadcast/tour/1.html
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{% from "components/banner.html" import banner_wrapper %}
|
||||||
|
|
||||||
|
{% extends "admin_template.html" %}
|
||||||
|
|
||||||
|
{% block per_page_title %}
|
||||||
|
Step 1
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% set mainClasses = "govuk-!-padding-top-0 govuk-!-padding-bottom-0" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="banner-tour banner-tour-no-fixed-height govuk-!-margin-top-0">
|
||||||
|
<div class="govuk-grid-row">
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<h1 class="heading-medium">
|
||||||
|
You’ve been invited to use GOV.UK Notify to broadcast alerts
|
||||||
|
</h1>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Broadcasting is a new technology for alerting members of the
|
||||||
|
public
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
It should be used when there’s an imminent risk to life
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p class="govuk-body heading-medium">
|
||||||
|
<a class="govuk-link govuk-link--no-visited-state" href='{{ url_for(".broadcast_tour", service_id=current_service.id, step_index=2) }}'>
|
||||||
|
Find out how it works
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<img src="{{ asset_url('images/broadcast-tour/1.png') }}" alt="">
|
||||||
|
<link rel="preload" href="{{ asset_url('images/broadcast-tour/2.png') }}" as="image">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
44
app/templates/views/broadcast/tour/2.html
Normal file
44
app/templates/views/broadcast/tour/2.html
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{% from "components/banner.html" import banner_wrapper %}
|
||||||
|
|
||||||
|
{% extends "admin_template.html" %}
|
||||||
|
|
||||||
|
{% block per_page_title %}
|
||||||
|
Step 2
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% set mainClasses = "govuk-!-padding-top-0 govuk-!-padding-bottom-0" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="banner-tour banner-tour-no-fixed-height govuk-!-margin-top-0">
|
||||||
|
<div class="govuk-grid-row">
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<h1 class="heading-medium">
|
||||||
|
A broadcast will alert every phone in an area
|
||||||
|
</h1>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The alert will appear even if the phone’s screen is locked
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The phone will play an alarm sound even if it’s set to silent
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Any phone that enters the area while the broadcast is live will
|
||||||
|
get the alert
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p class="govuk-body heading-medium govuk-!-margin-bottom-6">
|
||||||
|
<a class="govuk-link govuk-link--no-visited-state" href='{{ url_for(".broadcast_tour", service_id=current_service.id, step_index=3) }}'>
|
||||||
|
How to try it out
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<img src="{{ asset_url('images/broadcast-tour/2.png') }}" alt="">
|
||||||
|
<link rel="preload" href="{{ asset_url('images/broadcast-tour/3.png') }}" as="image">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
43
app/templates/views/broadcast/tour/3.html
Normal file
43
app/templates/views/broadcast/tour/3.html
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{% from "components/banner.html" import banner_wrapper %}
|
||||||
|
|
||||||
|
{% extends "admin_template.html" %}
|
||||||
|
|
||||||
|
{% block per_page_title %}
|
||||||
|
Step 3
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% set mainClasses = "govuk-!-padding-top-0 govuk-!-padding-bottom-0" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="banner-tour banner-tour-no-fixed-height govuk-!-margin-top-0">
|
||||||
|
<div class="govuk-grid-row">
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<h1 class="heading-medium">
|
||||||
|
You have a trial account
|
||||||
|
</h1>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
There’s no risk of triggering a real, live broadcast
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Get familiar with the system now, so you’re ready to use it if
|
||||||
|
there’s an emergency
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
When you’re ready, apply for a live account
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<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 to dashboard
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="govuk-grid-column-one-half">
|
||||||
|
<img src="{{ asset_url('images/broadcast-tour/3.png') }}" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -94,6 +94,7 @@ def test_empty_broadcast_dashboard(
|
|||||||
client_request,
|
client_request,
|
||||||
service_one,
|
service_one,
|
||||||
mock_get_no_broadcast_messages,
|
mock_get_no_broadcast_messages,
|
||||||
|
mock_get_service_templates_when_no_templates_exist,
|
||||||
):
|
):
|
||||||
service_one['permissions'] += ['broadcast']
|
service_one['permissions'] += ['broadcast']
|
||||||
page = client_request.get(
|
page = client_request.get(
|
||||||
@@ -114,6 +115,7 @@ def test_broadcast_dashboard(
|
|||||||
client_request,
|
client_request,
|
||||||
service_one,
|
service_one,
|
||||||
mock_get_broadcast_messages,
|
mock_get_broadcast_messages,
|
||||||
|
mock_get_service_templates,
|
||||||
):
|
):
|
||||||
service_one['permissions'] += ['broadcast']
|
service_one['permissions'] += ['broadcast']
|
||||||
page = client_request.get(
|
page = client_request.get(
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ def test_register_from_email_auth_invite(
|
|||||||
mock_accept_invite,
|
mock_accept_invite,
|
||||||
mock_create_event,
|
mock_create_event,
|
||||||
mock_add_user_to_service,
|
mock_add_user_to_service,
|
||||||
|
mock_get_service,
|
||||||
invite_email_address,
|
invite_email_address,
|
||||||
):
|
):
|
||||||
sample_invite['auth_type'] = 'email_auth'
|
sample_invite['auth_type'] = 'email_auth'
|
||||||
@@ -372,6 +373,7 @@ def test_can_register_email_auth_without_phone_number(
|
|||||||
mock_accept_invite,
|
mock_accept_invite,
|
||||||
mock_create_event,
|
mock_create_event,
|
||||||
mock_add_user_to_service,
|
mock_add_user_to_service,
|
||||||
|
mock_get_service,
|
||||||
):
|
):
|
||||||
sample_invite['auth_type'] = 'email_auth'
|
sample_invite['auth_type'] = 'email_auth'
|
||||||
with client.session_transaction() as session:
|
with client.session_transaction() as session:
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ def test_activate_user_redirects_to_service_dashboard_if_user_already_belongs_to
|
|||||||
sample_invite,
|
sample_invite,
|
||||||
api_user_active,
|
api_user_active,
|
||||||
mock_login,
|
mock_login,
|
||||||
|
mock_get_service,
|
||||||
):
|
):
|
||||||
mocker.patch('app.user_api_client.add_user_to_service', side_effect=HTTPError(
|
mocker.patch('app.user_api_client.add_user_to_service', side_effect=HTTPError(
|
||||||
response=Mock(
|
response=Mock(
|
||||||
|
|||||||
Reference in New Issue
Block a user