Preview service name when adding a new service

This commit adds a new page, which appears after a user enters the name for
their new service. It shows how the service name will appear in emails and
text messages.

This means that the new service is not created until after they have confirmed
that the name is appropriate in context.

This has also involved:
- visual changes to the ‘email template’ pattern, which wasn’t very refined
  before
- removing a bunch of words from the enter service name page, because most users
  don’t read them, and we reckon that showing a preview is a better way of
  getting them to understand what is meant by service name

Still to do:
- validating the the generated email address for a service is unique (on the
  API) side
- having the API return the generated email address, rather than determining it
  in the admin app
This commit is contained in:
Chris Hill-Scott
2016-02-18 14:54:59 +00:00
parent 6616182ab3
commit 9d38cd98b0
12 changed files with 211 additions and 50 deletions

View File

@@ -1,11 +1,17 @@
.column-one-quarter {
@include grid-column(1/4);
}
.column-three-quarters {
@include grid-column(3/4);
}
.column-one-eighth {
@include grid-column(1/8);
}
.column-seven-eighths {
@include grid-column(7/8);
}
.bottom-gutter {
margin-bottom: $gutter;
clear: both;
}

View File

@@ -1,24 +1,30 @@
.email-message {
margin-bottom: $gutter;
border: 1px solid $border-colour;
&-subject {
@include bold-19;
border-bottom: 1px solid $border-colour;
padding: 10px;
}
&-body {
border-bottom: 1px solid $white;
padding: 10px;
overflow: hidden;
max-height: 103px;
}
&-name {
@include bold-19;
margin: 50px 0 10px 0;
margin: 20px 0 10px 0;
}
&-subject,
&-from {
margin: 10px 0;
}
&-from {
padding-top: 15px;
border-top: 1px solid $border-colour;
}
&-body {
width: 100%;
box-sizing: border-box;
padding: $gutter-half 0 0 0;
margin: 0 0 $gutter 0;
clear: both;
border-top: 1px solid $border-colour;
border-bottom: 1px solid $border-colour;
}
}

View File

@@ -8,6 +8,7 @@
border-radius: 5px;
white-space: normal;
margin: 0 0 $gutter 0;
clear: both;
}
.sms-message-wrapper-with-radio {
@@ -53,3 +54,8 @@
}
}
.sms-message-from {
@include bold-19;
display: block;
}

View File

@@ -85,3 +85,7 @@
.textbox-help-link {
margin: 5px 0 0 0;
}
.textbox-right-aligned {
text-align: right;
}

View File

@@ -1,5 +1,6 @@
from flask import url_for
from app import notifications_api_client
from notifications_python_client.errors import HTTPError
from app.utils import BrowsableItem
@@ -26,6 +27,16 @@ def get_service_by_id(id_):
return notifications_api_client.get_service(id_)
def get_service_by_id_or_404(id_):
try:
return get_service_by_id(id_)
except HTTPError as e:
if e.status_code == 404:
abort(404)
else:
raise e
def get_services(user_id=None):
if user_id:
return notifications_api_client.get_services({'user_id': str(user_id)})

View File

@@ -1,4 +1,6 @@
from flask import render_template, redirect, session, url_for
import re
from flask import render_template, request, redirect, session, url_for
from flask_login import login_required, current_user
from app.main import main
from app.main.dao import services_dao, users_dao
@@ -15,13 +17,33 @@ def add_service():
else:
heading = 'Add a new service'
if form.validate_on_submit():
user = users_dao.get_user_by_id(session['user_id'])
service_id = services_dao.insert_new_service(form.name.data, user.id)
session['service_name'] = form.name.data
return redirect(url_for('main.service_dashboard', service_id=service_id))
return redirect(url_for('main.add_from_address'))
else:
return render_template(
'views/add-service.html',
form=form,
heading=heading
)
@main.route("/confirm-add-service", methods=['GET', 'POST'])
@login_required
def add_from_address():
if request.method == 'POST':
user = users_dao.get_user_by_id(session['user_id'])
service_id = services_dao.insert_new_service(session['service_name'], user.id)
return redirect(url_for('main.service_dashboard', service_id=service_id))
else:
return render_template(
'views/add-from-address.html',
service_name=session['service_name'],
from_address="{}@notifications.service.gov.uk".format(_email_safe(session['service_name']))
)
def _email_safe(string):
return "".join([
character.lower() if character.isalnum() or character == "." else ""
for character in re.sub("\s+", ".", string.strip())
])

View File

@@ -1,4 +1,4 @@
{% macro email_message(subject, body, name=None, edit_link=None) %}
{% macro email_message(subject, body, name=None, edit_link=None, from_name=None, from_address=None) %}
{% if name %}
<h3 class="email-message-name">
{% if edit_link %}
@@ -9,9 +9,30 @@
</h3>
{% endif %}
<div class="email-message">
<div class="email-message-subject">
{{ subject }}
</div>
{% if from_name and from_address %}
<div class="email-message-from">
<div class="grid-row">
<div class="column-one-eighth">
<span class="form-hint">From</span>
</div>
<div class="column-seven-eighths">
{{ from_name }} &lt;{{ from_address }}&gt;
</div>
</div>
</div>
{% endif %}
{% if subject %}
<div class="email-message-subject">
<div class="grid-row">
<div class="column-one-eighth">
<span class="form-hint">Subject</span>
</div>
<div class="column-seven-eighths">
{{ subject }}
</div>
</div>
</div>
{% endif %}
<div class="email-message-body">
{{ body|nl2br }}
</div>

View File

@@ -1,5 +1,5 @@
{% macro sms_message(
body, recipient=None, name=None, id=None, edit_link=None
body, recipient=None, name=None, id=None, edit_link=None, from=None
) %}
{% if name %}
<h3 class="sms-message-name">
@@ -11,6 +11,11 @@
</h3>
{% endif %}
<div class="sms-message-wrapper{% if input_name %}-with-radio{% endif %}">
{% if from %}
<span class="sms-message-from">
{{ from }}
</span>
{% endif %}
{{ body }}
</div>
{% if recipient %}

View File

@@ -5,7 +5,8 @@
autofocus=False,
help_link=None,
help_link_text=None,
width='2-3'
width='2-3',
suffix=None
) %}
<div class="form-group{% if field.errors %} error{% endif %}" {% if autofocus %}data-module="autofocus"{% endif %}>
<label class="form-label" for="{{ field.name }}">
@@ -22,9 +23,12 @@
{% endif %}
</label>
{{ field(**{
'class': 'form-control form-control-{} textbox-highlight-textbox'.format(width) if highlight_tags else 'form-control form-control-{}'.format(width),
'class': 'form-control form-control-{} textbox-highlight-textbox'.format(width) if highlight_tags else 'form-control form-control-{} {}'.format(width, 'textbox-right-aligned' if suffix else ''),
'data-module': 'highlight-tags' if highlight_tags else ''
}) }}
{% if suffix %}
<span>{{ suffix }}</span>
{% endif %}
{% if help_link and help_link_text %}
<p class="textbox-help-link">
<a href='{{ help_link }}'>{{ help_link_text }}</a>

View File

@@ -0,0 +1,42 @@
{% extends "withoutnav_template.html" %}
{% from "components/textbox.html" import textbox %}
{% from "components/page-footer.html" import page_footer %}
{% from "components/sms-message.html" import sms_message %}
{% from "components/email-message.html" import email_message %}
{% block page_title %}
Preview your service name GOV.UK Notify
{% endblock %}
{% block maincolumn_content %}
<h1 class="heading-large">
Preview your service name
</h1>
<div class="grid-row">
<div class="column-two-thirds">
{{ sms_message(
"{}: we received your payment, thank you".format(service_name),
name="Text message",
recipient='Sent from 40604'
) }}
</div>
</div>
<div class="grid-row">
<div class='column-two-thirds'>
{{ email_message(
subject="We received your payment, thank you",
body="Dear Alice Smith,\n\nThank you for…",
from_name=service_name,
from_address=from_address,
name="Email",
) }}
</div>
</div>
<form method="post">
{{page_footer('Looks good', back_link=url_for(".add_service"))}}
</form>
{% endblock %}

View File

@@ -12,27 +12,21 @@
<div class="column-two-thirds">
<h1 class="heading-large">
{{ heading }}
When people receive notifications, who should they be from?
</h1>
<p>
Users will see your service name when they receive messages through GOV.UK
Notify:
Be specific. Remember that there might be other people in your
organisation using GOV.UK Notify.
</p>
<ul class="list-bullet bottom-gutter">
<li>
at the start of every text message, eg Vehicle tax: we received your
payment, thank you
</li>
<li>
as your email sender name
</li>
</ul>
<form autocomplete="off" method="post">
{{ textbox(form.name, hint="You can change this later") }}
{{ page_footer('Continue') }}
</form>
</div>

View File

@@ -17,13 +17,14 @@ def test_get_should_render_add_service_template(app_,
assert 'Add a new service' in response.get_data(as_text=True)
def test_should_add_service_and_redirect_to_next_page(app_,
mock_login,
mock_create_service,
mock_get_services,
api_user_active,
mock_get_user,
mock_get_user_by_email):
def test_should_add_service_and_redirect_to_next_page(
app_,
mock_login,
mock_get_services,
api_user_active,
mock_get_user,
mock_get_user_by_email
):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
@@ -31,6 +32,45 @@ def test_should_add_service_and_redirect_to_next_page(app_,
url_for('main.add_service'),
data={'name': 'testing the post'})
assert response.status_code == 302
assert response.location == url_for('main.add_from_address', _external=True)
def test_should_confirm_add_service(
app_,
mock_login,
mock_get_services,
api_user_active,
mock_get_user,
mock_get_user_by_email
):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
with client.session_transaction() as session:
session['service_name'] = 'Renew Your Pet Passport'
response = client.get(url_for('main.add_from_address'))
assert response.status_code == 200
assert 'Preview your service name' in response.get_data(as_text=True)
assert 'Renew Your Pet Passport' in response.get_data(as_text=True)
assert 'renew.your.pet.passport@notifications.service.gov.uk' in response.get_data(as_text=True)
def test_should_add_service_after_confirmation(
app_,
mock_login,
mock_create_service,
mock_get_services,
api_user_active,
mock_get_user,
mock_get_user_by_email
):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
with client.session_transaction() as session:
session['service_name'] = 'Renew Your Pet Passport'
response = client.post(url_for('main.add_from_address'))
assert response.status_code == 302
assert response.location == url_for('main.service_dashboard', service_id=101, _external=True)
assert mock_create_service.called
assert mock_get_services.called