From fe9fbf82d09dbda323389ac37c3eec6a73b48549 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 27 Feb 2024 23:38:49 +0530 Subject: [PATCH] fix: validate fetch from (#25116) --- frappe/core/doctype/doctype/doctype.py | 43 +++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index bec8e62316..07475bfadd 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -355,6 +355,8 @@ class DocType(Document): for df in new_fields_to_fetch: if df.fieldname not in old_fields_to_fetch: link_fieldname, source_fieldname = df.fetch_from.split(".", 1) + if not source_fieldname: + continue # Invalid expression link_df = new_meta.get_field(link_fieldname) if frappe.db.db_type == "postgres": @@ -1187,7 +1189,7 @@ def validate_fields_for_doctype(doctype): # this is separate because it is also called via custom field -def validate_fields(meta): +def validate_fields(meta: Meta): """Validate doctype fields. Checks 1. There are no illegal characters in fieldnames 2. If fieldnames are unique. @@ -1594,6 +1596,44 @@ def validate_fields(meta): if docfield.options and (int(docfield.options) > 10 or int(docfield.options) < 3): frappe.throw(_("Options for Rating field can range from 3 to 10")) + def check_fetch_from(docfield): + fetch_from = docfield.fetch_from + fieldname = docfield.fieldname + if not fetch_from: + return + + if "." not in fetch_from: + frappe.throw( + _("Fetch From syntax for field {0} is invalid. `.` dot missing: {1}").format( + frappe.bold(fieldname), frappe.bold(fetch_from) + ) + ) + link_fieldname, source_fieldname = docfield.fetch_from.split(".", 1) + if not link_fieldname or not source_fieldname: + frappe.throw( + _( + "Fetch From syntax for field {0} is invalid: {1}. Fetch From should be in form of 'link_fieldname.source_fieldname'" + ).format(frappe.bold(fieldname), frappe.bold(fetch_from)) + ) + + link_df = meta.get("fields", {"fieldname": link_fieldname, "fieldtype": "Link"}) + if not link_df: + frappe.throw( + _("Fetch From for field {0} is invalid: {1}. Link field {2} not found.").format( + frappe.bold(fieldname), frappe.bold(fetch_from), frappe.bold(link_fieldname) + ) + ) + + doctype = link_df[0].options + fetch_from_doctype = frappe.get_meta(doctype) + + if not fetch_from_doctype.get_field(source_fieldname): + frappe.throw( + _("Fetch From for field {0} is invalid: {1} does not have a field {2}").format( + frappe.bold(fieldname), frappe.bold(doctype), frappe.bold(source_fieldname) + ) + ) + fields = meta.get("fields") fieldname_list = [d.fieldname for d in fields] @@ -1629,6 +1669,7 @@ def validate_fields(meta): check_child_table_option(d) check_max_height(d) check_no_of_ratings(d) + check_fetch_from(d) if not frappe.flags.in_migrate: check_fold(fields)