mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-19 05:58:53 -04:00
add name to personalisation and urlencode next param
also add tests
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from flask import (jsonify, request, Blueprint, current_app)
|
from flask import (jsonify, request, Blueprint, current_app)
|
||||||
|
|
||||||
@@ -157,7 +158,7 @@ def send_user_sms_code(user_id):
|
|||||||
mobile = data.get('to') or user_to_send_to.mobile_number
|
mobile = data.get('to') or user_to_send_to.mobile_number
|
||||||
template = dao_get_template_by_id(current_app.config['SMS_CODE_TEMPLATE_ID'])
|
template = dao_get_template_by_id(current_app.config['SMS_CODE_TEMPLATE_ID'])
|
||||||
|
|
||||||
personalisation = {'verify_code': secret_code},
|
personalisation = {'verify_code': secret_code}
|
||||||
|
|
||||||
create_2fa_code(template, mobile, personalisation)
|
create_2fa_code(template, mobile, personalisation)
|
||||||
return jsonify({}), 204
|
return jsonify({}), 204
|
||||||
@@ -165,14 +166,15 @@ def send_user_sms_code(user_id):
|
|||||||
|
|
||||||
@user_blueprint.route('/<uuid:user_id>/email-code', methods=['POST'])
|
@user_blueprint.route('/<uuid:user_id>/email-code', methods=['POST'])
|
||||||
def send_user_email_code(user_id):
|
def send_user_email_code(user_id):
|
||||||
user_to_send_to = validate_2fa_call(user_id, request.get_json(), post_send_user_email_code_schema)
|
data = request.get_json()
|
||||||
|
user_to_send_to = validate_2fa_call(user_id, data, post_send_user_email_code_schema)
|
||||||
if not user_to_send_to:
|
if not user_to_send_to:
|
||||||
return jsonify({}), 204
|
return jsonify({}), 204
|
||||||
|
|
||||||
create_user_code(user_to_send_to, uuid.uuid4(), EMAIL_TYPE)
|
create_user_code(user_to_send_to, str(uuid.uuid4()), EMAIL_TYPE)
|
||||||
|
|
||||||
template = dao_get_template_by_id(current_app.config['EMAIL_2FA_TEMPLATE_ID'])
|
template = dao_get_template_by_id(current_app.config['EMAIL_2FA_TEMPLATE_ID'])
|
||||||
personalisation = {'url': _create_2fa_url(user_to_send_to)},
|
personalisation = {'name': user_to_send_to.name, 'url': _create_2fa_url(user_to_send_to, data.get('next'))}
|
||||||
|
|
||||||
create_2fa_code(template, user_to_send_to.email_address, personalisation)
|
create_2fa_code(template, user_to_send_to.email_address, personalisation)
|
||||||
|
|
||||||
@@ -384,10 +386,10 @@ def _create_confirmation_url(user, email_address):
|
|||||||
return url_with_token(data, url, current_app.config)
|
return url_with_token(data, url, current_app.config)
|
||||||
|
|
||||||
|
|
||||||
def _create_2fa_url(user, next_redir=None):
|
def _create_2fa_url(user, next_redir):
|
||||||
data = json.dumps({'user_id': str(user.id), 'email': user.email_address})
|
data = json.dumps({'user_id': str(user.id), 'email': user.email_address})
|
||||||
url = '/email-auth/'
|
url = '/email-auth/'
|
||||||
ret = url_with_token(data, url, current_app.config)
|
ret = url_with_token(data, url, current_app.config)
|
||||||
if next_redir:
|
if next_redir:
|
||||||
ret += '?next={}'.format(next_redir)
|
ret += '?{}'.format(urlencode({'next': next_redir}))
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ post_verify_code_schema = {
|
|||||||
'code': {'type': 'string'},
|
'code': {'type': 'string'},
|
||||||
'code_type': {'type': 'string'},
|
'code_type': {'type': 'string'},
|
||||||
},
|
},
|
||||||
'required': ['code', 'code_type']
|
'required': ['code', 'code_type'],
|
||||||
|
'additionalProperties': False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -15,11 +16,13 @@ post_send_user_email_code_schema = {
|
|||||||
'description': 'POST schema for generating a 2fa email',
|
'description': 'POST schema for generating a 2fa email',
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
# doesn't need 'to' as we'll just grab user.email_address
|
# doesn't need 'to' as we'll just grab user.email_address. but lets keep it
|
||||||
|
# as allowed to keep admin code cleaner, but only as null to prevent confusion
|
||||||
|
'to': {'type': 'null'},
|
||||||
'next': {'type': ['string', 'null']},
|
'next': {'type': ['string', 'null']},
|
||||||
},
|
},
|
||||||
'required': [],
|
'required': [],
|
||||||
'additionalProperties': []
|
'additionalProperties': False
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -31,5 +34,5 @@ post_send_user_sms_code_schema = {
|
|||||||
'to': {'type': ['string', 'null']},
|
'to': {'type': ['string', 'null']},
|
||||||
},
|
},
|
||||||
'required': [],
|
'required': [],
|
||||||
'additionalProperties': []
|
'additionalProperties': False
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -864,6 +864,24 @@ def sms_code_template(notify_db,
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function')
|
||||||
|
def email_2fa_code_template(notify_db, notify_db_session):
|
||||||
|
service, user = notify_service(notify_db, notify_db_session)
|
||||||
|
return create_custom_template(
|
||||||
|
service=service,
|
||||||
|
user=user,
|
||||||
|
template_config_name='EMAIL_2FA_TEMPLATE_ID',
|
||||||
|
content=(
|
||||||
|
'Hi ((name)),'
|
||||||
|
''
|
||||||
|
'To sign in to GOV.UK Notify please open this link:'
|
||||||
|
'((url))'
|
||||||
|
),
|
||||||
|
subject='Sign in to GOV.UK Notify',
|
||||||
|
template_type='email'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def email_verification_template(notify_db,
|
def email_verification_template(notify_db,
|
||||||
notify_db_session):
|
notify_db_session):
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import pytest
|
|||||||
from flask import url_for, current_app
|
from flask import url_for, current_app
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
|
from app.dao.users_dao import create_user_code
|
||||||
from app.dao.services_dao import dao_update_service, dao_fetch_service_by_id
|
from app.dao.services_dao import dao_update_service, dao_fetch_service_by_id
|
||||||
from app.models import (
|
from app.models import (
|
||||||
VerifyCode,
|
VerifyCode,
|
||||||
User,
|
User,
|
||||||
Notification
|
Notification,
|
||||||
|
EMAIL_TYPE
|
||||||
)
|
)
|
||||||
from app import db
|
from app import db
|
||||||
import app.celery.tasks
|
import app.celery.tasks
|
||||||
@@ -334,3 +336,75 @@ def test_reset_failed_login_count_returns_404_when_user_does_not_exist(client):
|
|||||||
data={},
|
data={},
|
||||||
headers=[('Content-Type', 'application/json'), create_authorization_header()])
|
headers=[('Content-Type', 'application/json'), create_authorization_header()])
|
||||||
assert resp.status_code == 404
|
assert resp.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_user_email_code(admin_request, mocker, sample_user, email_2fa_code_template):
|
||||||
|
deliver_email = mocker.patch('app.celery.provider_tasks.deliver_email.apply_async')
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'to': None
|
||||||
|
}
|
||||||
|
admin_request.post(
|
||||||
|
'user.send_user_email_code',
|
||||||
|
user_id=sample_user.id,
|
||||||
|
_data=data,
|
||||||
|
_expected_status=204
|
||||||
|
)
|
||||||
|
noti = Notification.query.one()
|
||||||
|
assert noti.to == sample_user.email_address
|
||||||
|
assert str(noti.template_id) == current_app.config['EMAIL_2FA_TEMPLATE_ID']
|
||||||
|
assert noti.personalisation['name'] == 'Test User'
|
||||||
|
deliver_email.assert_called_once_with(
|
||||||
|
[str(noti.id)],
|
||||||
|
queue='notify-internal-tasks'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_user_email_code_with_urlencoded_next_param(admin_request, mocker, sample_user, email_2fa_code_template):
|
||||||
|
mocker.patch('app.celery.provider_tasks.deliver_email.apply_async')
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'to': None,
|
||||||
|
'next': '/services'
|
||||||
|
}
|
||||||
|
admin_request.post(
|
||||||
|
'user.send_user_email_code',
|
||||||
|
user_id=sample_user.id,
|
||||||
|
_data=data,
|
||||||
|
_expected_status=204
|
||||||
|
)
|
||||||
|
noti = Notification.query.one()
|
||||||
|
code = VerifyCode.query.one()
|
||||||
|
assert noti.personalisation['url'].endswith('?next=%2Fservices')
|
||||||
|
|
||||||
|
|
||||||
|
def test_send_email_code_returns_404_for_bad_input_data(admin_request):
|
||||||
|
resp = admin_request.post(
|
||||||
|
'user.send_user_email_code',
|
||||||
|
user_id=uuid.uuid4(),
|
||||||
|
_data={},
|
||||||
|
_expected_status=404
|
||||||
|
)
|
||||||
|
assert resp['message'] == 'No result found'
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time('2016-01-01T12:00:00')
|
||||||
|
def test_user_verify_email_code(admin_request, sample_user):
|
||||||
|
magic_code = str(uuid.uuid4())
|
||||||
|
verify_code = create_user_code(sample_user, magic_code, EMAIL_TYPE)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'code_type': 'email',
|
||||||
|
'code': magic_code
|
||||||
|
}
|
||||||
|
|
||||||
|
admin_request.post(
|
||||||
|
'user.verify_user_code',
|
||||||
|
user_id=sample_user.id,
|
||||||
|
_data=data,
|
||||||
|
_expected_status=204
|
||||||
|
)
|
||||||
|
|
||||||
|
assert verify_code.code_used
|
||||||
|
assert sample_user.logged_in_at == datetime.utcnow()
|
||||||
|
assert sample_user.current_session_id is not None
|
||||||
|
|||||||
Reference in New Issue
Block a user