mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-05 10:53:28 -05:00
Add endpoints for forgot-password.
This commit is contained in:
@@ -2,8 +2,7 @@ from flask import Blueprint
|
||||
|
||||
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
|
||||
code_not_received, jobs, dashboard, templates, service_settings, forgot_password
|
||||
)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from datetime import datetime
|
||||
|
||||
from app import db, login_manager
|
||||
from app.models import User
|
||||
from app.main.encryption import hashpw
|
||||
@@ -53,3 +55,11 @@ def update_mobile_number(id, mobile_number):
|
||||
user.mobile_number = mobile_number
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
|
||||
def update_password(id, password):
|
||||
user = get_user_by_id(id)
|
||||
user.password = hashpw(password)
|
||||
user.password_changed_at = datetime.now()
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
from datetime import datetime
|
||||
|
||||
from flask_wtf import Form
|
||||
from wtforms import StringField, PasswordField, ValidationError
|
||||
from wtforms.validators import DataRequired, Email, Length, Regexp
|
||||
from app.main.dao import verify_codes_dao
|
||||
from app.main.encryption import check_hash
|
||||
from app.main.validators import Blacklist, ValidateUserCodes
|
||||
|
||||
|
||||
@@ -123,3 +120,14 @@ class AddServiceForm(Form):
|
||||
def validate_service_name(self, a):
|
||||
if self.service_name.data in self.service_names:
|
||||
raise ValidationError('Service name already exists')
|
||||
|
||||
|
||||
class ForgotPassword(Form):
|
||||
email_address = StringField('Email address',
|
||||
validators=[Length(min=5, max=255),
|
||||
DataRequired(message='Email cannot be empty'),
|
||||
Email(message='Please enter a valid email address'),
|
||||
Regexp(regex=gov_uk_email, message='Please enter a gov.uk email address')
|
||||
])
|
||||
|
||||
|
||||
|
||||
@@ -31,3 +31,17 @@ def send_email_code(user_id, email):
|
||||
raise AdminApiClientException('Exception when sending email.')
|
||||
|
||||
return email_code
|
||||
|
||||
|
||||
def send_change_password_email(email):
|
||||
code = create_verify_code()
|
||||
link_to_change_password = 'thelink' + code
|
||||
# TODO needs an expiry date to check?
|
||||
try:
|
||||
admin_api_client.send_email(email_address=email,
|
||||
from_str='notify@digital.cabinet-office.gov.uk',
|
||||
message=link_to_change_password,
|
||||
subject='Verification code',
|
||||
token=admin_api_client.auth_token)
|
||||
except:
|
||||
raise AdminApiClientException('Exception when sending email.')
|
||||
|
||||
21
app/main/views/forgot_password.py
Normal file
21
app/main/views/forgot_password.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from flask import render_template, jsonify
|
||||
|
||||
from app.main import main
|
||||
from app.main.forms import ForgotPassword
|
||||
from app.main.views import send_change_password_email
|
||||
|
||||
|
||||
@main.route('/forgot-password', methods=['GET'])
|
||||
def render_forgot_my_password():
|
||||
return render_template('views/forgot-password.html', form=ForgotPassword())
|
||||
|
||||
|
||||
@main.route('/forgot-password', methods=['POST'])
|
||||
def change_password():
|
||||
form = ForgotPassword()
|
||||
if form.validate_on_submit():
|
||||
send_change_password_email(form.email_address)
|
||||
|
||||
return 'You have been sent an email with a link to change your password'
|
||||
else:
|
||||
return jsonify(form.errors), 400
|
||||
@@ -39,6 +39,21 @@ def forgotpassword():
|
||||
return render_template('views/forgot-password.html')
|
||||
|
||||
|
||||
@main.route("/jobs")
|
||||
def showjobs():
|
||||
return render_template('views/jobs.html')
|
||||
|
||||
|
||||
@main.route("/jobs/job")
|
||||
def showjob():
|
||||
return render_template('views/job.html')
|
||||
|
||||
|
||||
@main.route("/jobs/job/notification")
|
||||
def shownotification():
|
||||
return render_template('views/notification.html')
|
||||
|
||||
|
||||
@main.route("/new-password")
|
||||
def newpassword():
|
||||
return render_template('views/new-password.html')
|
||||
@@ -62,3 +77,12 @@ def apikeys():
|
||||
@main.route("/verification-not-received")
|
||||
def verificationnotreceived():
|
||||
return render_template('views/verification-not-received.html')
|
||||
|
||||
@main.route("/manage-templates")
|
||||
def managetemplates():
|
||||
return render_template('views/manage-templates.html')
|
||||
|
||||
|
||||
@main.route("/edit-template")
|
||||
def edittemplate():
|
||||
return render_template('views/edit-template.html')
|
||||
|
||||
@@ -12,15 +12,17 @@ GOV.UK Notify
|
||||
|
||||
<p>If you have forgotten your password, we can send you an email to create a new password.</p>
|
||||
|
||||
<p>
|
||||
<label class="form-label" for="email">Email address</label>
|
||||
<input class="form-control" id="email" type="text" value="">
|
||||
<form autocomplete="off" action="" method="post">
|
||||
{{ form.hidden_tag() }}
|
||||
<p>
|
||||
<label class="form-label">Email address </label>
|
||||
{{ form.email_address(class="form-control-2-3", autocomplete="off") }} <br>
|
||||
<span class="font-xsmall">Your email address must end in .gov.uk</span>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<a class="button" href="sign-in" role="button">Send email</a>
|
||||
<button class="button" href="sign-in" role="button">Send email</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
18
app/templates/views/password-reset-sent.html
Normal file
18
app/templates/views/password-reset-sent.html
Normal file
@@ -0,0 +1,18 @@
|
||||
{% extends "admin_template.html" %}
|
||||
|
||||
{% block page_title %}
|
||||
GOV.UK Notify |
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="grid-row">
|
||||
<div class="column-two-thirds">
|
||||
<h1 class="heading-xlarge">GOV.UK Notify</h1>
|
||||
|
||||
<p>You have been sent an email containing a url to reset your password.</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -3,6 +3,7 @@ from datetime import datetime
|
||||
import pytest
|
||||
import sqlalchemy
|
||||
|
||||
from app.main.encryption import check_hash
|
||||
from app.models import User
|
||||
from app.main.dao import users_dao
|
||||
|
||||
@@ -161,3 +162,24 @@ def test_should_update_email_address(notifications_admin, notifications_admin_db
|
||||
users_dao.update_email_address(user.id, 'new_email@testit.gov.uk')
|
||||
updated = users_dao.get_user_by_id(user.id)
|
||||
assert updated.email_address == 'new_email@testit.gov.uk'
|
||||
|
||||
|
||||
def test_should_update_password(notifications_admin, notifications_admin_db, notify_db_session):
|
||||
user = User(name='Update Email',
|
||||
password='somepassword',
|
||||
email_address='test@it.gov.uk',
|
||||
mobile_number='+441234123412',
|
||||
created_at=datetime.now(),
|
||||
role_id=1,
|
||||
state='active')
|
||||
start = datetime.now()
|
||||
users_dao.insert_user(user)
|
||||
|
||||
saved = users_dao.get_user_by_id(user.id)
|
||||
assert check_hash('somepassword', saved.password)
|
||||
assert saved.password_changed_at is None
|
||||
users_dao.update_password(saved.id, 'newpassword')
|
||||
updated = users_dao.get_user_by_id(user.id)
|
||||
assert check_hash('newpassword', updated.password)
|
||||
assert updated.password_changed_at < datetime.now()
|
||||
assert updated.password_changed_at > start
|
||||
|
||||
16
tests/app/main/views/test_forgot_password.py
Normal file
16
tests/app/main/views/test_forgot_password.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from flask import current_app
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def test_should_return_400_when_email_is_invalid(notifications_admin, notifications_admin_db, notify_db_session):
|
||||
response = notifications_admin.test_client().post('/forgot-password',
|
||||
data={'email_address': 'not_a_valid_email'})
|
||||
x = current_app._get_current_object()
|
||||
assert response.status_code == 400
|
||||
assert 'Please enter a valid email address' in response.get_data(as_text=True)
|
||||
Reference in New Issue
Block a user