feat: allow wildcard for doctype in permission hooks (#25729)

* feat: allow wildcard for doctype in permission hooks

* fix: pass doctype to permission query

* fix: combine methods instead of alternate

* test: wildcard has_permssion hook

* test: wildcard has_permssion make note public

* fix: fetch list of hooks once
This commit is contained in:
Revant Nandgaonkar 2024-04-10 11:44:37 +05:30 committed by GitHub
parent bef9bdc5ee
commit 7e16e902d9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 21 additions and 3 deletions

View file

@ -1036,10 +1036,11 @@ class DatabaseQuery:
def get_permission_query_conditions(self):
conditions = []
condition_methods = frappe.get_hooks("permission_query_conditions", {}).get(self.doctype, [])
hooks = frappe.get_hooks("permission_query_conditions", {})
condition_methods = hooks.get(self.doctype, []) + hooks.get("*", [])
if condition_methods:
for method in condition_methods:
c = frappe.call(frappe.get_attr(method), self.user)
c = frappe.call(frappe.get_attr(method), self.user, doctype=self.doctype)
if c:
conditions.append(c)

View file

@ -438,7 +438,8 @@ def has_controller_permissions(doc, ptype, user=None, debug=False) -> bool:
if not user:
user = frappe.session.user
methods = frappe.get_hooks("has_permission").get(doc.doctype, [])
hooks = frappe.get_hooks("has_permission")
methods = hooks.get(doc.doctype, []) + hooks.get("*", [])
if not methods:
return True

View file

@ -44,6 +44,14 @@ class TestHooks(FrappeTestCase):
hooks.has_permission["Address"] = address_has_permission_hook
wildcard_has_permission_hook = hooks.has_permission.get("*", [])
if isinstance(wildcard_has_permission_hook, str):
wildcard_has_permission_hook = [wildcard_has_permission_hook]
wildcard_has_permission_hook.append("frappe.tests.test_hooks.custom_has_permission")
hooks.has_permission["*"] = wildcard_has_permission_hook
# Clear cache
frappe.cache.delete_value("app_hooks")
@ -53,12 +61,20 @@ class TestHooks(FrappeTestCase):
user.add_roles("System Manager")
address = frappe.new_doc("Address")
# Create Note
note = frappe.new_doc("Note")
note.public = 1
# Test!
self.assertTrue(frappe.has_permission("Address", doc=address, user=username))
self.assertTrue(frappe.has_permission("Note", doc=note, user=username))
address.flags.dont_touch_me = True
self.assertFalse(frappe.has_permission("Address", doc=address, user=username))
note.flags.dont_touch_me = True
self.assertFalse(frappe.has_permission("Note", doc=note, user=username))
def test_ignore_links_on_delete(self):
email_unsubscribe = frappe.get_doc(
{"doctype": "Email Unsubscribe", "email": "test@example.com", "global_unsubscribe": 1}