From 9503e7788a6578e14cd4fb4f66e2fe8e6ea592b6 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Wed, 10 Nov 2021 22:51:12 +0530 Subject: [PATCH 1/4] fix: restore `validate_link` --- frappe/client.py | 17 ++++++++ frappe/public/js/frappe/form/controls/link.js | 42 ++++++++++--------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/frappe/client.py b/frappe/client.py index 0e9be0a7ee..01991e1b51 100644 --- a/frappe/client.py +++ b/frappe/client.py @@ -405,3 +405,20 @@ def is_document_amended(doctype, docname): pass return False + +@frappe.whitelist() +def validate_link(doctype: str, docname): + if not isinstance(doctype, str): + frappe.throw(_("DocType must be a string")) + + if doctype != "DocType" and not ( + frappe.has_permission(doctype, "select") + or frappe.has_permission(doctype, "read") + ): + frappe.throw( + _("You do not have Read or Select Permissions for {}") + .format(frappe.bold(doctype)), + frappe.PermissionError + ) + + return frappe.db.get_value(doctype, docname, cache=True) diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js index e7339372b3..a7a201b414 100644 --- a/frappe/public/js/frappe/form/controls/link.js +++ b/frappe/public/js/frappe/form/controls/link.js @@ -454,38 +454,40 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat validate_link_and_fetch(df, options, docname, value) { if (!value) return; - return new Promise((resolve) => { + return new Promise(async (resolve) => { const fetch_map = this.fetch_map; + const columns_to_fetch = Object.values(fetch_map); // if default and no fetch, no need to validate - if ($.isEmptyObject(fetch_map) && df.__default_value === value) { + if (!columns_to_fetch.length && df.__default_value === value) { return resolve(value); } + const name = await frappe.xcall("frappe.client.validate_link", { + doctype: options, + docname: value + }); + + if (!name) return resolve(""); + if (!docname || !columns_to_fetch.length) return resolve(name); + + console.log(columns_to_fetch); frappe.db.get_value( options, value, - ["name", ...Object.values(fetch_map)], + columns_to_fetch, (response) => { - if (!response.name) { - return resolve(""); + for (const [target_field, source_field] of Object.entries(fetch_map)) { + frappe.model.set_value( + df.parent, + docname, + target_field, + response[source_field], + df.fieldtype, + ); } - - if (docname) { - for (const [target_field, source_field] of Object.entries(fetch_map)) { - frappe.model.set_value( - df.parent, - docname, - target_field, - response[source_field], - df.fieldtype, - ); - } - } - - return resolve(response.name); } - ) + ).always(() => resolve(name)); }); } From af41d9f8a5ffd71cd400ca0e726e304ce825a9e5 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Thu, 11 Nov 2021 12:29:49 +0530 Subject: [PATCH 2/4] fix: stricter validation --- frappe/client.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frappe/client.py b/frappe/client.py index 01991e1b51..bd331168c2 100644 --- a/frappe/client.py +++ b/frappe/client.py @@ -407,10 +407,13 @@ def is_document_amended(doctype, docname): return False @frappe.whitelist() -def validate_link(doctype: str, docname): +def validate_link(doctype: str, docname: str): if not isinstance(doctype, str): frappe.throw(_("DocType must be a string")) + if not isinstance(docname, str): + frappe.throw(_("Document Name must be a string")) + if doctype != "DocType" and not ( frappe.has_permission(doctype, "select") or frappe.has_permission(doctype, "read") @@ -420,5 +423,5 @@ def validate_link(doctype: str, docname): .format(frappe.bold(doctype)), frappe.PermissionError ) - + return frappe.db.get_value(doctype, docname, cache=True) From 1fd53c43068fb636b1cb22150a0c278d5835a2f4 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Thu, 11 Nov 2021 12:30:30 +0530 Subject: [PATCH 3/4] test: intercept `validate_link` instead of `get_value` --- cypress/integration/control_link.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cypress/integration/control_link.js b/cypress/integration/control_link.js index 2a81338c59..898ae1df03 100644 --- a/cypress/integration/control_link.js +++ b/cypress/integration/control_link.js @@ -49,19 +49,19 @@ context('Control Link', () => { it('should unset invalid value', () => { get_dialog_with_link().as('dialog'); - cy.intercept('GET', '/api/method/frappe.client.get_value*').as('get_value'); + cy.intercept('POST', '/api/method/frappe.client.validate_link*').as('validate_link'); cy.get('.frappe-control[data-fieldname=link] input') .type('invalid value', { delay: 100 }) .blur(); - cy.wait('@get_value'); + cy.wait('@validate_link'); cy.get('.frappe-control[data-fieldname=link] input').should('have.value', ''); }); it('should route to form on arrow click', () => { get_dialog_with_link().as('dialog'); - cy.intercept('GET', '/api/method/frappe.client.get_value*').as('get_value'); + cy.intercept('POST', '/api/method/frappe.client.validate_link*').as('validate_link'); cy.intercept('POST', '/api/method/frappe.desk.search.search_link').as('search_link'); cy.get('@todos').then(todos => { @@ -69,7 +69,7 @@ context('Control Link', () => { cy.get('@input').focus(); cy.wait('@search_link'); cy.get('@input').type(todos[0]).blur(); - cy.wait('@get_value'); + cy.wait('@validate_link'); cy.get('@input').focus(); cy.findByTitle('Open Link') .should('be.visible') From cc5c1532995f6e0089475597d0fe92b4eb539840 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Thu, 11 Nov 2021 13:29:38 +0530 Subject: [PATCH 4/4] fix: remove `console.log` --- frappe/public/js/frappe/form/controls/link.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js index a7a201b414..aa3753e67f 100644 --- a/frappe/public/js/frappe/form/controls/link.js +++ b/frappe/public/js/frappe/form/controls/link.js @@ -471,7 +471,6 @@ frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlDat if (!name) return resolve(""); if (!docname || !columns_to_fetch.length) return resolve(name); - console.log(columns_to_fetch); frappe.db.get_value( options, value,