From eab4a75e29a2cf7d96d5c2143d9d294d106e0b09 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Thu, 11 Mar 2021 20:26:44 +0000 Subject: [PATCH] remove the global_invite (accept_invite) endpoint move the endpoints into service_invite/rest.py and organisation/invite_rest.py respectively. Remove the prefix from all the blueprints to allow this. --- app/__init__.py | 10 +- app/global_invite/__init__.py | 0 app/global_invite/rest.py | 52 -------- app/organisation/invite_rest.py | 61 +++++++-- app/service_invite/rest.py | 51 +++++-- tests/app/global_invite/__init__.py | 0 .../global_invite/test_global_invite_rest.py | 124 ------------------ tests/app/organisation/test_invite_rest.py | 85 ++++++++++++ .../test_service_invite_rest.py | 89 +++++++++++++ 9 files changed, 267 insertions(+), 205 deletions(-) delete mode 100644 app/global_invite/__init__.py delete mode 100644 app/global_invite/rest.py delete mode 100644 tests/app/global_invite/__init__.py delete mode 100644 tests/app/global_invite/test_global_invite_rest.py diff --git a/app/__init__.py b/app/__init__.py index 3c94d0581..3752cfba4 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -146,7 +146,6 @@ def register_blueprint(application): from app.complaint.complaint_rest import complaint_blueprint from app.email_branding.rest import email_branding_blueprint from app.events.rest import events as events_blueprint - from app.global_invite.rest import global_invite_blueprint from app.inbound_number.rest import inbound_number_blueprint from app.inbound_sms.rest import inbound_sms as inbound_sms_blueprint from app.job.rest import job_blueprint @@ -215,15 +214,15 @@ def register_blueprint(application): service_invite_blueprint.before_request(requires_admin_auth) application.register_blueprint(service_invite_blueprint) + organisation_invite_blueprint.before_request(requires_admin_auth) + application.register_blueprint(organisation_invite_blueprint) + inbound_number_blueprint.before_request(requires_admin_auth) application.register_blueprint(inbound_number_blueprint) inbound_sms_blueprint.before_request(requires_admin_auth) application.register_blueprint(inbound_sms_blueprint) - global_invite_blueprint.before_request(requires_admin_auth) - application.register_blueprint(global_invite_blueprint, url_prefix='/invite') - template_statistics_blueprint.before_request(requires_admin_auth) application.register_blueprint(template_statistics_blueprint) @@ -251,9 +250,6 @@ def register_blueprint(application): organisation_blueprint.before_request(requires_admin_auth) application.register_blueprint(organisation_blueprint, url_prefix='/organisations') - organisation_invite_blueprint.before_request(requires_admin_auth) - application.register_blueprint(organisation_invite_blueprint) - complaint_blueprint.before_request(requires_admin_auth) application.register_blueprint(complaint_blueprint) diff --git a/app/global_invite/__init__.py b/app/global_invite/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/global_invite/rest.py b/app/global_invite/rest.py deleted file mode 100644 index 7727c44f3..000000000 --- a/app/global_invite/rest.py +++ /dev/null @@ -1,52 +0,0 @@ -from flask import Blueprint, current_app, jsonify -from itsdangerous import BadData, SignatureExpired -from notifications_utils.url_safe_token import check_token - -from app.dao.invited_user_dao import get_invited_user_by_id -from app.dao.organisation_dao import dao_get_invited_organisation_user -from app.errors import InvalidRequest, register_errors -from app.schemas import invited_user_schema - -global_invite_blueprint = Blueprint('global_invite', __name__) -register_errors(global_invite_blueprint) - - -@global_invite_blueprint.route('//', methods=['GET']) -def validate_invitation_token(invitation_type, token): - - max_age_seconds = 60 * 60 * 24 * current_app.config['INVITATION_EXPIRATION_DAYS'] - - try: - invited_user_id = check_token(token, - current_app.config['SECRET_KEY'], - current_app.config['DANGEROUS_SALT'], - max_age_seconds) - except SignatureExpired: - errors = {'invitation': - 'Your invitation to GOV.UK Notify has expired. ' - 'Please ask the person that invited you to send you another one'} - raise InvalidRequest(errors, status_code=400) - except BadData: - errors = {'invitation': 'Something’s wrong with this link. Make sure you’ve copied the whole thing.'} - raise InvalidRequest(errors, status_code=400) - - if invitation_type == 'service': - invited_user = get_invited_user_by_id(invited_user_id) - return jsonify(data=invited_user_schema.dump(invited_user).data), 200 - elif invitation_type == 'organisation': - invited_user = dao_get_invited_organisation_user(invited_user_id) - return jsonify(data=invited_user.serialize()), 200 - else: - raise InvalidRequest("Unrecognised invitation type: {}".format(invitation_type)) - - -@global_invite_blueprint.route('/service/', methods=['GET']) -def get_invited_user(invited_user_id): - invited_user = get_invited_user_by_id(invited_user_id) - return jsonify(data=invited_user_schema.dump(invited_user).data), 200 - - -@global_invite_blueprint.route('/organisation/', methods=['GET']) -def get_invited_org_user(invited_org_user_id): - invited_user = dao_get_invited_organisation_user(invited_org_user_id) - return jsonify(data=invited_user.serialize()), 200 diff --git a/app/organisation/invite_rest.py b/app/organisation/invite_rest.py index d6454643d..0e30ab6c8 100644 --- a/app/organisation/invite_rest.py +++ b/app/organisation/invite_rest.py @@ -1,14 +1,18 @@ from flask import Blueprint, current_app, jsonify, request -from notifications_utils.url_safe_token import generate_token +from itsdangerous import BadData, SignatureExpired +from notifications_utils.url_safe_token import check_token, generate_token from app.config import QueueNames from app.dao.invited_org_user_dao import ( - get_invited_org_user, + get_invited_org_user as dao_get_invited_org_user, +) +from app.dao.invited_org_user_dao import ( get_invited_org_users_for_organisation, save_invited_org_user, ) +from app.dao.organisation_dao import dao_get_invited_organisation_user from app.dao.templates_dao import dao_get_template_by_id -from app.errors import register_errors +from app.errors import InvalidRequest, register_errors from app.models import EMAIL_TYPE, KEY_TYPE_NORMAL, InvitedOrganisationUser from app.notifications.process_notifications import ( persist_notification, @@ -20,14 +24,12 @@ from app.organisation.organisation_schema import ( ) from app.schema_validation import validate -organisation_invite_blueprint = Blueprint( - 'organisation_invite', __name__, - url_prefix='/organisation//invite') +organisation_invite_blueprint = Blueprint('organisation_invite', __name__) register_errors(organisation_invite_blueprint) -@organisation_invite_blueprint.route('', methods=['POST']) +@organisation_invite_blueprint.route('/organisation//invite', methods=['POST']) def invite_user_to_org(organisation_id): data = request.get_json() validate(data, post_create_invited_org_user_status_schema) @@ -69,21 +71,27 @@ def invite_user_to_org(organisation_id): return jsonify(data=invited_org_user.serialize()), 201 -@organisation_invite_blueprint.route('', methods=['GET']) +@organisation_invite_blueprint.route('/organisation//invite', methods=['GET']) def get_invited_org_users_by_organisation(organisation_id): invited_org_users = get_invited_org_users_for_organisation(organisation_id) return jsonify(data=[x.serialize() for x in invited_org_users]), 200 -@organisation_invite_blueprint.route('/', methods=['GET']) +@organisation_invite_blueprint.route( + '/organisation//invite/', + methods=['GET'] +) def get_invited_org_user_by_organisation(organisation_id, invited_org_user_id): - invited_org_user = get_invited_org_user(organisation_id, invited_org_user_id) + invited_org_user = dao_get_invited_org_user(organisation_id, invited_org_user_id) return jsonify(data=invited_org_user.serialize()), 200 -@organisation_invite_blueprint.route('/', methods=['POST']) +@organisation_invite_blueprint.route( + '/organisation//invite/', + methods=['POST'] +) def update_org_invite_status(organisation_id, invited_org_user_id): - fetched = get_invited_org_user(organisation_id=organisation_id, invited_org_user_id=invited_org_user_id) + fetched = dao_get_invited_org_user(organisation_id=organisation_id, invited_org_user_id=invited_org_user_id) data = request.get_json() validate(data, post_update_invited_org_user_status_schema) @@ -105,3 +113,32 @@ def invited_org_user_url(invited_org_user_id, invite_link_host=None): invite_link_host = current_app.config['ADMIN_BASE_URL'] return '{0}/organisation-invitation/{1}'.format(invite_link_host, token) + + +@organisation_invite_blueprint.route('/invite/organisation/', methods=['GET']) +def get_invited_org_user(invited_org_user_id): + invited_user = dao_get_invited_organisation_user(invited_org_user_id) + return jsonify(data=invited_user.serialize()), 200 + + +@organisation_invite_blueprint.route('/invite/organisation/', methods=['GET']) +def validate_invitation_token(token): + + max_age_seconds = 60 * 60 * 24 * current_app.config['INVITATION_EXPIRATION_DAYS'] + + try: + invited_user_id = check_token(token, + current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT'], + max_age_seconds) + except SignatureExpired: + errors = {'invitation': + 'Your invitation to GOV.UK Notify has expired. ' + 'Please ask the person that invited you to send you another one'} + raise InvalidRequest(errors, status_code=400) + except BadData: + errors = {'invitation': 'Something’s wrong with this link. Make sure you’ve copied the whole thing.'} + raise InvalidRequest(errors, status_code=400) + + invited_user = dao_get_invited_organisation_user(invited_user_id) + return jsonify(data=invited_user.serialize()), 200 diff --git a/app/service_invite/rest.py b/app/service_invite/rest.py index 2bc71cf57..f29f62344 100644 --- a/app/service_invite/rest.py +++ b/app/service_invite/rest.py @@ -1,13 +1,16 @@ from flask import Blueprint, current_app, jsonify, request +from itsdangerous import BadData, SignatureExpired +from notifications_utils.url_safe_token import check_token, generate_token from app.config import QueueNames +from app.dao.invited_user_dao import get_invited_user as dao_get_invited_user from app.dao.invited_user_dao import ( - get_invited_user, + get_invited_user_by_id, get_invited_users_for_service, save_invited_user, ) from app.dao.templates_dao import dao_get_template_by_id -from app.errors import register_errors +from app.errors import InvalidRequest, register_errors from app.models import BROADCAST_TYPE, EMAIL_TYPE, KEY_TYPE_NORMAL, Service from app.notifications.process_notifications import ( persist_notification, @@ -15,12 +18,12 @@ from app.notifications.process_notifications import ( ) from app.schemas import invited_user_schema -service_invite = Blueprint('service_invite', __name__, url_prefix='/service//invite') +service_invite = Blueprint('service_invite', __name__) register_errors(service_invite) -@service_invite.route('', methods=['POST']) +@service_invite.route('/service//invite', methods=['POST']) def create_invited_user(service_id): request_json = request.get_json() invited_user, errors = invited_user_schema.load(request_json) @@ -58,21 +61,21 @@ def create_invited_user(service_id): return jsonify(data=invited_user_schema.dump(invited_user).data), 201 -@service_invite.route('', methods=['GET']) +@service_invite.route('/service//invite', methods=['GET']) def get_invited_users_by_service(service_id): invited_users = get_invited_users_for_service(service_id) return jsonify(data=invited_user_schema.dump(invited_users, many=True).data), 200 -@service_invite.route('/', methods=['GET']) +@service_invite.route('/service//invite/', methods=['GET']) def get_invited_user_by_service(service_id, invited_user_id): - invited_user = get_invited_user(service_id, invited_user_id) + invited_user = dao_get_invited_user(service_id, invited_user_id) return jsonify(data=invited_user_schema.dump(invited_user).data), 200 -@service_invite.route('/', methods=['POST']) +@service_invite.route('/service//invite/', methods=['POST']) def update_invited_user(service_id, invited_user_id): - fetched = get_invited_user(service_id=service_id, invited_user_id=invited_user_id) + fetched = dao_get_invited_user(service_id=service_id, invited_user_id=invited_user_id) current_data = dict(invited_user_schema.dump(fetched).data.items()) current_data.update(request.get_json()) @@ -82,10 +85,38 @@ def update_invited_user(service_id, 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']) if invite_link_host is None: invite_link_host = current_app.config['ADMIN_BASE_URL'] return '{0}/invitation/{1}'.format(invite_link_host, token) + + +@service_invite.route('/invite/service/', methods=['GET']) +def get_invited_user(invited_user_id): + invited_user = get_invited_user_by_id(invited_user_id) + return jsonify(data=invited_user_schema.dump(invited_user).data), 200 + + +@service_invite.route('/invite/service/', methods=['GET']) +def validate_service_invitation_token(token): + + max_age_seconds = 60 * 60 * 24 * current_app.config['INVITATION_EXPIRATION_DAYS'] + + try: + invited_user_id = check_token(token, + current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT'], + max_age_seconds) + except SignatureExpired: + errors = {'invitation': + 'Your invitation to GOV.UK Notify has expired. ' + 'Please ask the person that invited you to send you another one'} + raise InvalidRequest(errors, status_code=400) + except BadData: + errors = {'invitation': 'Something’s wrong with this link. Make sure you’ve copied the whole thing.'} + raise InvalidRequest(errors, status_code=400) + + invited_user = get_invited_user_by_id(invited_user_id) + return jsonify(data=invited_user_schema.dump(invited_user).data), 200 diff --git a/tests/app/global_invite/__init__.py b/tests/app/global_invite/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/app/global_invite/test_global_invite_rest.py b/tests/app/global_invite/test_global_invite_rest.py deleted file mode 100644 index 41f125f38..000000000 --- a/tests/app/global_invite/test_global_invite_rest.py +++ /dev/null @@ -1,124 +0,0 @@ -import uuid - -import pytest -from flask import current_app, json -from freezegun import freeze_time -from notifications_utils.url_safe_token import generate_token - -from tests import create_authorization_header - - -@pytest.mark.parametrize('invitation_type', ['service', 'organisation']) -def test_validate_invitation_token_for_expired_token_returns_400(client, invitation_type): - with freeze_time('2016-01-01T12:00:00'): - token = generate_token(str(uuid.uuid4()), current_app.config['SECRET_KEY'], - current_app.config['DANGEROUS_SALT']) - url = '/invite/{}/{}'.format(invitation_type, token) - auth_header = create_authorization_header() - response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) - - assert response.status_code == 400 - json_resp = json.loads(response.get_data(as_text=True)) - assert json_resp['result'] == 'error' - assert json_resp['message'] == { - 'invitation': 'Your invitation to GOV.UK Notify has expired. ' - 'Please ask the person that invited you to send you another one'} - - -@pytest.mark.parametrize('invitation_type', ['service', 'organisation']) -def test_validate_invitation_token_returns_200_when_token_valid( - client, invitation_type, sample_invited_user, sample_invited_org_user -): - invited_user = sample_invited_user if invitation_type == 'service' else sample_invited_org_user - - token = generate_token(str(invited_user.id), current_app.config['SECRET_KEY'], - current_app.config['DANGEROUS_SALT']) - url = '/invite/{}/{}'.format(invitation_type, token) - auth_header = create_authorization_header() - response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) - - assert response.status_code == 200 - json_resp = json.loads(response.get_data(as_text=True)) - if invitation_type == 'service': - assert json_resp['data']['id'] == str(sample_invited_user.id) - assert json_resp['data']['email_address'] == sample_invited_user.email_address - assert json_resp['data']['from_user'] == str(sample_invited_user.user_id) - assert json_resp['data']['service'] == str(sample_invited_user.service_id) - assert json_resp['data']['status'] == sample_invited_user.status - assert json_resp['data']['permissions'] == sample_invited_user.permissions - assert json_resp['data']['folder_permissions'] == sample_invited_user.folder_permissions - if invitation_type == 'organisation': - assert json_resp['data'] == sample_invited_org_user.serialize() - - -@pytest.mark.parametrize('invitation_type', ['service', 'organisation']) -def test_validate_invitation_token_returns_400_when_invited_user_does_not_exist(client, invitation_type): - token = generate_token(str(uuid.uuid4()), current_app.config['SECRET_KEY'], - current_app.config['DANGEROUS_SALT']) - url = '/invite/{}/{}'.format(invitation_type, token) - auth_header = create_authorization_header() - response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) - - assert response.status_code == 404 - json_resp = json.loads(response.get_data(as_text=True)) - assert json_resp['result'] == 'error' - assert json_resp['message'] == 'No result found' - - -@pytest.mark.parametrize('invitation_type', ['service', 'organisation']) -def test_validate_invitation_token_returns_400_when_token_is_malformed(client, invitation_type): - token = generate_token( - str(uuid.uuid4()), - current_app.config['SECRET_KEY'], - current_app.config['DANGEROUS_SALT'] - )[:-2] - - url = '/invite/{}/{}'.format(invitation_type, token) - auth_header = create_authorization_header() - response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) - - assert response.status_code == 400 - json_resp = json.loads(response.get_data(as_text=True)) - assert json_resp['result'] == 'error' - assert json_resp['message'] == { - 'invitation': 'Something’s wrong with this link. Make sure you’ve copied the whole thing.' - } - - -def test_get_invited_user(admin_request, sample_invited_user): - json_resp = admin_request.get( - 'global_invite.get_invited_user', - invited_user_id=sample_invited_user.id - ) - assert json_resp['data']['id'] == str(sample_invited_user.id) - assert json_resp['data']['email_address'] == sample_invited_user.email_address - assert json_resp['data']['service'] == str(sample_invited_user.service_id) - assert json_resp['data']['permissions'] == sample_invited_user.permissions - - -def test_get_invited_user_404s_if_invite_doesnt_exist(admin_request, sample_invited_user, fake_uuid): - json_resp = admin_request.get( - 'global_invite.get_invited_user', - invited_user_id=fake_uuid, - _expected_status=404 - ) - assert json_resp['result'] == 'error' - - -def test_get_invited_org_user(admin_request, sample_invited_org_user): - json_resp = admin_request.get( - 'global_invite.get_invited_org_user', - invited_org_user_id=sample_invited_org_user.id - ) - assert json_resp['data']['id'] == str(sample_invited_org_user.id) - assert json_resp['data']['email_address'] == sample_invited_org_user.email_address - assert json_resp['data']['organisation'] == str(sample_invited_org_user.organisation_id) - - -def test_get_invited_org_user_404s_if_invite_doesnt_exist(admin_request, sample_invited_org_user, fake_uuid): - json_resp = admin_request.get( - 'global_invite.get_invited_org_user', - invited_org_user_id=fake_uuid, - _expected_status=404 - ) - assert json_resp['result'] == 'error' diff --git a/tests/app/organisation/test_invite_rest.py b/tests/app/organisation/test_invite_rest.py index eae278e0e..0656d1ea8 100644 --- a/tests/app/organisation/test_invite_rest.py +++ b/tests/app/organisation/test_invite_rest.py @@ -1,6 +1,12 @@ +import uuid + import pytest +from flask import current_app, json +from freezegun import freeze_time +from notifications_utils.url_safe_token import generate_token from app.models import INVITE_PENDING, Notification +from tests import create_authorization_header from tests.app.db import create_invited_org_user @@ -175,3 +181,82 @@ def test_update_org_invited_user_for_invalid_data_returns_400(admin_request, sam ) assert len(json_resp['errors']) == 1 assert json_resp['errors'][0]['message'] == 'status garbage is not one of [pending, accepted, cancelled]' + + +def test_validate_invitation_token_returns_200_when_token_valid(client, sample_invited_org_user): + token = generate_token(str(sample_invited_org_user.id), current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT']) + url = '/invite/organisation/{}'.format(token) + auth_header = create_authorization_header() + response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) + + assert response.status_code == 200 + json_resp = json.loads(response.get_data(as_text=True)) + assert json_resp['data'] == sample_invited_org_user.serialize() + + +def test_validate_invitation_token_for_expired_token_returns_400(client): + with freeze_time('2016-01-01T12:00:00'): + token = generate_token(str(uuid.uuid4()), current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT']) + url = '/invite/organisation/{}'.format(token) + auth_header = create_authorization_header() + response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) + + assert response.status_code == 400 + json_resp = json.loads(response.get_data(as_text=True)) + assert json_resp['result'] == 'error' + assert json_resp['message'] == { + 'invitation': 'Your invitation to GOV.UK Notify has expired. ' + 'Please ask the person that invited you to send you another one'} + + +def test_validate_invitation_token_returns_400_when_invited_user_does_not_exist(client): + token = generate_token(str(uuid.uuid4()), current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT']) + url = '/invite/organisation/{}'.format(token) + auth_header = create_authorization_header() + response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) + + assert response.status_code == 404 + json_resp = json.loads(response.get_data(as_text=True)) + assert json_resp['result'] == 'error' + assert json_resp['message'] == 'No result found' + + +def test_validate_invitation_token_returns_400_when_token_is_malformed(client): + token = generate_token( + str(uuid.uuid4()), + current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT'] + )[:-2] + + url = '/invite/organisation/{}'.format(token) + auth_header = create_authorization_header() + response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) + + assert response.status_code == 400 + json_resp = json.loads(response.get_data(as_text=True)) + assert json_resp['result'] == 'error' + assert json_resp['message'] == { + 'invitation': 'Something’s wrong with this link. Make sure you’ve copied the whole thing.' + } + + +def test_get_invited_org_user(admin_request, sample_invited_org_user): + json_resp = admin_request.get( + 'organisation_invite.get_invited_org_user', + invited_org_user_id=sample_invited_org_user.id + ) + assert json_resp['data']['id'] == str(sample_invited_org_user.id) + assert json_resp['data']['email_address'] == sample_invited_org_user.email_address + assert json_resp['data']['organisation'] == str(sample_invited_org_user.organisation_id) + + +def test_get_invited_org_user_404s_if_invite_doesnt_exist(admin_request, sample_invited_org_user, fake_uuid): + json_resp = admin_request.get( + 'organisation_invite.get_invited_org_user', + invited_org_user_id=fake_uuid, + _expected_status=404 + ) + assert json_resp['result'] == 'error' diff --git a/tests/app/service_invite/test_service_invite_rest.py b/tests/app/service_invite/test_service_invite_rest.py index 4d69f879b..cddbc7d31 100644 --- a/tests/app/service_invite/test_service_invite_rest.py +++ b/tests/app/service_invite/test_service_invite_rest.py @@ -1,7 +1,10 @@ import json +import uuid import pytest from flask import current_app +from freezegun import freeze_time +from notifications_utils.url_safe_token import generate_token from app.models import EMAIL_AUTH_TYPE, SMS_AUTH_TYPE, Notification from tests import create_authorization_header @@ -270,3 +273,89 @@ def test_update_invited_user_for_invalid_data_returns_400(client, sample_invited response = client.post(url, data=json.dumps(data), headers=[('Content-Type', 'application/json'), auth_header]) assert response.status_code == 400 + + +def test_validate_invitation_token_returns_200_when_token_valid(client, sample_invited_user): + token = generate_token(str(sample_invited_user.id), current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT']) + url = '/invite/service/{}'.format(token) + auth_header = create_authorization_header() + response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) + + assert response.status_code == 200 + json_resp = json.loads(response.get_data(as_text=True)) + assert json_resp['data']['id'] == str(sample_invited_user.id) + assert json_resp['data']['email_address'] == sample_invited_user.email_address + assert json_resp['data']['from_user'] == str(sample_invited_user.user_id) + assert json_resp['data']['service'] == str(sample_invited_user.service_id) + assert json_resp['data']['status'] == sample_invited_user.status + assert json_resp['data']['permissions'] == sample_invited_user.permissions + assert json_resp['data']['folder_permissions'] == sample_invited_user.folder_permissions + + +def test_validate_invitation_token_for_expired_token_returns_400(client): + with freeze_time('2016-01-01T12:00:00'): + token = generate_token(str(uuid.uuid4()), current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT']) + url = '/invite/service/{}'.format(token) + auth_header = create_authorization_header() + response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) + + assert response.status_code == 400 + json_resp = json.loads(response.get_data(as_text=True)) + assert json_resp['result'] == 'error' + assert json_resp['message'] == { + 'invitation': 'Your invitation to GOV.UK Notify has expired. ' + 'Please ask the person that invited you to send you another one'} + + +def test_validate_invitation_token_returns_400_when_invited_user_does_not_exist(client): + token = generate_token(str(uuid.uuid4()), current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT']) + url = '/invite/service/{}'.format(token) + auth_header = create_authorization_header() + response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) + + assert response.status_code == 404 + json_resp = json.loads(response.get_data(as_text=True)) + assert json_resp['result'] == 'error' + assert json_resp['message'] == 'No result found' + + +def test_validate_invitation_token_returns_400_when_token_is_malformed(client): + token = generate_token( + str(uuid.uuid4()), + current_app.config['SECRET_KEY'], + current_app.config['DANGEROUS_SALT'] + )[:-2] + + url = '/invite/service/{}'.format(token) + auth_header = create_authorization_header() + response = client.get(url, headers=[('Content-Type', 'application/json'), auth_header]) + + assert response.status_code == 400 + json_resp = json.loads(response.get_data(as_text=True)) + assert json_resp['result'] == 'error' + assert json_resp['message'] == { + 'invitation': 'Something’s wrong with this link. Make sure you’ve copied the whole thing.' + } + + +def test_get_invited_user(admin_request, sample_invited_user): + json_resp = admin_request.get( + 'service_invite.get_invited_user', + invited_user_id=sample_invited_user.id + ) + assert json_resp['data']['id'] == str(sample_invited_user.id) + assert json_resp['data']['email_address'] == sample_invited_user.email_address + assert json_resp['data']['service'] == str(sample_invited_user.service_id) + assert json_resp['data']['permissions'] == sample_invited_user.permissions + + +def test_get_invited_user_404s_if_invite_doesnt_exist(admin_request, sample_invited_user, fake_uuid): + json_resp = admin_request.get( + 'service_invite.get_invited_user', + invited_user_id=fake_uuid, + _expected_status=404 + ) + assert json_resp['result'] == 'error'