diff --git a/frappe/permissions.py b/frappe/permissions.py index d719bfe6dded..3485883b89c9 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -234,10 +234,6 @@ def get_doc_permissions(doc, user=None, ptype=None, debug=False): def is_user_owner(): return (doc.get("owner") or "").lower() == user.lower() - if not has_controller_permissions(doc, ptype, user=user, debug=debug): - push_perm_check_log(_("Not allowed via controller permission check"), debug=debug) - return {ptype: 0} - permissions = copy.deepcopy(get_role_permissions(meta, user=user, is_owner=is_user_owner(), debug=debug)) debug and _debug_log( @@ -272,6 +268,10 @@ def is_user_owner(): debug and _debug_log("User has no permissions because of User Permissions") permissions = {} + if not has_controller_permissions(doc, ptype, permissions, user=user, debug=debug): + push_perm_check_log(_("Not allowed via controller permission check"), debug=debug) + return {ptype: 0} + debug and _debug_log( "Final applicable permissions after evaluating user permissions: " + frappe.as_json(permissions, indent=8) @@ -478,7 +478,7 @@ def check_user_permission_on_link_fields(d): return True -def has_controller_permissions(doc, ptype, user=None, debug=False) -> bool: +def has_controller_permissions(doc, ptype, permissions, user=None, debug=False) -> bool: """Return controller permissions if denied, True if not defined. Controllers can only deny permission, they can not explicitly grant any permission that wasn't @@ -488,9 +488,16 @@ def has_controller_permissions(doc, ptype, user=None, debug=False) -> bool: hooks = frappe.get_hooks("has_permission") methods = hooks.get(doc.doctype, []) + hooks.get("*", []) + org_permissions = copy.deepcopy(permissions) for method in reversed(methods): - controller_permission = frappe.call(method, doc=doc, ptype=ptype, user=user, debug=debug) + controller_permission = frappe.call( + method, doc=doc, ptype=ptype, permissions=permissions, user=user, debug=debug + ) + if permissions != org_permissions: + for key, value in permissions.items(): + if org_permissions.get(key) == 0 and value == 1: + permissions[key] = 0 debug and _debug_log(f"Controller permission check from {method}: {controller_permission}") if not controller_permission: return bool(controller_permission) diff --git a/frappe/public/js/frappe/form/toolbar.js b/frappe/public/js/frappe/form/toolbar.js index 0d8c80ae5a4f..5cd70656c681 100644 --- a/frappe/public/js/frappe/form/toolbar.js +++ b/frappe/public/js/frappe/form/toolbar.js @@ -494,7 +494,8 @@ frappe.ui.form.Toolbar = class Toolbar { cint(this.frm.doc.docstatus) != 1 && !this.frm.doc.__islocal && !frappe.model.is_single(this.frm.doctype) && - frappe.model.can_delete(this.frm.doctype) + frappe.model.can_delete(this.frm.doctype) && + this.frm.perm[0].delete ) { this.page.add_menu_item( __("Delete"),