Allow admin to domain to use for invite links

When we’re doing user research we often:
- start the task by inviting the participant to a service on Notify
- have them use a prototype version of the admin app, hosted on a
  different domain

Currently we can’t do both of these things together, because the invite
emails always send people to `notifications.service.gov.uk` (because
it’s the API that sends the emails, and the prototype admin app points
at the production API).

This commit changes the API to optionally allow an instance of the admin
app to specify which domain should be used when generating invite links.
This commit is contained in:
Chris Hill-Scott
2017-12-20 14:38:49 +00:00
parent 713b1eaf35
commit a6a44987a1
2 changed files with 46 additions and 12 deletions

View File

@@ -23,7 +23,8 @@ register_errors(invite)
@invite.route('', methods=['POST'])
def create_invited_user(service_id):
invited_user, errors = invited_user_schema.load(request.get_json())
request_json = request.get_json()
invited_user, errors = invited_user_schema.load(request_json)
save_invited_user(invited_user)
template = dao_get_template_by_id(current_app.config['INVITATION_EMAIL_TEMPLATE_ID'])
@@ -37,7 +38,10 @@ def create_invited_user(service_id):
personalisation={
'user_name': invited_user.from_user.name,
'service_name': invited_user.service.name,
'url': invited_user_url(invited_user.id)
'url': invited_user_url(
invited_user.id,
request_json.get('invite_link_host'),
),
},
notification_type=EMAIL_TYPE,
api_key_id=None,
@@ -74,8 +78,11 @@ def update_invited_user(service_id, invited_user_id):
return jsonify(data=invited_user_schema.dump(fetched).data), 200
def invited_user_url(invited_user_id):
def invited_user_url(invited_user_id, invite_link_host=None):
from notifications_utils.url_safe_token import generate_token
token = generate_token(str(invited_user_id), current_app.config['SECRET_KEY'], current_app.config['DANGEROUS_SALT'])
return '{0}/invitation/{1}'.format(current_app.config['ADMIN_BASE_URL'], token)
if invite_link_host is None:
invite_link_host = current_app.config['ADMIN_BASE_URL']
return '{0}/invitation/{1}'.format(invite_link_host, token)

View File

@@ -1,22 +1,41 @@
import json
import pytest
import uuid
from app.models import Notification, SMS_AUTH_TYPE, EMAIL_AUTH_TYPE
from tests import create_authorization_header
def test_create_invited_user(admin_request, sample_service, mocker, invitation_email_template):
@pytest.mark.parametrize('extra_args, expected_start_of_invite_url', [
(
{},
'http://localhost:6012/invitation/'
),
(
{'invite_link_host': 'https://www.example.com'},
'https://www.example.com/invitation/'
),
])
def test_create_invited_user(
admin_request,
sample_service,
mocker,
invitation_email_template,
extra_args,
expected_start_of_invite_url,
):
mocked = mocker.patch('app.celery.provider_tasks.deliver_email.apply_async')
email_address = 'invited_user@service.gov.uk'
invite_from = sample_service.users[0]
data = {
'service': str(sample_service.id),
'email_address': email_address,
'from_user': str(invite_from.id),
'permissions': 'send_messages,manage_service,manage_api_keys',
'auth_type': EMAIL_AUTH_TYPE
}
data = dict(
service=str(sample_service.id),
email_address=email_address,
from_user=str(invite_from.id),
permissions='send_messages,manage_service,manage_api_keys',
auth_type=EMAIL_AUTH_TYPE,
**extra_args
)
json_resp = admin_request.post(
'invite.create_invited_user',
@@ -33,7 +52,15 @@ def test_create_invited_user(admin_request, sample_service, mocker, invitation_e
assert json_resp['data']['id']
notification = Notification.query.first()
assert notification.reply_to_text == invite_from.email_address
assert len(notification.personalisation.keys()) == 3
assert notification.personalisation['service_name'] == 'Sample service'
assert notification.personalisation['user_name'] == 'Test User'
assert notification.personalisation['url'].startswith(expected_start_of_invite_url)
assert len(notification.personalisation['url']) > len(expected_start_of_invite_url)
mocked.assert_called_once_with([(str(notification.id))], queue="notify-internal-tasks")