From d6bdd636dcc358a308ec72acade69af2875915b6 Mon Sep 17 00:00:00 2001 From: marination Date: Fri, 25 Nov 2022 12:09:36 +0530 Subject: [PATCH] fix: Check Reference Doctype perms & control indicator change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Don’t change indicator on filter change if user can’t write to board. They can’t save filters - Invoke `update_order` on Kanban board init() only if user has `write` access to reference doctype (non-deliberate invocation) - All deliberate invocations of `update_order` via UI actions are blocked/hidden without `write` access - Remove elements with no access instead of hiding to avoid inspect element hacks - Card Actions: Block card dragging if no `write` access to reference doctype - Card Actions: Block card adding if no `create` access to reference doctype --- frappe/client.py | 2 ++ .../views/kanban/kanban_board.bundle.js | 22 ++++++++++++++++--- .../js/frappe/views/kanban/kanban_view.js | 2 ++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/frappe/client.py b/frappe/client.py index afbb0df5ee..4dc118ea06 100644 --- a/frappe/client.py +++ b/frappe/client.py @@ -302,6 +302,7 @@ def has_permission(doctype, docname, perm_type="read"): # perm_type can be one of read, write, create, submit, cancel, report return {"has_permission": frappe.has_permission(doctype, perm_type.lower(), docname)} + @frappe.whitelist() def get_doc_permissions(doctype, docname): """Returns an evaluated document permissions dict like `{"read":1, "write":1}` @@ -312,6 +313,7 @@ def get_doc_permissions(doctype, docname): doc = frappe.get_doc(doctype, docname) return {"permissions": frappe.permissions.get_doc_permissions(doc)} + @frappe.whitelist() def get_password(doctype, name, fieldname): """Return a password type property. Only applicable for System Managers diff --git a/frappe/public/js/frappe/views/kanban/kanban_board.bundle.js b/frappe/public/js/frappe/views/kanban/kanban_board.bundle.js index f8782e9f21..651b94f28f 100644 --- a/frappe/public/js/frappe/views/kanban/kanban_board.bundle.js +++ b/frappe/public/js/frappe/views/kanban/kanban_board.bundle.js @@ -326,7 +326,12 @@ frappe.provide("frappe.views"); store.watch((state, getters) => { return state.empty_state; }, show_empty_state); - store.dispatch("update_order"); + + if (frappe.model.can_write(store.state.doctype)) { + // Check for reference doctype access before initiating + // non-deliberate action + store.dispatch("update_order"); + } } function prepare() { @@ -377,7 +382,7 @@ frappe.provide("frappe.views"); function bind_add_column() { if (!self.board_perms.write) { // If no write access, editing board (by adding column) should be blocked - self.$kanban_board.find(".add-new-column").hide(); + self.$kanban_board.find(".add-new-column").remove(); return; } @@ -576,6 +581,9 @@ frappe.provide("frappe.views"); } function setup_sortable() { + // Block card dragging/record editing without 'write' access + if (!frappe.model.can_write(store.state.doctype)) return; + Sortable.create(self.$kanban_cards.get(0), { group: "cards", animation: 150, @@ -609,6 +617,14 @@ frappe.provide("frappe.views"); var $wrapper = self.$kanban_column; var $btn_add = $wrapper.find(".add-card"); var $new_card_area = $wrapper.find(".new-card-area"); + + if (!frappe.model.can_create(store.state.doctype)) { + // Block record/card creation without 'create' access + $btn_add.remove(); + $new_card_area.remove(); + return; + } + var $textarea = $new_card_area.find("textarea"); //Add card button @@ -652,7 +668,7 @@ frappe.provide("frappe.views"); function bind_options() { if (!board_perms.write) { // If no write access, column options should be hidden - self.$kanban_column.find(".column-options").hide(); + self.$kanban_column.find(".column-options").remove(); return; } diff --git a/frappe/public/js/frappe/views/kanban/kanban_view.js b/frappe/public/js/frappe/views/kanban/kanban_view.js index 693326b062..f0b0cb8adf 100644 --- a/frappe/public/js/frappe/views/kanban/kanban_view.js +++ b/frappe/public/js/frappe/views/kanban/kanban_view.js @@ -151,6 +151,8 @@ frappe.views.KanbanView = class KanbanView extends frappe.views.ListView { render_list() {} on_filter_change() { + if (!this.board_perms.write) return; // avoid misleading ux + if (JSON.stringify(this.board.filters_array) !== JSON.stringify(this.filter_area.get())) { this.page.set_indicator(__("Not Saved"), "orange"); } else {