Merge branch 'master' into add_proxy_header_check

This commit is contained in:
Athanasios Voutsadakis
2017-11-14 18:02:53 +00:00
12 changed files with 274 additions and 84 deletions

View File

@@ -109,7 +109,8 @@ class UKMobileNumber(TelField):
class InternationalPhoneNumber(TelField):
def pre_validate(self, form):
try:
validate_phone_number(self.data, international=True)
if self.data:
validate_phone_number(self.data, international=True)
except InvalidPhoneError as e:
raise ValidationError(str(e))
@@ -170,15 +171,31 @@ class RegisterUserForm(Form):
email_address = email_address()
mobile_number = international_phone_number()
password = password()
# always register as sms type
auth_type = HiddenField('auth_type', default='sms_auth')
class RegisterUserFromInviteForm(Form):
name = StringField('Full name',
validators=[DataRequired(message='Cant be empty')])
mobile_number = international_phone_number()
def __init__(self, invited_user):
super().__init__(
service=invited_user['service'],
email_address=invited_user['email_address'],
auth_type=invited_user['auth_type'],
)
name = StringField(
'Full name',
validators=[DataRequired(message='Cant be empty')]
)
mobile_number = InternationalPhoneNumber('Mobile number', validators=[])
password = password()
service = HiddenField('service')
email_address = HiddenField('email_address')
auth_type = HiddenField('auth_type', validators=[DataRequired()])
def validate_mobile_number(self, field):
if self.auth_type.data == 'sms_auth' and not field.data:
raise ValidationError('Cant be empty')
class PermissionsForm(Form):

View File

@@ -19,6 +19,7 @@ from app.main.forms import (
RegisterUserForm,
RegisterUserFromInviteForm
)
from app.main.views.verify import activate_user
from app import (
user_api_client,
@@ -41,30 +42,36 @@ def register():
@main.route('/register-from-invite', methods=['GET', 'POST'])
def register_from_invite():
form = RegisterUserFromInviteForm()
invited_user = session.get('invited_user')
if not invited_user:
abort(404)
is_sms_auth = invited_user['auth_type'] == 'sms_auth'
form = RegisterUserFromInviteForm(invited_user)
if form.validate_on_submit():
if form.service.data != invited_user['service'] or form.email_address.data != invited_user['email_address']:
abort(400)
_do_registration(form, send_email=False)
_do_registration(form, send_email=False, send_sms=is_sms_auth)
invite_api_client.accept_invite(invited_user['service'], invited_user['id'])
return redirect(url_for('main.verify'))
if is_sms_auth:
return redirect(url_for('main.verify'))
else:
# we've already proven this user has email because they clicked the invite link,
# so just activate them straight away
return activate_user(session['user_details']['id'])
form.service.data = invited_user['service']
form.email_address.data = invited_user['email_address']
return render_template('views/register-from-invite.html', email_address=invited_user['email_address'], form=form)
return render_template('views/register-from-invite.html', invited_user=invited_user, form=form)
def _do_registration(form, service=None, send_sms=True, send_email=True):
def _do_registration(form, send_sms=True, send_email=True):
if user_api_client.is_email_unique(form.email_address.data):
user = user_api_client.register_user(form.name.data,
form.email_address.data,
form.mobile_number.data,
form.password.data)
form.mobile_number.data or None,
form.password.data,
form.auth_type.data)
# TODO possibly there should be some exception handling
# for sending sms and email codes.

View File

@@ -35,12 +35,7 @@ def verify():
if form.validate_on_submit():
try:
user = user_api_client.get_user(user_id)
# the user will have a new current_session_id set by the API - store it in the cookie for future requests
session['current_session_id'] = user.current_session_id
activated_user = user_api_client.activate_user(user)
login_user(activated_user)
return redirect(url_for('main.add_service', first='first'))
return activate_user(user_id)
finally:
session.pop('user_details', None)
@@ -73,3 +68,12 @@ def verify_email(token):
session['user_details'] = {"email": user.email_address, "id": user.id}
user_api_client.send_verify_code(user.id, 'sms', user.mobile_number)
return redirect('verify')
def activate_user(user_id):
user = user_api_client.get_user(user_id)
# the user will have a new current_session_id set by the API - store it in the cookie for future requests
session['current_session_id'] = user.current_session_id
activated_user = user_api_client.activate_user(user)
login_user(activated_user)
return redirect(url_for('main.add_service', first='first'))

View File

@@ -150,7 +150,7 @@ class User(UserMixin):
class InvitedUser(object):
def __init__(self, id, service, from_user, email_address, permissions, status, created_at, auth_type=None):
def __init__(self, id, service, from_user, email_address, permissions, status, created_at, auth_type):
self.id = id
self.service = str(service)
self.from_user = from_user

View File

@@ -21,12 +21,13 @@ class UserApiClient(NotifyAdminAPIClient):
self.api_key = app.config['ADMIN_CLIENT_SECRET']
self.max_failed_login_count = app.config["MAX_FAILED_LOGIN_COUNT"]
def register_user(self, name, email_address, mobile_number, password):
def register_user(self, name, email_address, mobile_number, password, auth_type):
data = {
"name": name,
"email_address": email_address,
"mobile_number": mobile_number,
"password": password
"password": password,
"auth_type": auth_type
}
user_data = self.post("/user", data)
return User(user_data['data'], max_failed_login_count=self.max_failed_login_count)

View File

@@ -11,16 +11,19 @@ Create an account
<div class="grid-row">
<div class="column-two-thirds">
<h1 class="heading-large">Create an account</h1>
<p>Your account will be created with this email: {{email_address}}</p>
<p>Your account will be created with this email: {{invited_user.email_address}}</p>
<form method="post" autocomplete="off">
{{ textbox(form.name, width='3-4') }}
<div class="extra-tracking">
{{ textbox(form.mobile_number, width='3-4', hint='Well send you a security code by text message') }}
</div>
{% if invited_user.auth_type == 'sms_auth' %}
<div class="extra-tracking">
{{ textbox(form.mobile_number, width='3-4', hint='Well send you a security code by text message') }}
</div>
{% endif %}
{{ textbox(form.password, hint="At least 8 characters", width='3-4') }}
{{ page_footer("Continue") }}
{{form.service}}
{{form.email_address}}
{{form.auth_type}}
</form>
</div>
</div>

View File

@@ -19,6 +19,7 @@ Create an account
</div>
<input class="visually-hidden" aria-hidden="true" tabindex="-1" id="defeat-chrome-autocomplete">
{{ textbox(form.password, hint="At least 8 characters", width='3-4') }}
{{form.auth_type}}
{{ page_footer("Continue") }}
</form>
</div>

View File

@@ -1,5 +1,6 @@
{% extends "withoutnav_template.html" %}
{% from "components/table.html" import list_table, row, field %}
{% from "components/table.html" import mapping_table, row, text_field, optional_text_field, edit_field, field, boolean_field %}
{% block per_page_title %}
Your profile
@@ -9,33 +10,40 @@
<h1 class="heading-large">Your profile</h1>
{% call(item, row_number) list_table(
[
{'label': 'Name', 'value': current_user.name, 'url': url_for('.user_profile_name')},
{'label': 'Email address', 'value': current_user.email_address, 'url': url_for('.user_profile_email')},
{'label': 'Mobile number', 'value': current_user.mobile_number, 'url': url_for('.user_profile_mobile_number')},
{'label': 'Password', 'value': 'Last changed ' + current_user.password_changed_at|format_delta, 'url': url_for('.user_profile_password')},
],
caption='Account settings',
field_headings=['Setting', 'Value', 'Link to change'],
{% call mapping_table(
caption='Your profile',
field_headings=['Label', 'Value', 'Action'],
field_headings_visible=False,
caption_visible=False
) %}
{% call field() %}
{{ item.label }}
{% call row() %}
{{ text_field('Name') }}
{{ text_field(current_user.name) }}
{{ edit_field('Change', url_for('.user_profile_name')) }}
{% endcall %}
{% call field() %}
{{ item.value }}
{% endcall %}
{% call field(align='right') %}
{% if item.label == 'Email address' %}
{% if can_see_edit %}
<a href="{{ item.url }}">Change</a>
{% endif %}
{% call row() %}
{{ text_field('Email address') }}
{{ text_field(current_user.email_address) }}
{% if can_see_edit %}
{{ edit_field('Change', url_for('.user_profile_email')) }}
{% else %}
<a href="{{ item.url }}">Change</a>
{{ text_field('') }}
{% endif %}
{% endcall %}
{% call row() %}
{{ text_field('Mobile number') }}
{{ optional_text_field(current_user.mobile_number) }}
{{ edit_field('Change', url_for('.user_profile_mobile_number')) }}
{% endcall %}
{% call row() %}
{{ text_field('Password') }}
{{ text_field('Last changed ' + current_user.password_changed_at|format_delta) }}
{{ edit_field('Change', url_for('.user_profile_password')) }}
{% endcall %}
{% endcall %}
{% endblock %}