Merge pull request #29888 from akhilnarang/bench-browse-updates
feat: fixed session duration + better visibility of changes done via `bench browse`
This commit is contained in:
commit
baf884d31f
5 changed files with 63 additions and 15 deletions
|
|
@ -163,12 +163,12 @@ class LoginManager:
|
|||
frappe.form_dict.pop("pwd", None)
|
||||
self.post_login()
|
||||
|
||||
def post_login(self):
|
||||
def post_login(self, session_end: str | None = None, audit_user: str | None = None):
|
||||
self.run_trigger("on_login")
|
||||
validate_ip_address(self.user)
|
||||
self.validate_hour()
|
||||
self.get_user_info()
|
||||
self.make_session()
|
||||
self.make_session(session_end=session_end, audit_user=audit_user)
|
||||
self.setup_boot_cache()
|
||||
self.set_user_info()
|
||||
|
||||
|
|
@ -216,10 +216,17 @@ class LoginManager:
|
|||
def clear_preferred_language(self):
|
||||
frappe.local.cookie_manager.delete_cookie("preferred_language")
|
||||
|
||||
def make_session(self, resume=False):
|
||||
def make_session(
|
||||
self, resume: bool = False, session_end: str | None = None, audit_user: str | None = None
|
||||
):
|
||||
# start session
|
||||
frappe.local.session_obj = Session(
|
||||
user=self.user, resume=resume, full_name=self.full_name, user_type=self.user_type
|
||||
user=self.user,
|
||||
resume=resume,
|
||||
full_name=self.full_name,
|
||||
user_type=self.user_type,
|
||||
session_end=session_end,
|
||||
audit_user=audit_user,
|
||||
)
|
||||
|
||||
# reset user if changed to Guest
|
||||
|
|
@ -339,15 +346,16 @@ class LoginManager:
|
|||
"""login as guest"""
|
||||
self.login_as("Guest")
|
||||
|
||||
def login_as(self, user):
|
||||
def login_as(self, user: str, session_end: str | None = None, audit_user: str | None = None):
|
||||
self.user = user
|
||||
self.post_login()
|
||||
self.post_login(session_end, audit_user)
|
||||
|
||||
def impersonate(self, user):
|
||||
current_user = frappe.session.user
|
||||
self.login_as(user)
|
||||
session_data = frappe.local.session_obj.data.data
|
||||
self.login_as(user, session_end=session_data.session_end, audit_user=session_data.audit_user)
|
||||
# Flag this session as impersonated session, so other code can log this.
|
||||
frappe.local.session_obj.set_impersonsated(current_user)
|
||||
frappe.local.session_obj.set_impersonated(current_user)
|
||||
|
||||
def logout(self, arg="", user=None):
|
||||
if not user:
|
||||
|
|
|
|||
|
|
@ -1175,8 +1175,20 @@ def publish_realtime(context: CliCtxObj, event, message, room, user, doctype, do
|
|||
@click.command("browse")
|
||||
@click.argument("site", required=False)
|
||||
@click.option("--user", required=False, help="Login as user")
|
||||
@click.option(
|
||||
"--session-end",
|
||||
required=False,
|
||||
help="Session end (in ISO8601 format and timezone-aware - 2025-01-24T12:26:29.200853+00:00)",
|
||||
)
|
||||
@click.option("--user-for-audit", required=False, help="The user to mention in audit trail")
|
||||
@pass_context
|
||||
def browse(context: CliCtxObj, site, user=None):
|
||||
def browse(
|
||||
context: CliCtxObj,
|
||||
site,
|
||||
user: str | None = None,
|
||||
session_end: str | None = None,
|
||||
user_for_audit: str | None = None,
|
||||
):
|
||||
"""Opens the site on web browser"""
|
||||
from frappe.auth import CookieManager, LoginManager
|
||||
|
||||
|
|
@ -1202,7 +1214,7 @@ def browse(context: CliCtxObj, site, user=None):
|
|||
frappe.utils.set_request(path="/")
|
||||
frappe.local.cookie_manager = CookieManager()
|
||||
frappe.local.login_manager = LoginManager()
|
||||
frappe.local.login_manager.login_as(user)
|
||||
frappe.local.login_manager.login_as(user, session_end, user_for_audit)
|
||||
sid = f"/app?sid={frappe.session.sid}"
|
||||
else:
|
||||
click.echo("Please enable developer mode to login as a user")
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ class Version(Document):
|
|||
if impersonator := frappe.session.data.get("impersonated_by"):
|
||||
data["impersonated_by"] = impersonator
|
||||
|
||||
if audit_user := frappe.session.data.get("audit_user"):
|
||||
data["audit_user"] = audit_user
|
||||
|
||||
def set_diff(self, old: Document, new: Document) -> bool:
|
||||
"""Set the data property with the diff of the docs if present"""
|
||||
diff = get_diff(old, new)
|
||||
|
|
|
|||
|
|
@ -246,6 +246,12 @@ function get_version_timeline_content(version_doc, frm) {
|
|||
const impersonated_msg = __("Impersonated by {0}", [get_user_link(impersonated_by)]);
|
||||
out = out.map((message) => `${message} · ${impersonated_msg.bold()}`);
|
||||
}
|
||||
|
||||
const audit_user = data.audit_user;
|
||||
if (audit_user) {
|
||||
const audit_msg = __("[Action taken by {0}]", [audit_user]);
|
||||
out = out.map((message) => `${message} · ${audit_msg.bold()}`);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ permission, homepage, default variables, system defaults etc
|
|||
"""
|
||||
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
from urllib.parse import unquote
|
||||
|
||||
import redis
|
||||
|
|
@ -205,7 +206,15 @@ def generate_csrf_token():
|
|||
class Session:
|
||||
__slots__ = ("_update_in_cache", "data", "full_name", "sid", "time_diff", "user", "user_type")
|
||||
|
||||
def __init__(self, user, resume=False, full_name=None, user_type=None):
|
||||
def __init__(
|
||||
self,
|
||||
user: str,
|
||||
resume: bool = False,
|
||||
full_name: str | None = None,
|
||||
user_type: str | None = None,
|
||||
session_end: str | None = None,
|
||||
audit_user: str | None = None,
|
||||
):
|
||||
self.sid = cstr(
|
||||
frappe.form_dict.pop("sid", None) or unquote(frappe.request.cookies.get("sid", "Guest"))
|
||||
)
|
||||
|
|
@ -225,7 +234,7 @@ class Session:
|
|||
else:
|
||||
if self.user:
|
||||
self.validate_user()
|
||||
self.start()
|
||||
self.start(session_end, audit_user)
|
||||
|
||||
def validate_user(self):
|
||||
if not frappe.get_cached_value("User", self.user, "enabled"):
|
||||
|
|
@ -234,7 +243,7 @@ class Session:
|
|||
frappe.ValidationError,
|
||||
)
|
||||
|
||||
def start(self):
|
||||
def start(self, session_end: str | None = None, audit_user: str | None = None):
|
||||
"""start a new session"""
|
||||
# generate sid
|
||||
if self.user == "Guest":
|
||||
|
|
@ -246,6 +255,13 @@ class Session:
|
|||
self.sid = self.data.sid = sid
|
||||
self.data.data.user = self.user
|
||||
self.data.data.session_ip = frappe.local.request_ip
|
||||
|
||||
if session_end:
|
||||
self.data.data.session_end = session_end
|
||||
|
||||
if audit_user:
|
||||
self.data.data.audit_user = audit_user
|
||||
|
||||
if self.user != "Guest":
|
||||
self.data.data.update(
|
||||
{
|
||||
|
|
@ -347,7 +363,10 @@ class Session:
|
|||
)
|
||||
expiry = get_expiry_in_seconds(session_data.get("session_expiry"))
|
||||
|
||||
if self.time_diff > expiry:
|
||||
if self.time_diff > expiry or (
|
||||
(session_end := session_data.get("session_end"))
|
||||
and datetime.now(tz=timezone.utc) > datetime.fromisoformat(session_end)
|
||||
):
|
||||
self._delete_session()
|
||||
data = None
|
||||
|
||||
|
|
@ -420,7 +439,7 @@ class Session:
|
|||
|
||||
return updated_in_db
|
||||
|
||||
def set_impersonsated(self, original_user):
|
||||
def set_impersonated(self, original_user):
|
||||
self.data.data.impersonated_by = original_user
|
||||
# Forcefully flush session
|
||||
self.update(force=True)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue