Merge pull request #3171 from alphagov/new-invite-endpoints

New invite endpoints
This commit is contained in:
Leo Hemsted
2021-03-12 14:16:19 +00:00
committed by GitHub
16 changed files with 295 additions and 190 deletions

View File

@@ -136,7 +136,6 @@ def create_app(application):
def register_blueprint(application):
from app.accept_invite.rest import accept_invite
from app.authentication.auth import (
requires_admin_auth,
requires_auth,
@@ -149,7 +148,6 @@ def register_blueprint(application):
from app.events.rest import events as events_blueprint
from app.inbound_number.rest import inbound_number_blueprint
from app.inbound_sms.rest import inbound_sms as inbound_sms_blueprint
from app.invite.rest import invite as invite_blueprint
from app.job.rest import job_blueprint
from app.letter_branding.letter_branding_rest import (
letter_branding_blueprint,
@@ -174,6 +172,9 @@ def register_blueprint(application):
)
from app.service.callback_rest import service_callback_blueprint
from app.service.rest import service_blueprint
from app.service_invite.rest import (
service_invite as service_invite_blueprint,
)
from app.status.healthcheck import status as status_blueprint
from app.template.rest import template_blueprint
from app.template_folder.rest import template_folder_blueprint
@@ -210,8 +211,11 @@ def register_blueprint(application):
job_blueprint.before_request(requires_admin_auth)
application.register_blueprint(job_blueprint)
invite_blueprint.before_request(requires_admin_auth)
application.register_blueprint(invite_blueprint)
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)
@@ -219,9 +223,6 @@ def register_blueprint(application):
inbound_sms_blueprint.before_request(requires_admin_auth)
application.register_blueprint(inbound_sms_blueprint)
accept_invite.before_request(requires_admin_auth)
application.register_blueprint(accept_invite, url_prefix='/invite')
template_statistics_blueprint.before_request(requires_admin_auth)
application.register_blueprint(template_statistics_blueprint)
@@ -249,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)

View File

@@ -1,40 +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
accept_invite = Blueprint('accept_invite', __name__)
register_errors(accept_invite)
@accept_invite.route('/<invitation_type>/<token>', 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': 'Somethings wrong with this link. Make sure youve 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))

View File

@@ -570,7 +570,7 @@ def bulk_invite_user_to_service(file_name, service_id, user_id, auth_type, permi
# platform_admin
# view_activity
# "send_texts,send_emails,send_letters,view_activity"
from app.invite.rest import create_invited_user
from app.service_invite.rest import create_invited_user
file = open(file_name)
for email_address in file:
data = {

View File

@@ -9,7 +9,7 @@ def save_invited_user(invited_user):
db.session.commit()
def get_invited_user(service_id, invited_user_id):
def get_invited_user_by_service_and_id(service_id, invited_user_id):
return InvitedUser.query.filter_by(service_id=service_id, id=invited_user_id).one()

View File

@@ -2,13 +2,7 @@ from sqlalchemy.sql.expression import func
from app import db
from app.dao.dao_utils import VersionOptions, transactional, version_class
from app.models import (
Domain,
InvitedOrganisationUser,
Organisation,
Service,
User,
)
from app.models import Domain, Organisation, Service, User
def dao_get_organisations():
@@ -125,10 +119,6 @@ def dao_add_service_to_organisation(service, organisation_id):
db.session.add(service)
def dao_get_invited_organisation_user(user_id):
return InvitedOrganisationUser.query.filter_by(id=user_id).one()
def dao_get_users_for_organisation(organisation_id):
return db.session.query(
User

View File

@@ -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_user_by_id,
get_invited_org_users_for_organisation,
save_invited_org_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/<uuid:organisation_id>/invite')
organisation_invite_blueprint = Blueprint('organisation_invite', __name__)
register_errors(organisation_invite_blueprint)
@organisation_invite_blueprint.route('', methods=['POST'])
@organisation_invite_blueprint.route('/organisation/<uuid:organisation_id>/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/<uuid:organisation_id>/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('/<invited_org_user_id>', methods=['GET'])
@organisation_invite_blueprint.route(
'/organisation/<uuid:organisation_id>/invite/<invited_org_user_id>',
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('/<invited_org_user_id>', methods=['POST'])
@organisation_invite_blueprint.route(
'/organisation/<uuid:organisation_id>/invite/<invited_org_user_id>',
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,33 @@ 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/<uuid:invited_org_user_id>', methods=['GET'])
def get_invited_org_user(invited_org_user_id):
invited_user = get_invited_org_user_by_id(invited_org_user_id)
return jsonify(data=invited_user.serialize()), 200
@organisation_invite_blueprint.route('/invite/organisation/<token>', methods=['GET'])
@organisation_invite_blueprint.route('/invite/organisation/check/<token>', 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': 'Somethings wrong with this link. Make sure youve copied the whole thing.'}
raise InvalidRequest(errors, status_code=400)
invited_user = get_invited_org_user_by_id(invited_user_id)
return jsonify(data=invited_user.serialize()), 200

View File

@@ -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,
get_invited_user_by_id,
get_invited_user_by_service_and_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
invite = Blueprint('invite', __name__, url_prefix='/service/<service_id>/invite')
service_invite = Blueprint('service_invite', __name__)
register_errors(invite)
register_errors(service_invite)
@invite.route('', methods=['POST'])
@service_invite.route('/service/<service_id>/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
@invite.route('', methods=['GET'])
@service_invite.route('/service/<service_id>/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
@invite.route('/<invited_user_id>', methods=['GET'])
@service_invite.route('/service/<service_id>/invite/<invited_user_id>', 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 = get_invited_user_by_service_and_id(service_id, invited_user_id)
return jsonify(data=invited_user_schema.dump(invited_user).data), 200
@invite.route('/<invited_user_id>', methods=['POST'])
@service_invite.route('/service/<service_id>/invite/<invited_user_id>', 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 = get_invited_user_by_service_and_id(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,39 @@ 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/<uuid:invited_user_id>', 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/<token>', methods=['GET'])
@service_invite.route('/invite/service/check/<token>', 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': 'Somethings wrong with this link. Make sure youve 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

View File

@@ -1,85 +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': 'Somethings wrong with this link. Make sure youve copied the whole thing.'
}

View File

@@ -7,8 +7,8 @@ from sqlalchemy.orm.exc import NoResultFound
from app import db
from app.dao.invited_user_dao import (
delete_invitations_created_more_than_two_days_ago,
get_invited_user,
get_invited_user_by_id,
get_invited_user_by_service_and_id,
get_invited_users_for_service,
save_invited_user,
)
@@ -65,7 +65,7 @@ def test_create_invited_user_sets_default_folder_permissions_of_empty_list(
def test_get_invited_user_by_service_and_id(notify_db, notify_db_session, sample_invited_user):
from_db = get_invited_user(sample_invited_user.service.id, sample_invited_user.id)
from_db = get_invited_user_by_service_and_id(sample_invited_user.service.id, sample_invited_user.id)
assert from_db == sample_invited_user
@@ -78,7 +78,7 @@ def test_get_unknown_invited_user_returns_none(notify_db, notify_db_session, sam
unknown_id = uuid.uuid4()
with pytest.raises(NoResultFound) as e:
get_invited_user(sample_service.id, unknown_id)
get_invited_user_by_service_and_id(sample_service.id, unknown_id)
assert 'No row was found for one()' in str(e.value)

View File

@@ -8,7 +8,6 @@ from app import db
from app.dao.organisation_dao import (
dao_add_service_to_organisation,
dao_add_user_to_organisation,
dao_get_invited_organisation_user,
dao_get_organisation_by_email_address,
dao_get_organisation_by_id,
dao_get_organisation_by_service_id,
@@ -275,16 +274,6 @@ def test_get_organisation_by_service_id(sample_service, sample_organisation):
assert organisation_2 == another_org
def test_dao_get_invited_organisation_user(sample_invited_org_user):
invited_org_user = dao_get_invited_organisation_user(sample_invited_org_user.id)
assert invited_org_user == sample_invited_org_user
def test_dao_get_invited_organisation_user_returns_none(notify_db):
with pytest.raises(expected_exception=SQLAlchemyError):
dao_get_invited_organisation_user(uuid.uuid4())
def test_dao_get_users_for_organisation(sample_organisation):
first = create_user(email='first@invited.com')
second = create_user(email='another@invited.com')

View File

@@ -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,87 @@ 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]'
@pytest.mark.parametrize('endpoint_format_str', [
'/invite/organisation/{}',
'/invite/organisation/check/{}',
])
def test_validate_invitation_token_returns_200_when_token_valid(client, sample_invited_org_user, endpoint_format_str):
token = generate_token(str(sample_invited_org_user.id), current_app.config['SECRET_KEY'],
current_app.config['DANGEROUS_SALT'])
url = endpoint_format_str.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': 'Somethings wrong with this link. Make sure youve 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'

View File

@@ -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
@@ -41,7 +44,7 @@ def test_create_invited_user(
)
json_resp = admin_request.post(
'invite.create_invited_user',
'service_invite.create_invited_user',
service_id=sample_service.id,
_data=data,
_expected_status=201
@@ -102,7 +105,7 @@ def test_invited_user_for_broadcast_service_receives_broadcast_invite_email(
)
admin_request.post(
'invite.create_invited_user',
'service_invite.create_invited_user',
service_id=sample_broadcast_service.id,
_data=data,
_expected_status=201
@@ -136,7 +139,7 @@ def test_create_invited_user_without_auth_type(admin_request, sample_service, mo
}
json_resp = admin_request.post(
'invite.create_invited_user',
'service_invite.create_invited_user',
service_id=sample_service.id,
_data=data,
_expected_status=201
@@ -218,7 +221,7 @@ def test_get_invited_users_by_service_with_no_invites(client, notify_db, notify_
def test_get_invited_user_by_service(admin_request, sample_invited_user):
json_resp = admin_request.get(
'invite.get_invited_user_by_service',
'service_invite.get_invited_user_by_service',
service_id=sample_invited_user.service.id,
invited_user_id=sample_invited_user.id
)
@@ -231,7 +234,7 @@ def test_get_invited_user_by_service_when_user_does_not_belong_to_the_service(
fake_uuid,
):
json_resp = admin_request.get(
'invite.get_invited_user_by_service',
'service_invite.get_invited_user_by_service',
service_id=fake_uuid,
invited_user_id=sample_invited_user.id,
_expected_status=404
@@ -270,3 +273,93 @@ 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
@pytest.mark.parametrize('endpoint_format_str', [
'/invite/service/{}',
'/invite/service/check/{}',
])
def test_validate_invitation_token_returns_200_when_token_valid(client, sample_invited_user, endpoint_format_str):
token = generate_token(str(sample_invited_user.id), current_app.config['SECRET_KEY'],
current_app.config['DANGEROUS_SALT'])
url = endpoint_format_str.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': 'Somethings wrong with this link. Make sure youve 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'