diff --git a/app/celery/tasks.py b/app/celery/tasks.py index 94fb59bc4..c354273a9 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -370,3 +370,23 @@ def email_reset_password(encrypted_reset_password_message): url=reset_password_message['reset_password_url'])) except AwsSesClientException as e: current_app.logger.exception(e) + + +def registration_verification_template(name, url): + from string import Template + t = Template("Hi $name,\n\n" + "To complete your registration for GOV.UK Notify please click the link below\n\n $url") + return t.substitute(name=name, url=url) + + +@notify_celery.task(name='email-registration-verification') +def email_registration_verification(encrypted_verification_message): + verification_message = encryption.decrypt(encrypted_verification_message) + try: + aws_ses_client.send_email(current_app.config['VERIFY_CODE_FROM_EMAIL_ADDRESS'], + verification_message['to'], + "Confirm GOV.UK Notify registration", + registration_verification_template(name=verification_message['name'], + url=verification_message['url'])) + except AwsSesClientException as e: + current_app.logger.exception(e) diff --git a/app/user/rest.py b/app/user/rest.py index cb574a909..06adc72e4 100644 --- a/app/user/rest.py +++ b/app/user/rest.py @@ -24,7 +24,13 @@ from app.schemas import ( permission_schema ) -from app.celery.tasks import (send_sms_code, send_email_code, email_reset_password) +from app.celery.tasks import ( + send_sms_code, + send_email_code, + email_reset_password, + email_registration_verification +) + from app.errors import register_errors user = Blueprint('user', __name__) @@ -148,6 +154,28 @@ def send_user_email_code(user_id): return jsonify({}), 204 +@user.route('//email-verification', methods=['POST']) +def send_user_email_verification(user_id): + user_to_send_to = get_model_users(user_id=user_id) + verify_code, errors = request_verify_code_schema.load(request.get_json()) + if errors: + return jsonify(result="error", message=errors), 400 + + from app.dao.users_dao import create_secret_code + secret_code = create_secret_code() + create_user_code(user_to_send_to, secret_code, 'email') + + email = user_to_send_to.email_address + verification_message = {'to': email, + 'name': user_to_send_to.name, + 'url': _create_verification_url(user_to_send_to, secret_code)} + + email_registration_verification.apply_async([encryption.encrypt(verification_message)], + queue='email-registration-verification') + + return jsonify({}), 204 + + @user.route('/', methods=['GET']) @user.route('', methods=['GET']) def get_user(user_id=None): @@ -207,3 +235,12 @@ def _create_reset_password_url(email): token = generate_token(data, current_app.config['SECRET_KEY'], current_app.config['DANGEROUS_SALT']) return current_app.config['ADMIN_BASE_URL'] + '/new-password/' + token + + +def _create_verification_url(user, secret_code): + from utils.url_safe_token import generate_token + import json + data = json.dumps({'user_id': user.id, 'email': user.email_address, 'secret_code': secret_code}) + token = generate_token(data, current_app.config['SECRET_KEY'], current_app.config['DANGEROUS_SALT']) + + return current_app.config['ADMIN_BASE_URL'] + '/verify-email/' + token diff --git a/config.py b/config.py index 0234e9e7b..0bf45618c 100644 --- a/config.py +++ b/config.py @@ -69,7 +69,8 @@ class Config(object): Queue('process-job', Exchange('default'), routing_key='process-job'), Queue('bulk-sms', Exchange('default'), routing_key='bulk-sms'), Queue('bulk-email', Exchange('default'), routing_key='bulk-email'), - Queue('email-invited-user', Exchange('default'), routing_key='email-invited-user') + Queue('email-invited-user', Exchange('default'), routing_key='email-invited-user'), + Queue('email-registration-verification', Exchange('default'), routing_key='email-registration-verification') ] TWILIO_ACCOUNT_SID = os.getenv('TWILIO_ACCOUNT_SID') TWILIO_AUTH_TOKEN = os.getenv('TWILIO_AUTH_TOKEN') diff --git a/tests/app/conftest.py b/tests/app/conftest.py index e954d6cb0..63bad1b8f 100644 --- a/tests/app/conftest.py +++ b/tests/app/conftest.py @@ -327,6 +327,11 @@ def mock_celery_send_email_code(mocker): return mocker.patch('app.celery.tasks.send_email_code.apply_async') +@pytest.fixture(scope='function') +def mock_celery_email_registration_verification(mocker): + return mocker.patch('app.celery.tasks.email_registration_verification.apply_async') + + @pytest.fixture(scope='function') def mock_encryption(mocker): return mocker.patch('app.encryption.encrypt', return_value="something_encrypted") diff --git a/tests/app/user/test_rest_verify.py b/tests/app/user/test_rest_verify.py index 12dd3b5ba..e666c0140 100644 --- a/tests/app/user/test_rest_verify.py +++ b/tests/app/user/test_rest_verify.py @@ -1,13 +1,25 @@ import json import moto -from datetime import (datetime, timedelta) + +from datetime import ( + datetime, + timedelta +) + from flask import url_for -from app.models import (VerifyCode, User) -import app.celery.tasks + +from app.models import ( + VerifyCode, + User +) + from app import db, encryption + from tests import create_authorization_header from freezegun import freeze_time +import app.celery.tasks + def test_user_verify_code_sms(notify_api, sample_sms_code): @@ -341,3 +353,23 @@ def test_send_user_email_code_returns_404_for_when_user_does_not_exist(notify_ap headers=[('Content-Type', 'application/json'), auth_header]) assert resp.status_code == 404 assert json.loads(resp.get_data(as_text=True))['message'] == 'No result found' + + +def test_send_user_email_verification(notify_api, + sample_email_code, + mock_celery_email_registration_verification, + mock_encryption): + + with notify_api.test_request_context(): + with notify_api.test_client() as client: + data = json.dumps({}) + auth_header = create_authorization_header( + path=url_for('user.send_user_email_verification', user_id=sample_email_code.user.id), + method='POST', + request_body=data) + resp = client.post( + url_for('user.send_user_email_verification', user_id=sample_email_code.user.id), + data=data, + headers=[('Content-Type', 'application/json'), auth_header]) + assert resp.status_code == 204 + app.celery.tasks.email_registration_verification.apply_async.assert_called_once_with(['something_encrypted'], queue='email-registration-verification') # noqa