From 2d8d2d712aaca00fb45964be8d5d5db24ad8c43f Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Fri, 6 Mar 2020 11:53:55 +0000 Subject: [PATCH] move invite error handler to top level ensure we catch org errors as well as regular errors --- app/__init__.py | 7 +++++++ app/main/forms.py | 5 +++-- app/main/views/invites.py | 8 ++------ app/models/__init__.py | 4 ---- tests/app/main/views/test_accept_invite.py | 10 ++++++++-- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index ac6386e02..625a697b0 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -13,6 +13,7 @@ from flask import ( flash, g, make_response, + redirect, render_template, request, session, @@ -59,6 +60,7 @@ from app.navigation import ( MainNavigation, OrgNavigation, ) +from app.notify_client import InviteTokenError from app.notify_client.api_key_api_client import api_key_api_client from app.notify_client.billing_api_client import billing_api_client from app.notify_client.complaint_api_client import complaint_api_client @@ -702,6 +704,11 @@ def register_errorhandlers(application): # noqa (C901 too complex) return _error_response(error.code) + @application.errorhandler(InviteTokenError) + def handle_bad_invite_token(error): + flash(str(error)) + return redirect(url_for('main.sign_in')) + @application.errorhandler(500) @application.errorhandler(Exception) def handle_bad_request(error): diff --git a/app/main/forms.py b/app/main/forms.py index 3dbd11116..84017130a 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -4,6 +4,7 @@ from itertools import chain import pytz from flask import request +from flask_login import current_user from flask_wtf import FlaskForm as Form from flask_wtf.file import FileAllowed from flask_wtf.file import FileField as FileField_wtf @@ -500,7 +501,7 @@ class InviteUserForm(PermissionsForm): self.invalid_email_address = invalid_email_address.lower() def validate_email_address(self, field): - if field.data.lower() == self.invalid_email_address: + if field.data.lower() == self.invalid_email_address and not current_user.platform_admin: raise ValidationError("You cannot send an invitation to yourself") @@ -512,7 +513,7 @@ class InviteOrgUserForm(StripWhitespaceForm): self.invalid_email_address = invalid_email_address.lower() def validate_email_address(self, field): - if field.data.lower() == self.invalid_email_address: + if field.data.lower() == self.invalid_email_address and not current_user.platform_admin: raise ValidationError("You cannot send an invitation to yourself") diff --git a/app/main/views/invites.py b/app/main/views/invites.py index c1e03d402..e2b32219f 100644 --- a/app/main/views/invites.py +++ b/app/main/views/invites.py @@ -12,16 +12,11 @@ from app.models.user import ( User, Users, ) -from app.notify_client import InviteTokenError @main.route("/invitation/") def accept_invite(token): - try: - invited_user = InvitedUser.from_token(token) - except InviteTokenError as exception: - flash(str(exception)) - return redirect(url_for('main.sign_in')) + invited_user = InvitedUser.from_token(token) if not current_user.is_anonymous and current_user.email_address.lower() != invited_user.email_address.lower(): message = Markup(""" @@ -78,6 +73,7 @@ def accept_invite(token): @main.route("/organisation-invitation/") def accept_org_invite(token): invited_org_user = InvitedOrgUser.from_token(token) + if not current_user.is_anonymous and current_user.email_address.lower() != invited_org_user.email_address.lower(): message = Markup(""" You’re signed in as {}. diff --git a/app/models/__init__.py b/app/models/__init__.py index 3a01e8a81..d63f21bbe 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -77,7 +77,3 @@ class ModelList(ABC, Sequence): def __radd__(self, other): return list(other) + list(self) - - -class InviteTokenError(Exception): - pass diff --git a/tests/app/main/views/test_accept_invite.py b/tests/app/main/views/test_accept_invite.py index b00b4209b..c5631ce2a 100644 --- a/tests/app/main/views/test_accept_invite.py +++ b/tests/app/main/views/test_accept_invite.py @@ -308,12 +308,18 @@ def test_cancelled_invited_user_accepts_invited_redirect_to_cancelled_invitation assert page.h1.string.strip() == 'The invitation you were sent has been cancelled' +@pytest.mark.parametrize('admin_endpoint, api_endpoint', [ + ('main.accept_invite', 'app.invite_api_client.check_token'), + ('main.accept_org_invite', 'app.org_invite_api_client.check_token'), +]) def test_new_user_accept_invite_with_malformed_token( + admin_endpoint, + api_endpoint, client, service_one, mocker, ): - mocker.patch('app.invite_api_client.check_token', side_effect=HTTPError( + mocker.patch(api_endpoint, side_effect=HTTPError( response=Mock( status_code=400, json={ @@ -328,7 +334,7 @@ def test_new_user_accept_invite_with_malformed_token( message={'invitation': 'Something’s wrong with this link. Make sure you’ve copied the whole thing.'} )) - response = client.get(url_for('main.accept_invite', token='thisisnotarealtoken'), follow_redirects=True) + response = client.get(url_for(admin_endpoint, token='thisisnotarealtoken'), follow_redirects=True) assert response.status_code == 200 page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')