From e7b4bd5666742ce91e63382d90434cb57cf0691c Mon Sep 17 00:00:00 2001 From: Ejaaz Khan <67804911+iamejaaz@users.noreply.github.com> Date: Thu, 12 Mar 2026 02:24:03 +0530 Subject: [PATCH] fix: ignore fieldname validating `ignore_user_permissions` for Link fields (#37942) * fix: validate ignore_user_permissions for alternative Link fields * fix: handle alternative Link fields with ignore_user_permissions * fix: move early exit earlier to avoid edge cases * test: validate case of bulk edit --------- Co-authored-by: Sagar Vora --- frappe/desk/search.py | 18 ++++++++++++++---- frappe/tests/test_search.py | 31 ++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/frappe/desk/search.py b/frappe/desk/search.py index 7b5c65dca4..18c8754b13 100644 --- a/frappe/desk/search.py +++ b/frappe/desk/search.py @@ -256,8 +256,16 @@ def validate_ignore_user_permissions(form_doctype, link_fieldname, link_doctype) frappe.throw(message, title=_('Error validating "Ignore User Permissions"')) meta = frappe.get_meta(form_doctype) - link_field = meta.get_field(link_fieldname) + # special early exit - link_fieldname is not being considered here + # to avoid cases like bulk edit which have link_fieldname as "value" from failing + if any( + (field.fieldtype == "Link" and field.options == link_doctype and field.ignore_user_permissions) + for field in meta.fields + ): + return + + link_field = meta.get_field(link_fieldname) if not link_field: _throw( _("Field {0} not found in {1}").format( @@ -268,9 +276,6 @@ def validate_ignore_user_permissions(form_doctype, link_fieldname, link_doctype) ignore_user_permissions = link_field.ignore_user_permissions found_doctype = None - if link_field.fieldtype == "Link": - found_doctype = link_field.options - if link_field.fieldtype == "Table MultiSelect": child_meta = frappe.get_meta(link_field.options) child_link_field = next((field for field in child_meta.fields if field.fieldtype == "Link"), None) @@ -297,6 +302,11 @@ def validate_ignore_user_permissions(form_doctype, link_fieldname, link_doctype) if link_field.fieldtype == "Dynamic Link": return # skip doctype check for Dynamic Link fields + # all cases of valid Link fields are already covered in the early exit above + # the following block only serves to show appropriate error message + if link_field.fieldtype == "Link": + found_doctype = link_field.options + if found_doctype != link_doctype: _throw( _("The field {0} in {1} links to {2} and not {3}").format( diff --git a/frappe/tests/test_search.py b/frappe/tests/test_search.py index 502e24cd2d..93967f71e6 100644 --- a/frappe/tests/test_search.py +++ b/frappe/tests/test_search.py @@ -290,7 +290,12 @@ class TestSearch(IntegrationTestCase): """Test that ignore_user_permissions is validated correctly""" # Clean up any leftover doctypes from previous test runs - for dt in ("Test Search Form No Ignore", "Test Search Form Wrong Link", "Test Search Linked2"): + for dt in ( + "Test Search Form No Ignore", + "Test Search Form Wrong Link", + "Test Search Form With Ignore", + "Test Search Linked2", + ): if frappe.db.exists("DocType", dt): frappe.delete_doc("DocType", dt, force=True) @@ -375,6 +380,30 @@ class TestSearch(IntegrationTestCase): link_fieldname="wrong_link", ) + # Should NOT throw when link_fieldname is bogus (e.g. bulk edit sends "value") + # but a Link field with ignore_user_permissions exists on the form doctype + new_doctype( + name="Test Search Form With Ignore", + fields=[ + { + "label": "Linked Doc", + "fieldname": "linked_doc", + "fieldtype": "Link", + "options": "Test Search Linked2", + "ignore_user_permissions": 1, + } + ], + ).insert() + self.addCleanup(lambda: frappe.delete_doc("DocType", "Test Search Form With Ignore", force=True)) + + search_link( + doctype="Test Search Linked2", + txt="test", + ignore_user_permissions=True, + reference_doctype="Test Search Form With Ignore", + link_fieldname="value", + ) + @frappe.validate_and_sanitize_search_inputs def get_data(doctype, txt, searchfield, start, page_len, filters):