diff --git a/README.md b/README.md
index 984842c8e..0f963d9c5 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
-[](https://api.travis-ci.org/alphagov/notifications-admin.svg?branch=master)
+[](https://travis-ci.org/alphagov/notifications-admin)
+[](https://requires.io/github/alphagov/notifications-admin/requirements/?branch=master)
# notifications-admin
diff --git a/app/assets/stylesheets/components/banner.scss b/app/assets/stylesheets/components/banner.scss
index a801b2ec7..70555d2d1 100644
--- a/app/assets/stylesheets/components/banner.scss
+++ b/app/assets/stylesheets/components/banner.scss
@@ -1,14 +1,22 @@
+%banner,
.banner {
@include core-19;
background: $turquoise;
color: $white;
display: block;
- padding: $gutter-half $gutter;
+ padding: $gutter-half;
margin: 0 0 $gutter 0;
text-align: center;
position: relative;
+}
+
+.banner-with-tick {
+
+ @extend %banner;
+ padding: $gutter-half $gutter;
+
&:before {
@include core-24;
content: '✔';
diff --git a/app/assets/stylesheets/components/sms-message.scss b/app/assets/stylesheets/components/sms-message.scss
index 4fa727388..abdd5f9bf 100644
--- a/app/assets/stylesheets/components/sms-message.scss
+++ b/app/assets/stylesheets/components/sms-message.scss
@@ -45,27 +45,4 @@
margin: -$gutter-half 0 $gutter 0;
}
- &-history {
-
- background: $turquoise;
- color: $white;
- padding: $gutter-half;
- @include bold-19;
- margin: 0 0 $gutter 0;
-
- &-heading {
-
- @include bold-19;
- margin: 0;
-
- &-time {
- @include inline-block;
- margin-left: 10px;
- font-weight: normal;
- }
-
- }
-
- }
-
}
diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss
index 7a0a95feb..bcd47c542 100644
--- a/app/assets/stylesheets/main.scss
+++ b/app/assets/stylesheets/main.scss
@@ -22,6 +22,7 @@
@import '../govuk_elements/public/sass/elements/forms';
@import '../govuk_elements/public/sass/elements/forms/form-validation';
@import '../govuk_elements/public/sass/elements/forms/form-block-labels';
+@import '../govuk_elements/public/sass/elements/forms/form-validation';
@import '../govuk_elements/public/sass/elements/icons';
@import '../govuk_elements/public/sass/elements/layout';
@import '../govuk_elements/public/sass/elements/lists';
diff --git a/app/main/__init__.py b/app/main/__init__.py
index 3d3ab5cde..578ea5e92 100644
--- a/app/main/__init__.py
+++ b/app/main/__init__.py
@@ -4,5 +4,5 @@ main = Blueprint('main', __name__)
from app.main.views import (
index, sign_in, sign_out, register, two_factor, verify, sms, add_service,
- code_not_received, jobs, dashboard, templates, service_settings, forgot_password, new_password
+ code_not_received, jobs, dashboard, templates, service_settings, forgot_password, new_password, styleguide
)
diff --git a/app/main/forms.py b/app/main/forms.py
index b0438e942..e4559a164 100644
--- a/app/main/forms.py
+++ b/app/main/forms.py
@@ -1,5 +1,12 @@
from flask_wtf import Form
-from wtforms import StringField, PasswordField, ValidationError, FileField
+
+from wtforms import (
+ StringField,
+ PasswordField,
+ ValidationError,
+ TextAreaField,
+ FileField
+)
from wtforms.validators import DataRequired, Email, Length, Regexp
from app.main.validators import Blacklist, ValidateUserCodes, CsvFileValidator
@@ -124,6 +131,19 @@ class AddServiceForm(Form):
raise ValidationError('Service name already exists')
+class ServiceNameForm(Form):
+ service_name = StringField(u'New name')
+
+
+class ConfirmPasswordForm(Form):
+ password = PasswordField(u'Enter password')
+
+
+class TemplateForm(Form):
+ template_name = StringField(u'Template name')
+ template_body = TextAreaField(u'Message')
+
+
class ForgotPasswordForm(Form):
email_address = email_address()
@@ -133,6 +153,5 @@ class NewPasswordForm(Form):
class CsvUploadForm(Form):
- file = FileField('File to upload',
- validators=[DataRequired(message='Please pick a file'),
- CsvFileValidator()])
+ file = FileField('File to upload', validators=[DataRequired(
+ message='Please pick a file'), CsvFileValidator()])
diff --git a/app/main/notifications/__init__.py b/app/main/notifications/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/app/main/views/__init__.py b/app/main/views/__init__.py
index a76b4feb4..e69de29bb 100644
--- a/app/main/views/__init__.py
+++ b/app/main/views/__init__.py
@@ -1,54 +0,0 @@
-from random import randint
-
-from flask import url_for, current_app
-
-from app import admin_api_client
-from app.main.dao import verify_codes_dao
-
-
-def create_verify_code():
- return ''.join(["%s" % randint(0, 9) for _ in range(0, 5)])
-
-
-def send_sms_code(user_id, mobile_number):
- sms_code = create_verify_code()
- verify_codes_dao.add_code(user_id=user_id, code=sms_code, code_type='sms')
- admin_api_client.send_sms(mobile_number=mobile_number, message=sms_code, token=admin_api_client.auth_token)
-
- return sms_code
-
-
-def send_email_code(user_id, email):
- email_code = create_verify_code()
- verify_codes_dao.add_code(user_id=user_id, code=email_code, code_type='email')
- 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)
- return email_code
-
-
-def send_change_password_email(email):
- link_to_change_password = url_for('.new_password', token=generate_token(email), _external=True)
- admin_api_client.send_email(email_address=email,
- from_str='notify@digital.cabinet-office.gov.uk',
- message=link_to_change_password,
- subject='Reset password for GOV.UK Notify',
- token=admin_api_client.auth_token)
-
-
-def generate_token(email):
- from itsdangerous import TimestampSigner
- signer = TimestampSigner(current_app.config['SECRET_KEY'])
- return signer.sign(email).decode('utf8')
-
-
-def check_token(token):
- from itsdangerous import TimestampSigner, SignatureExpired
- signer = TimestampSigner(current_app.config['SECRET_KEY'])
- try:
- email = signer.unsign(token, max_age=current_app.config['TOKEN_MAX_AGE_SECONDS'])
- return email
- except SignatureExpired as e:
- current_app.logger.info('token expired %s' % e)
diff --git a/app/main/views/code_not_received.py b/app/main/views/code_not_received.py
index 4f0962653..56d68025e 100644
--- a/app/main/views/code_not_received.py
+++ b/app/main/views/code_not_received.py
@@ -1,10 +1,10 @@
from flask import (
- render_template, redirect, jsonify, session, url_for)
+ render_template, redirect, session, url_for)
from app.main import main
from app.main.dao import users_dao
from app.main.forms import EmailNotReceivedForm, TextNotReceivedForm
-from app.main.views import send_sms_code, send_email_code
+from app.notify_client.sender import send_sms_code, send_email_code
@main.route('/email-not-received', methods=['GET', 'POST'])
diff --git a/app/main/views/forgot_password.py b/app/main/views/forgot_password.py
index 0e5c81bda..21d7d8f1c 100644
--- a/app/main/views/forgot_password.py
+++ b/app/main/views/forgot_password.py
@@ -1,8 +1,8 @@
-from flask import render_template, flash, current_app
+from flask import render_template, current_app
from app.main import main
from app.main.dao import users_dao
from app.main.forms import ForgotPasswordForm
-from app.main.views import send_change_password_email
+from app.notify_client.sender import send_change_password_email
@main.route('/forgot-password', methods=['GET', 'POST'])
diff --git a/app/main/views/new_password.py b/app/main/views/new_password.py
index c1b0e1e04..7a46f5c18 100644
--- a/app/main/views/new_password.py
+++ b/app/main/views/new_password.py
@@ -3,7 +3,7 @@ from flask import (render_template, url_for, redirect, flash)
from app.main import main
from app.main.dao import users_dao
from app.main.forms import NewPasswordForm
-from app.main.views import send_sms_code, check_token
+from app.notify_client.sender import check_token, send_sms_code
@main.route('/new-password/', methods=['GET', 'POST'])
@@ -13,7 +13,7 @@ def new_password(token):
flash('The link in the email we sent you has expired. Enter your email address to resend.')
return redirect(url_for('.forgot_password'))
- user = users_dao.get_user_by_email(email_address=email_address.decode('utf-8'))
+ user = users_dao.get_user_by_email(email_address=email_address)
if user and user.state != 'request_password_reset':
flash('The link in the email we sent you has already been used.')
return redirect(url_for('.index'))
diff --git a/app/main/views/register.py b/app/main/views/register.py
index 9eef37a4a..2ca7d8faa 100644
--- a/app/main/views/register.py
+++ b/app/main/views/register.py
@@ -5,12 +5,14 @@ from flask import render_template, redirect, session
from app.main import main
from app.main.dao import users_dao
from app.main.forms import RegisterUserForm
-from app.main.views import send_sms_code, send_email_code
from app.models import User
# TODO how do we handle duplicate unverifed email addresses?
# malicious or otherwise.
+from app.notify_client.sender import send_sms_code, send_email_code
+
+
@main.route('/register', methods=['GET', 'POST'])
def register():
form = RegisterUserForm(users_dao.get_user_by_email)
diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py
index 6553a876e..b031fd447 100644
--- a/app/main/views/service_settings.py
+++ b/app/main/views/service_settings.py
@@ -2,6 +2,7 @@ from flask import render_template, redirect, request, url_for, abort
from flask_login import login_required
from app.main import main
+from app.main.forms import ConfirmPasswordForm, ServiceNameForm
service = {
'name': 'Service name',
@@ -20,10 +21,15 @@ def service_settings():
@main.route("/service-settings/name", methods=['GET', 'POST'])
def name():
+
+ form = ServiceNameForm()
+ form.service_name.data = 'Service name'
+
if request.method == 'GET':
return render_template(
'views/service-settings/name.html',
- service=service
+ service=service,
+ form=form
)
elif request.method == 'POST':
return redirect(url_for('.confirm_name_change'))
@@ -31,10 +37,14 @@ def name():
@main.route("/service-settings/name/confirm", methods=['GET', 'POST'])
def confirm_name_change():
+
+ form = ConfirmPasswordForm()
+
if request.method == 'GET':
return render_template(
'views/service-settings/confirm.html',
- heading='Change your service name'
+ heading='Change your service name',
+ form=form
)
elif request.method == 'POST':
return redirect(url_for('.service_settings'))
@@ -64,11 +74,15 @@ def status():
@main.route("/service-settings/status/confirm", methods=['GET', 'POST'])
def confirm_status_change():
+
+ form = ConfirmPasswordForm()
+
if request.method == 'GET':
return render_template(
'views/service-settings/confirm.html',
heading='Turn off all outgoing notifications',
- destructive=True
+ destructive=True,
+ form=form
)
elif request.method == 'POST':
return redirect(url_for('.service_settings'))
@@ -87,11 +101,15 @@ def delete():
@main.route("/service-settings/delete/confirm", methods=['GET', 'POST'])
def confirm_delete():
+
+ form = ConfirmPasswordForm()
+
if request.method == 'GET':
return render_template(
'views/service-settings/confirm.html',
heading='Delete this service from Notify',
- destructive=True
+ destructive=True,
+ form=form
)
elif request.method == 'POST':
return redirect(url_for('.dashboard'))
diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py
index 0f3be0c2d..7c0e28a26 100644
--- a/app/main/views/sign_in.py
+++ b/app/main/views/sign_in.py
@@ -1,12 +1,12 @@
from flask import (
- render_template, redirect, jsonify, url_for)
+ render_template, redirect, url_for)
from flask import session
from app.main import main
from app.main.dao import users_dao
from app.main.encryption import check_hash
from app.main.forms import LoginForm
-from app.main.views import send_sms_code
+from app.notify_client.sender import send_sms_code
@main.route('/sign-in', methods=(['GET', 'POST']))
diff --git a/app/main/views/styleguide.py b/app/main/views/styleguide.py
new file mode 100644
index 000000000..f778f9dcf
--- /dev/null
+++ b/app/main/views/styleguide.py
@@ -0,0 +1,24 @@
+from flask import render_template
+from flask_wtf import Form
+from wtforms import StringField, PasswordField, TextAreaField, validators
+from app.main import main
+
+
+@main.route('/_styleguide')
+def styleguide():
+
+ class FormExamples(Form):
+ username = StringField(u'Username')
+ password = PasswordField(u'Password', [validators.required()])
+ message = TextAreaField(u'Message')
+
+ form = FormExamples()
+
+ form.message.data = "Your vehicle tax for ((registration number)) is due on ((date)). Renew online at www.gov.uk/vehicle-tax" # noqa
+
+ form.validate()
+
+ return render_template(
+ 'views/styleguide.html',
+ form=form
+ )
diff --git a/app/main/views/templates.py b/app/main/views/templates.py
index ff80cb353..2d7d38e85 100644
--- a/app/main/views/templates.py
+++ b/app/main/views/templates.py
@@ -1,6 +1,7 @@
from flask import request, render_template, redirect, url_for
from app.main import main
+from app.main.forms import TemplateForm
@main.route("/templates")
@@ -10,12 +11,17 @@ def manage_templates():
@main.route("/templates/template", methods=['GET', 'POST'])
def add_template():
+
+ form = TemplateForm()
+
+ form.template_name.data = 'Reminder'
+ form.template_body.data = 'Vehicle tax: Your vehicle tax for ((registration number)) expires on ((date)). Tax your vehicle at www.gov.uk/vehicle-tax' # noqa
+
if request.method == 'GET':
return render_template(
'views/edit-template.html',
- template_name='Reminder',
- template_body='Vehicle tax: Your vehicle tax for ((registration number)) expires on ((date)). Tax your vehicle at www.gov.uk/vehicle-tax', # noqa
- h1='Edit template'
+ h1='Edit template',
+ form=form
)
elif request.method == 'POST':
return redirect(url_for('.manage_templates'))
@@ -23,10 +29,14 @@ def add_template():
@main.route("/templates/template/add", methods=['GET', 'POST'])
def edit_template():
+
+ form = TemplateForm()
+
if request.method == 'GET':
return render_template(
'views/edit-template.html',
- h1='Add template'
+ h1='Add template',
+ form=form
)
elif request.method == 'POST':
return redirect(url_for('.manage_templates'))
diff --git a/app/notify_client/sender.py b/app/notify_client/sender.py
new file mode 100644
index 000000000..1a509a820
--- /dev/null
+++ b/app/notify_client/sender.py
@@ -0,0 +1,52 @@
+from random import randint
+from flask import url_for, current_app
+from itsdangerous import URLSafeTimedSerializer, SignatureExpired
+from app import admin_api_client
+from app.main.dao import verify_codes_dao
+
+
+def create_verify_code():
+ return ''.join(["%s" % randint(0, 9) for _ in range(0, 5)])
+
+
+def send_sms_code(user_id, mobile_number):
+ sms_code = create_verify_code()
+ verify_codes_dao.add_code(user_id=user_id, code=sms_code, code_type='sms')
+ admin_api_client.send_sms(mobile_number=mobile_number, message=sms_code, token=admin_api_client.auth_token)
+
+ return sms_code
+
+
+def send_email_code(user_id, email):
+ email_code = create_verify_code()
+ verify_codes_dao.add_code(user_id=user_id, code=email_code, code_type='email')
+ 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)
+ return email_code
+
+
+def send_change_password_email(email):
+ link_to_change_password = url_for('.new_password', token=generate_token(email), _external=True)
+ admin_api_client.send_email(email_address=email,
+ from_str='notify@digital.cabinet-office.gov.uk',
+ message=link_to_change_password,
+ subject='Reset password for GOV.UK Notify',
+ token=admin_api_client.auth_token)
+
+
+def generate_token(email):
+ ser = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
+ return ser.dumps(email, current_app.config.get('DANGEROUS_SALT'))
+
+
+def check_token(token):
+ ser = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
+ try:
+ email = ser.loads(token, max_age=current_app.config['TOKEN_MAX_AGE_SECONDS'],
+ salt=current_app.config.get('DANGEROUS_SALT'))
+ return email
+ except SignatureExpired as e:
+ current_app.logger.info('token expired %s' % e)
diff --git a/app/templates/admin_template.html b/app/templates/admin_template.html
index a03e47612..c127da3f7 100644
--- a/app/templates/admin_template.html
+++ b/app/templates/admin_template.html
@@ -1,4 +1,3 @@
-{%- from "components/form-field.html" import render_field %}
{% extends "govuk_template.html" %}
{% block head %}
diff --git a/app/templates/components/banner.html b/app/templates/components/banner.html
index 2dab12c5d..a03d2cb0a 100644
--- a/app/templates/components/banner.html
+++ b/app/templates/components/banner.html
@@ -1,3 +1,5 @@
-{% macro banner(body) %}
- {{ body }}
+{% macro banner(body, with_tick=False) %}
+
+ {{ body }}
+
{% endmacro %}
diff --git a/app/templates/components/form-field.html b/app/templates/components/form-field.html
deleted file mode 100644
index 691b4c579..000000000
--- a/app/templates/components/form-field.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{% macro render_field(field) %}
- {{ field.label }}
- {{ field(**kwargs)|safe }}
- {% if field.errors %}
-
- {% for error in field.errors %}
- - {{ error }}
- {% endfor %}
-
- {% endif %}
-
-{% endmacro %}
diff --git a/app/templates/components/sms-message.html b/app/templates/components/sms-message.html
index 38d30b877..d0d0f92ce 100644
--- a/app/templates/components/sms-message.html
+++ b/app/templates/components/sms-message.html
@@ -10,11 +10,3 @@
{% endif %}
{% endmacro %}
-
-{% macro message_status(status, time) %}
-
-
- {{ status }} {{ time }}
-
-
-{% endmacro %}
diff --git a/app/templates/components/textbox.html b/app/templates/components/textbox.html
index 7a74f0985..918fc33d7 100644
--- a/app/templates/components/textbox.html
+++ b/app/templates/components/textbox.html
@@ -1,15 +1,21 @@
-{% macro textbox(name, label, value='', small=True, highlight_tags=False, password=False) %}
-
diff --git a/app/templates/views/forgot-password.html b/app/templates/views/forgot-password.html
index 4d36f2a86..c4062e6b9 100644
--- a/app/templates/views/forgot-password.html
+++ b/app/templates/views/forgot-password.html
@@ -1,4 +1,6 @@
{% extends "admin_template.html" %}
+{% from "components/textbox.html" import textbox %}
+{% from "components/page-footer.html" import page_footer %}
{% block page_title %}
GOV.UK Notify
@@ -12,13 +14,11 @@ GOV.UK Notify
If you have forgotten your password, we can send you an email to create a new password.
-
+
diff --git a/app/templates/views/job.html b/app/templates/views/job.html
index 29ae57ba7..b733a5e61 100644
--- a/app/templates/views/job.html
+++ b/app/templates/views/job.html
@@ -14,7 +14,7 @@ GOV.UK Notify | Notifications activity
- {{ banner(flash_message) }}
+ {{ banner(flash_message, with_tick=True) }}
{% else %}
Message about email address does not exist. Some one needs to figure out the words here.
diff --git a/app/templates/views/notification.html b/app/templates/views/notification.html
index 1e771062a..4f21b6a96 100644
--- a/app/templates/views/notification.html
+++ b/app/templates/views/notification.html
@@ -1,5 +1,6 @@
{% extends "withnav_template.html" %}
{% from "components/sms-message.html" import sms_message, message_status %}
+{% from "components/banner.html" import banner %}
{% from "components/page-footer.html" import page_footer %}
{% block page_title %}
@@ -18,7 +19,9 @@ GOV.UK Notify | Notifications activity
{{ sms_message(message.message, message.phone) }}
- {{ message_status(message.status, delivered_at) }}
+ {{ banner(
+ "{} {}".format(message.status, delivered_at)
+ ) }}
diff --git a/app/templates/views/register.html b/app/templates/views/register.html
index f640ac116..9bb45a3a8 100644
--- a/app/templates/views/register.html
+++ b/app/templates/views/register.html
@@ -1,4 +1,5 @@
{% extends "admin_template.html" %}
+{% from "components/textbox.html" import textbox %}
{% from "components/page-footer.html" import page_footer %}
{% block page_title %}
@@ -16,12 +17,10 @@ GOV.UK Notify | Create an account
diff --git a/app/templates/views/send-sms.html b/app/templates/views/send-sms.html
index ad2843156..bca23f6d9 100644
--- a/app/templates/views/send-sms.html
+++ b/app/templates/views/send-sms.html
@@ -1,7 +1,7 @@
{% extends "withnav_template.html" %}
{% from "components/sms-message.html" import sms_message %}
{% from "components/page-footer.html" import page_footer %}
-{% from "components/form-field.html" import render_field %}
+{% from "components/textbox.html" import textbox %}
{% block page_title %}
GOV.UK Notify | Send text messages
@@ -38,7 +38,7 @@
You can also download an example CSV.
- {{render_field(form.file)}}
+ {{textbox(form.file)}}
{{ page_footer("Continue") }}
diff --git a/app/templates/views/service-settings/confirm.html b/app/templates/views/service-settings/confirm.html
index fe0cd05c9..20206724c 100644
--- a/app/templates/views/service-settings/confirm.html
+++ b/app/templates/views/service-settings/confirm.html
@@ -14,7 +14,7 @@ GOV.UK Notify | Service settings
diff --git a/app/templates/views/two-factor.html b/app/templates/views/two-factor.html
index 46724c617..44cd98739 100644
--- a/app/templates/views/two-factor.html
+++ b/app/templates/views/two-factor.html
@@ -1,4 +1,5 @@
{% extends "admin_template.html" %}
+{% from "components/textbox.html" import textbox %}
{% from "components/page-footer.html" import page_footer %}
{% block page_title %}
@@ -14,9 +15,8 @@ GOV.UK Notify | Text verification
We've sent you a text message with a verification code.
-
diff --git a/app/templates/views/verify.html b/app/templates/views/verify.html
index 94e594d1a..7c4c41180 100644
--- a/app/templates/views/verify.html
+++ b/app/templates/views/verify.html
@@ -1,4 +1,5 @@
{% extends "admin_template.html" %}
+{% from "components/textbox.html" import textbox %}
{% from "components/page-footer.html" import page_footer %}
{% block page_title %}
@@ -13,11 +14,10 @@ GOV.UK Notify | Confirm email address and mobile number
We've sent you confirmation codes by email and text message. You need to enter both codes here.
-
diff --git a/appspec.yml b/appspec.yml
index 56488949b..c6a713089 100644
--- a/appspec.yml
+++ b/appspec.yml
@@ -13,7 +13,7 @@ hooks:
location: scripts/aws_change_ownership.sh
runas: root
timeout: 300
- ApplicationStart:
+ ApplicationStart:
-
location: scripts/aws_start_app.sh
runas: root
diff --git a/config.py b/config.py
index 6f36584ff..80825d4cd 100644
--- a/config.py
+++ b/config.py
@@ -29,7 +29,7 @@ class Config(object):
SECRET_KEY = 'secret-key'
HTTP_PROTOCOL = 'http'
DANGEROUS_SALT = 'itsdangeroussalt'
- TOKEN_MAX_AGE_SECONDS = 120000
+ TOKEN_MAX_AGE_SECONDS = 3600
MAX_CONTENT_LENGTH = 10 * 1024 * 1024 # 10mb
diff --git a/tests/app/main/notify_client/__init__.py b/tests/app/main/notify_client/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/app/main/notify_client/test_sender.py b/tests/app/main/notify_client/test_sender.py
new file mode 100644
index 000000000..129b1f3b1
--- /dev/null
+++ b/tests/app/main/notify_client/test_sender.py
@@ -0,0 +1,35 @@
+from itsdangerous import BadSignature
+from pytest import fail
+
+from app.notify_client.sender import generate_token, check_token
+
+
+def test_should_return_email_from_signed_token(notifications_admin,
+ notifications_admin_db,
+ notify_db_session):
+ email = 'email@something.com'
+ token = generate_token(email)
+ assert email == check_token(token)
+
+
+def test_should_throw_exception_when_token_is_tampered_with(notifications_admin,
+ notifications_admin_db,
+ notify_db_session):
+ email = 'email@something.com'
+ token = generate_token(email)
+ try:
+ check_token(token + 'qerqwer')
+ fail()
+ except BadSignature:
+ pass
+
+
+def test_return_none_when_token_is_expired(notifications_admin,
+ notifications_admin_db,
+ notify_db_session):
+ with notifications_admin.test_request_context():
+ notifications_admin.config['TOKEN_MAX_AGE_SECONDS'] = -1000
+ email = 'email@something.com'
+ token = generate_token(email)
+ assert check_token(token) is None
+ notifications_admin.config['TOKEN_MAX_AGE_SECONDS'] = 120000
diff --git a/tests/app/main/views/test_forgot_password.py b/tests/app/main/views/test_forgot_password.py
index c7dac0177..9b4e82a81 100644
--- a/tests/app/main/views/test_forgot_password.py
+++ b/tests/app/main/views/test_forgot_password.py
@@ -1,15 +1,14 @@
from flask import url_for
-
from app.main.dao import users_dao
-from app.main.views import generate_token
from tests.app.main import create_test_user
def test_should_render_forgot_password(notifications_admin, notifications_admin_db, notify_db_session):
- response = notifications_admin.test_client().get('/forgot-password')
- assert response.status_code == 200
- assert 'If you have forgotten your password, we can send you an email to create a new password.' \
- in response.get_data(as_text=True)
+ with notifications_admin.test_request_context():
+ response = notifications_admin.test_client().get(url_for('.forgot_password'))
+ assert response.status_code == 200
+ assert 'If you have forgotten your password, we can send you an email to create a new password.' \
+ in response.get_data(as_text=True)
def test_should_redirect_to_password_reset_sent_and_state_updated(notifications_admin,
@@ -17,25 +16,11 @@ def test_should_redirect_to_password_reset_sent_and_state_updated(notifications_
mocker,
notify_db_session):
mocker.patch("app.admin_api_client.send_email")
- user = create_test_user('active')
- response = notifications_admin.test_client().post('/forgot-password',
- data={'email_address': user.email_address})
- assert response.status_code == 200
- assert 'You have been sent an email containing a link to reset your password.' in response.get_data(
- as_text=True)
- assert users_dao.get_user_by_id(user.id).state == 'request_password_reset'
-
-
-def test_should_redirect_to_forgot_password_with_flash_message_when_token_is_expired(notifications_admin,
- notifications_admin_db,
- notify_db_session):
with notifications_admin.test_request_context():
- with notifications_admin.test_client() as client:
- notifications_admin.config['TOKEN_MAX_AGE_SECONDS'] = -1000
- user = create_test_user('active')
- token = generate_token(user.email_address)
- response = client.post('/new-password/{}'.format(token),
- data={'new_password': 'a-new_password'})
- assert response.status_code == 302
- assert response.location == url_for('.forgot_password', _external=True)
- notifications_admin.config['TOKEN_MAX_AGE_SECONDS'] = 86400
+ user = create_test_user('active')
+ response = notifications_admin.test_client().post(url_for('.forgot_password'),
+ data={'email_address': user.email_address})
+ assert response.status_code == 200
+ assert 'You have been sent an email containing a link to reset your password.' in response.get_data(
+ as_text=True)
+ assert users_dao.get_user_by_id(user.id).state == 'request_password_reset'
diff --git a/tests/app/main/views/test_new_password.py b/tests/app/main/views/test_new_password.py
index 4f1aeba6b..ca89da594 100644
--- a/tests/app/main/views/test_new_password.py
+++ b/tests/app/main/views/test_new_password.py
@@ -2,7 +2,7 @@ from flask import url_for
from app.main.dao import users_dao
from app.main.encryption import check_hash
-from app.main.views import generate_token
+from app.notify_client.sender import generate_token
from tests.app.main import create_test_user
@@ -56,7 +56,7 @@ def test_should_redirect_to_forgot_password_with_flash_message_when_token_is_exp
response = client.post(url_for('.new_password', token=token), data={'new_password': 'a-new_password'})
assert response.status_code == 302
assert response.location == url_for('.forgot_password', _external=True)
- notifications_admin.config['TOKEN_MAX_AGE_SECONDS'] = 86400
+ notifications_admin.config['TOKEN_MAX_AGE_SECONDS'] = 3600
def test_should_redirect_to_forgot_password_when_user_is_active_should_be_request_password_reset(notifications_admin,
diff --git a/tests/app/main/views/test_styleguide.py b/tests/app/main/views/test_styleguide.py
new file mode 100644
index 000000000..10004b847
--- /dev/null
+++ b/tests/app/main/views/test_styleguide.py
@@ -0,0 +1,4 @@
+def test_styleguide_can_render(notifications_admin):
+ response = notifications_admin.test_client().get('/_styleguide')
+
+ assert response.status_code == 200