Add confirm loop

For pages where
- we want you to be sure that you want to do what you’re about to do
- we want to be sure it’s you trying to do the thing

This adds a page that asks the user to confirm their password.
This commit is contained in:
Chris Hill-Scott
2016-01-07 16:24:43 +00:00
parent 3989d1b576
commit 0b62d1e755
12 changed files with 227 additions and 82 deletions

View File

@@ -20,7 +20,7 @@
} }
&-hint { &-hint {
@include core-16; @include core-19;
margin-top: 5px; margin-top: 5px;
} }

View File

@@ -12,7 +12,8 @@
.button {} .button {}
.button-destructive { .button-destructive {
@include button($error-colour) @include button($error-colour);
padding: 0.52632em 0.78947em 0.26316em 0.78947em;
} }
} }

View File

@@ -1,4 +1,4 @@
from flask import render_template, redirect, request, url_for from flask import render_template, redirect, request, url_for, abort
from flask_login import login_required from flask_login import login_required
from app.main import main from app.main import main
@@ -25,6 +25,18 @@ def name():
'views/service-settings/name.html', 'views/service-settings/name.html',
service=service service=service
) )
elif request.method == 'POST':
return redirect(url_for('.confirm_name_change'))
@main.route("/service-settings/name/confirm", methods=['GET', 'POST'])
def confirm_name_change():
if request.method == 'GET':
return render_template(
'views/service-settings/confirm.html',
heading='Rename service',
submit_button_text='Confirm'
)
elif request.method == 'POST': elif request.method == 'POST':
return redirect(url_for('.service_settings')) return redirect(url_for('.service_settings'))
@@ -47,6 +59,19 @@ def status():
'views/service-settings/status.html', 'views/service-settings/status.html',
service=service service=service
) )
elif request.method == 'POST':
return redirect(url_for('.confirm_status_change'))
@main.route("/service-settings/status/confirm", methods=['GET', 'POST'])
def confirm_status_change():
if request.method == 'GET':
return render_template(
'views/service-settings/confirm.html',
heading='Turn off outgoing messages',
submit_button_text='Confirm',
destructive=True
)
elif request.method == 'POST': elif request.method == 'POST':
return redirect(url_for('.service_settings')) return redirect(url_for('.service_settings'))
@@ -59,4 +84,17 @@ def delete():
service=service service=service
) )
elif request.method == 'POST': elif request.method == 'POST':
return redirect(url_for('.index')) return redirect(url_for('.confirm_delete'))
@main.route("/service-settings/delete/confirm", methods=['GET', 'POST'])
def confirm_delete():
if request.method == 'GET':
return render_template(
'views/service-settings/confirm.html',
heading='Delete service',
submit_button_text='Confirm',
destructive=True
)
elif request.method == 'POST':
return redirect(url_for('.dashboard'))

View File

@@ -1,11 +0,0 @@
{% macro list(items) %}
{% if items %}
<ul class="list list-bullet">
{% for item in items %}
<li>
{{ item }}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}

View File

@@ -1,8 +1,8 @@
{% macro textbox(name, label, value='', small=True, highlight_tags=False) %} {% macro textbox(name, label, value='', small=True, highlight_tags=False, password=False) %}
<div class="form-group"> <div class="form-group">
<label class="form-label" for="{{ name }}">{{ label }}</label> <label class="form-label" for="{{ name }}">{{ label }}</label>
{% if small %} {% if small %}
<input class="form-control" id="{{ name }}" name="{{ name }}" type="text" value="{{ value }}"> <input class="form-control" id="{{ name }}" name="{{ name }}" type="{{ 'password' if password else 'text' }}" value="{{ value }}">
{% else %} {% else %}
<textarea <textarea
class="form-control {% if highlight_tags %}textbox-highlight-textbox{% endif %}" class="form-control {% if highlight_tags %}textbox-highlight-textbox{% endif %}"

View File

@@ -2,38 +2,38 @@
{% from "components/browse-list.html" import browse_list %} {% from "components/browse-list.html" import browse_list %}
{% block page_title %} {% block page_title %}
GOV.UK Notify | Service settings GOV.UK Notify | Service settings
{% endblock %} {% endblock %}
{% block maincolumn_content %} {% block maincolumn_content %}
<h1 class="heading-xlarge">Service settings</h1> <h1 class="heading-xlarge">Service settings</h1>
{{ browse_list([ {{ browse_list([
{ {
'title': 'Rename service', 'title': 'Rename service',
'link': url_for('.name'), 'link': url_for('.name'),
'hint': 'Your service is named {}'.format(service.name) 'hint': 'Your service is called {}'.format(service.name)
}, },
{ {
'title': 'Make service live', 'title': 'Request to make service live',
'link': url_for('.request_to_go_live'), 'link': url_for('.request_to_go_live'),
'hint': 'A live service can send messages to anyone', 'hint': 'A live service can send messages to any phone number or email address',
} if not service.live else { } if not service.live else {
}, },
{ {
'title': 'Stop sending messages', 'title': 'Turn off outgoing messages',
'link': url_for('.status') 'link': url_for('.status'),
} if service.active else { 'destructive': True
'title': 'Unsuspend service', } if service.active else {
'link': url_for('.status') 'title': 'Desuspend service',
}, 'link': url_for('.status')
{ },
'title': 'Delete everything', {
'link': url_for('.delete'), 'title': 'Delete service',
'hint': '', 'link': url_for('.delete'),
'destructive': True 'destructive': True
}, },
]) }} ]) }}
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,27 @@
{% extends "withnav_template.html" %}
{% from "components/textbox.html" import textbox %}
{% from "components/submit-form.html" import submit_form %}
{% block page_title %}
GOV.UK Notify | Service settings
{% endblock %}
{% block maincolumn_content %}
<h1 class="heading-xlarge">{{ heading }}</h1>
<div class="grid-row">
<div class="column-three-quarters">
<form method="post">
{{ textbox('new_name', 'Enter your password', password=True) }}
{{ submit_form(
submit_button_text,
destructive=destructive,
back_link=url_for('.service_settings')
) }}
</form>
</div>
</div>
{% endblock %}

View File

@@ -7,16 +7,37 @@
{% block maincolumn_content %} {% block maincolumn_content %}
<h1 class="heading-xlarge">Delete this service</h1> <div class="grid-row">
<div class="column-three-quarters">
<h1 class="heading-xlarge">Delete service</h1>
<p> <p>
All will be lost. This cant be undone. You will lose:
</p> </p>
<form method="post"> <ul class="list list-bullet">
{{ submit_form('Delete', destructive=True) }} <li>
</form> any data youve uploaded messages
</li>
<li>
any templates youve created
</li>
<li>
the history of
</li>
<li>
API keys
</li>
</ul>
<p><a href="{{ url_for('.service_settings') }}">Back to service settings</a></p> <form method="post">
{{ submit_form(
'Yes, delete {}'.format(service.name),
destructive=True,
back_link=url_for('.service_settings')
) }}
</form>
</div>
</div>
{% endblock %} {% endblock %}

View File

@@ -8,15 +8,23 @@ GOV.UK Notify | Service settings
{% block maincolumn_content %} {% block maincolumn_content %}
<h1 class="heading-xlarge">Rename your service</h1> <div class="grid-row">
<div class="column-three-quarters">
<form method="post"> <h1 class="heading-xlarge">Rename service</h1>
{{ textbox('new_name', 'New name', value=service.name) }}
{{ submit_form('Save') }}
</form>
<p><a href="{{ url_for('.service_settings') }}">Back to service settings</a></p>
<p>
Users will see this name where?
</p>
<form method="post">
{{ textbox('new_name', 'New name', value=service.name) }}
{{ submit_form(
'Save',
back_link=url_for('.service_settings')
) }}
</form>
</div>
</div>
{% endblock %} {% endblock %}

View File

@@ -1,6 +1,5 @@
{% extends "withnav_template.html" %} {% extends "withnav_template.html" %}
{% from "components/submit-form.html" import submit_form %} {% from "components/submit-form.html" import submit_form %}
{% from "components/list.html" import list %}
{% block page_title %} {% block page_title %}
GOV.UK Notify | Service settings GOV.UK Notify | Service settings
@@ -8,26 +7,42 @@ GOV.UK Notify | Service settings
{% block maincolumn_content %} {% block maincolumn_content %}
<h1 class="heading-xlarge">Make your service live</h1> <h1 class="heading-xlarge">Request to make service live</h1>
<div class="grid-row"> <div class="grid-row">
<div class="column-two-thirds"> <div class="column-three-quarters">
<p> <p>
Before you can send messages to anyone, you need to: A live service can send messages to any phone number or email address.
</p> </p>
{{ list([ <p>
"Have spoken to someone", First you need to:
"Have permission from someone else", </p>
"etc."
]) }} <ul class="list list-bullet">
<li>
have spoken to someone
</li>
<li>
have permission from someone else
</li>
<li>
etc.
</li>
</ul>
<p>
It takes a few working days for your request to be approved.
</p>
<form method="post"> <form method="post">
{{ submit_form("Request to go live") }} {{ submit_form(
'Request to make service live',
back_link=url_for('.service_settings')
) }}
</form> </form>
<p><a href="{{ url_for('.service_settings') }}">Back to service settings</a></p>
</div> </div>
</div> </div>

View File

@@ -7,24 +7,28 @@ GOV.UK Notify | Service settings
{% block maincolumn_content %} {% block maincolumn_content %}
<h1 class="heading-xlarge">Turn off outgoing messages</h1>
<div class="grid-row"> <div class="grid-row">
<div class="column-two-thirds"> <div class="column-three-quarters">
<h1 class="heading-xlarge">Suspend your service</h1>
<p> <p>
Suspending a service means it wont send messages. Any messages that are Youll still be able to send messages to yourself by uploading a CSV
already queued will still be sent. file.
</p> </p>
<p> <p>
You can undo this at any time. You can start sending messages again when youre ready.
</p> </p>
<form method="post"> <form method="post">
{{ submit_form('Suspend') }} {{ submit_form(
'Turn off outgoing messages',
destructive=True,
back_link=url_for('.service_settings')
) }}
</form> </form>
<p><a href="{{ url_for('.service_settings') }}">Back to service settings</a></p>
</div> </div>
</div> </div>

View File

@@ -9,7 +9,7 @@ def test_should_show_service_name(notifications_admin):
response = notifications_admin.test_client().get('/service-settings/name') response = notifications_admin.test_client().get('/service-settings/name')
assert response.status_code == 200 assert response.status_code == 200
assert 'Service name' in response.get_data(as_text=True) assert 'Rename service' in response.get_data(as_text=True)
def test_should_redirect_after_change_service_name(notifications_admin): def test_should_redirect_after_change_service_name(notifications_admin):
@@ -19,11 +19,25 @@ def test_should_redirect_after_change_service_name(notifications_admin):
assert 'http://localhost/service-settings' == response.location assert 'http://localhost/service-settings' == response.location
def test_should_show_service_name_confirmation(notifications_admin):
response = notifications_admin.test_client().get('/service-settings/name/confirm')
assert response.status_code == 200
assert 'Rename service' in response.get_data(as_text=True)
def test_should_redirect_after_service_name_confirmation(notifications_admin):
response = notifications_admin.test_client().post('/service-settings/name/confirm')
assert response.status_code == 302
assert 'http://localhost/service-settings' == response.location
def test_should_show_request_to_go_live(notifications_admin): def test_should_show_request_to_go_live(notifications_admin):
response = notifications_admin.test_client().get('/service-settings/request-to-go-live') response = notifications_admin.test_client().get('/service-settings/request-to-go-live')
assert response.status_code == 200 assert response.status_code == 200
assert 'Request to go live' in response.get_data(as_text=True) assert 'Request to make service live' in response.get_data(as_text=True)
def test_should_redirect_after_request_to_go_live(notifications_admin): def test_should_redirect_after_request_to_go_live(notifications_admin):
@@ -37,12 +51,26 @@ def test_should_show_status_page(notifications_admin):
response = notifications_admin.test_client().get('/service-settings/status') response = notifications_admin.test_client().get('/service-settings/status')
assert response.status_code == 200 assert response.status_code == 200
assert 'Suspend your service' in response.get_data(as_text=True) assert 'Turn off outgoing messages' in response.get_data(as_text=True)
def test_should_show_redirect_after_status_change(notifications_admin): def test_should_show_redirect_after_status_change(notifications_admin):
response = notifications_admin.test_client().post('/service-settings/status') response = notifications_admin.test_client().post('/service-settings/status')
assert response.status_code == 302
assert 'http://localhost/service-settings/status/confirm' == response.location
def test_should_show_status_confirmation(notifications_admin):
response = notifications_admin.test_client().get('/service-settings/status/confirm')
assert response.status_code == 200
assert 'Turn off outgoing messages' in response.get_data(as_text=True)
def test_should_redirect_after_status_confirmation(notifications_admin):
response = notifications_admin.test_client().post('/service-settings/status/confirm')
assert response.status_code == 302 assert response.status_code == 302
assert 'http://localhost/service-settings' == response.location assert 'http://localhost/service-settings' == response.location
@@ -58,4 +86,18 @@ def test_should_show_redirect_after_deleting_service(notifications_admin):
response = notifications_admin.test_client().post('/service-settings/delete') response = notifications_admin.test_client().post('/service-settings/delete')
assert response.status_code == 302 assert response.status_code == 302
assert 'http://localhost/' == response.location assert 'http://localhost/service-settings/delete/confirm' == response.location
def test_should_show_delete_confirmation(notifications_admin):
response = notifications_admin.test_client().get('/service-settings/delete/confirm')
assert response.status_code == 200
assert 'Delete service' in response.get_data(as_text=True)
def test_should_redirect_delete_confirmation(notifications_admin):
response = notifications_admin.test_client().post('/service-settings/delete/confirm')
assert response.status_code == 302
assert 'http://localhost/dashboard' == response.location