From 6bac132a32edfad785bf8048a34b818176551333 Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 15 Apr 2026 11:20:54 +0200 Subject: [PATCH] modified: web/app.py --- web/app.py | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/web/app.py b/web/app.py index b8d6fab..b4ce931 100644 --- a/web/app.py +++ b/web/app.py @@ -8,7 +8,7 @@ from datetime import datetime from flask import Flask, abort, render_template, request, session, url_for from werkzeug.middleware.proxy_fix import ProxyFix from config import Config -from panel_db import init_databases, get_user_groups +from panel_db import init_databases, get_user_groups, get_group_member from roles import can_manage_group from limiter import limiter @@ -80,6 +80,39 @@ def create_app() -> Flask: if not session_token or not request_token or session_token != request_token: abort(400) + @app.before_request + def refresh_session_role(): + """Keeps session role/permissions in sync with the DB. + Runs on every request so role changes by an admin take effect + immediately without requiring the affected user to re-login.""" + user_id = session.get("user_id") + group_id = session.get("group_id") + # Only for regular panel users (not site-admin-only sessions, + # not admin-viewing-group sessions, not unauthenticated requests). + if not user_id or session.get("is_site_admin") or session.get("admin_viewing"): + return + if not group_id: + return + try: + member = get_group_member(user_id, group_id) + if not member: + # User was removed from the group — clear their group context + session.pop("group_id", None) + session.pop("group_name", None) + session.pop("role", None) + session.pop("permissions", None) + return + import json as _json + raw = member.get("permissions") + perms = ( + raw if isinstance(raw, dict) + else (_json.loads(raw) if isinstance(raw, str) else {}) + ) + session["role"] = member["role"] + session["permissions"] = perms + except Exception: + pass # DB unavailable — keep existing session as-is + @app.after_request def set_security_headers(resp): resp.headers.setdefault("X-Content-Type-Options", "nosniff")