From db5185407883dfbe1af700c67c07d10332e129e5 Mon Sep 17 00:00:00 2001 From: Daniel Grams Date: Tue, 20 Jul 2021 11:47:21 +0200 Subject: [PATCH] Optimize onboarding for invitations #225 --- project/__init__.py | 2 +- project/services/admin_unit.py | 8 ++++++- project/services/user.py | 2 +- project/templates/security/login_user.html | 2 +- project/views/admin_unit_member_invitation.py | 4 +++- project/views/manage.py | 23 ++++++++++++++++--- project/views/user.py | 7 +++--- .../test_admin_unit_member_invitation.py | 5 ++-- tests/views/test_manage.py | 19 +++++++++++++++ 9 files changed, 57 insertions(+), 15 deletions(-) diff --git a/project/__init__.py b/project/__init__.py index 2034953..957504e 100644 --- a/project/__init__.py +++ b/project/__init__.py @@ -18,7 +18,7 @@ app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DATABASE_URL"] app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False app.config["SECURITY_CONFIRMABLE"] = True -app.config["SECURITY_POST_LOGIN_VIEW"] = "manage" +app.config["SECURITY_POST_LOGIN_VIEW"] = "manage_after_login" app.config["SECURITY_TRACKABLE"] = True app.config["SECURITY_REGISTERABLE"] = True app.config["SECURITY_SEND_REGISTER_EMAIL"] = True diff --git a/project/services/admin_unit.py b/project/services/admin_unit.py index c96cfd1..7b196d6 100644 --- a/project/services/admin_unit.py +++ b/project/services/admin_unit.py @@ -67,11 +67,17 @@ def find_admin_unit_member_invitation(email, admin_unit_id): return AdminUnitMemberInvitation.query.filter( and_( AdminUnitMemberInvitation.admin_unit_id == admin_unit_id, - AdminUnitMemberInvitation.email == email, + func.lower(AdminUnitMemberInvitation.email) == func.lower(email), ) ).first() +def get_admin_unit_member_invitations(email): + return AdminUnitMemberInvitation.query.filter( + func.lower(AdminUnitMemberInvitation.email) == func.lower(email) + ).all() + + def insert_admin_unit_member_invitation(admin_unit_id, email, role_names): invitation = AdminUnitMemberInvitation() invitation.admin_unit_id = admin_unit_id diff --git a/project/services/user.py b/project/services/user.py index f101235..44c2f0e 100644 --- a/project/services/user.py +++ b/project/services/user.py @@ -47,7 +47,7 @@ def upsert_user_role(role_name, role_title, permissions): def find_user_by_email(email): - return user_datastore.find_user(email=email) + return user_datastore.find_user(email=email, case_insensitive=True) def get_user(id): diff --git a/project/templates/security/login_user.html b/project/templates/security/login_user.html index b033de7..6e9e01a 100644 --- a/project/templates/security/login_user.html +++ b/project/templates/security/login_user.html @@ -4,7 +4,7 @@ {% block content %}

{{ _fsdomain('Login') }}

-{% set next = request.args['next'] if 'next' in request.args and 'authorize' in request.args['next'] else 'manage' %} +{% set next = request.args['next'] if 'next' in request.args and 'authorize' in request.args['next'] else 'manage_after_login' %}
{{ login_user_form.hidden_tag() }} {{ render_field_with_errors(login_user_form.email) }} diff --git a/project/views/admin_unit_member_invitation.py b/project/views/admin_unit_member_invitation.py index fe991f0..3399a08 100644 --- a/project/views/admin_unit_member_invitation.py +++ b/project/views/admin_unit_member_invitation.py @@ -46,13 +46,15 @@ def admin_unit_member_invitation(id): add_user_to_admin_unit_with_roles( current_user, invitation.adminunit, roles ) + url = url_for("manage_admin_unit", id=invitation.admin_unit_id) else: message = gettext("Invitation successfully declined") + url = url_for("manage") db.session.delete(invitation) db.session.commit() flash(message, "success") - return redirect(url_for("manage")) + return redirect(url) except SQLAlchemyError as e: db.session.rollback() flash(handleSqlError(e), "danger") diff --git a/project/views/manage.py b/project/views/manage.py index f1a0028..fd19ad7 100644 --- a/project/views/manage.py +++ b/project/views/manage.py @@ -22,6 +22,7 @@ from project.models import ( EventSuggestion, User, ) +from project.services.admin_unit import get_admin_unit_member_invitations from project.services.event import get_events_query from project.services.event_search import EventSearchParams from project.services.event_suggestion import get_event_reviews_query @@ -34,6 +35,12 @@ from project.views.utils import ( ) +@app.route("/manage_after_login") +@auth_required() +def manage_after_login(): + return redirect(url_for("manage", from_login=1)) + + @app.route("/manage") @auth_required() def manage(): @@ -47,6 +54,18 @@ def manage(): except Exception: pass + if "from_login" in request.args: + admin_units = get_admin_units_for_manage() + invitations = get_admin_unit_member_invitations(current_user.email) + + if len(admin_units) == 1 and len(invitations) == 0: + return redirect(url_for("manage_admin_unit", id=admin_units[0].id)) + + if len(admin_units) == 0 and len(invitations) == 1: + return redirect( + url_for("admin_unit_member_invitation", id=invitations[0].id) + ) + return redirect(url_for("manage_admin_units")) @@ -54,9 +73,7 @@ def manage(): @auth_required() def manage_admin_units(): admin_units = get_admin_units_for_manage() - invitations = AdminUnitMemberInvitation.query.filter( - AdminUnitMemberInvitation.email == current_user.email - ).all() + invitations = get_admin_unit_member_invitations(current_user.email) admin_units.sort(key=lambda x: x.name) invitations.sort(key=lambda x: x.adminunit.name) diff --git a/project/views/user.py b/project/views/user.py index 3ab006f..2583362 100644 --- a/project/views/user.py +++ b/project/views/user.py @@ -2,16 +2,15 @@ from flask import render_template from flask_security import auth_required, current_user from project import app -from project.models import AdminUnitMember, AdminUnitMemberInvitation +from project.models import AdminUnitMember +from project.services.admin_unit import get_admin_unit_member_invitations @app.route("/profile") @auth_required() def profile(): admin_unit_members = AdminUnitMember.query.filter_by(user_id=current_user.id).all() - invitations = AdminUnitMemberInvitation.query.filter( - AdminUnitMemberInvitation.email == current_user.email - ).all() + invitations = get_admin_unit_member_invitations(current_user.email) return render_template( "profile.html", admin_unit_members=admin_unit_members, invitations=invitations diff --git a/tests/views/test_admin_unit_member_invitation.py b/tests/views/test_admin_unit_member_invitation.py index b29044c..6d7af1c 100644 --- a/tests/views/test_admin_unit_member_invitation.py +++ b/tests/views/test_admin_unit_member_invitation.py @@ -87,8 +87,7 @@ def test_read_accept(client, app, db, utils, seeder): "accept": "Akzeptieren", }, ) - assert response.status_code == 302 - assert response.headers["Location"] == "http://localhost/manage" + utils.assert_response_redirect(response, "manage_admin_unit", id=admin_unit_id) with app.app_context(): from project.services.admin_unit import ( @@ -128,7 +127,7 @@ def test_read_accept_WrongRole(client, app, db, utils, seeder): "accept": "Akzeptieren", }, ) - utils.assert_response_redirect(response, "manage") + utils.assert_response_redirect(response, "manage_admin_unit", id=admin_unit_id) def test_read_decline(client, app, db, utils, seeder): diff --git a/tests/views/test_manage.py b/tests/views/test_manage.py index 2ffea5b..879ec97 100644 --- a/tests/views/test_manage.py +++ b/tests/views/test_manage.py @@ -24,6 +24,25 @@ def test_index_withInvalidCookie(client, seeder, utils): utils.assert_response_redirect(response, "manage_admin_units") +def test_index_after_login(client, app, db, utils, seeder): + user_id = seeder.create_user() + admin_unit_id = seeder.create_admin_unit(user_id, "Meine Crew") + + email = "new@member.de" + invitation_id = seeder.create_invitation(admin_unit_id, email) + + seeder.create_user(email) + utils.login(email) + + response = utils.get_endpoint("manage_after_login") + utils.assert_response_redirect(response, "manage", from_login=1) + + response = utils.get_endpoint("manage", from_login=1) + utils.assert_response_redirect( + response, "admin_unit_member_invitation", id=invitation_id + ) + + def test_admin_unit(client, seeder, utils): user_id, admin_unit_id = seeder.setup_base()