mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-05 10:53:28 -05:00
Merge branch 'master' of github.com:alphagov/notifications-admin
This commit is contained in:
@@ -9,6 +9,7 @@ from flask_wtf import CsrfProtect
|
|||||||
from webassets.filter import get_filter
|
from webassets.filter import get_filter
|
||||||
from werkzeug.exceptions import abort
|
from werkzeug.exceptions import abort
|
||||||
|
|
||||||
|
from app.notify_client.api_client import AdminAPIClient
|
||||||
from app.its_dangerous_session import ItsdangerousSessionInterface
|
from app.its_dangerous_session import ItsdangerousSessionInterface
|
||||||
import app.proxy_fix
|
import app.proxy_fix
|
||||||
from config import configs
|
from config import configs
|
||||||
@@ -18,6 +19,8 @@ db = SQLAlchemy()
|
|||||||
login_manager = LoginManager()
|
login_manager = LoginManager()
|
||||||
csrf = CsrfProtect()
|
csrf = CsrfProtect()
|
||||||
|
|
||||||
|
admin_api_client = AdminAPIClient()
|
||||||
|
|
||||||
|
|
||||||
def create_app(config_name):
|
def create_app(config_name):
|
||||||
application = Flask(__name__)
|
application = Flask(__name__)
|
||||||
@@ -39,6 +42,7 @@ def create_app(config_name):
|
|||||||
proxy_fix.init_app(application)
|
proxy_fix.init_app(application)
|
||||||
|
|
||||||
application.session_interface = ItsdangerousSessionInterface()
|
application.session_interface = ItsdangerousSessionInterface()
|
||||||
|
admin_api_client.init_app(application)
|
||||||
|
|
||||||
return application
|
return application
|
||||||
|
|
||||||
@@ -98,7 +102,8 @@ def init_asset_environment(app):
|
|||||||
assets.Bundle(
|
assets.Bundle(
|
||||||
'govuk_template/govuk-template.scss',
|
'govuk_template/govuk-template.scss',
|
||||||
filters='scss',
|
filters='scss',
|
||||||
output='stylesheets/govuk-template.css'
|
output='stylesheets/govuk-template.css',
|
||||||
|
depends='*.scss'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -19,4 +19,29 @@
|
|||||||
font-size: 19px;
|
font-size: 19px;
|
||||||
line-height: 1.31579;
|
line-height: 1.31579;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.phase-tag {
|
||||||
|
@include phase-tag(beta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 641px) {
|
||||||
|
.phase-tag {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.25;
|
||||||
|
margin-top: 7px;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 641px) {
|
||||||
|
.phase-tag {
|
||||||
|
margin-top: 11px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#global-header #logo {
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
5
app/main/exceptions.py
Normal file
5
app/main/exceptions.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class AdminApiClientException(Exception):
|
||||||
|
def __init__(self, message):
|
||||||
|
self.value = message
|
||||||
@@ -2,6 +2,8 @@ from flask_wtf import Form
|
|||||||
from wtforms import StringField, PasswordField
|
from wtforms import StringField, PasswordField
|
||||||
from wtforms.validators import DataRequired, Email, Length, Regexp
|
from wtforms.validators import DataRequired, Email, Length, Regexp
|
||||||
|
|
||||||
|
from app.main.validators import Blacklist
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(Form):
|
class LoginForm(Form):
|
||||||
email_address = StringField('Email address', validators=[
|
email_address = StringField('Email address', validators=[
|
||||||
@@ -19,7 +21,7 @@ mobile_number = "^\\+44[\\d]{10}$"
|
|||||||
|
|
||||||
|
|
||||||
class RegisterUserForm(Form):
|
class RegisterUserForm(Form):
|
||||||
name = StringField('Name',
|
name = StringField('Full name',
|
||||||
validators=[DataRequired(message='Name can not be empty')])
|
validators=[DataRequired(message='Name can not be empty')])
|
||||||
email_address = StringField('Email address', validators=[
|
email_address = StringField('Email address', validators=[
|
||||||
Length(min=5, max=255),
|
Length(min=5, max=255),
|
||||||
@@ -30,6 +32,7 @@ class RegisterUserForm(Form):
|
|||||||
mobile_number = StringField('Mobile phone number',
|
mobile_number = StringField('Mobile phone number',
|
||||||
validators=[DataRequired(message='Please enter your mobile number'),
|
validators=[DataRequired(message='Please enter your mobile number'),
|
||||||
Regexp(regex=mobile_number, message='Please enter a +44 mobile number')])
|
Regexp(regex=mobile_number, message='Please enter a +44 mobile number')])
|
||||||
password = PasswordField('Password',
|
password = PasswordField('Create a password',
|
||||||
validators=[DataRequired(message='Please enter your password'),
|
validators=[DataRequired(message='Please enter your password'),
|
||||||
Length(10, 255, message='Password must be at least 10 characters')])
|
Length(10, 255, message='Password must be at least 10 characters'),
|
||||||
|
Blacklist(message='That password is blacklisted, too common')])
|
||||||
|
|||||||
12
app/main/validators.py
Normal file
12
app/main/validators.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
from wtforms import ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
class Blacklist(object):
|
||||||
|
def __init__(self, message=None):
|
||||||
|
if not message:
|
||||||
|
message = 'Password is blacklisted.'
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def __call__(self, form, field):
|
||||||
|
if field.data in ['password1234', 'passw0rd1234']:
|
||||||
|
raise ValidationError(self.message)
|
||||||
@@ -15,19 +15,16 @@ def govuk():
|
|||||||
|
|
||||||
|
|
||||||
@main.route("/register-from-invite")
|
@main.route("/register-from-invite")
|
||||||
@login_required
|
|
||||||
def registerfrominvite():
|
def registerfrominvite():
|
||||||
return render_template('register-from-invite.html')
|
return render_template('register-from-invite.html')
|
||||||
|
|
||||||
|
|
||||||
@main.route("/verify")
|
@main.route("/verify")
|
||||||
@login_required
|
|
||||||
def verify():
|
def verify():
|
||||||
return render_template('verify.html')
|
return render_template('verify.html')
|
||||||
|
|
||||||
|
|
||||||
@main.route("/verify-mobile")
|
@main.route("/verify-mobile")
|
||||||
@login_required
|
|
||||||
def verifymobile():
|
def verifymobile():
|
||||||
return render_template('verify-mobile.html')
|
return render_template('verify-mobile.html')
|
||||||
|
|
||||||
@@ -50,7 +47,6 @@ def addservice():
|
|||||||
|
|
||||||
|
|
||||||
@main.route("/two-factor")
|
@main.route("/two-factor")
|
||||||
@login_required
|
|
||||||
def twofactor():
|
def twofactor():
|
||||||
return render_template('two-factor.html')
|
return render_template('two-factor.html')
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
|
from random import randint
|
||||||
|
|
||||||
from flask import render_template, redirect, jsonify
|
from flask import render_template, redirect, jsonify, session
|
||||||
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
|
||||||
|
from app import admin_api_client
|
||||||
from app.main import main
|
from app.main import main
|
||||||
from app.main.dao import users_dao
|
from app.main.dao import users_dao
|
||||||
|
from app.main.encryption import hashpw
|
||||||
|
from app.main.exceptions import AdminApiClientException
|
||||||
from app.main.forms import RegisterUserForm
|
from app.main.forms import RegisterUserForm
|
||||||
from app.models import User
|
from app.models import User
|
||||||
|
|
||||||
@@ -25,9 +30,43 @@ def process_register():
|
|||||||
created_at=datetime.now(),
|
created_at=datetime.now(),
|
||||||
role_id=1)
|
role_id=1)
|
||||||
try:
|
try:
|
||||||
|
sms_code = send_sms_code(form.mobile_number.data)
|
||||||
|
email_code = send_email_code(form.email_address.data)
|
||||||
|
session['sms_code'] = hashpw(sms_code)
|
||||||
|
session['email_code'] = hashpw(email_code)
|
||||||
|
session['expiry_date'] = str(datetime.now() + timedelta(hours=1))
|
||||||
users_dao.insert_user(user)
|
users_dao.insert_user(user)
|
||||||
return redirect('/two-factor')
|
except AdminApiClientException as e:
|
||||||
except Exception as e:
|
return jsonify(admin_api_client_error=e.value)
|
||||||
|
except SQLAlchemyError:
|
||||||
return jsonify(database_error='encountered database error'), 400
|
return jsonify(database_error='encountered database error'), 400
|
||||||
else:
|
else:
|
||||||
return jsonify(form.errors), 400
|
return jsonify(form.errors), 400
|
||||||
|
return redirect('/verify')
|
||||||
|
|
||||||
|
|
||||||
|
def send_sms_code(mobile_number):
|
||||||
|
sms_code = _create_code()
|
||||||
|
try:
|
||||||
|
admin_api_client.send_sms(mobile_number, message=sms_code, token=admin_api_client.auth_token)
|
||||||
|
except:
|
||||||
|
raise AdminApiClientException('Exception when sending sms.')
|
||||||
|
return sms_code
|
||||||
|
|
||||||
|
|
||||||
|
def send_email_code(email):
|
||||||
|
email_code = _create_code()
|
||||||
|
try:
|
||||||
|
admin_api_client.send_email(email_address=email,
|
||||||
|
from_str='notify@digital.cabinet-office.gov.uk',
|
||||||
|
message=email_code,
|
||||||
|
subject='Verification code',
|
||||||
|
token=admin_api_client.auth_token)
|
||||||
|
except:
|
||||||
|
raise AdminApiClientException('Exception when sending email.')
|
||||||
|
|
||||||
|
return email_code
|
||||||
|
|
||||||
|
|
||||||
|
def _create_code():
|
||||||
|
return ''.join(["%s" % randint(0, 9) for _ in range(0, 5)])
|
||||||
|
|||||||
0
app/notify_client/__init__.py
Normal file
0
app/notify_client/__init__.py
Normal file
8
app/notify_client/api_client.py
Normal file
8
app/notify_client/api_client.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
from notify_client import NotifyAPIClient
|
||||||
|
|
||||||
|
|
||||||
|
class AdminAPIClient(NotifyAPIClient):
|
||||||
|
def init_app(self, app):
|
||||||
|
self.base_url = app.config['NOTIFY_DATA_API_URL']
|
||||||
|
self.auth_token = app.config['NOTIFY_DATA_API_AUTH_TOKEN']
|
||||||
@@ -9,6 +9,12 @@ GOV.UK Notify | Set up service
|
|||||||
<div class="grid-row">
|
<div class="grid-row">
|
||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Set up notifications for your service</h1>
|
<h1 class="heading-xlarge">Set up notifications for your service</h1>
|
||||||
|
|
||||||
|
<p>Users will see your service name:</p>
|
||||||
|
<ul>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -17,11 +23,6 @@ GOV.UK Notify | Set up service
|
|||||||
<span class="font-xsmall">For example, 'Vehicle tax' or 'Carer's allowance'</span>
|
<span class="font-xsmall">For example, 'Vehicle tax' or 'Carer's allowance'</span>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="heading-small">We'll create your service in test mode</h2>
|
|
||||||
<p>In test mode you can only send notifications to people in your team.</p>
|
|
||||||
<p>When you're ready to go live we'll remove this restriction.</p>
|
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a class="button" href="dashboard" role="button">Continue</a>
|
<a class="button" href="dashboard" role="button">Continue</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -7,5 +7,13 @@ GOV.UK notifications admin
|
|||||||
{% block cookie_message %}
|
{% block cookie_message %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block inside_header %}
|
||||||
|
<div class="phase-banner-beta">
|
||||||
|
|
||||||
|
<strong class="phase-tag">BETA</strong>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% set global_header_text = "GOV.UK Notify" %}
|
{% set global_header_text = "GOV.UK Notify" %}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ GOV.UK Notify
|
|||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Check your email address</h1>
|
<h1 class="heading-xlarge">Check your email address</h1>
|
||||||
|
|
||||||
<p>Check your email address is correct and resend a confirmation code.</p>
|
<p>Check your email address is correct and then resend the confirmation code.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="email">Email address</label>
|
<label class="form-label" for="email">Email address</label>
|
||||||
@@ -25,4 +25,4 @@ GOV.UK Notify
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -9,10 +9,13 @@ GOV.UK Notify
|
|||||||
<div class="grid-row">
|
<div class="grid-row">
|
||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Create a new password</h1>
|
<h1 class="heading-xlarge">Create a new password</h1>
|
||||||
|
|
||||||
|
<p> You can now create a new password for your account.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="password">Password</label>
|
<label class="form-label" for="password">Create a password</label>
|
||||||
<input class="form-control-1-4" id="password" type="password">
|
<input class="form-control-1-4" id="password" type="password">
|
||||||
|
<span class="font-xsmall">Your password must have at least 10 characters</span></label>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -21,4 +24,4 @@ GOV.UK Notify
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ GOV.UK Notify | Create a user account
|
|||||||
<p>If you've used GOV.UK Notify before, <a href="">sign in to your account</a>.</p>
|
<p>If you've used GOV.UK Notify before, <a href="">sign in to your account</a>.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="name-f1">Name</label>
|
<label class="form-label" for="name-f1">Full name</label>
|
||||||
<input class="form-control-2-3" id="name-f1" type="text">
|
<input class="form-control-2-3" id="name-f1" type="text">
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@@ -21,8 +21,9 @@ GOV.UK Notify | Create a user account
|
|||||||
<input class="form-control-1-4" id="mobile" type="text">
|
<input class="form-control-1-4" id="mobile" type="text">
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="password">Password</label>
|
<label class="form-label" for="password">Create a password</label>
|
||||||
<input class="form-control-1-4" id="password" type="password">
|
<input class="form-control-1-4" id="password" type="password">
|
||||||
|
<span class="font-xsmall">Your password must have at least 10 characters</span></label>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ GOV.UK Notify | Create an account
|
|||||||
|
|
||||||
<p>If you've used GOV.UK Notify before, <a href="">sign in to your account</a>.</p>
|
<p>If you've used GOV.UK Notify before, <a href="">sign in to your account</a>.</p>
|
||||||
|
|
||||||
<p>You need to have access to your email account and a mobile phone to register.</p>
|
<form autocomplete="off" action="" method="post">
|
||||||
|
|
||||||
<form autocomplete="off" action="" method="post">
|
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label"> {{ form.name.label }} </label>
|
<label class="form-label"> {{ form.name.label }} </label>
|
||||||
@@ -32,6 +30,7 @@ GOV.UK Notify | Create an account
|
|||||||
<p>
|
<p>
|
||||||
<label class="form-label"> {{ form.password.label}} </label>
|
<label class="form-label"> {{ form.password.label}} </label>
|
||||||
{{ form.password(class="form-control-1-4", autocomplete="off") }} <br>
|
{{ form.password(class="form-control-1-4", autocomplete="off") }} <br>
|
||||||
|
<span class="font-xsmall">Your password must have at least 10 characters</span></label>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<button class="button" role="button">Continue</button>
|
<button class="button" role="button">Continue</button>
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ GOV.UK Notify | Get started
|
|||||||
|
|
||||||
<p>Use GOV.UK Notify to send notifications by text message, email and letter.</p>
|
<p>Use GOV.UK Notify to send notifications by text message, email and letter.</p>
|
||||||
<p>We're making it easy to keep your users informed.</p>
|
<p>We're making it easy to keep your users informed.</p>
|
||||||
<p>If you work for a central UK Government department or agency you can set up a test account now.</p>
|
<p>If you work for a UK government department or agency you can set up a test account now.</p>
|
||||||
|
|
||||||
<a class="button" href="register" role="button">Set up an account</a>
|
<a class="button" href="register" role="button">Set up an account</a>
|
||||||
|
|
||||||
<!-- <h2 class="heading-large">Used GOV.UK Notify before?</h2> -->
|
<!-- <h2 class="heading-large">Used GOV.UK Notify before?</h2> -->
|
||||||
|
|
||||||
<p><a href="sign-in">Sign in</a></p>
|
<p>If you've used GOV.UK Notify before, <a href="sign-in">sign in to your account</a>.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Sign in
|
|||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Sign in</h1>
|
<h1 class="heading-xlarge">Sign in</h1>
|
||||||
|
|
||||||
<p>If you do not have an account, you can <a href="register">register</a>.</p>
|
<p>If you do not have an account, you can <a href="register">register for one now</a>.</p>
|
||||||
|
|
||||||
<form autocomplete="off" action="" method="post">
|
<form autocomplete="off" action="" method="post">
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
@@ -33,4 +33,4 @@ Sign in
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ GOV.UK Notify
|
|||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Check your mobile number</h1>
|
<h1 class="heading-xlarge">Check your mobile number</h1>
|
||||||
|
|
||||||
<p>Check your mobile phone number is correct and resend a confirmation code.</p>
|
<p>Check your mobile phone number is correct and then resend the confirmation code.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="mobile">Mobile phone number</label>
|
<label class="form-label" for="mobile">Mobile phone number</label>
|
||||||
@@ -26,4 +26,4 @@ GOV.UK Notify
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ GOV.UK Notify
|
|||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Check your mobile number</h1>
|
<h1 class="heading-xlarge">Check your mobile number</h1>
|
||||||
|
|
||||||
<p>Check your mobile phone number is correct and resend a confirmation code.</p>
|
<p>Check your mobile phone number is correct and then resend the confirmation code.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="mobile">Mobile phone number</label>
|
<label class="form-label" for="mobile">Mobile phone number</label>
|
||||||
@@ -24,4 +24,4 @@ GOV.UK Notify
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -10,11 +10,10 @@ GOV.UK Notify | Text verification
|
|||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Text verification</h1>
|
<h1 class="heading-xlarge">Text verification</h1>
|
||||||
|
|
||||||
<p>We've sent you a text message containing a verification code.</p>
|
<p>We've sent you a text message with a verification code.</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="email">Text message verification code<br>
|
<label class="form-label" for="email">Enter verification code<br>
|
||||||
<span class="font-xsmall">Enter the code we sent you by email</span></label>
|
|
||||||
<input class="form-control-1-4" id="email" type="text"><br>
|
<input class="form-control-1-4" id="email" type="text"><br>
|
||||||
<span class="font-xsmall"><a href="verification-not-received">I haven't received a text</a></span>
|
<span class="font-xsmall"><a href="verification-not-received">I haven't received a text</a></span>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ GOV.UK Notify
|
|||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Resend verification code</h1>
|
<h1 class="heading-xlarge">Resend verification code</h1>
|
||||||
|
|
||||||
<p>Text messages sometimes take a few minutes to be received. <br> If you have not received a text message, you can resend.</p>
|
<p>Text messages sometimes take a few minutes to arrive. If you do not receive the text message, you can resend it.</p>
|
||||||
|
|
||||||
<p>If you no longer have access to your mobile phone and registered number, get in contact with your service manager to reset your number.</p>P>
|
<p>If you no longer have access to the phone with the number you registered for this service, speak to your service manager to reset the number.</p>
|
||||||
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a class="button" href="two-factor" role="button">Resend confirmation code</a>
|
<a class="button" href="two-factor" role="button">Resend verification code</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -10,12 +10,10 @@ GOV.UK Notify | Confirm mobile number
|
|||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Confirm your mobile number</h1>
|
<h1 class="heading-xlarge">Confirm your mobile number</h1>
|
||||||
|
|
||||||
<p>You need to prove the contact details you gave us are yours.</p>
|
<p>We've sent you a confirmation code by text message.</p>
|
||||||
<p>We've sent you an email and a text message containing confirmation codes.</p>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="email">Text message confirmation code<br>
|
<label class="form-label" for="email">Enter confirmation code<br>
|
||||||
<span class="font-xsmall">Enter the code we sent you by text</span></label>
|
|
||||||
<input class="form-control-1-4" id="email" type="text"><br>
|
<input class="form-control-1-4" id="email" type="text"><br>
|
||||||
<span class="font-xsmall"><a href="text-not-received-2">I haven't received a text</a></span>
|
<span class="font-xsmall"><a href="text-not-received-2">I haven't received a text</a></span>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -8,20 +8,17 @@ GOV.UK Notify | Confirm email address and mobile number
|
|||||||
|
|
||||||
<div class="grid-row">
|
<div class="grid-row">
|
||||||
<div class="column-two-thirds">
|
<div class="column-two-thirds">
|
||||||
<h1 class="heading-xlarge">Confirm your email address and mobile number</h1>
|
<h1 class="heading-xlarge">Activate your account</h1>
|
||||||
|
|
||||||
<p>You need to prove the contact details you gave us are yours.</p>
|
<p>We've sent you confirmation codes by email and text message. You need to enter both codes here.</p>
|
||||||
<p>We've sent you an email and a text message containing confirmation codes.</p>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="emailverify">Email confirmation code<br>
|
<label class="form-label" for="emailverify">Email confirmation code<br>
|
||||||
<span class="font-xsmall">Enter the code we sent you by email</span></label>
|
|
||||||
<input class="form-control-1-4" id="emailverify" type="text"><br>
|
<input class="form-control-1-4" id="emailverify" type="text"><br>
|
||||||
<span class="font-xsmall"><a href="email-not-received">I haven't received an email</a></span>
|
<span class="font-xsmall"><a href="email-not-received">I haven't received an email</a></span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label class="form-label" for="email">Text message confirmation code<br>
|
<label class="form-label" for="email">Text message confirmation code<br>
|
||||||
<span class="font-xsmall">Enter the code we sent you by text</span></label>
|
|
||||||
<input class="form-control-1-4" id="email" type="text"><br>
|
<input class="form-control-1-4" id="email" type="text"><br>
|
||||||
<span class="font-xsmall"><a href="text-not-received">I haven't received a text</a></span>
|
<span class="font-xsmall"><a href="text-not-received">I haven't received a text</a></span>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
10
config.py
10
config.py
@@ -1,3 +1,5 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
@@ -11,6 +13,14 @@ class Config(object):
|
|||||||
MAX_FAILED_LOGIN_COUNT = 10
|
MAX_FAILED_LOGIN_COUNT = 10
|
||||||
PASS_SECRET_KEY = 'secret-key-unique-changeme'
|
PASS_SECRET_KEY = 'secret-key-unique-changeme'
|
||||||
|
|
||||||
|
SESSION_COOKIE_NAME = 'notify_admin_session'
|
||||||
|
SESSION_COOKIE_PATH = '/admin'
|
||||||
|
SESSION_COOKIE_HTTPONLY = True
|
||||||
|
SESSION_COOKIE_SECURE = True
|
||||||
|
|
||||||
|
NOTIFY_DATA_API_URL = os.getenv('NOTIFY_API_URL', "http://localhost:6001")
|
||||||
|
NOTIFY_DATA_API_AUTH_TOKEN = os.getenv('NOTIFY_API_TOKEN', "dev-token")
|
||||||
|
|
||||||
WTF_CSRF_ENABLED = True
|
WTF_CSRF_ENABLED = True
|
||||||
SECRET_KEY = 'secret-key'
|
SECRET_KEY = 'secret-key'
|
||||||
HTTP_PROTOCOL = 'http'
|
HTTP_PROTOCOL = 'http'
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ SQLAlchemy==1.0.5
|
|||||||
SQLAlchemy-Utils==0.30.5
|
SQLAlchemy-Utils==0.30.5
|
||||||
Flask-WTF==0.11
|
Flask-WTF==0.11
|
||||||
Flask-Login==0.2.11
|
Flask-Login==0.2.11
|
||||||
Flask-Bcrypt==0.6.2
|
Flask-Bcrypt==0.6.2
|
||||||
|
|
||||||
|
git+https://github.com/alphagov/notify-api-client.git@0.1.4#egg=notify-api-client==0.1.4
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
-r requirements.txt
|
-r requirements.txt
|
||||||
pep8==1.5.7
|
pep8==1.5.7
|
||||||
pytest==2.8.1
|
pytest==2.8.1
|
||||||
|
pytest-mock==0.8.1
|
||||||
|
|||||||
17
tests/app/main/test_validators.py
Normal file
17
tests/app/main/test_validators.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from pytest import fail
|
||||||
|
|
||||||
|
from app.main.forms import RegisterUserForm
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_validation_error_for_password(notifications_admin):
|
||||||
|
form = RegisterUserForm()
|
||||||
|
form.name.data = 'test'
|
||||||
|
form.email_address.data = 'teset@example.gov.uk'
|
||||||
|
form.mobile_number.data = '+441231231231'
|
||||||
|
form.password.data = 'password1234'
|
||||||
|
|
||||||
|
try:
|
||||||
|
form.validate()
|
||||||
|
fail()
|
||||||
|
except:
|
||||||
|
assert 'That password is blacklisted, too common' in form.errors['password']
|
||||||
@@ -7,17 +7,22 @@ def test_render_register_returns_template_with_form(notifications_admin, notific
|
|||||||
assert 'Create an account' in response.get_data(as_text=True)
|
assert 'Create an account' in response.get_data(as_text=True)
|
||||||
|
|
||||||
|
|
||||||
def test_process_register_creates_new_user(notifications_admin, notifications_admin_db):
|
def test_process_register_creates_new_user(notifications_admin, notifications_admin_db, mocker):
|
||||||
|
_set_up_mocker(mocker)
|
||||||
|
|
||||||
response = notifications_admin.test_client().post('/register',
|
response = notifications_admin.test_client().post('/register',
|
||||||
data={'name': 'Some One Valid',
|
data={'name': 'Some One Valid',
|
||||||
'email_address': 'someone@example.gov.uk',
|
'email_address': 'someone@example.gov.uk',
|
||||||
'mobile_number': '+441231231231',
|
'mobile_number': '+441231231231',
|
||||||
'password': 'validPassword!'})
|
'password': 'validPassword!'})
|
||||||
assert response.status_code == 302
|
assert response.status_code == 302
|
||||||
assert response.location == 'http://localhost/two-factor'
|
assert response.location == 'http://localhost/verify'
|
||||||
|
|
||||||
|
|
||||||
def test_process_register_returns_400_when_mobile_number_is_invalid(notifications_admin, notifications_admin_db):
|
def test_process_register_returns_400_when_mobile_number_is_invalid(notifications_admin,
|
||||||
|
notifications_admin_db,
|
||||||
|
mocker):
|
||||||
|
_set_up_mocker(mocker)
|
||||||
response = notifications_admin.test_client().post('/register',
|
response = notifications_admin.test_client().post('/register',
|
||||||
data={'name': 'Bad Mobile',
|
data={'name': 'Bad Mobile',
|
||||||
'email_address': 'bad_mobile@example.gov.uk',
|
'email_address': 'bad_mobile@example.gov.uk',
|
||||||
@@ -28,7 +33,8 @@ def test_process_register_returns_400_when_mobile_number_is_invalid(notification
|
|||||||
assert 'Please enter a +44 mobile number' in response.get_data(as_text=True)
|
assert 'Please enter a +44 mobile number' in response.get_data(as_text=True)
|
||||||
|
|
||||||
|
|
||||||
def test_should_return_400_when_email_is_not_gov_uk(notifications_admin, notifications_admin_db):
|
def test_should_return_400_when_email_is_not_gov_uk(notifications_admin, notifications_admin_db, mocker):
|
||||||
|
_set_up_mocker(mocker)
|
||||||
response = notifications_admin.test_client().post('/register',
|
response = notifications_admin.test_client().post('/register',
|
||||||
data={'name': 'Bad Mobile',
|
data={'name': 'Bad Mobile',
|
||||||
'email_address': 'bad_mobile@example.not.right',
|
'email_address': 'bad_mobile@example.not.right',
|
||||||
@@ -37,3 +43,31 @@ def test_should_return_400_when_email_is_not_gov_uk(notifications_admin, notific
|
|||||||
|
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
assert 'Please enter a gov.uk email address' in response.get_data(as_text=True)
|
assert 'Please enter a gov.uk email address' in response.get_data(as_text=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_add_verify_codes_on_session(notifications_admin, notifications_admin_db, mocker):
|
||||||
|
_set_up_mocker(mocker)
|
||||||
|
with notifications_admin.test_client() as client:
|
||||||
|
response = client.post('/register',
|
||||||
|
data={'name': 'Test Codes',
|
||||||
|
'email_address': 'test_codes@example.gov.uk',
|
||||||
|
'mobile_number': '+441234567890',
|
||||||
|
'password': 'validPassword!'})
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert 'notify_admin_session' in response.headers.get('Set-Cookie')
|
||||||
|
|
||||||
|
|
||||||
|
def _set_up_mocker(mocker):
|
||||||
|
mocker.patch("app.admin_api_client.send_sms")
|
||||||
|
mocker.patch("app.admin_api_client.send_email")
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_return_400_if_password_is_blacklisted(notifications_admin, notifications_admin_db):
|
||||||
|
response = notifications_admin.test_client().post('/register',
|
||||||
|
data={'name': 'Bad Mobile',
|
||||||
|
'email_address': 'bad_mobile@example.not.right',
|
||||||
|
'mobile_number': '+44123412345',
|
||||||
|
'password': 'password1234'})
|
||||||
|
|
||||||
|
response.status_code == 400
|
||||||
|
assert 'That password is blacklisted, too common' in response.get_data(as_text=True)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
from _pytest.monkeypatch import monkeypatch
|
||||||
from sqlalchemy.schema import MetaData, DropConstraint
|
from sqlalchemy.schema import MetaData, DropConstraint
|
||||||
|
|
||||||
from app import create_app, db
|
from app import create_app, db
|
||||||
|
|||||||
Reference in New Issue
Block a user