Skip to content

Commit

Permalink
Merge pull request #335 from alphagov/create-user-account-email-class
Browse files Browse the repository at this point in the history
Create user account email class
  • Loading branch information
Wynndow authored Sep 22, 2017
2 parents ec6d690 + 2578841 commit d90832e
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 1 deletion.
2 changes: 1 addition & 1 deletion dmutils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
import flask_featureflags # noqa


__version__ = '28.3.0'
__version__ = '28.4.0'
1 change: 1 addition & 0 deletions dmutils/email/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@

from .exceptions import EmailError
from .dm_notify import DMNotifyClient
from .user_account_email import send_user_account_email
42 changes: 42 additions & 0 deletions dmutils/email/user_account_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from flask import current_app, session, abort, url_for
from . import DMNotifyClient, generate_token, EmailError
from .helpers import hash_string


def send_user_account_email(role, email_address, template_id, extra_token_data={}, personalisation={}):
notify_client = DMNotifyClient(current_app.config['DM_NOTIFY_API_KEY'])

token_data = {
'role': role,
'email_address': email_address
}
token_data.update(extra_token_data)

token = generate_token(
token_data,
current_app.config['SHARED_EMAIL_KEY'],
current_app.config['INVITE_EMAIL_SALT']
)

link_url = url_for('external.create_user', encoded_token=token, _external=True)

personalisation_with_link = personalisation.copy()
personalisation_with_link.update({'url': link_url})

try:
notify_client.send_email(
email_address,
template_id=template_id,
personalisation=personalisation_with_link,
reference='create-user-account-{}'.format(hash_string(email_address))
)
session['email_sent_to'] = email_address
except EmailError as e:
current_app.logger.error(
"{code}: Create user email for email_hash {email_hash} failed to send. Error: {error}",
extra={
'error': str(e),
'email_hash': hash_string(email_address),
'code': '{}create.fail'.format(role)
})
abort(503, response="Failed to send user creation email.")
18 changes: 18 additions & 0 deletions dmutils/external.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from flask import Blueprint

external = Blueprint('external', __name__)


@external.route('/suppliers/opportunities/<int:brief_id>/responses/result')
def view_response_result(brief_id):
raise NotImplementedError()


@external.route('/suppliers/opportunities/frameworks/<framework_slug>')
def opportunities_dashboard(framework_slug):
raise NotImplementedError()


@external.route('/user/create/<encoded_token>')
def create_user(encoded_token):
raise NotImplementedError()
115 changes: 115 additions & 0 deletions tests/email/test_user_account_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import mock
import pytest
from flask import session, current_app

from dmutils.config import init_app
from dmutils.email import send_user_account_email, EmailError
from dmutils.email.tokens import decode_invitation_token
from dmutils.external import external as external_blueprint


@pytest.yield_fixture
def email_app(app):
init_app(app)
app.register_blueprint(external_blueprint)
app.config['SHARED_EMAIL_KEY'] = 'shared_email_key'
app.config['INVITE_EMAIL_SALT'] = 'invite_email_salt'
app.config['SECRET_KEY'] = 'secet_key'
app.config['DM_NOTIFY_API_KEY'] = 'dm_notify_api_key'
app.config['NOTIFY_TEMPLATES'] = {'create_user_account': 'this-would-be-the-id-of-the-template'}
yield app


class TestSendUserAccountEmail():

@mock.patch('dmutils.email.user_account_email.generate_token')
@mock.patch('dmutils.email.user_account_email.DMNotifyClient')
def test_correctly_calls_notify_client_for_buyer(
self, DMNotifyClient, generate_token, email_app
):
with email_app.test_request_context():
generate_token.return_value = 'mocked-token'
notify_client_mock = mock.Mock()
DMNotifyClient.return_value = notify_client_mock

send_user_account_email(
'buyer',
'[email protected]',
current_app.config['NOTIFY_TEMPLATES']['create_user_account']
)

notify_client_mock.send_email.assert_called_once_with(
'[email protected]',
template_id='this-would-be-the-id-of-the-template',
personalisation={
'url': 'http://localhost/user/create/mocked-token'
},
reference='create-user-account-KmmJkEa5sLyv7vuxG3xja3S3fnnM6Rgq5EZY0S_kCjE='
)
assert session['email_sent_to'] == '[email protected]'

@mock.patch('dmutils.email.user_account_email.generate_token')
@mock.patch('dmutils.email.user_account_email.DMNotifyClient')
def test_correctly_calls_notify_client_for_supplier(
self, DMNotifyClient, generate_token, email_app
):
with email_app.test_request_context():
generate_token.return_value = 'mocked-token'
notify_client_mock = mock.Mock()
DMNotifyClient.return_value = notify_client_mock

token_data = {
'role': 'supplier',
'email_address': '[email protected]'
}

send_user_account_email(
'supplier',
'[email protected]',
current_app.config['NOTIFY_TEMPLATES']['create_user_account'],
extra_token_data={
'supplier_id': 12345,
'supplier_name': 'Digital Marketplace'
},
personalisation={
'user': 'Digital Marketplace Team',
'supplier': 'Digital Marketplace'
}
)

notify_client_mock.send_email.assert_called_once_with(
'[email protected]',
template_id=current_app.config['NOTIFY_TEMPLATES']['create_user_account'],
personalisation={
'url': 'http://localhost/user/create/mocked-token',
'user': 'Digital Marketplace Team',
'supplier': 'Digital Marketplace'
},
reference='create-user-account-KmmJkEa5sLyv7vuxG3xja3S3fnnM6Rgq5EZY0S_kCjE='
)
assert session['email_sent_to'] == '[email protected]'

@mock.patch('dmutils.email.user_account_email.current_app')
@mock.patch('dmutils.email.user_account_email.abort')
@mock.patch('dmutils.email.user_account_email.DMNotifyClient')
def test_abort_with_503_if_send_email_fails_with_EmailError(self, DMNotifyClient, abort, current_app, email_app):
with email_app.test_request_context():
notify_client_mock = mock.Mock()
notify_client_mock.send_email.side_effect = EmailError('OMG!')
DMNotifyClient.return_value = notify_client_mock

send_user_account_email(
'buyer',
'[email protected]',
current_app.config['NOTIFY_TEMPLATES']['create_user_account']
)

current_app.logger.error.assert_called_once_with(
"{code}: Create user email for email_hash {email_hash} failed to send. Error: {error}",
extra={
'error': 'OMG!',
'email_hash': 'KmmJkEa5sLyv7vuxG3xja3S3fnnM6Rgq5EZY0S_kCjE=',
'code': 'buyercreate.fail'
}
)
abort.assert_called_once_with(503, response="Failed to send user creation email.")

0 comments on commit d90832e

Please sign in to comment.