diff --git a/app/main/views/register.py b/app/main/views/register.py index e6350c8f7..ed0b60f41 100644 --- a/app/main/views/register.py +++ b/app/main/views/register.py @@ -1,9 +1,12 @@ +import base64 +import json import uuid from datetime import datetime, timedelta from flask import ( abort, current_app, + flash, redirect, render_template, request, @@ -22,8 +25,9 @@ from app.main.forms import ( ) from app.main.views import sign_in from app.main.views.verify import activate_user +from app.models.service import Service from app.models.user import InvitedOrgUser, InvitedUser, User -from app.utils import hide_from_search_engines +from app.utils import hide_from_search_engines, hilite @main.route("/register", methods=["GET", "POST"]) @@ -150,7 +154,26 @@ def set_up_your_profile(): if code and state: access_token = sign_in._get_access_token(code, state) user_email, user_uuid = sign_in._get_user_email_and_uuid(access_token) - redirect_url = request.args.get("next") + + invite_data = state.encode("utf8") + invite_data = base64.b64decode(invite_data) + invite_data = json.loads(invite_data) + invited_service = Service.from_id(invite_data["service_id"]) + invited_user_id = invite_data["invited_user_id"] + invited_user = InvitedUser.by_id(invited_user_id) + + if user_email.lower() != invited_user.email_address.lower(): + flash("You cannot accept an invite for another person.") + session.pop("invited_user_id", None) + abort(403) + else: + invited_user.accept_invite() + current_app.logger.debug( + hilite( + f"INVITED USER {invited_user.email_address} to service {invited_service.name}" + ) + ) + current_app.logger.debug(hilite("ACCEPTED INVITE")) elif login_gov_error: current_app.logger.error(f"login.gov error: {login_gov_error}") @@ -174,5 +197,16 @@ def set_up_your_profile(): # activate the user user = user_api_client.get_user_by_uuid_or_email(user_uuid, user_email) activate_user(user["id"]) - return redirect(url_for("main.show_accounts_or_dashboard", next=redirect_url)) + usr = User.from_id(user["id"]) + usr.add_to_service( + invited_service.id, + invite_data["permissions"], + invite_data["folder_permissions"], + invite_data["from_user_id"], + ) + current_app.logger.debug( + hilite(f"Added user {usr.email_address} to service {invited_service.name}") + ) + return redirect(url_for("main.show_accounts_or_dashboard")) + return render_template("views/set-up-your-profile.html", form=form) diff --git a/app/main/views/sign_in.py b/app/main/views/sign_in.py index ee427322e..2a205c9aa 100644 --- a/app/main/views/sign_in.py +++ b/app/main/views/sign_in.py @@ -220,7 +220,6 @@ def sign_in(): if url is not None: url = url.replace("NONCE", token) url = url.replace("STATE", token) - return render_template( "views/signin.html", form=form, diff --git a/app/main/views/verify.py b/app/main/views/verify.py index dc530bce9..114e95ddd 100644 --- a/app/main/views/verify.py +++ b/app/main/views/verify.py @@ -8,7 +8,6 @@ from app import user_api_client from app.main import main from app.main.forms import TwoFactorForm from app.models.user import User -from app.notify_client import service_api_client from app.utils.login import redirect_to_sign_in @@ -66,35 +65,6 @@ def verify_email(token): def activate_user(user_id): user = User.from_id(user_id) - # This is the login.gov path - try: - login_gov_invite_data = service_api_client.retrieve_service_invite_data( - f"service-invite-{user.email_address}" - ) - except BaseException: # noqa - # We will hit an exception if we can't find invite data, - # but that will be the normal sign in use case - login_gov_invite_data = None - if login_gov_invite_data: - login_gov_invite_data = json.loads(login_gov_invite_data) - service_id = login_gov_invite_data["service_id"] - user_id = user_id - permissions = login_gov_invite_data["permissions"] - folder_permissions = login_gov_invite_data["folder_permissions"] - - # Actually call the back end and add the user to the service - try: - user_api_client.add_user_to_service( - service_id, user_id, permissions, folder_permissions - ) - except BaseException as be: # noqa - # TODO if the user is already part of service we should ignore - current_app.logger.warning(f"Exception adding user to service {be}") - - activated_user = user.activate() - activated_user.login() - return redirect(url_for("main.service_dashboard", service_id=service_id)) - # TODO add org invites back in the new way # organization_id = redis_client.raw_get( # f"organization-invite-{user.email_address}" @@ -111,15 +81,3 @@ def activate_user(user_id): activated_user.login() return redirect(url_for("main.add_service", first="first")) - - -def _add_invited_user_to_service(invitation): - user = User.from_id(session["user_id"]) - service_id = invitation.service - user.add_to_service( - service_id, - invitation.permissions, - invitation.folder_permissions, - invitation.from_user.id, - ) - return service_id diff --git a/poetry.lock b/poetry.lock index 0e93fd083..f70d06207 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1211,6 +1211,7 @@ description = "Powerful and Pythonic XML processing library combining libxml2/li optional = false python-versions = ">=3.6" files = [ + {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:704f5572ff473a5f897745abebc6df40f22d4133c1e0a1f124e4f2bd3330ff7e"}, {file = "lxml-5.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d3c0f8567ffe7502d969c2c1b809892dc793b5d0665f602aad19895f8d508da"}, {file = "lxml-5.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5fcfbebdb0c5d8d18b84118842f31965d59ee3e66996ac842e21f957eb76138c"}, {file = "lxml-5.1.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f37c6d7106a9d6f0708d4e164b707037b7380fcd0b04c5bd9cae1fb46a856fb"}, @@ -1220,6 +1221,7 @@ files = [ {file = "lxml-5.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:82bddf0e72cb2af3cbba7cec1d2fd11fda0de6be8f4492223d4a268713ef2147"}, {file = "lxml-5.1.0-cp310-cp310-win32.whl", hash = "sha256:b66aa6357b265670bb574f050ffceefb98549c721cf28351b748be1ef9577d93"}, {file = "lxml-5.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:4946e7f59b7b6a9e27bef34422f645e9a368cb2be11bf1ef3cafc39a1f6ba68d"}, + {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:14deca1460b4b0f6b01f1ddc9557704e8b365f55c63070463f6c18619ebf964f"}, {file = "lxml-5.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ed8c3d2cd329bf779b7ed38db176738f3f8be637bb395ce9629fc76f78afe3d4"}, {file = "lxml-5.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:436a943c2900bb98123b06437cdd30580a61340fbdb7b28aaf345a459c19046a"}, {file = "lxml-5.1.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acb6b2f96f60f70e7f34efe0c3ea34ca63f19ca63ce90019c6cbca6b676e81fa"}, @@ -1229,6 +1231,7 @@ files = [ {file = "lxml-5.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4c9bda132ad108b387c33fabfea47866af87f4ea6ffb79418004f0521e63204"}, {file = "lxml-5.1.0-cp311-cp311-win32.whl", hash = "sha256:bc64d1b1dab08f679fb89c368f4c05693f58a9faf744c4d390d7ed1d8223869b"}, {file = "lxml-5.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5ab722ae5a873d8dcee1f5f45ddd93c34210aed44ff2dc643b5025981908cda"}, + {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9aa543980ab1fbf1720969af1d99095a548ea42e00361e727c58a40832439114"}, {file = "lxml-5.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6f11b77ec0979f7e4dc5ae081325a2946f1fe424148d3945f943ceaede98adb8"}, {file = "lxml-5.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a36c506e5f8aeb40680491d39ed94670487ce6614b9d27cabe45d94cd5d63e1e"}, {file = "lxml-5.1.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f643ffd2669ffd4b5a3e9b41c909b72b2a1d5e4915da90a77e119b8d48ce867a"}, @@ -1254,8 +1257,8 @@ files = [ {file = "lxml-5.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8f52fe6859b9db71ee609b0c0a70fea5f1e71c3462ecf144ca800d3f434f0764"}, {file = "lxml-5.1.0-cp37-cp37m-win32.whl", hash = "sha256:d42e3a3fc18acc88b838efded0e6ec3edf3e328a58c68fbd36a7263a874906c8"}, {file = "lxml-5.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:eac68f96539b32fce2c9b47eb7c25bb2582bdaf1bbb360d25f564ee9e04c542b"}, + {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ae15347a88cf8af0949a9872b57a320d2605ae069bcdf047677318bc0bba45b1"}, {file = "lxml-5.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c26aab6ea9c54d3bed716b8851c8bfc40cb249b8e9880e250d1eddde9f709bf5"}, - {file = "lxml-5.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cfbac9f6149174f76df7e08c2e28b19d74aed90cad60383ad8671d3af7d0502f"}, {file = "lxml-5.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:342e95bddec3a698ac24378d61996b3ee5ba9acfeb253986002ac53c9a5f6f84"}, {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725e171e0b99a66ec8605ac77fa12239dbe061482ac854d25720e2294652eeaa"}, {file = "lxml-5.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d184e0d5c918cff04cdde9dbdf9600e960161d773666958c9d7b565ccc60c45"}, @@ -1263,6 +1266,7 @@ files = [ {file = "lxml-5.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d48fc57e7c1e3df57be5ae8614bab6d4e7b60f65c5457915c26892c41afc59e"}, {file = "lxml-5.1.0-cp38-cp38-win32.whl", hash = "sha256:7ec465e6549ed97e9f1e5ed51c657c9ede767bc1c11552f7f4d022c4df4a977a"}, {file = "lxml-5.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:b21b4031b53d25b0858d4e124f2f9131ffc1530431c6d1321805c90da78388d1"}, + {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:52427a7eadc98f9e62cb1368a5079ae826f94f05755d2d567d93ee1bc3ceb354"}, {file = "lxml-5.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6a2a2c724d97c1eb8cf966b16ca2915566a4904b9aad2ed9a09c748ffe14f969"}, {file = "lxml-5.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:843b9c835580d52828d8f69ea4302537337a21e6b4f1ec711a52241ba4a824f3"}, {file = "lxml-5.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b99f564659cfa704a2dd82d0684207b1aadf7d02d33e54845f9fc78e06b7581"}, @@ -1513,6 +1517,7 @@ files = [ {file = "msgpack-1.0.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273"}, {file = "msgpack-1.0.8-cp39-cp39-win32.whl", hash = "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d"}, {file = "msgpack-1.0.8-cp39-cp39-win_amd64.whl", hash = "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011"}, + {file = "msgpack-1.0.8-py3-none-any.whl", hash = "sha256:24f727df1e20b9876fa6e95f840a2a2651e34c0ad147676356f4bf5fbb0206ca"}, {file = "msgpack-1.0.8.tar.gz", hash = "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3"}, ] diff --git a/tests/app/main/views/test_verify.py b/tests/app/main/views/test_verify.py index 80b12336c..3c4a93725 100644 --- a/tests/app/main/views/test_verify.py +++ b/tests/app/main/views/test_verify.py @@ -42,10 +42,6 @@ def test_should_redirect_to_add_service_when_sms_code_is_correct( mock_create_event, fake_uuid, ): - mocker.patch( - "app.main.views.verify.service_api_client.retrieve_service_invite_data", - return_value={}, - ) api_user_active["current_session_id"] = str(uuid.UUID(int=1)) mocker.patch("app.user_api_client.get_user", return_value=api_user_active) @@ -81,10 +77,6 @@ def test_should_activate_user_after_verify( mock_create_event, mock_activate_user, ): - mocker.patch( - "app.main.views.verify.service_api_client.retrieve_service_invite_data", - return_value={}, - ) client_request.logout() mocker.patch("app.user_api_client.get_user", return_value=api_user_pending) with client_request.session_transaction() as session: @@ -156,10 +148,6 @@ def test_verify_email_doesnt_verify_sms_if_user_on_email_auth( mock_activate_user, fake_uuid, ): - mocker.patch( - "app.main.views.verify.service_api_client.retrieve_service_invite_data", - return_value={}, - ) pending_user_with_email_auth = create_user( auth_type="email_auth", state="pending", id=fake_uuid ) @@ -250,10 +238,6 @@ def test_activate_user_redirects_to_service_dashboard_if_user_already_belongs_to mock_get_service, mock_get_invited_user_by_id, ): - mocker.patch( - "app.main.views.verify.service_api_client.retrieve_service_invite_data", - return_value={}, - ) mocker.patch( "app.user_api_client.add_user_to_service", side_effect=HTTPError( diff --git a/tests/end_to_end/test_invite_team_member_to_service.py b/tests/end_to_end/test_invite_team_member_to_service.py index 50b74b0d1..f1711dca9 100644 --- a/tests/end_to_end/test_invite_team_member_to_service.py +++ b/tests/end_to_end/test_invite_team_member_to_service.py @@ -117,19 +117,17 @@ def test_invite_team_member_to_service(authenticated_page): # Check permission labels are on page for permission in permissions: - expect( - page.get_by_label(permission) - ).to_be_visible + expect(page.get_by_label(permission)).to_be_visible # There is an issue with checking the send messages box due to possible duplicate # "Send messages" appearing on the page. # Put checkboxes into checked state. checkbox_list = [ - 'See dashboard', - 'Add and edit templates', - 'Manage settings, team and usage', - 'Manage API integration', - ] + "See dashboard", + "Add and edit templates", + "Manage settings, team and usage", + "Manage API integration", + ] for checkbox in checkbox_list: page.check(f"text={checkbox}", force=True) @@ -138,7 +136,9 @@ def test_invite_team_member_to_service(authenticated_page): expect(permission_box_activity).to_be_checked() # Check for send invitation email button - send_invite_email_button = page.get_by_role("button", name=re.compile("Send invitation email")) + send_invite_email_button = page.get_by_role( + "button", name=re.compile("Send invitation email") + ) expect(send_invite_email_button).to_be_visible() # send_invite_email_button.click() # Check to make sure that we've arrived at the next page.