From 24499d93f8e87240d2e3feebceaa661e90b4da58 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 24 Feb 2024 17:29:14 +0530 Subject: [PATCH] fix: notify user that they were impersonated --- frappe/core/doctype/user/user.js | 24 ++++++++++++++++-------- frappe/core/doctype/user/user.py | 16 ++++++++++++++-- frappe/sessions.py | 3 --- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/frappe/core/doctype/user/user.js b/frappe/core/doctype/user/user.js index b84128a11e..dc40fb0336 100644 --- a/frappe/core/doctype/user/user.js +++ b/frappe/core/doctype/user/user.js @@ -343,7 +343,7 @@ frappe.ui.form.on("User", { }, setup_impersonation: function (frm) { if (frappe.session.user === "Administrator" && frm.doc.name != "Administrator") { - frm.add_custom_button("Login as User", () => { + frm.add_custom_button(__("Impersonate"), () => { if (frm.doc.restrict_ip) { frappe.msgprint({ message: @@ -352,18 +352,26 @@ frappe.ui.form.on("User", { }); return; } - frappe.confirm( - __( - "Current session will be logged out and you will login as {0}. Are you sure?", - [frm.doc.name.bold()] - ), - () => { + frappe.prompt( + [ + { + fieldname: "reason", + fieldtype: "Small Text", + label: "Reason for impersonating", + description: __("Note: This will be shared with user."), + reqd: 1, + }, + ], + (values) => { frappe .xcall("frappe.core.doctype.user.user.impersonate", { user: frm.doc.name, + reason: values.reason, }) .then(() => window.location.reload()); - } + }, + __("Impersonate as {0}", [frm.doc.name]), + __("Confirm") ); }); } diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index beaa3f80af..f44224e9b5 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -1346,16 +1346,28 @@ def get_enabled_users(): @frappe.whitelist(methods=["POST"]) -def impersonate(user: str): +def impersonate(user: str, reason: str): + # Note: For now we only allow admins, we MIGHT allow system manager in future. + # All the impersonation code doesn't assume anything about user. frappe.only_for("Administrator") + impersonator = frappe.session.user frappe.get_doc( { "doctype": "Activity Log", "user": user, "status": "Success", - "subject": _("User {0} impersonated as {1}").format(frappe.session.user, user), + "subject": _("User {0} impersonated as {1}").format(impersonator, user), "operation": "Impersonate", } ).insert(ignore_permissions=True, ignore_links=True) + + notification = frappe.new_doc( + "Notification Log", + for_user=user, + from_user=frappe.session.user, + subject=_("{0} just impersonated as you. They gave this reason: {1}").format(impersonator, reason), + ) + notification.set("type", "Alert") + notification.insert(ignore_permissions=True) frappe.local.login_manager.impersonate(user) diff --git a/frappe/sessions.py b/frappe/sessions.py index 40db0e69ce..35790d2cbf 100644 --- a/frappe/sessions.py +++ b/frappe/sessions.py @@ -391,9 +391,6 @@ class Session: # Forcefully flush session self.update(force=True) - def impersonated_by(self) -> str | None: - return self.data.data.impersonated_by - def get_expiry_period_for_query(): if frappe.db.db_type == "postgres":