Skip to content

Commit

Permalink
refactor: store user profile in g.user
Browse files Browse the repository at this point in the history
  • Loading branch information
azmeuk committed Aug 13, 2023
1 parent 1f9d148 commit c895366
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 8 deletions.
7 changes: 6 additions & 1 deletion canaille/app/flask.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from canaille.app import models
from flask import abort
from flask import current_app
from flask import g
from flask import render_template
from flask import request
from flask import session
Expand All @@ -14,12 +15,16 @@


def current_user():
if "user" in g:
return g.user

for user_id in session.get("user_id", [])[::-1]:
user = models.User.get(id=user_id)
if user and (
not current_app.backend.has_account_lockability() or not user.locked
):
return user
g.user = user
return g.user

session["user_id"].remove(user_id)

Expand Down
3 changes: 3 additions & 0 deletions canaille/backends/ldap/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ def save(self, *args, **kwargs):

def load_permissions(self):
conn = Backend.get().connection
self.permissions = set()
self.read = set()
self.write = set()

for access_group_name, details in current_app.config["ACL"].items():
filter_ = self.acl_filter_to_ldap_filter(details.get("FILTER"))
Expand Down
14 changes: 11 additions & 3 deletions canaille/core/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from flask import Blueprint
from flask import current_app
from flask import flash
from flask import g
from flask import redirect
from flask import request
from flask import send_file
Expand Down Expand Up @@ -494,6 +495,8 @@ def profile_create(current_app, form):
user.set_password(form["password1"].data)
user.save()

user.load_permissions()

flash(_("User account creation succeed."), "success")

return user
Expand Down Expand Up @@ -568,6 +571,7 @@ def profile_edition_main_form_validation(user, edited_user, profile_form):
edited_user.preferred_language = None

edited_user.save()
g.user.reload()


def profile_edition_emails_form(user, edited_user, has_smtp):
Expand Down Expand Up @@ -611,10 +615,12 @@ def profile_edition_remove_email(user, edited_user, email):
@bp.route("/profile/<user:edited_user>", methods=("GET", "POST"))
@user_needed()
def profile_edition(user, edited_user):
if not user.can_manage_users and not (user.can_edit_self and edited_user == user):
if not user.can_manage_users and not (
user.can_edit_self and edited_user.id == user.id
):
abort(404)

menuitem = "profile" if edited_user == user else "users"
menuitem = "profile" if edited_user.id == user.id else "users"
has_smtp = "SMTP" in current_app.config
has_email_confirmation = current_app.config.get("EMAIL_CONFIRMATION") is True or (
current_app.config.get("EMAIL_CONFIRMATION") is None and has_smtp
Expand Down Expand Up @@ -681,7 +687,9 @@ def profile_edition(user, edited_user):
@bp.route("/profile/<user:edited_user>/settings", methods=("GET", "POST"))
@user_needed()
def profile_settings(user, edited_user):
if not user.can_manage_users and not (user.can_edit_self and edited_user == user):
if not user.can_manage_users and not (
user.can_edit_self and edited_user.id == user.id
):
abort(404)

if (
Expand Down
3 changes: 3 additions & 0 deletions canaille/core/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import datetime

from flask import g
from flask import session


Expand All @@ -15,6 +16,7 @@ def get_from_login(cls, login=None, **kwargs):
raise NotImplementedError()

def login(self):
g.user = self
try:
previous = (
session["user_id"]
Expand All @@ -29,6 +31,7 @@ def login(self):
def logout(self):
try:
session["user_id"].pop()
del g.user
if not session["user_id"]:
del session["user_id"]
except (IndexError, KeyError):
Expand Down
3 changes: 3 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ def user(app, backend):
formatted_address="1235, somewhere",
)
u.save()
u.load_permissions()
yield u
u.delete()

Expand All @@ -164,6 +165,7 @@ def admin(app, backend):
password="admin",
)
u.save()
u.load_permissions()
yield u
u.delete()

Expand All @@ -178,6 +180,7 @@ def moderator(app, backend):
password="moderator",
)
u.save()
u.load_permissions()
yield u
u.delete()

Expand Down
8 changes: 4 additions & 4 deletions tests/core/test_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@
from unittest import mock

from canaille.app import models
from flask import g


def test_index(testclient, user):
res = testclient.get("/", status=302)
assert res.location == "/login"

with testclient.session_transaction() as sess:
sess["user_id"] = [user.id]
g.user = user
res = testclient.get("/", status=302)
assert res.location == "/profile/user"

testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = ["use_oidc"]
g.user.reload()
res = testclient.get("/", status=302)
assert res.location == "/consent/"

testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = []
g.user.reload()
res = testclient.get("/", status=302)
assert res.location == "/about"

Expand Down Expand Up @@ -243,7 +245,6 @@ def test_user_deleted_in_session(testclient, backend):
with testclient.session_transaction() as session:
session["user_id"] = [u.id]

testclient.get("/profile/jake", status=200)
u.delete()

testclient.get("/profile/jake", status=404)
Expand Down Expand Up @@ -425,7 +426,6 @@ def test_signin_locked_account(testclient, user):


def test_account_locked_during_session(testclient, logged_user):
testclient.get("/profile/user/settings", status=200)
logged_user.lock_date = datetime.datetime.now(datetime.timezone.utc)
logged_user.save()
testclient.get("/profile/user/settings", status=403)
5 changes: 5 additions & 0 deletions tests/core/test_invitation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from canaille.app import models
from canaille.core.account import Invitation
from flask import g


def test_invitation(testclient, logged_admin, foo_group, smtpd):
Expand All @@ -19,9 +20,11 @@ def test_invitation(testclient, logged_admin, foo_group, smtpd):
url = res.pyquery(".copy-text")[0].value

# logout
g.user = None
with testclient.session_transaction() as sess:
del sess["user_id"]

testclient.get("/logout")
res = testclient.get(url, status=200)

assert res.form["user_name"].value == "someone"
Expand Down Expand Up @@ -68,6 +71,7 @@ def test_invitation_editable_user_name(testclient, logged_admin, foo_group, smtp
url = res.pyquery(".copy-text")[0].value

# logout
g.user = None
with testclient.session_transaction() as sess:
del sess["user_id"]

Expand Down Expand Up @@ -114,6 +118,7 @@ def test_generate_link(testclient, logged_admin, foo_group, smtpd):
url = res.pyquery(".copy-text")[0].value

# logout
g.user = None
with testclient.session_transaction() as sess:
del sess["user_id"]

Expand Down
6 changes: 6 additions & 0 deletions tests/core/test_profile_edition.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
from canaille.core.populate import fake_users
from flask import g
from webtest import Upload


Expand Down Expand Up @@ -86,6 +87,7 @@ def test_user_list_search_only_allowed_fields(
res.mustcontain(no=moderator.formatted_name[0])

testclient.app.config["ACL"]["DEFAULT"]["READ"].remove("user_name")
g.user.reload()

form = res.forms["search"]
form["query"] = "user"
Expand All @@ -105,6 +107,7 @@ def test_edition_permission(
testclient.get("/profile/user", status=404)

testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = ["edit_self"]
g.user.reload()
testclient.get("/profile/user", status=200)


Expand Down Expand Up @@ -204,6 +207,7 @@ def test_field_permissions_none(testclient, logged_user):
"PERMISSIONS": ["edit_self"],
}

g.user.reload()
res = testclient.get("/profile/user", status=200)
form = res.forms["baseform"]
assert "phone_numbers-0" not in form.fields
Expand All @@ -230,6 +234,7 @@ def test_field_permissions_read(testclient, logged_user):
"WRITE": [],
"PERMISSIONS": ["edit_self"],
}
g.user.reload()
res = testclient.get("/profile/user", status=200)
form = res.forms["baseform"]
assert "phone_numbers-0" in form.fields
Expand All @@ -256,6 +261,7 @@ def test_field_permissions_write(testclient, logged_user):
"WRITE": ["phone_numbers"],
"PERMISSIONS": ["edit_self"],
}
g.user.reload()
res = testclient.get("/profile/user", status=200)
form = res.forms["baseform"]
assert "phone_numbers-0" in form.fields
Expand Down
2 changes: 2 additions & 0 deletions tests/core/test_profile_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from unittest import mock

from canaille.app import models
from flask import g


def test_edition(
Expand Down Expand Up @@ -300,6 +301,7 @@ def test_edition_permission(
testclient.get("/profile/user/settings", status=404)

testclient.app.config["ACL"]["DEFAULT"]["PERMISSIONS"] = ["edit_self"]
g.user.reload()
testclient.get("/profile/user/settings", status=200)


Expand Down
2 changes: 2 additions & 0 deletions tests/oidc/test_authorization_code_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from authlib.oauth2.rfc7636 import create_s256_code_challenge
from canaille.app import models
from canaille.oidc.oauth import setup_oauth
from flask import g
from werkzeug.security import gen_salt

from . import client_credentials
Expand Down Expand Up @@ -234,6 +235,7 @@ def test_logout_login(testclient, logged_user, client):
)

res = res.form.submit(name="answer", value="logout", status=302)
g.user = None
res = res.follow(status=200)

res.form["login"] = logged_user.user_name[0]
Expand Down

0 comments on commit c895366

Please sign in to comment.