diff --git a/app/dao/users_dao.py b/app/dao/users_dao.py index d3f77b9e9..19cd4089a 100644 --- a/app/dao/users_dao.py +++ b/app/dao/users_dao.py @@ -1,11 +1,8 @@ import random from datetime import (datetime, timedelta) -from . import DAOException -from sqlalchemy.orm import load_only from app import db from app.models import (User, VerifyCode) -from app.encryption import hashpw def create_secret_code(): diff --git a/app/user/rest.py b/app/user/rest.py index 0be775617..325253fd0 100644 --- a/app/user/rest.py +++ b/app/user/rest.py @@ -5,12 +5,10 @@ from sqlalchemy.orm.exc import NoResultFound from app.dao.services_dao import get_model_services from app.dao.users_dao import ( get_model_users, save_model_user, delete_model_user, - create_user_code, get_user_code, use_user_code, increment_failed_login_count, - create_secret_code) + create_user_code, get_user_code, use_user_code, increment_failed_login_count) from app.schemas import ( - user_schema, users_schema, service_schema, services_schema, - verify_code_schema) -from app import db + user_schema, users_schema, service_schema, services_schema, verify_code_schema) +from app import db, notify_alpha_client from flask import Blueprint @@ -114,22 +112,28 @@ def send_user_code(user_id): return jsonify(result="error", message="Invalid user id"), 400 except NoResultFound: return jsonify(result="error", message="User not found"), 404 - text_pwd = None - verify_code, errors = verify_code_schema.load(request.get_json()) + + request_json = request.get_json() + + verify_code, errors = verify_code_schema.load(request_json) if errors: return jsonify(result="error", message=errors), 400 - code = create_user_code( - user, create_secret_code(), verify_code.code_type) + + from app.dao.users_dao import create_secret_code + secret_code = create_secret_code() + create_user_code(user, secret_code, verify_code.code_type) # TODO this will need to fixed up when we stop using # notify_alpha_client if verify_code.code_type == 'sms': + mobile = user.mobile_number if 'to' not in request_json else request_json['to'] notify_alpha_client.send_sms( - mobile_number=user.mobile_number, - message=code.code) + mobile_number=mobile, + message=secret_code) elif verify_code.code_type == 'email': + email = user.email_address if 'to' not in request_json else request_json['to'] notify_alpha_client.send_email( - user.email_address, - code.code, + email, + secret_code, 'notify@digital.cabinet-office.gov.uk', 'Verification code') else: diff --git a/tests/app/conftest.py b/tests/app/conftest.py index 11731608e..d016b7daf 100644 --- a/tests/app/conftest.py +++ b/tests/app/conftest.py @@ -151,3 +151,30 @@ def sample_admin_service_id(notify_db, notify_db_session): api_key = ApiKey(**data) save_model_api_key(api_key) return admin_service.id + + +@pytest.fixture(scope='function') +def mock_notify_client_send_sms(mocker): + def _send(mobile_number, message): + pass + + mock_class = mocker.patch('app.notify_alpha_client.send_sms', side_effect=_send) + return mock_class + + +@pytest.fixture(scope='function') +def mock_notify_client_send_email(mocker): + def _send(email_address, message, from_address, subject): + pass + + mock_class = mocker.patch('app.notify_alpha_client.send_email', side_effect=_send) + return mock_class + + +@pytest.fixture(scope='function') +def mock_secret_code(mocker): + def _create(): + return '11111' + + mock_class = mocker.patch('app.dao.users_dao.create_secret_code', side_effect=_create) + return mock_class diff --git a/tests/app/user/test_rest_verify.py b/tests/app/user/test_rest_verify.py index bb1876e81..21710b5e9 100644 --- a/tests/app/user/test_rest_verify.py +++ b/tests/app/user/test_rest_verify.py @@ -1,7 +1,8 @@ import json from datetime import (datetime, timedelta) from flask import url_for -from app.models import (User, Service, VerifyCode) + +from app.models import (VerifyCode) from app import db from tests import create_authorization_header @@ -9,7 +10,6 @@ from tests import create_authorization_header def test_user_verify_code_sms(notify_api, notify_db, notify_db_session, - sample_admin_service_id, sample_sms_code): """ Tests POST endpoint '//verify/code' @@ -21,7 +21,6 @@ def test_user_verify_code_sms(notify_api, 'code_type': sample_sms_code.code_type, 'code': sample_sms_code.txt_code}) auth_header = create_authorization_header( - service_id=sample_admin_service_id, path=url_for('user.verify_user_code', user_id=sample_sms_code.user.id), method='POST', request_body=data) @@ -36,7 +35,6 @@ def test_user_verify_code_sms(notify_api, def test_user_verify_code_sms_missing_code(notify_api, notify_db, notify_db_session, - sample_admin_service_id, sample_sms_code): """ Tests POST endpoint '//verify/code' @@ -46,7 +44,6 @@ def test_user_verify_code_sms_missing_code(notify_api, assert not VerifyCode.query.first().code_used data = json.dumps({'code_type': sample_sms_code.code_type}) auth_header = create_authorization_header( - service_id=sample_admin_service_id, path=url_for('user.verify_user_code', user_id=sample_sms_code.user.id), method='POST', request_body=data) @@ -61,7 +58,6 @@ def test_user_verify_code_sms_missing_code(notify_api, def test_user_verify_code_email(notify_api, notify_db, notify_db_session, - sample_admin_service_id, sample_email_code): """ Tests POST endpoint '//verify/code' @@ -73,7 +69,6 @@ def test_user_verify_code_email(notify_api, 'code_type': sample_email_code.code_type, 'code': sample_email_code.txt_code}) auth_header = create_authorization_header( - service_id=sample_admin_service_id, path=url_for('user.verify_user_code', user_id=sample_email_code.user.id), method='POST', request_body=data) @@ -88,7 +83,6 @@ def test_user_verify_code_email(notify_api, def test_user_verify_code_email_bad_code(notify_api, notify_db, notify_db_session, - sample_admin_service_id, sample_email_code): """ Tests POST endpoint '//verify/code' @@ -100,7 +94,6 @@ def test_user_verify_code_email_bad_code(notify_api, 'code_type': sample_email_code.code_type, 'code': "blah"}) auth_header = create_authorization_header( - service_id=sample_admin_service_id, path=url_for('user.verify_user_code', user_id=sample_email_code.user.id), method='POST', request_body=data) @@ -115,7 +108,6 @@ def test_user_verify_code_email_bad_code(notify_api, def test_user_verify_code_email_expired_code(notify_api, notify_db, notify_db_session, - sample_admin_service_id, sample_email_code): """ Tests POST endpoint '//verify/code' @@ -131,7 +123,6 @@ def test_user_verify_code_email_expired_code(notify_api, 'code_type': sample_email_code.code_type, 'code': sample_email_code.txt_code}) auth_header = create_authorization_header( - service_id=sample_admin_service_id, path=url_for('user.verify_user_code', user_id=sample_email_code.user.id), method='POST', request_body=data) @@ -146,8 +137,7 @@ def test_user_verify_code_email_expired_code(notify_api, def test_user_verify_password(notify_api, notify_db, notify_db_session, - sample_user, - sample_admin_service_id): + sample_user): """ Tests POST endpoint '//verify/password' """ @@ -155,7 +145,6 @@ def test_user_verify_password(notify_api, with notify_api.test_client() as client: data = json.dumps({'password': 'password'}) auth_header = create_authorization_header( - service_id=sample_admin_service_id, path=url_for('user.verify_user_password', user_id=sample_user.id), method='POST', request_body=data) @@ -169,8 +158,7 @@ def test_user_verify_password(notify_api, def test_user_verify_password_invalid_password(notify_api, notify_db, notify_db_session, - sample_user, - sample_admin_service_id): + sample_user): """ Tests POST endpoint '//verify/password' invalid endpoint. """ @@ -178,7 +166,6 @@ def test_user_verify_password_invalid_password(notify_api, with notify_api.test_client() as client: data = json.dumps({'password': 'bad password'}) auth_header = create_authorization_header( - service_id=sample_admin_service_id, path=url_for('user.verify_user_password', user_id=sample_user.id), method='POST', request_body=data) @@ -198,8 +185,7 @@ def test_user_verify_password_invalid_password(notify_api, def test_user_verify_password_missing_password(notify_api, notify_db, notify_db_session, - sample_user, - sample_admin_service_id): + sample_user): """ Tests POST endpoint '//verify/password' missing password. """ @@ -207,7 +193,6 @@ def test_user_verify_password_missing_password(notify_api, with notify_api.test_client() as client: data = json.dumps({'bingo': 'bongo'}) auth_header = create_authorization_header( - service_id=sample_admin_service_id, path=url_for('user.verify_user_password', user_id=sample_user.id), method='POST', request_body=data) @@ -218,3 +203,109 @@ def test_user_verify_password_missing_password(notify_api, assert resp.status_code == 400 json_resp = json.loads(resp.get_data(as_text=True)) assert 'Required field missing data' in json_resp['message']['password'] + + +def test_send_user_code_for_sms(notify_api, + notify_db, + notify_db_session, + sample_sms_code, + mock_notify_client_send_sms, + mock_secret_code): + """ + Tests POST endpoint '//code' successful sms + """ + with notify_api.test_request_context(): + with notify_api.test_client() as client: + data = json.dumps({'code_type': 'sms'}) + auth_header = create_authorization_header( + path=url_for('user.send_user_code', user_id=sample_sms_code.user.id), + method='POST', + request_body=data) + resp = client.post( + url_for('user.send_user_code', user_id=sample_sms_code.user.id), + data=data, + headers=[('Content-Type', 'application/json'), auth_header]) + + assert resp.status_code == 204 + mock_notify_client_send_sms.assert_called_once_with(mobile_number=sample_sms_code.user.mobile_number, + message='11111') + + +def test_send_user_code_for_sms_with_optional_to_field(notify_api, + notify_db, + notify_db_session, + sample_sms_code, + mock_notify_client_send_sms, + mock_secret_code): + """ + Tests POST endpoint '//code' successful sms with optional to field + """ + with notify_api.test_request_context(): + with notify_api.test_client() as client: + data = json.dumps({'code_type': 'sms', 'to': '+441119876757'}) + auth_header = create_authorization_header( + path=url_for('user.send_user_code', user_id=sample_sms_code.user.id), + method='POST', + request_body=data) + resp = client.post( + url_for('user.send_user_code', user_id=sample_sms_code.user.id), + data=data, + headers=[('Content-Type', 'application/json'), auth_header]) + + assert resp.status_code == 204 + mock_notify_client_send_sms.assert_called_once_with(mobile_number='+441119876757', + message='11111') + + +def test_send_user_code_for_email(notify_api, + notify_db, + notify_db_session, + sample_email_code, + mock_notify_client_send_email, + mock_secret_code): + """ + Tests POST endpoint '//code' successful email + """ + with notify_api.test_request_context(): + with notify_api.test_client() as client: + data = json.dumps({'code_type': 'email'}) + auth_header = create_authorization_header( + path=url_for('user.send_user_code', user_id=sample_email_code.user.id), + method='POST', + request_body=data) + resp = client.post( + url_for('user.send_user_code', user_id=sample_email_code.user.id), + data=data, + headers=[('Content-Type', 'application/json'), auth_header]) + assert resp.status_code == 204 + mock_notify_client_send_email.assert_called_once_with(sample_email_code.user.email_address, + '11111', + 'notify@digital.cabinet-office.gov.uk', + 'Verification code') + + +def test_send_user_code_for_email_uses_optional_to_field(notify_api, + notify_db, + notify_db_session, + sample_email_code, + mock_notify_client_send_email, + mock_secret_code): + """ + Tests POST endpoint '//code' successful email with included in body + """ + with notify_api.test_request_context(): + with notify_api.test_client() as client: + data = json.dumps({'code_type': 'email', 'to': 'different@email.gov.uk'}) + auth_header = create_authorization_header( + path=url_for('user.send_user_code', user_id=sample_email_code.user.id), + method='POST', + request_body=data) + resp = client.post( + url_for('user.send_user_code', user_id=sample_email_code.user.id), + data=data, + headers=[('Content-Type', 'application/json'), auth_header]) + assert resp.status_code == 204 + mock_notify_client_send_email.assert_called_once_with('different@email.gov.uk', + '11111', + 'notify@digital.cabinet-office.gov.uk', + 'Verification code')