diff --git a/app/main/views/add_service.py b/app/main/views/add_service.py index 700d4eb74..05febf569 100644 --- a/app/main/views/add_service.py +++ b/app/main/views/add_service.py @@ -12,7 +12,10 @@ from app.main.dao import services_dao, users_dao from app.main.forms import AddServiceForm from app.notify_client.models import InvitedUser -from app import user_api_client +from app import ( + invite_api_client, + user_api_client +) @main.route("/add-service", methods=['GET', 'POST']) @@ -25,7 +28,9 @@ def add_service(): # if invited user add to service and redirect to dashboard user = users_dao.get_user_by_id(session['user_id']) service_id = invited_user['service'] - user_api_client.add_user_to_service(service_id, user.id, invitation) + user_api_client.add_user_to_service(service_id, user.id, invitation.permissions) + invite_api_client.accept_invite(service_id, invitation.id) + session.pop('invited_user', None) return redirect(url_for('main.service_dashboard', service_id=service_id)) diff --git a/app/main/views/invites.py b/app/main/views/invites.py index cad3bf3b4..4fce06803 100644 --- a/app/main/views/invites.py +++ b/app/main/views/invites.py @@ -1,9 +1,12 @@ from flask import ( redirect, url_for, - session + session, + abort ) +from notifications_python_client.errors import HTTPError + from app.main import main from app import ( invite_api_client, @@ -14,14 +17,23 @@ from app import ( @main.route("/invitation/") def accept_invite(token): - invited_user = invite_api_client.accept_invite(token) - existing_user = user_api_client.get_user_by_email(invited_user.email_address) + try: - if existing_user: - user_api_client.add_user_to_service(invited_user.service, - existing_user.id, - invited_user) - return redirect(url_for('main.service_dashboard', service_id=invited_user.service)) - else: - session['invited_user'] = invited_user.serialize() - return redirect(url_for('main.register_from_invite')) + invited_user = invite_api_client.check_token(token) + existing_user = user_api_client.get_user_by_email(invited_user.email_address) + + if existing_user: + user_api_client.add_user_to_service(invited_user.service, + existing_user.id, + invited_user.permissions) + invite_api_client.accept_invite(invited_user.service, invited_user.id) + return redirect(url_for('main.service_dashboard', service_id=invited_user.service)) + else: + session['invited_user'] = invited_user.serialize() + return redirect(url_for('main.register_from_invite')) + + except HTTPError as e: + if e.status_code == 404: + abort(404) + else: + raise e diff --git a/app/notify_client/invite_api_client.py b/app/notify_client/invite_api_client.py index 6f2712848..03ce6e85c 100644 --- a/app/notify_client/invite_api_client.py +++ b/app/notify_client/invite_api_client.py @@ -31,7 +31,7 @@ class InviteApiClient(BaseAPIClient): invited_users = self._get_invited_users(invites) return invited_users - def accept_invite(self, token): + def check_token(self, token): resp = self.get(url='/invite/{}'.format(token)) return InvitedUser(**resp['data']) @@ -40,6 +40,11 @@ class InviteApiClient(BaseAPIClient): self.post(url='/service/{0}/invite/{1}'.format(service_id, invited_user_id), data=data) + def accept_invite(self, service_id, invited_user_id): + data = {'status': 'accepted'} + self.post(url='/service/{0}/invite/{1}'.format(service_id, invited_user_id), + data=data) + def _get_invited_users(self, invites): invited_users = [] for invite in invites: diff --git a/app/notify_client/user_api_client.py b/app/notify_client/user_api_client.py index ce9d83bce..74c1f9af9 100644 --- a/app/notify_client/user_api_client.py +++ b/app/notify_client/user_api_client.py @@ -94,9 +94,9 @@ class UserApiClient(BaseAPIClient): resp = self.get(endpoint) return [User(data) for data in resp['data']] - def add_user_to_service(self, service_id, user_id, invited_user): + def add_user_to_service(self, service_id, user_id, permissions): endpoint = '/service/{}/users/{}'.format(service_id, user_id) - resp = self.post(endpoint, data=invited_user.serialize(permissions_as_string=True)) + resp = self.post(endpoint, data={'permissions': permissions}) return User(resp['data'], max_failed_login_count=self.max_failed_login_count) def set_user_permissions(self, user_id, service_id, permissions): diff --git a/tests/app/main/views/test_accept_invite.py b/tests/app/main/views/test_accept_invite.py index 7ea04af93..2c0d001be 100644 --- a/tests/app/main/views/test_accept_invite.py +++ b/tests/app/main/views/test_accept_invite.py @@ -7,22 +7,24 @@ def test_existing_user_accept_invite_calls_api_and_redirects_to_dashboard(app_, service_one, api_user_active, sample_invite, - sample_invited_user, - mock_accept_invite, + mock_check_invite_token, mock_get_user_by_email, - mock_add_user_to_service): + mock_add_user_to_service, + mock_accept_invite): expected_service = service_one['id'] expected_redirect_location = 'http://localhost/services/{}/dashboard'.format(expected_service) + expected_permissions = ['send_messages', 'manage_service', 'manage_api_keys'] with app_.test_request_context(): with app_.test_client() as client: response = client.get(url_for('main.accept_invite', token='thisisnotarealtoken')) - mock_accept_invite.assert_called_with('thisisnotarealtoken') + mock_check_invite_token.assert_called_with('thisisnotarealtoken') mock_get_user_by_email.assert_called_with('invited_user@test.gov.uk') - mock_add_user_to_service.assert_called_with(expected_service, api_user_active.id, sample_invited_user) + mock_add_user_to_service.assert_called_with(expected_service, api_user_active.id, expected_permissions) + mock_accept_invite.assert_called_with(expected_service, sample_invite['id']) assert response.status_code == 302 assert response.location == expected_redirect_location @@ -32,21 +34,22 @@ def test_existing_signed_out_user_accept_invite_redirects_to_sign_in(app_, service_one, api_user_active, sample_invite, - sample_invited_user, - mock_accept_invite, + mock_check_invite_token, mock_get_user_by_email, - mock_add_user_to_service): + mock_add_user_to_service, + mock_accept_invite): expected_service = service_one['id'] - + expected_permissions = ['send_messages', 'manage_service', 'manage_api_keys'] with app_.test_request_context(): with app_.test_client() as client: response = client.get(url_for('main.accept_invite', token='thisisnotarealtoken'), follow_redirects=True) - mock_accept_invite.assert_called_with('thisisnotarealtoken') + mock_check_invite_token.assert_called_with('thisisnotarealtoken') mock_get_user_by_email.assert_called_with('invited_user@test.gov.uk') - mock_add_user_to_service.assert_called_with(expected_service, api_user_active.id, sample_invited_user) + mock_add_user_to_service.assert_called_with(expected_service, api_user_active.id, expected_permissions) + mock_accept_invite.assert_called_with(expected_service, sample_invite['id']) assert response.status_code == 200 page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') @@ -56,9 +59,10 @@ def test_existing_signed_out_user_accept_invite_redirects_to_sign_in(app_, def test_new_user_accept_invite_calls_api_and_redirects_to_registration(app_, service_one, sample_invite, - mock_accept_invite, + mock_check_invite_token, mock_dont_get_user_by_email, - mock_add_user_to_service): + mock_add_user_to_service, + mock_accept_invite): expected_redirect_location = 'http://localhost/register-from-invite' @@ -67,7 +71,7 @@ def test_new_user_accept_invite_calls_api_and_redirects_to_registration(app_, response = client.get(url_for('main.accept_invite', token='thisisnotarealtoken')) - mock_accept_invite.assert_called_with('thisisnotarealtoken') + mock_check_invite_token.assert_called_with('thisisnotarealtoken') mock_dont_get_user_by_email.assert_called_with('invited_user@test.gov.uk') assert response.status_code == 302 @@ -77,11 +81,12 @@ def test_new_user_accept_invite_calls_api_and_redirects_to_registration(app_, def test_new_user_accept_invite_completes_new_registration_redirects_to_verify(app_, service_one, sample_invite, - mock_accept_invite, + mock_check_invite_token, mock_dont_get_user_by_email, mock_register_user, mock_send_verify_code, - mock_add_user_to_service): + mock_add_user_to_service, + mock_accept_invite): expected_service = service_one['id'] expected_email = sample_invite['email_address'] @@ -122,8 +127,7 @@ def test_new_user_accept_invite_completes_new_registration_redirects_to_verify(a def test_new_invited_user_verifies_and_added_to_service(app_, service_one, sample_invite, - sample_invited_user, - mock_accept_invite, + mock_check_invite_token, mock_dont_get_user_by_email, mock_register_user, mock_send_verify_code, @@ -131,6 +135,7 @@ def test_new_invited_user_verifies_and_added_to_service(app_, mock_get_user, mock_update_user, mock_add_user_to_service, + mock_accept_invite, mock_get_service, mock_get_service_templates, mock_get_jobs): @@ -156,9 +161,12 @@ def test_new_invited_user_verifies_and_added_to_service(app_, # when they post codes back to admin user should be added to # service and sent on to dash board + expected_permissions = ['send_messages', 'manage_service', 'manage_api_keys'] with client.session_transaction() as session: new_user_id = session['user_id'] - mock_add_user_to_service.assert_called_with(data['service'], new_user_id, sample_invited_user) + mock_add_user_to_service.assert_called_with(data['service'], new_user_id, expected_permissions) + + mock_accept_invite.assert_called_with(data['service'], sample_invite['id']) page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') element = page.find('h2', class_='navigation-service-name').find('a') diff --git a/tests/conftest.py b/tests/conftest.py index 399d10539..2f627e5a8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -629,14 +629,21 @@ def mock_get_invites_for_service(mocker, service_one, sample_invite): @pytest.fixture(scope='function') -def mock_accept_invite(mocker, sample_invite): - def _accept_token(token): +def mock_check_invite_token(mocker, sample_invite): + def _check_token(token): return InvitedUser(**sample_invite) - return mocker.patch('app.invite_api_client.accept_invite', side_effect=_accept_token) + return mocker.patch('app.invite_api_client.check_token', side_effect=_check_token) + + +@pytest.fixture(scope='function') +def mock_accept_invite(mocker, sample_invite): + def _accept(service_id, invite_id): + return InvitedUser(**sample_invite) + return mocker.patch('app.invite_api_client.accept_invite', side_effect=_accept) @pytest.fixture(scope='function') def mock_add_user_to_service(mocker, service_one, api_user_active): - def _add_user(service_id, user_id, invited_user): + def _add_user(service_id, user_id, permissions): return api_user_active return mocker.patch('app.user_api_client.add_user_to_service', side_effect=_add_user)