From c111040373b0fabda8a848bfb22e00d42a1b9df1 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 23 Jan 2019 14:34:56 +0530 Subject: [PATCH 01/47] intitial commit --- .../user_permission/user_permission_list.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 39a4648334..6ffb716d27 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -1,5 +1,46 @@ frappe.listview_settings['User Permission'] = { onload: function(list_view) { + list_view.page.add_menu_item(__("Add"), function() { + const dialog =new frappe.ui.Dialog({ + title : __('Add'), + fields: [ + { + 'fieldname': 'user', + 'label': __('For User'), + 'fieldtype': 'Link', + 'options': 'User', + 'reqd': 1 + }, + { + 'fieldname': 'doctype', + 'label': __('Document Type'), + 'fieldtype': 'Link', + 'options': 'DocType', + 'reqd': 1 + }, + { + 'fieldname': 'docname', + 'label': __('Document Name'), + 'fieldtype': 'Link', + 'options': 'doctype', + 'reqd': 1 + }, + { + 'fieldname': 'apply_to_all_doctypes', + 'label': __('Apply to all Doctypes'), + 'fieldtype': 'Check', + 'default': 1, + 'reqd': 1 + }, + ], + primary_action: (data) => { + dialog.hide() + }, + primary_action_label: __('Submit') + }); + dialog.show(); + }); + list_view.page.add_menu_item(__("Clear User Permissions"), () => { const dialog = new frappe.ui.Dialog({ title: __('Clear User Permissions'), From f1ce9ce57e600af12de38cc04cf5b64bfeb83d6a Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Thu, 24 Jan 2019 18:25:03 +0530 Subject: [PATCH 02/47] Ui --- .../user_permission/user_permission_list.js | 59 ++++++++++++++++--- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 6ffb716d27..150d19b872 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -1,8 +1,8 @@ frappe.listview_settings['User Permission'] = { onload: function(list_view) { - list_view.page.add_menu_item(__("Add"), function() { - const dialog =new frappe.ui.Dialog({ - title : __('Add'), + list_view.page.add_menu_item(__("Add User Permissions"), function() { + var dialog =new frappe.ui.Dialog({ + title : __('Add User Permissions'), fields: [ { 'fieldname': 'user', @@ -16,21 +16,63 @@ frappe.listview_settings['User Permission'] = { 'label': __('Document Type'), 'fieldtype': 'Link', 'options': 'DocType', - 'reqd': 1 + 'reqd': 1, + 'onchange': function() { + dialog.set_df_property("docname", "get_data", function(){ + var options = [] + frappe.call({ + method:"frappe.client.get_list", + async: false, + args: { + doctype: dialog.fields_dict.doctype.value, + }, + callback: function(r) { + for(var d in r.message){ + options.push(r.message[d].name) + } + } + }); + return options + }) + } }, { 'fieldname': 'docname', 'label': __('Document Name'), - 'fieldtype': 'Link', - 'options': 'doctype', - 'reqd': 1 + 'fieldtype': 'MultiSelect', + 'reqd': 1, }, { 'fieldname': 'apply_to_all_doctypes', 'label': __('Apply to all Doctypes'), 'fieldtype': 'Check', 'default': 1, - 'reqd': 1 + 'onchange': function() { + if(dialog.fields_dict.apply_to_all_doctypes.get_value() == 0){ + frappe.call({ + method:'frappe.desk.form.linked_with.get_linked_doctypes', + async: false, + args: { + doctype: dialog.fields_dict.doctype.value, + }, + callback: function(r) { + var options = [] + for(var d in r.message){ + options.push({ "label":d, "value": d }) + } + dialog.set_df_property("aplicable_doctypes", "options", options) + } + }); + }else{ + dialog.set_df_property("aplicable_doctypes", "options", undefined) + } + } + }, + { + "label": "Aplicable Doctypes", + "fieldname": "aplicable_doctypes", + "fieldtype": "MultiCheck", + "columns": 2 }, ], primary_action: (data) => { @@ -39,6 +81,7 @@ frappe.listview_settings['User Permission'] = { primary_action_label: __('Submit') }); dialog.show(); + dialog }); list_view.page.add_menu_item(__("Clear User Permissions"), () => { From ea914f0234fdcf311f2385a4ff5d78f5a83d07b9 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Mon, 28 Jan 2019 14:26:15 +0530 Subject: [PATCH 03/47] Backend and ui fixes --- .../user_permission/user_permission.py | 44 ++++++ .../user_permission/user_permission_list.js | 128 ++++++++++++++---- 2 files changed, 145 insertions(+), 27 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index 43dff47745..3d4d1a627c 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -9,6 +9,7 @@ from frappe.permissions import (get_valid_perms, update_permission_property) from frappe import _ from frappe.core.utils import find from frappe.desk.form.linked_with import get_linked_doctypes +from pprint import pprint class UserPermission(Document): def validate(self): @@ -112,6 +113,16 @@ def get_permitted_documents(doctype): return [d.get('doc') for d in get_user_permissions().get(doctype, []) \ if d.get('doc')] +@frappe.whitelist() +def check_applicable_doc_perm(user,doctype,docname): + return frappe.get_all('User Permission', + fields=['applicable_for'], + filters={"user": user, + "allow": doctype, + "for_value":docname, + }) + + @frappe.whitelist() def clear_user_permissions(user, for_doctype): frappe.only_for('System Manager') @@ -121,3 +132,36 @@ def clear_user_permissions(user, for_doctype): frappe.db.sql('DELETE FROM `tabUser Permission` WHERE user=%s AND allow=%s', (user, for_doctype)) frappe.clear_cache() return total + +@frappe.whitelist() +def add_user_permissions(data): + if isinstance(data, frappe.string_types): + data = json.loads(data) + data = frappe._dict(data) + + if data.apply_to_all_doctypes == 1: + user_perm = frappe.new_doc("User Permission") + user_perm.user = data.user + user_perm.allow = data.doctype + user_perm.for_value = data.docname + user_perm.apply_to_all_doctypes = 1 + user_perm.insert() + return 1 + else: + failed = "" + d = check_applicable_doc_perm(data.user, data.doctype, data.docname) + for applicable in data.aplicable_doctypes : + if {'applicable_for': applicable} in d: + failed += applicable + ", " + else: + user_perm = frappe.new_doc("User Permission") + user_perm.user = data.user + user_perm.allow = data.doctype + user_perm.for_value = data.docname + user_perm.apply_to_all_doctypes = 0 + user_perm.applicable_for = applicable + user_perm.insert() + frappe.msgprint(_("User Permission for applicable Doctypes: {0} already exists").format(failed)) + return 1 + + return 0 \ No newline at end of file diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 150d19b872..5e91d1109d 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -1,5 +1,7 @@ frappe.listview_settings['User Permission'] = { + onload: function(list_view) { + var me =this list_view.page.add_menu_item(__("Add User Permissions"), function() { var dialog =new frappe.ui.Dialog({ title : __('Add User Permissions'), @@ -9,7 +11,7 @@ frappe.listview_settings['User Permission'] = { 'label': __('For User'), 'fieldtype': 'Link', 'options': 'User', - 'reqd': 1 + 'reqd': 1, }, { 'fieldname': 'doctype', @@ -18,8 +20,8 @@ frappe.listview_settings['User Permission'] = { 'options': 'DocType', 'reqd': 1, 'onchange': function() { - dialog.set_df_property("docname", "get_data", function(){ - var options = [] + var options = [] + if(dialog.fields_dict.doctype.value){ frappe.call({ method:"frappe.client.get_list", async: false, @@ -32,56 +34,88 @@ frappe.listview_settings['User Permission'] = { } } }); - return options - }) + } + dialog.set_df_property("docname", "options", options) + dialog.set_df_property("docname", "hidden", 0) + dialog.set_df_property("docname", "reqd", 1) + dialog.set_df_property("apply_to_all_doctypes", "hidden", 0) + dialog.set_value("apply_to_all_doctypes","checked",1) } }, { 'fieldname': 'docname', 'label': __('Document Name'), - 'fieldtype': 'MultiSelect', - 'reqd': 1, + 'fieldtype': 'Select', + 'hidden': 1, + 'onchange': function(){ + me.get_applicable_doctype(dialog).then(applicable => { + if(applicable.length != 0 ){ + me.get_multi_select_options(dialog, applicable).then(options =>{ + dialog.set_df_property("apply_to_all_doctypes", "checked", 0) + dialog.set_df_property("aplicable_doctypes", "hidden", 0) + dialog.set_df_property("aplicable_doctypes", "options", options) + }) + }else{ + dialog.set_value("apply_to_all_doctypes","checked",1) + dialog.set_df_property("aplicable_doctypes", "options", undefined) + dialog.set_df_property("aplicable_doctypes", "hidden", 1) + } + }) + } }, { 'fieldname': 'apply_to_all_doctypes', 'label': __('Apply to all Doctypes'), 'fieldtype': 'Check', - 'default': 1, + 'checked': 1, + 'hidden': 1, 'onchange': function() { - if(dialog.fields_dict.apply_to_all_doctypes.get_value() == 0){ - frappe.call({ - method:'frappe.desk.form.linked_with.get_linked_doctypes', - async: false, - args: { - doctype: dialog.fields_dict.doctype.value, - }, - callback: function(r) { - var options = [] - for(var d in r.message){ - options.push({ "label":d, "value": d }) - } + if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ + me.get_applicable_doctype(dialog).then(applicable => { + me.get_multi_select_options(dialog, applicable).then(options =>{ + if(dialog.fields_dict.apply_to_all_doctypes.get_value() == 0){ + dialog.set_df_property("aplicable_doctypes", "hidden", 0) dialog.set_df_property("aplicable_doctypes", "options", options) + }else{ + dialog.set_df_property("aplicable_doctypes", "hidden", 1) + dialog.set_df_property("aplicable_doctypes", "options", undefined) } - }); - }else{ - dialog.set_df_property("aplicable_doctypes", "options", undefined) - } + }) + }) } + } }, { - "label": "Aplicable Doctypes", + "label": __("Aplicable Doctypes"), "fieldname": "aplicable_doctypes", "fieldtype": "MultiCheck", - "columns": 2 + "columns": 2, + "hidden": 1 }, ], primary_action: (data) => { + frappe.call({ + async: false, + method: "frappe.core.doctype.user_permission.user_permission.add_user_permissions", + args: { + data : data + }, + callback: function(r){ + if (r.message == 1){ + console.log("helloo") + frappe.show_alert({message:__("User Permissions Created Sucessfully"), indicator:'blue'}); + }else{ + frappe.show_alert({message:__("User Permissions Not Created"), indicator:'red'}); + + } + } + }) dialog.hide() + list_view.refresh(); }, primary_action_label: __('Submit') }); dialog.show(); - dialog }); list_view.page.add_menu_item(__("Clear User Permissions"), () => { @@ -132,5 +166,45 @@ frappe.listview_settings['User Permission'] = { dialog.show(); }); + }, + + get_applicable_doctype: function(dialog){ + return new Promise(resolve => { + frappe.call({ + method: 'frappe.core.doctype.user_permission.user_permission.check_applicable_doc_perm', + async: false, + args:{ + user: dialog.fields_dict.user.value, + doctype: dialog.fields_dict.doctype.value, + docname: dialog.fields_dict.docname.value + }}).then(r => { + var applicable = [] + for (var doc in r.message){ + applicable.push(r.message[doc].applicable_for) + } + resolve(applicable) + }) + }) + }, + + get_multi_select_options: function(dialog, applicable){ + return new Promise(resolve => { + frappe.call({ + method: 'frappe.desk.form.linked_with.get_linked_doctypes', + async: false, + args:{ + user: dialog.fields_dict.user.value, + doctype: dialog.fields_dict.doctype.value, + docname: dialog.fields_dict.docname.value + }}).then(r => { + var options = [] + for(var d in r.message){ + var checked = ($.inArray(d, applicable) != -1) ? 1 : 0; + options.push({ "label":d, "value": d , "checked": checked}) + } + resolve(options) + }) + }) } + }; From 5a370e917aecc3286ea6e113ccbf2573ddeba6d7 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Mon, 28 Jan 2019 16:17:16 +0530 Subject: [PATCH 04/47] backend --- .../user_permission/user_permission.py | 19 ++++++++++------- .../user_permission/user_permission_list.js | 21 ++++++++++--------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index 3d4d1a627c..c3e95932c8 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -139,7 +139,10 @@ def add_user_permissions(data): data = json.loads(data) data = frappe._dict(data) + d = check_applicable_doc_perm(data.user, data.doctype, data.docname) + if data.apply_to_all_doctypes == 1: + remove_applicable(d, data.user, data.doctype, data.docname) user_perm = frappe.new_doc("User Permission") user_perm.user = data.user user_perm.allow = data.doctype @@ -148,12 +151,8 @@ def add_user_permissions(data): user_perm.insert() return 1 else: - failed = "" - d = check_applicable_doc_perm(data.user, data.doctype, data.docname) - for applicable in data.aplicable_doctypes : - if {'applicable_for': applicable} in d: - failed += applicable + ", " - else: + for applicable in data.applicable_doctypes : + if {'applicable_for': applicable} not in d: user_perm = frappe.new_doc("User Permission") user_perm.user = data.user user_perm.allow = data.doctype @@ -161,7 +160,11 @@ def add_user_permissions(data): user_perm.apply_to_all_doctypes = 0 user_perm.applicable_for = applicable user_perm.insert() - frappe.msgprint(_("User Permission for applicable Doctypes: {0} already exists").format(failed)) return 1 - return 0 \ No newline at end of file + return 0 + +def remove_applicable(d, user, doctype, docname): + for data in d: + print(data) + frappe.db.sql("delete from `tabUser Permission` where user='"+user+"' and applicable_for ='"+data.applicable_for+"' and allow='"+doctype+"' and for_value='"+docname+"';") diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 5e91d1109d..ce00e878e8 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -52,13 +52,13 @@ frappe.listview_settings['User Permission'] = { if(applicable.length != 0 ){ me.get_multi_select_options(dialog, applicable).then(options =>{ dialog.set_df_property("apply_to_all_doctypes", "checked", 0) - dialog.set_df_property("aplicable_doctypes", "hidden", 0) - dialog.set_df_property("aplicable_doctypes", "options", options) + dialog.set_df_property("applicable_doctypes", "hidden", 0) + dialog.set_df_property("applicable_doctypes", "options", options) }) }else{ dialog.set_value("apply_to_all_doctypes","checked",1) - dialog.set_df_property("aplicable_doctypes", "options", undefined) - dialog.set_df_property("aplicable_doctypes", "hidden", 1) + dialog.set_df_property("applicable_doctypes", "options", undefined) + dialog.set_df_property("applicable_doctypes", "hidden", 1) } }) } @@ -74,11 +74,11 @@ frappe.listview_settings['User Permission'] = { me.get_applicable_doctype(dialog).then(applicable => { me.get_multi_select_options(dialog, applicable).then(options =>{ if(dialog.fields_dict.apply_to_all_doctypes.get_value() == 0){ - dialog.set_df_property("aplicable_doctypes", "hidden", 0) - dialog.set_df_property("aplicable_doctypes", "options", options) + dialog.set_df_property("applicable_doctypes", "hidden", 0) + dialog.set_df_property("applicable_doctypes", "options", options) }else{ - dialog.set_df_property("aplicable_doctypes", "hidden", 1) - dialog.set_df_property("aplicable_doctypes", "options", undefined) + dialog.set_df_property("applicable_doctypes", "hidden", 1) + dialog.set_df_property("applicable_doctypes", "options", undefined) } }) }) @@ -86,14 +86,15 @@ frappe.listview_settings['User Permission'] = { } }, { - "label": __("Aplicable Doctypes"), - "fieldname": "aplicable_doctypes", + "label": __("Applicable Doctypes"), + "fieldname": "applicable_doctypes", "fieldtype": "MultiCheck", "columns": 2, "hidden": 1 }, ], primary_action: (data) => { + console.log(data) frappe.call({ async: false, method: "frappe.core.doctype.user_permission.user_permission.add_user_permissions", From f780b42cfb6a5fbf69d31f63a32a826e9be2cb9d Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Tue, 29 Jan 2019 16:13:56 +0530 Subject: [PATCH 05/47] fix: multicheck and feat:update some ui fixes --- .../user_permission/user_permission.py | 40 ++++++++-- .../user_permission/user_permission_list.js | 74 +++++++++++-------- .../js/frappe/form/controls/multicheck.js | 4 +- 3 files changed, 78 insertions(+), 40 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index c3e95932c8..ad7b551a50 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -114,13 +114,28 @@ def get_permitted_documents(doctype): if d.get('doc')] @frappe.whitelist() -def check_applicable_doc_perm(user,doctype,docname): - return frappe.get_all('User Permission', +def check_applicable_doc_perm(user, doctype, docname): + applicable = [] + all_perm =frappe.get_all('User Permission', fields=['applicable_for'], filters={"user": user, "allow": doctype, - "for_value":docname, - }) + "apply_to_all_doctypes":1, + },limit=1) + if len(all_perm) > 0: + data = get_linked_doctypes(doctype) + for key in data: + applicable.append(key) + else: + data = frappe.get_all('User Permission', + fields=['applicable_for'], + filters={"user": user, + "allow": doctype, + "for_value":docname, + }) + for d in data: + applicable.append(d.applicable_for) + return applicable @frappe.whitelist() @@ -151,8 +166,10 @@ def add_user_permissions(data): user_perm.insert() return 1 else: + remove_apply_to_all(data.user, data.doctype, data.docname) + update_applicable(d, data.applicable_doctypes, data.user, data.doctype, data.docname) for applicable in data.applicable_doctypes : - if {'applicable_for': applicable} not in d: + if applicable not in d: user_perm = frappe.new_doc("User Permission") user_perm.user = data.user user_perm.allow = data.doctype @@ -166,5 +183,14 @@ def add_user_permissions(data): def remove_applicable(d, user, doctype, docname): for data in d: - print(data) - frappe.db.sql("delete from `tabUser Permission` where user='"+user+"' and applicable_for ='"+data.applicable_for+"' and allow='"+doctype+"' and for_value='"+docname+"';") + frappe.db.sql("delete from `tabUser Permission` where user='"+user+"' and applicable_for ='"+data+"' and allow='"+doctype+"' and for_value='"+docname+"';") + +def remove_apply_to_all(user, doctype, docname): + frappe.db.sql("delete from `tabUser Permission` where user='"+user+"' and apply_to_all_doctypes =1 and allow='"+doctype+"' and for_value='"+docname+"';") + +def update_applicable(already_applied, to_apply, user, doctype, docname): + for applied in already_applied: + print(applied,to_apply) + if applied not in to_apply: + print("----------->>deleting",applied) + frappe.db.sql("delete from `tabUser Permission` where user='"+user+"' and applicable_for='"+ applied +"' and allow='"+doctype+"' and for_value='"+docname+"';") \ No newline at end of file diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index ce00e878e8..946ae0d6ca 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -2,7 +2,7 @@ frappe.listview_settings['User Permission'] = { onload: function(list_view) { var me =this - list_view.page.add_menu_item(__("Add User Permissions"), function() { + list_view.page.add_menu_item(__("Create/Update User Permissions"), function() { var dialog =new frappe.ui.Dialog({ title : __('Add User Permissions'), fields: [ @@ -49,18 +49,29 @@ frappe.listview_settings['User Permission'] = { 'hidden': 1, 'onchange': function(){ me.get_applicable_doctype(dialog).then(applicable => { - if(applicable.length != 0 ){ - me.get_multi_select_options(dialog, applicable).then(options =>{ - dialog.set_df_property("apply_to_all_doctypes", "checked", 0) - dialog.set_df_property("applicable_doctypes", "hidden", 0) - dialog.set_df_property("applicable_doctypes", "options", options) - }) + me.get_multi_select_options(dialog, applicable).then(options =>{ + if (options.length == applicable.length){ + console.log("inside if") + dialog.set_primary_action("Update") + dialog.set_title("Update User Permissions") + dialog.set_value("apply_to_all_doctypes", "checked",1) + dialog.set_df_property("applicable_doctypes", "options", options) + dialog.set_df_property("applicable_doctypes", "hidden", 1) + }else if(applicable.length != 0 ){ + console.log("inside elseif") + dialog.set_primary_action("Update") + dialog.set_title("Update User Permissions") + dialog.set_df_property("apply_to_all_doctypes", "checked", 0) + dialog.set_df_property("applicable_doctypes", "hidden", 0) + dialog.set_df_property("applicable_doctypes", "options", options) }else{ - dialog.set_value("apply_to_all_doctypes","checked",1) - dialog.set_df_property("applicable_doctypes", "options", undefined) + console.log("inside else") + dialog.set_value("apply_to_all_doctypes", "checked",1) + dialog.set_df_property("applicable_doctypes", "options", options) dialog.set_df_property("applicable_doctypes", "hidden", 1) } }) + }) } }, { @@ -78,7 +89,7 @@ frappe.listview_settings['User Permission'] = { dialog.set_df_property("applicable_doctypes", "options", options) }else{ dialog.set_df_property("applicable_doctypes", "hidden", 1) - dialog.set_df_property("applicable_doctypes", "options", undefined) + dialog.set_df_property("applicable_doctypes", "options", options) } }) }) @@ -89,29 +100,32 @@ frappe.listview_settings['User Permission'] = { "label": __("Applicable Doctypes"), "fieldname": "applicable_doctypes", "fieldtype": "MultiCheck", + "options": [], "columns": 2, "hidden": 1 }, ], primary_action: (data) => { - console.log(data) - frappe.call({ - async: false, - method: "frappe.core.doctype.user_permission.user_permission.add_user_permissions", - args: { - data : data - }, - callback: function(r){ - if (r.message == 1){ - console.log("helloo") - frappe.show_alert({message:__("User Permissions Created Sucessfully"), indicator:'blue'}); - }else{ - frappe.show_alert({message:__("User Permissions Not Created"), indicator:'red'}); - - } + if(dialog.fields_dict.applicable_doctypes.get_unchecked_options().length == 0){ + data.apply_to_all_doctypes = 1 + data.applicable_doctypes = [] } - }) - dialog.hide() + frappe.call({ + async: false, + method: "frappe.core.doctype.user_permission.user_permission.add_user_permissions", + args: { + data : data + }, + callback: function(r){ + if (r.message == 1){ + frappe.show_alert({message:__("User Permissions Created Sucessfully"), indicator:'blue'}); + }else{ + frappe.show_alert({message:__("User Permissions Not Created"), indicator:'red'}); + + } + } + }) + dialog.hide(); list_view.refresh(); }, primary_action_label: __('Submit') @@ -179,11 +193,7 @@ frappe.listview_settings['User Permission'] = { doctype: dialog.fields_dict.doctype.value, docname: dialog.fields_dict.docname.value }}).then(r => { - var applicable = [] - for (var doc in r.message){ - applicable.push(r.message[doc].applicable_for) - } - resolve(applicable) + resolve(r.message) }) }) }, diff --git a/frappe/public/js/frappe/form/controls/multicheck.js b/frappe/public/js/frappe/form/controls/multicheck.js index 35e1a1a19b..5e8c437445 100644 --- a/frappe/public/js/frappe/form/controls/multicheck.js +++ b/frappe/public/js/frappe/form/controls/multicheck.js @@ -86,7 +86,9 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({ this.selected_options.push(option_name); } else { let index = this.selected_options.indexOf(option_name); - this.selected_options.splice(index, 1); + if(index > -1) { + this.selected_options.splice(index, 1); + } } this.df.on_change && this.df.on_change(); }); From 969866233794b3c95b6df262f23f48171dcf6ad2 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 30 Jan 2019 15:01:34 +0530 Subject: [PATCH 06/47] fix: Update on change of user, Avoid duplication error,if no applicable selected,readability --- .../user_permission/user_permission.py | 29 +++- .../user_permission/user_permission_list.js | 146 +++++++++++------- 2 files changed, 112 insertions(+), 63 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index ad7b551a50..39c62fb786 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -120,6 +120,7 @@ def check_applicable_doc_perm(user, doctype, docname): fields=['applicable_for'], filters={"user": user, "allow": doctype, + "for_value": docname, "apply_to_all_doctypes":1, },limit=1) if len(all_perm) > 0: @@ -155,7 +156,8 @@ def add_user_permissions(data): data = frappe._dict(data) d = check_applicable_doc_perm(data.user, data.doctype, data.docname) - + exists = frappe.db.exists("User Permission", {"user": data.user, "allow": data.doctype, "for_value": data.docname, "apply_to_all_doctypes": 1}) + if exists: return 0 if data.apply_to_all_doctypes == 1: remove_applicable(d, data.user, data.doctype, data.docname) user_perm = frappe.new_doc("User Permission") @@ -182,15 +184,28 @@ def add_user_permissions(data): return 0 def remove_applicable(d, user, doctype, docname): - for data in d: - frappe.db.sql("delete from `tabUser Permission` where user='"+user+"' and applicable_for ='"+data+"' and allow='"+doctype+"' and for_value='"+docname+"';") + for applicable_for in d: + frappe.db.sql("""DELETE FROM `tabUser Permission` + WHERE `user`=%s + AND `applicable_for`=%s + AND `allow`=%s + AND `for_value`=%s + """, (user, applicable_for, doctype, docname)) def remove_apply_to_all(user, doctype, docname): - frappe.db.sql("delete from `tabUser Permission` where user='"+user+"' and apply_to_all_doctypes =1 and allow='"+doctype+"' and for_value='"+docname+"';") + frappe.db.sql("""DELETE from `tabUser Permission` + WHERE `user`=%s + AND `apply_to_all_doctypes`=1 + AND `allow`=%s + AND `for_value`=%s + """,(user, doctype, docname)) def update_applicable(already_applied, to_apply, user, doctype, docname): for applied in already_applied: - print(applied,to_apply) if applied not in to_apply: - print("----------->>deleting",applied) - frappe.db.sql("delete from `tabUser Permission` where user='"+user+"' and applicable_for='"+ applied +"' and allow='"+doctype+"' and for_value='"+docname+"';") \ No newline at end of file + frappe.db.sql("""DELETE FROM `tabUser Permission` + WHERE `user`=%s + AND `applicable_for`=%s + AND `allow`=%s + AND `for_value`=%s + """,(user, applied, doctype, docname)) \ No newline at end of file diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 946ae0d6ca..bdcd406733 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -12,6 +12,13 @@ frappe.listview_settings['User Permission'] = { 'fieldtype': 'Link', 'options': 'User', 'reqd': 1, + 'onchange': function () { + dialog.fields_dict.doctype.set_input(undefined) + dialog.fields_dict.docname.set_input(undefined) + dialog.set_df_property("docname", "hidden", 1) + dialog.set_df_property("apply_to_all_doctypes", "hidden", 1) + dialog.set_df_property("applicable_doctypes", "hidden", 1) + } }, { 'fieldname': 'doctype', @@ -20,26 +27,9 @@ frappe.listview_settings['User Permission'] = { 'options': 'DocType', 'reqd': 1, 'onchange': function() { - var options = [] - if(dialog.fields_dict.doctype.value){ - frappe.call({ - method:"frappe.client.get_list", - async: false, - args: { - doctype: dialog.fields_dict.doctype.value, - }, - callback: function(r) { - for(var d in r.message){ - options.push(r.message[d].name) - } - } - }); - } - dialog.set_df_property("docname", "options", options) - dialog.set_df_property("docname", "hidden", 0) - dialog.set_df_property("docname", "reqd", 1) - dialog.set_df_property("apply_to_all_doctypes", "hidden", 0) - dialog.set_value("apply_to_all_doctypes","checked",1) + me.get_docname_options(dialog).then(options => { + me.on_doctype_change(options, dialog) + }) } }, { @@ -50,33 +40,14 @@ frappe.listview_settings['User Permission'] = { 'onchange': function(){ me.get_applicable_doctype(dialog).then(applicable => { me.get_multi_select_options(dialog, applicable).then(options =>{ - if (options.length == applicable.length){ - console.log("inside if") - dialog.set_primary_action("Update") - dialog.set_title("Update User Permissions") - dialog.set_value("apply_to_all_doctypes", "checked",1) - dialog.set_df_property("applicable_doctypes", "options", options) - dialog.set_df_property("applicable_doctypes", "hidden", 1) - }else if(applicable.length != 0 ){ - console.log("inside elseif") - dialog.set_primary_action("Update") - dialog.set_title("Update User Permissions") - dialog.set_df_property("apply_to_all_doctypes", "checked", 0) - dialog.set_df_property("applicable_doctypes", "hidden", 0) - dialog.set_df_property("applicable_doctypes", "options", options) - }else{ - console.log("inside else") - dialog.set_value("apply_to_all_doctypes", "checked",1) - dialog.set_df_property("applicable_doctypes", "options", options) - dialog.set_df_property("applicable_doctypes", "hidden", 1) - } + me.on_docname_change(dialog, options, applicable) }) }) } }, { 'fieldname': 'apply_to_all_doctypes', - 'label': __('Apply to all Doctypes'), + 'label': __('Apply to all Documents Type'), 'fieldtype': 'Check', 'checked': 1, 'hidden': 1, @@ -84,20 +55,14 @@ frappe.listview_settings['User Permission'] = { if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ me.get_applicable_doctype(dialog).then(applicable => { me.get_multi_select_options(dialog, applicable).then(options =>{ - if(dialog.fields_dict.apply_to_all_doctypes.get_value() == 0){ - dialog.set_df_property("applicable_doctypes", "hidden", 0) - dialog.set_df_property("applicable_doctypes", "options", options) - }else{ - dialog.set_df_property("applicable_doctypes", "hidden", 1) - dialog.set_df_property("applicable_doctypes", "options", options) - } + me.on_apply_to_all_doctypes_change(dialog,options) }) }) } } }, { - "label": __("Applicable Doctypes"), + "label": __("Applicable Document Types"), "fieldname": "applicable_doctypes", "fieldtype": "MultiCheck", "options": [], @@ -106,10 +71,7 @@ frappe.listview_settings['User Permission'] = { }, ], primary_action: (data) => { - if(dialog.fields_dict.applicable_doctypes.get_unchecked_options().length == 0){ - data.apply_to_all_doctypes = 1 - data.applicable_doctypes = [] - } + data = me.validate(dialog, data) frappe.call({ async: false, method: "frappe.core.doctype.user_permission.user_permission.add_user_permissions", @@ -120,7 +82,7 @@ frappe.listview_settings['User Permission'] = { if (r.message == 1){ frappe.show_alert({message:__("User Permissions Created Sucessfully"), indicator:'blue'}); }else{ - frappe.show_alert({message:__("User Permissions Not Created"), indicator:'red'}); + frappe.show_alert({message:__("Nothing to update"), indicator:'red'}); } } @@ -164,6 +126,8 @@ frappe.listview_settings['User Permission'] = { let message = ''; if (data === 0) { message = __('No records deleted'); + } else if(data === 1) { + message = __('{0} record deleted', [data]); } else { message = __('{0} records deleted', [data]); } @@ -183,6 +147,17 @@ frappe.listview_settings['User Permission'] = { }); }, + validate: function(dialog, data){ + if(dialog.fields_dict.applicable_doctypes.get_unchecked_options().length == 0){ + data.apply_to_all_doctypes = 1 + data.applicable_doctypes = [] + return data + } + if(data.apply_to_all_doctypes == 0 && !("applicable_doctypes" in data) ){ + frappe.throw("Please select applicable Doctypes") + } + }, + get_applicable_doctype: function(dialog){ return new Promise(resolve => { frappe.call({ @@ -216,6 +191,65 @@ frappe.listview_settings['User Permission'] = { resolve(options) }) }) - } + }, -}; + get_docname_options: function(dialog) { + return new Promise(resolve => { + var options = [] + if(dialog.fields_dict.doctype.value){ + frappe.call({ + method:"frappe.client.get_list", + async: false, + args: { + doctype: dialog.fields_dict.doctype.value, + }, + callback: function(r) { + for(var d in r.message){ + options.push(r.message[d].name) + } + resolve(options) + } + }); + } + }) + }, + + on_doctype_change: function(options, dialog){ + dialog.set_df_property("docname", "options", options) + dialog.set_df_property("docname", "hidden", 0) + dialog.set_df_property("docname", "reqd", 1) + dialog.set_df_property("apply_to_all_doctypes", "hidden", 0) + dialog.set_value("apply_to_all_doctypes","checked",1) + }, + + on_docname_change: function(dialog, options, applicable){ + if(applicable.length != 0 ){ + dialog.set_primary_action("Update") + dialog.set_title("Update User Permissions") + dialog.set_df_property("applicable_doctypes", "options", options) + if(dialog.fields_dict.applicable_doctypes.get_checked_options().length == options.length){ + dialog.set_df_property("applicable_doctypes", "hidden", 1) + dialog.set_value("apply_to_all_doctypes", "checked", 1) + }else{ + dialog.set_df_property("applicable_doctypes", "hidden", 0) + dialog.set_df_property("apply_to_all_doctypes", "checked", 0) + } + }else{ + dialog.set_primary_action("Submit") + dialog.set_title("Add User Permissions") + dialog.set_value("apply_to_all_doctypes", "checked",1) + dialog.set_df_property("applicable_doctypes", "options", options) + dialog.set_df_property("applicable_doctypes", "hidden", 1) + } + }, + + on_apply_to_all_doctypes_change: function(dialog, options){ + if(dialog.fields_dict.apply_to_all_doctypes.get_value() == 0){ + dialog.set_df_property("applicable_doctypes", "hidden", 0) + dialog.set_df_property("applicable_doctypes", "options", options) + }else{ + dialog.set_df_property("applicable_doctypes", "hidden", 1) + dialog.set_df_property("applicable_doctypes", "options", options) + } + } +}; \ No newline at end of file From 1940a45dc701876774d585b723e93c16c47d0d98 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 30 Jan 2019 15:34:43 +0530 Subject: [PATCH 07/47] fix: codacy --- .../user_permission/user_permission.py | 28 +-- .../user_permission/user_permission_list.js | 181 +++++++++--------- 2 files changed, 106 insertions(+), 103 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index 39c62fb786..19423f429b 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -115,25 +115,26 @@ def get_permitted_documents(doctype): @frappe.whitelist() def check_applicable_doc_perm(user, doctype, docname): + frappe.only_for('System Manager') applicable = [] - all_perm =frappe.get_all('User Permission', - fields=['applicable_for'], - filters={"user": user, - "allow": doctype, - "for_value": docname, - "apply_to_all_doctypes":1, - },limit=1) + all_perm = frappe.get_all('User Permission', + fields=['applicable_for'], + filters={"user": user, + "allow": doctype, + "for_value": docname, + "apply_to_all_doctypes":1, + }, limit=1) if len(all_perm) > 0: data = get_linked_doctypes(doctype) for key in data: applicable.append(key) else: data = frappe.get_all('User Permission', - fields=['applicable_for'], - filters={"user": user, - "allow": doctype, - "for_value":docname, - }) + fields=['applicable_for'], + filters={"user": user, + "allow": doctype, + "for_value":docname, + }) for d in data: applicable.append(d.applicable_for) return applicable @@ -142,7 +143,6 @@ def check_applicable_doc_perm(user, doctype, docname): @frappe.whitelist() def clear_user_permissions(user, for_doctype): frappe.only_for('System Manager') - total = frappe.db.count('User Permission', filters = dict(user=user, allow=for_doctype)) if total: frappe.db.sql('DELETE FROM `tabUser Permission` WHERE user=%s AND allow=%s', (user, for_doctype)) @@ -151,6 +151,7 @@ def clear_user_permissions(user, for_doctype): @frappe.whitelist() def add_user_permissions(data): + frappe.only_for('System Manager') if isinstance(data, frappe.string_types): data = json.loads(data) data = frappe._dict(data) @@ -180,7 +181,6 @@ def add_user_permissions(data): user_perm.applicable_for = applicable user_perm.insert() return 1 - return 0 def remove_applicable(d, user, doctype, docname): diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index bdcd406733..dc39cedf95 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -1,7 +1,7 @@ frappe.listview_settings['User Permission'] = { onload: function(list_view) { - var me =this + var me = this; list_view.page.add_menu_item(__("Create/Update User Permissions"), function() { var dialog =new frappe.ui.Dialog({ title : __('Add User Permissions'), @@ -12,12 +12,12 @@ frappe.listview_settings['User Permission'] = { 'fieldtype': 'Link', 'options': 'User', 'reqd': 1, - 'onchange': function () { - dialog.fields_dict.doctype.set_input(undefined) - dialog.fields_dict.docname.set_input(undefined) - dialog.set_df_property("docname", "hidden", 1) - dialog.set_df_property("apply_to_all_doctypes", "hidden", 1) - dialog.set_df_property("applicable_doctypes", "hidden", 1) + 'onchange': function() { + dialog.fields_dict.doctype.set_input(undefined); + dialog.fields_dict.docname.set_input(undefined); + dialog.set_df_property("docname", "hidden", 1); + dialog.set_df_property("apply_to_all_doctypes", "hidden", 1); + dialog.set_df_property("applicable_doctypes", "hidden", 1); } }, { @@ -28,8 +28,8 @@ frappe.listview_settings['User Permission'] = { 'reqd': 1, 'onchange': function() { me.get_docname_options(dialog).then(options => { - me.on_doctype_change(options, dialog) - }) + me.on_doctype_change(options, dialog); + }); } }, { @@ -37,12 +37,12 @@ frappe.listview_settings['User Permission'] = { 'label': __('Document Name'), 'fieldtype': 'Select', 'hidden': 1, - 'onchange': function(){ + 'onchange': function() { me.get_applicable_doctype(dialog).then(applicable => { - me.get_multi_select_options(dialog, applicable).then(options =>{ - me.on_docname_change(dialog, options, applicable) - }) - }) + me.get_multi_select_options(dialog, applicable).then(options => { + me.on_docname_change(dialog, options, applicable); + }); + }); } }, { @@ -54,12 +54,12 @@ frappe.listview_settings['User Permission'] = { 'onchange': function() { if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ me.get_applicable_doctype(dialog).then(applicable => { - me.get_multi_select_options(dialog, applicable).then(options =>{ - me.on_apply_to_all_doctypes_change(dialog,options) - }) - }) + me.get_multi_select_options(dialog, applicable).then(options => { + me.on_apply_to_all_doctypes_change(dialog,options); + }); + }); + } } - } }, { "label": __("Applicable Document Types"), @@ -71,22 +71,22 @@ frappe.listview_settings['User Permission'] = { }, ], primary_action: (data) => { - data = me.validate(dialog, data) - frappe.call({ - async: false, - method: "frappe.core.doctype.user_permission.user_permission.add_user_permissions", - args: { - data : data - }, - callback: function(r){ - if (r.message == 1){ - frappe.show_alert({message:__("User Permissions Created Sucessfully"), indicator:'blue'}); - }else{ - frappe.show_alert({message:__("Nothing to update"), indicator:'red'}); + data = me.validate(dialog, data); + frappe.call({ + async: false, + method: "frappe.core.doctype.user_permission.user_permission.add_user_permissions", + args: { + data : data + }, + callback: function(r) { + if (r.message == 1) { + frappe.show_alert({message:__("User Permissions Created Sucessfully"), indicator:'blue'}); + } else { + frappe.show_alert({message:__("Nothing to update"), indicator:'red'}); - } } - }) + } + }); dialog.hide(); list_view.refresh(); }, @@ -147,18 +147,19 @@ frappe.listview_settings['User Permission'] = { }); }, - validate: function(dialog, data){ - if(dialog.fields_dict.applicable_doctypes.get_unchecked_options().length == 0){ - data.apply_to_all_doctypes = 1 - data.applicable_doctypes = [] - return data + validate: function(dialog, data) { + if(dialog.fields_dict.applicable_doctypes.get_unchecked_options().length == 0) { + data.apply_to_all_doctypes = 1; + data.applicable_doctypes = []; + return data; } - if(data.apply_to_all_doctypes == 0 && !("applicable_doctypes" in data) ){ - frappe.throw("Please select applicable Doctypes") + if(data.apply_to_all_doctypes == 0 && !("applicable_doctypes" in data)) { + frappe.throw("Please select applicable Doctypes"); } + return data; }, - get_applicable_doctype: function(dialog){ + get_applicable_doctype: function(dialog) { return new Promise(resolve => { frappe.call({ method: 'frappe.core.doctype.user_permission.user_permission.check_applicable_doc_perm', @@ -167,10 +168,11 @@ frappe.listview_settings['User Permission'] = { user: dialog.fields_dict.user.value, doctype: dialog.fields_dict.doctype.value, docname: dialog.fields_dict.docname.value - }}).then(r => { - resolve(r.message) - }) - }) + } + }).then(r => { + resolve(r.message); + }); + }); }, get_multi_select_options: function(dialog, applicable){ @@ -182,20 +184,21 @@ frappe.listview_settings['User Permission'] = { user: dialog.fields_dict.user.value, doctype: dialog.fields_dict.doctype.value, docname: dialog.fields_dict.docname.value - }}).then(r => { - var options = [] - for(var d in r.message){ - var checked = ($.inArray(d, applicable) != -1) ? 1 : 0; - options.push({ "label":d, "value": d , "checked": checked}) - } - resolve(options) - }) - }) + } + }).then(r => { + var options = []; + for(var d in r.message){ + var checked = ($.inArray(d, applicable) != -1) ? 1 : 0; + options.push({ "label":d, "value": d , "checked": checked}); + } + resolve(options); + }); + }); }, get_docname_options: function(dialog) { return new Promise(resolve => { - var options = [] + var options = []; if(dialog.fields_dict.doctype.value){ frappe.call({ method:"frappe.client.get_list", @@ -204,52 +207,52 @@ frappe.listview_settings['User Permission'] = { doctype: dialog.fields_dict.doctype.value, }, callback: function(r) { - for(var d in r.message){ - options.push(r.message[d].name) + for(var d in r.message) { + options.push(r.message[d].name); } - resolve(options) + resolve(options); } }); } - }) + }); }, - on_doctype_change: function(options, dialog){ - dialog.set_df_property("docname", "options", options) - dialog.set_df_property("docname", "hidden", 0) - dialog.set_df_property("docname", "reqd", 1) - dialog.set_df_property("apply_to_all_doctypes", "hidden", 0) - dialog.set_value("apply_to_all_doctypes","checked",1) + on_doctype_change: function(options, dialog) { + dialog.set_df_property("docname", "options", options); + dialog.set_df_property("docname", "hidden", 0); + dialog.set_df_property("docname", "reqd", 1); + dialog.set_df_property("apply_to_all_doctypes", "hidden", 0); + dialog.set_value("apply_to_all_doctypes","checked",1); }, - on_docname_change: function(dialog, options, applicable){ - if(applicable.length != 0 ){ - dialog.set_primary_action("Update") - dialog.set_title("Update User Permissions") - dialog.set_df_property("applicable_doctypes", "options", options) - if(dialog.fields_dict.applicable_doctypes.get_checked_options().length == options.length){ - dialog.set_df_property("applicable_doctypes", "hidden", 1) - dialog.set_value("apply_to_all_doctypes", "checked", 1) - }else{ - dialog.set_df_property("applicable_doctypes", "hidden", 0) - dialog.set_df_property("apply_to_all_doctypes", "checked", 0) + on_docname_change: function(dialog, options, applicable) { + if(applicable.length != 0 ) { + dialog.set_primary_action("Update"); + dialog.set_title("Update User Permissions"); + dialog.set_df_property("applicable_doctypes", "options", options); + if(dialog.fields_dict.applicable_doctypes.get_checked_options().length == options.length) { + dialog.set_df_property("applicable_doctypes", "hidden", 1); + dialog.set_value("apply_to_all_doctypes", "checked", 1); + } else { + dialog.set_df_property("applicable_doctypes", "hidden", 0); + dialog.set_df_property("apply_to_all_doctypes", "checked", 0); } - }else{ - dialog.set_primary_action("Submit") - dialog.set_title("Add User Permissions") - dialog.set_value("apply_to_all_doctypes", "checked",1) - dialog.set_df_property("applicable_doctypes", "options", options) - dialog.set_df_property("applicable_doctypes", "hidden", 1) + } else { + dialog.set_primary_action("Submit"); + dialog.set_title("Add User Permissions"); + dialog.set_value("apply_to_all_doctypes", "checked",1); + dialog.set_df_property("applicable_doctypes", "options", options); + dialog.set_df_property("applicable_doctypes", "hidden", 1); } }, - on_apply_to_all_doctypes_change: function(dialog, options){ - if(dialog.fields_dict.apply_to_all_doctypes.get_value() == 0){ - dialog.set_df_property("applicable_doctypes", "hidden", 0) - dialog.set_df_property("applicable_doctypes", "options", options) - }else{ - dialog.set_df_property("applicable_doctypes", "hidden", 1) - dialog.set_df_property("applicable_doctypes", "options", options) + on_apply_to_all_doctypes_change: function(dialog, options) { + if(dialog.fields_dict.apply_to_all_doctypes.get_value() == 0) { + dialog.set_df_property("applicable_doctypes", "hidden", 0); + dialog.set_df_property("applicable_doctypes", "options", options); + } else { + dialog.set_df_property("applicable_doctypes", "hidden", 1); + dialog.set_df_property("applicable_doctypes", "options", options); } } }; \ No newline at end of file From 0001a77cfbbe8b300eaeb66fe0d95951e0a73ed8 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 30 Jan 2019 16:23:08 +0530 Subject: [PATCH 08/47] fix: codacy --- frappe/core/doctype/user_permission/user_permission.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index 19423f429b..354a88c353 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -9,7 +9,6 @@ from frappe.permissions import (get_valid_perms, update_permission_property) from frappe import _ from frappe.core.utils import find from frappe.desk.form.linked_with import get_linked_doctypes -from pprint import pprint class UserPermission(Document): def validate(self): From c62f3155f2107f1cc9ccf296957571a9811ebc7e Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 25 Jan 2019 18:31:52 +0530 Subject: [PATCH 09/47] update(frappe): Update dependency Oauthlib (#6832) Update dependency oauthlib to 3.0.0 updates interdependent lib requests-oauthlib to 1.2.0 --- frappe/oauth.py | 9 +-------- requirements.txt | 4 ++-- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/frappe/oauth.py b/frappe/oauth.py index 0359e75214..4dc50366be 100644 --- a/frappe/oauth.py +++ b/frappe/oauth.py @@ -5,7 +5,7 @@ import pytz from frappe import _ from frappe.auth import LoginManager from oauthlib.oauth2.rfc6749.tokens import BearerToken -from oauthlib.oauth2.rfc6749.grant_types import AuthorizationCodeGrant, ImplicitGrant, ResourceOwnerPasswordCredentialsGrant, ClientCredentialsGrant, RefreshTokenGrant, OpenIDConnectAuthCode +from oauthlib.oauth2.rfc6749.grant_types import AuthorizationCodeGrant, ImplicitGrant, ResourceOwnerPasswordCredentialsGrant, ClientCredentialsGrant, RefreshTokenGrant from oauthlib.oauth2 import RequestValidator from oauthlib.oauth2.rfc6749.endpoints.authorization import AuthorizationEndpoint from oauthlib.oauth2.rfc6749.endpoints.token import TokenEndpoint @@ -40,19 +40,12 @@ class WebApplicationServer(AuthorizationEndpoint, TokenEndpoint, ResourceEndpoin implicit_grant = ImplicitGrant(request_validator) auth_grant = AuthorizationCodeGrant(request_validator) refresh_grant = RefreshTokenGrant(request_validator) - openid_connect_auth = OpenIDConnectAuthCode(request_validator) resource_owner_password_credentials_grant = ResourceOwnerPasswordCredentialsGrant(request_validator) bearer = BearerToken(request_validator, token_generator, token_expires_in, refresh_token_generator) AuthorizationEndpoint.__init__(self, default_response_type='code', response_types={ 'code': auth_grant, - 'code+token': openid_connect_auth, - 'code+id_token': openid_connect_auth, - 'code+token+id_token': openid_connect_auth, - 'code token': openid_connect_auth, - 'code id_token': openid_connect_auth, - 'code token id_token': openid_connect_auth, 'token': implicit_grant }, default_token_type=bearer) diff --git a/requirements.txt b/requirements.txt index 4c6510df51..7c4f0d2962 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,8 +34,8 @@ ndg-httpsclient pyasn1 zxcvbn-python unittest-xml-reporting -oauthlib==2.1.0 -requests-oauthlib==1.1.0 +oauthlib==3.0.0 +requests-oauthlib==1.2.0 pdfkit PyJWT PyPDF2 From c79abc6d7734fa2ed6c672d0d41fa52c2f79b2a4 Mon Sep 17 00:00:00 2001 From: britlog Date: Thu, 31 Jan 2019 22:34:15 +0100 Subject: [PATCH 10/47] Fix encoding --- frappe/email/doctype/newsletter/newsletter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/email/doctype/newsletter/newsletter.py b/frappe/email/doctype/newsletter/newsletter.py index d69fae1f1d..9344ae1b3e 100755 --- a/frappe/email/doctype/newsletter/newsletter.py +++ b/frappe/email/doctype/newsletter/newsletter.py @@ -137,7 +137,7 @@ def unsubscribe(email, name): return primary_action = frappe.utils.get_url() + "/api/method/frappe.email.doctype.newsletter.newsletter.confirmed_unsubscribe"+\ - "?" + get_signed_params({"email": email, "name":name}) + "?" + get_signed_params({"email": email, "name":name.encode('utf-8')}) return_confirmation_page(email, name, primary_action) From 6ab07995f9e95061c6e462d81e8b96beb19f00a0 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Fri, 1 Feb 2019 12:11:42 +0530 Subject: [PATCH 11/47] fix: changes requested --- .../user_permission/user_permission.py | 26 +++--- .../user_permission/user_permission_list.js | 80 +++++++++---------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index 354a88c353..cfd67fb5c4 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -160,28 +160,28 @@ def add_user_permissions(data): if exists: return 0 if data.apply_to_all_doctypes == 1: remove_applicable(d, data.user, data.doctype, data.docname) - user_perm = frappe.new_doc("User Permission") - user_perm.user = data.user - user_perm.allow = data.doctype - user_perm.for_value = data.docname - user_perm.apply_to_all_doctypes = 1 - user_perm.insert() + insert_user_perm(data.user, data.doctype, data.docname, apply_to_all = 1) return 1 else: remove_apply_to_all(data.user, data.doctype, data.docname) update_applicable(d, data.applicable_doctypes, data.user, data.doctype, data.docname) for applicable in data.applicable_doctypes : if applicable not in d: - user_perm = frappe.new_doc("User Permission") - user_perm.user = data.user - user_perm.allow = data.doctype - user_perm.for_value = data.docname - user_perm.apply_to_all_doctypes = 0 - user_perm.applicable_for = applicable - user_perm.insert() + insert_user_perm(data.user, data.doctype, data.docname, applicable = applicable) return 1 return 0 +def insert_user_perm(user, doctype, docname, apply_to_all=None, applicable=None): + user_perm = frappe.new_doc("User Permission") + user_perm.user = user + user_perm.allow = doctype + user_perm.for_value = docname + if apply_to_all: + user_perm.apply_to_all_doctypes = 1 + if applicable: + user_perm.applicable_for = applicable + user_perm.insert() + def remove_applicable(d, user, doctype, docname): for applicable_for in d: frappe.db.sql("""DELETE FROM `tabUser Permission` diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index dc39cedf95..f4f2578797 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -7,12 +7,12 @@ frappe.listview_settings['User Permission'] = { title : __('Add User Permissions'), fields: [ { - 'fieldname': 'user', - 'label': __('For User'), - 'fieldtype': 'Link', - 'options': 'User', - 'reqd': 1, - 'onchange': function() { + fieldname: 'user', + label: __('For User'), + fieldtype: 'Link', + options: 'User', + reqd: 1, + onchange: function() { dialog.fields_dict.doctype.set_input(undefined); dialog.fields_dict.docname.set_input(undefined); dialog.set_df_property("docname", "hidden", 1); @@ -21,23 +21,23 @@ frappe.listview_settings['User Permission'] = { } }, { - 'fieldname': 'doctype', - 'label': __('Document Type'), - 'fieldtype': 'Link', - 'options': 'DocType', - 'reqd': 1, - 'onchange': function() { + fieldname: 'doctype', + label: __('Document Type'), + fieldtype: 'Link', + options: 'DocType', + reqd: 1, + onchange: function() { me.get_docname_options(dialog).then(options => { me.on_doctype_change(options, dialog); }); } }, { - 'fieldname': 'docname', - 'label': __('Document Name'), - 'fieldtype': 'Select', - 'hidden': 1, - 'onchange': function() { + fieldname: 'docname', + label: __('Document Name'), + fieldtype: 'Select', + hidden: 1, + onchange: function() { me.get_applicable_doctype(dialog).then(applicable => { me.get_multi_select_options(dialog, applicable).then(options => { me.on_docname_change(dialog, options, applicable); @@ -46,12 +46,12 @@ frappe.listview_settings['User Permission'] = { } }, { - 'fieldname': 'apply_to_all_doctypes', - 'label': __('Apply to all Documents Type'), - 'fieldtype': 'Check', - 'checked': 1, - 'hidden': 1, - 'onchange': function() { + fieldname: 'apply_to_all_doctypes', + label: __('Apply to all Documents Type'), + fieldtype: 'Check', + checked: 1, + hidden: 1, + onchange: function() { if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ me.get_applicable_doctype(dialog).then(applicable => { me.get_multi_select_options(dialog, applicable).then(options => { @@ -62,12 +62,12 @@ frappe.listview_settings['User Permission'] = { } }, { - "label": __("Applicable Document Types"), - "fieldname": "applicable_doctypes", - "fieldtype": "MultiCheck", - "options": [], - "columns": 2, - "hidden": 1 + label: __("Applicable Document Types"), + fieldname: "applicable_doctypes", + fieldtype: "MultiCheck", + options: [], + columns: 2, + hidden: 1 }, ], primary_action: (data) => { @@ -80,7 +80,7 @@ frappe.listview_settings['User Permission'] = { }, callback: function(r) { if (r.message == 1) { - frappe.show_alert({message:__("User Permissions Created Sucessfully"), indicator:'blue'}); + frappe.show_alert({message:__("User Permissions created sucessfully"), indicator:'blue'}); } else { frappe.show_alert({message:__("Nothing to update"), indicator:'red'}); @@ -100,18 +100,18 @@ frappe.listview_settings['User Permission'] = { title: __('Clear User Permissions'), fields: [ { - 'fieldname': 'user', - 'label': __('For User'), - 'fieldtype': 'Link', - 'options': 'User', - 'reqd': 1 + fieldname: 'user', + label: __('For User'), + fieldtype: 'Link', + options: 'User', + reqd: 1 }, { - 'fieldname': 'for_doctype', - 'label': __('For Document Type'), - 'fieldtype': 'Link', - 'options': 'DocType', - 'reqd': 1 + fieldname: 'for_doctype', + label: __('For Document Type'), + fieldtype: 'Link', + options: 'DocType', + reqd: 1 }, ], primary_action: (data) => { From ff1b2b1297966eff4fe533843a5d95051e06e109 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Fri, 1 Feb 2019 13:10:15 +0530 Subject: [PATCH 12/47] fix: founded bug --- .../doctype/user_permission/user_permission.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index cfd67fb5c4..92a04fec99 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -117,7 +117,7 @@ def check_applicable_doc_perm(user, doctype, docname): frappe.only_for('System Manager') applicable = [] all_perm = frappe.get_all('User Permission', - fields=['applicable_for'], + fields=['name'], filters={"user": user, "allow": doctype, "for_value": docname, @@ -157,16 +157,15 @@ def add_user_permissions(data): d = check_applicable_doc_perm(data.user, data.doctype, data.docname) exists = frappe.db.exists("User Permission", {"user": data.user, "allow": data.doctype, "for_value": data.docname, "apply_to_all_doctypes": 1}) - if exists: return 0 - if data.apply_to_all_doctypes == 1: + if data.apply_to_all_doctypes == 1 and not exists: remove_applicable(d, data.user, data.doctype, data.docname) insert_user_perm(data.user, data.doctype, data.docname, apply_to_all = 1) return 1 else: - remove_apply_to_all(data.user, data.doctype, data.docname) + removed = remove_apply_to_all(data.user, data.doctype, data.docname) update_applicable(d, data.applicable_doctypes, data.user, data.doctype, data.docname) for applicable in data.applicable_doctypes : - if applicable not in d: + if applicable not in d or removed: insert_user_perm(data.user, data.doctype, data.docname, applicable = applicable) return 1 return 0 @@ -176,10 +175,11 @@ def insert_user_perm(user, doctype, docname, apply_to_all=None, applicable=None) user_perm.user = user user_perm.allow = doctype user_perm.for_value = docname - if apply_to_all: - user_perm.apply_to_all_doctypes = 1 if applicable: user_perm.applicable_for = applicable + user_perm.apply_to_all_doctypes = 0 + else: + user_perm.apply_to_all_doctypes = 1 user_perm.insert() def remove_applicable(d, user, doctype, docname): @@ -198,6 +198,7 @@ def remove_apply_to_all(user, doctype, docname): AND `allow`=%s AND `for_value`=%s """,(user, doctype, docname)) + return 1 def update_applicable(already_applied, to_apply, user, doctype, docname): for applied in already_applied: From c50ad322254cc417018358390656e5b5716b70a9 Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Sun, 3 Feb 2019 05:20:30 +0500 Subject: [PATCH 13/47] fix(Query Report): Do not preformat before frappe.format --- frappe/public/js/frappe/views/reports/query_report.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 8a73bf8d83..58127b190d 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -639,7 +639,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { } const format_cell = (value, row, column, data) => { - return frappe.format(value == null ? '' : value, column, + return frappe.format(value, column, {for_print: false, always_show_decimals: true}, data); }; From c66a26cbd573e32a0b528ad42cd5f842b2ab6b14 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Mon, 4 Feb 2019 11:38:54 +0530 Subject: [PATCH 14/47] fix: codacy --- .../user_permission/user_permission.py | 19 ++++++++++--------- .../user_permission/user_permission_list.js | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index 92a04fec99..6263fd3143 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -162,10 +162,12 @@ def add_user_permissions(data): insert_user_perm(data.user, data.doctype, data.docname, apply_to_all = 1) return 1 else: - removed = remove_apply_to_all(data.user, data.doctype, data.docname) + remove_apply_to_all(data.user, data.doctype, data.docname) update_applicable(d, data.applicable_doctypes, data.user, data.doctype, data.docname) for applicable in data.applicable_doctypes : - if applicable not in d or removed: + if applicable not in d: + insert_user_perm(data.user, data.doctype, data.docname, applicable = applicable) + elif exists: insert_user_perm(data.user, data.doctype, data.docname, applicable = applicable) return 1 return 0 @@ -192,13 +194,12 @@ def remove_applicable(d, user, doctype, docname): """, (user, applicable_for, doctype, docname)) def remove_apply_to_all(user, doctype, docname): - frappe.db.sql("""DELETE from `tabUser Permission` - WHERE `user`=%s - AND `apply_to_all_doctypes`=1 - AND `allow`=%s - AND `for_value`=%s - """,(user, doctype, docname)) - return 1 + q = frappe.db.sql("""DELETE from `tabUser Permission` + WHERE `user`=%s + AND `apply_to_all_doctypes`=1 + AND `allow`=%s + AND `for_value`=%s + """,(user, doctype, docname)) def update_applicable(already_applied, to_apply, user, doctype, docname): for applied in already_applied: diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index f4f2578797..1499d1265e 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -79,7 +79,7 @@ frappe.listview_settings['User Permission'] = { data : data }, callback: function(r) { - if (r.message == 1) { + if(r.message === 1) { frappe.show_alert({message:__("User Permissions created sucessfully"), indicator:'blue'}); } else { frappe.show_alert({message:__("Nothing to update"), indicator:'red'}); @@ -230,7 +230,7 @@ frappe.listview_settings['User Permission'] = { dialog.set_primary_action("Update"); dialog.set_title("Update User Permissions"); dialog.set_df_property("applicable_doctypes", "options", options); - if(dialog.fields_dict.applicable_doctypes.get_checked_options().length == options.length) { + if(dialog.fields_dict.applicable_doctypes.get_checked_options().length == options.length){ dialog.set_df_property("applicable_doctypes", "hidden", 1); dialog.set_value("apply_to_all_doctypes", "checked", 1); } else { From ff1d430af6f4c1b10c9bb40ecbe543d855487ae1 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 4 Feb 2019 13:51:38 +0530 Subject: [PATCH 15/47] fix: Set field default based on user permissions --- .../user_permission/user_permission.py | 3 ++ frappe/model/create_new.py | 34 +++++++++++-------- frappe/public/js/frappe/model/create_new.js | 28 ++++++--------- frappe/public/js/frappe/model/perm.js | 22 ++++++------ frappe/tests/test_permissions.py | 10 ++++++ 5 files changed, 53 insertions(+), 44 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index 43dff47745..f53338fd1d 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -42,6 +42,9 @@ def get_user_permissions(user=None): if not user: user = frappe.session.user + if user == "Administrator": + return {} + cached_user_permissions = frappe.cache().hget("user_permissions", user) if cached_user_permissions is not None: diff --git a/frappe/model/create_new.py b/frappe/model/create_new.py index c6bcc42f06..b48f279a5e 100644 --- a/frappe/model/create_new.py +++ b/frappe/model/create_new.py @@ -12,6 +12,7 @@ import frappe.defaults from frappe.model.db_schema import type_map import copy from frappe.core.doctype.user_permission.user_permission import get_user_permissions +from frappe.permissions import get_allowed_docs_for_doctype def get_new_doc(doctype, parent_doc = None, parentfield = None, as_dict=False): if doctype not in frappe.local.new_doc_templates: @@ -53,36 +54,39 @@ def set_user_and_static_default_values(doc): for df in doc.meta.get("fields"): if df.fieldtype in type_map: - user_default_value = get_user_default_value(df, defaults, user_permissions) + # user permissions for link options + doctype_user_permissions = user_permissions.get(df.options, []) + # Allowed records for the reference doctype (link field) + allowed_records = get_allowed_docs_for_doctype(doctype_user_permissions, df.parent) + + user_default_value = get_user_default_value(df, defaults, doctype_user_permissions, allowed_records) if user_default_value is not None: doc.set(df.fieldname, user_default_value) else: if df.fieldname != doc.meta.title_field: - static_default_value = get_static_default_value(df, user_permissions) + static_default_value = get_static_default_value(df, doctype_user_permissions, allowed_records) if static_default_value is not None: doc.set(df.fieldname, static_default_value) -def get_user_default_value(df, defaults, user_permissions): +def get_user_default_value(df, defaults, doctype_user_permissions, allowed_records): # don't set defaults for "User" link field using User Permissions! if df.fieldtype == "Link" and df.options != "User": # 1 - look in user permissions only for document_type==Setup # We don't want to include permissions of transactions to be used for defaults. - if (frappe.get_meta(df.options).document_type=="Setup" - and user_permissions_exist(df, user_permissions) - and len(user_permissions.get(df.options))==1): - return user_permissions.get(df.options)[0].get("doc") + if frappe.get_meta(df.options).document_type=="Setup" and len(allowed_records)==1: + return allowed_records[0] # 2 - Look in user defaults user_default = defaults.get(df.fieldname) - is_allowed_user_default = user_default and (not user_permissions_exist(df, user_permissions) - or (user_default in user_permissions.get(df.options, []))) + is_allowed_user_default = user_default and (not user_permissions_exist(df, doctype_user_permissions) + or user_default in allowed_records) # is this user default also allowed as per user permissions? if is_allowed_user_default: return user_default -def get_static_default_value(df, user_permissions): +def get_static_default_value(df, doctype_user_permissions, allowed_records): # 3 - look in default of docfield if df.get("default"): if df.default == "__user": @@ -93,8 +97,8 @@ def get_static_default_value(df, user_permissions): elif not df.default.startswith(":"): # a simple default value - is_allowed_default_value = (not user_permissions_exist(df, user_permissions) - or (df.default in user_permissions.get(df.options, []))) + is_allowed_default_value = (not user_permissions_exist(df, doctype_user_permissions) + or (df.default in allowed_records)) if df.fieldtype!="Link" or df.options=="User" or is_allowed_default_value: return df.default @@ -126,10 +130,10 @@ def set_dynamic_default_values(doc, parent_doc, parentfield): if parentfield: doc["parentfield"] = parentfield -def user_permissions_exist(df, user_permissions): +def user_permissions_exist(df, doctype_user_permissions): return (df.fieldtype=="Link" and not getattr(df, "ignore_user_permissions", False) - and df.options in (user_permissions or [])) + and doctype_user_permissions) def get_default_based_on_another_field(df, user_permissions, parent_doc): # default value based on another document @@ -139,7 +143,7 @@ def get_default_based_on_another_field(df, user_permissions, parent_doc): ref_fieldname = ref_doctype.lower().replace(" ", "_") reference_name = parent_doc.get(ref_fieldname) if parent_doc else frappe.db.get_default(ref_fieldname) default_value = frappe.db.get_value(ref_doctype, reference_name, df.fieldname) - is_allowed_default_value = (not user_permissions_exist(df, user_permissions) or + is_allowed_default_value = (not user_permissions_exist(df, user_permissions.get(df.options)) or (default_value in get_allowed_docs_for_doctype(user_permissions[df.options], df.parent))) # is this allowed as per user permissions diff --git a/frappe/public/js/frappe/model/create_new.js b/frappe/public/js/frappe/model/create_new.js index fbbc9a24c5..2ec52feb64 100644 --- a/frappe/public/js/frappe/model/create_new.js +++ b/frappe/public/js/frappe/model/create_new.js @@ -87,10 +87,8 @@ $.extend(frappe.model, { var doctype = doc.doctype; var docfields = frappe.meta.docfield_list[doctype] || []; var updated = []; - for(var fid=0;fid { - return perm.doc === docname && (perm.applicable_for === doc.doctype || !perm.applicable_for); - }); - } + && allowed_records.length); // don't set defaults for "User" link field using User Permissions! if (df.fieldtype==="Link" && df.options!=="User") { // 1 - look in user permissions for document_type=="Setup". // We don't want to include permissions of transactions to be used for defaults. if (df.linked_document_type==="Setup" - && has_user_permissions && user_permissions[df.options].length===1) { - return user_permissions[df.options][0].doc; + && has_user_permissions && allowed_records.length===1) { + return allowed_records[0]; } if(!df.ignore_user_permissions) { @@ -165,7 +161,7 @@ $.extend(frappe.model, { } var is_allowed_user_default = user_default && - (!has_user_permissions || is_doc_allowed(df.options, user_default)); + (!has_user_permissions || allowed_records.includes(user_default)); // is this user default also allowed as per user permissions? if (is_allowed_user_default) { @@ -190,7 +186,7 @@ $.extend(frappe.model, { } else if (df["default"][0]===":") { var boot_doc = frappe.model.get_default_from_boot_docs(df, doc, parent_doc); - var is_allowed_boot_doc = !has_user_permissions || is_doc_allowed(df.options, boot_doc); + var is_allowed_boot_doc = !has_user_permissions || allowed_records.includes(boot_doc); if (is_allowed_boot_doc) { return boot_doc; @@ -201,7 +197,7 @@ $.extend(frappe.model, { } // is this default value is also allowed as per user permissions? - var is_allowed_default = !has_user_permissions || is_doc_allowed(df.options, df.default); + var is_allowed_default = !has_user_permissions || allowed_records.includes(df.default); if (df.fieldtype!=="Link" || df.options==="User" || is_allowed_default) { return df["default"]; } @@ -342,5 +338,3 @@ frappe.new_doc = function (doctype, opts, init_callback) { }); } - - diff --git a/frappe/public/js/frappe/model/perm.js b/frappe/public/js/frappe/model/perm.js index 60ae89a3da..2396962b94 100644 --- a/frappe/public/js/frappe/model/perm.js +++ b/frappe/public/js/frappe/model/perm.js @@ -151,18 +151,10 @@ $.extend(frappe.perm, { let rules = {}; let fields_to_check = frappe.meta.get_fields_to_check_permissions(doctype); $.each(fields_to_check, (i, df) => { - const user_permissions_for_doctype = user_permissions[df.options]; - // check if there are any user permission applicable for parent doctype - const has_user_permission = user_permissions_for_doctype ? user_permissions_for_doctype - .some(perm => !perm.applicable_for || perm.applicable_for === doctype) : false; - - if (has_user_permission) { - rules[df.label] = []; - user_permissions_for_doctype.map(permission => { - if (!permission.applicable_for || permission.applicable_for === doctype) { - rules[df.label].push(permission.doc); - } - }); + const user_permissions_for_doctype = user_permissions[df.options] || []; + const allowed_records = frappe.perm.get_allowed_docs_for_doctype(user_permissions_for_doctype, doctype); + if (allowed_records.length) { + rules[df.label] = allowed_records; } }); if (!$.isEmptyObject(rules)) { @@ -260,4 +252,10 @@ $.extend(frappe.perm, { return status === "None" ? false : true; }, + + get_allowed_docs_for_doctype: (user_permissions, doctype) => { + return (user_permissions || []).filter(perm => { + return (perm.applicable_for === doctype || !perm.applicable_for); + }).map(perm => perm.doc); + } }); diff --git a/frappe/tests/test_permissions.py b/frappe/tests/test_permissions.py index 465034d7a2..71f8a4c20d 100644 --- a/frappe/tests/test_permissions.py +++ b/frappe/tests/test_permissions.py @@ -82,12 +82,22 @@ class TestPermissions(unittest.TestCase): self.assertFalse("-test-blog-post" in names) def test_default_values(self): + doc = frappe.new_doc("Blog Post") + self.assertFalse(doc.get("blog_category")) + + # Fetch default based on single user permission add_user_permission("Blog Category", "_Test Blog Category 1", "test2@example.com") frappe.set_user("test2@example.com") doc = frappe.new_doc("Blog Post") self.assertEqual(doc.get("blog_category"), "_Test Blog Category 1") + # Don't fetch default if user permissions is more than 1 + add_user_permission("Blog Category", "_Test Blog Category 2", "test2@example.com") + + doc = frappe.new_doc("Blog Post") + self.assertFalse(doc.get("blog_category")) + def test_user_link_match_doc(self): blogger = frappe.get_doc("Blogger", "_Test Blogger 1") blogger.user = "test2@example.com" From b38c018c3779ea4017b035539be9113e9e142be3 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Mon, 4 Feb 2019 15:37:49 +0530 Subject: [PATCH 16/47] Testing: unit test-cases --- .../user_permission/test_user_permission.py | 86 ++++++++++++++++++- .../user_permission/user_permission.py | 2 +- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/user_permission/test_user_permission.py b/frappe/core/doctype/user_permission/test_user_permission.py index 157fa44ae2..6d02e5a608 100644 --- a/frappe/core/doctype/user_permission/test_user_permission.py +++ b/frappe/core/doctype/user_permission/test_user_permission.py @@ -2,9 +2,91 @@ # Copyright (c) 2017, Frappe Technologies and Contributors # See license.txt from __future__ import unicode_literals +from frappe.core.doctype.user_permission.user_permission import add_user_permissions -#import frappe +import frappe import unittest class TestUserPermission(unittest.TestCase): - pass + def test_apply_to_all(self): + user = get_user() + created = add_user_permissions({ + "user": user.name, + "doctype":"User", + "docname":user.name , + "apply_to_all_doctypes":1}) + self.assertEquals(created, 1) + + def test_for_applicables_on_update_from_apply_to_all(self): + user = get_user() + create = add_user_permissions({ + "user": user.name, "doctype":"user", + "docname":user.name , + "apply_to_all_doctypes":0, + "applicable_doctypes":["Chat Room","Chat Message"]}) + frappe.db.commit() + + removed_apply_to_all = frappe.db.exists("User Permission", { + "user": user.name, + "allow": "User", + "for_value": user.name, + "apply_to_all_doctypes": 1}) + created_applicable_first = frappe.db.exists("User Permission", { + "user": user.name, + "allow": "User", + "for_value": user.name, + "apply_to_all_doctypes": 0, + "applicable_for": "Chat Room"}) + created_applicable_second = frappe.db.exists("User Permission", { + "user": user.name, + "allow": "User", + "for_value": user.name, + "apply_to_all_doctypes": 0, + "applicable_for": "Chat Message"}) + + self.assertIsNone(removed_apply_to_all) + self.assertIsNotNone(created_applicable_first) + self.assertIsNotNone(created_applicable_second) + self.assertEquals(create, 1) + + def test_for_apply_to_all_on_update_from_applicables(self): + user = get_user() + created = add_user_permissions({ + "user": user.name, + "doctype":"User", + "docname":user.name , + "apply_to_all_doctypes":1}) + created_apply_to_all = frappe.db.exists("User Permission", { + "user": user.name, + "allow": "User", + "for_value": user.name, + "apply_to_all_doctypes": 1}) + removed_applicable_first = frappe.db.exists("User Permission", { + "user": user.name, + "allow": "User", + "for_value": user.name, + "apply_to_all_doctypes": 0, + "applicable_for": "Chat Room"}) + removed_applicable_second = frappe.db.exists("User Permission", { + "user": user.name, "allow": "User", + "for_value": user.name, + "apply_to_all_doctypes": 0, + "applicable_for": "Chat Message"}) + + + self.assertIsNotNone(created_apply_to_all) + self.assertIsNone(removed_applicable_first) + self.assertIsNone(removed_applicable_second) + self.assertEquals(created, 1) + +def get_user(): + if frappe.db.exists('User', 'test_bulk_creation_update@example.com'): + return frappe.get_doc('User', 'test_bulk_creation_update@example.com') + else: + user = frappe.new_doc('User') + user.email = 'test_bulk_creation_update@example.com' + user.first_name = 'Test_Bulk_Creation' + user.add_roles("System Manager") + return user + + diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index 6263fd3143..c28a198036 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -194,7 +194,7 @@ def remove_applicable(d, user, doctype, docname): """, (user, applicable_for, doctype, docname)) def remove_apply_to_all(user, doctype, docname): - q = frappe.db.sql("""DELETE from `tabUser Permission` + frappe.db.sql("""DELETE from `tabUser Permission` WHERE `user`=%s AND `apply_to_all_doctypes`=1 AND `allow`=%s From a7a4679a09221100d64d66be9b2b41310f138ad6 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 5 Feb 2019 18:41:19 +0530 Subject: [PATCH 17/47] fix: tests for user permissions --- frappe/model/document.py | 4 ++-- frappe/tests/test_permissions.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index 6fdbf633d2..c635db45a5 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -166,10 +166,10 @@ class Document(BaseDocument): self.latest = frappe.get_doc(self.doctype, self.name) return self.latest - def check_permission(self, permtype='read', permlabel=None): + def check_permission(self, permtype='read', permlevel=None): """Raise `frappe.PermissionError` if not permitted""" if not self.has_permission(permtype): - self.raise_no_permission_to(permlabel or permtype) + self.raise_no_permission_to(permlevel or permtype) def has_permission(self, permtype="read", verbose=False): """Call `frappe.has_permission` if `self.flags.ignore_permissions` diff --git a/frappe/tests/test_permissions.py b/frappe/tests/test_permissions.py index 71f8a4c20d..52e42a8900 100644 --- a/frappe/tests/test_permissions.py +++ b/frappe/tests/test_permissions.py @@ -93,8 +93,8 @@ class TestPermissions(unittest.TestCase): self.assertEqual(doc.get("blog_category"), "_Test Blog Category 1") # Don't fetch default if user permissions is more than 1 - add_user_permission("Blog Category", "_Test Blog Category 2", "test2@example.com") - + add_user_permission("Blog Category", "_Test Blog Category", "test2@example.com", ignore_permissions=True) + frappe.clear_cache() doc = frappe.new_doc("Blog Post") self.assertFalse(doc.get("blog_category")) @@ -372,7 +372,7 @@ class TestPermissions(unittest.TestCase): posts = frappe.get_all('Blog Post', fields=['name', 'blogger']) # Get all posts for admin - self.assertEqual(len(posts), 4) + self.assertEqual(len(posts), 5) frappe.set_user('test2@example.com') From 8b759e049f4988d5949666e317689117ba0e882f Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Tue, 5 Feb 2019 19:04:28 +0530 Subject: [PATCH 18/47] fix: changes requested --- .../user_permission/test_user_permission.py | 3 +- .../user_permission/user_permission.py | 8 ++-- .../user_permission/user_permission_list.js | 41 +++++-------------- 3 files changed, 15 insertions(+), 37 deletions(-) diff --git a/frappe/core/doctype/user_permission/test_user_permission.py b/frappe/core/doctype/user_permission/test_user_permission.py index 6d02e5a608..a974aadb19 100644 --- a/frappe/core/doctype/user_permission/test_user_permission.py +++ b/frappe/core/doctype/user_permission/test_user_permission.py @@ -20,7 +20,8 @@ class TestUserPermission(unittest.TestCase): def test_for_applicables_on_update_from_apply_to_all(self): user = get_user() create = add_user_permissions({ - "user": user.name, "doctype":"user", + "user": user.name, + "doctype":"User", "docname":user.name , "apply_to_all_doctypes":0, "applicable_doctypes":["Chat Room","Chat Message"]}) diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index c28a198036..016e5a8a07 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -116,17 +116,15 @@ def get_permitted_documents(doctype): def check_applicable_doc_perm(user, doctype, docname): frappe.only_for('System Manager') applicable = [] - all_perm = frappe.get_all('User Permission', + doc_exists = frappe.get_all('User Permission', fields=['name'], filters={"user": user, "allow": doctype, "for_value": docname, "apply_to_all_doctypes":1, }, limit=1) - if len(all_perm) > 0: - data = get_linked_doctypes(doctype) - for key in data: - applicable.append(key) + if doc_exists: + applicable = get_linked_doctypes(doctype).keys() else: data = frappe.get_all('User Permission', fields=['applicable_for'], diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 1499d1265e..140d7f093f 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -27,22 +27,23 @@ frappe.listview_settings['User Permission'] = { options: 'DocType', reqd: 1, onchange: function() { - me.get_docname_options(dialog).then(options => { - me.on_doctype_change(options, dialog); - }); + me.on_doctype_change(dialog); } }, { fieldname: 'docname', label: __('Document Name'), - fieldtype: 'Select', + fieldtype: 'Dynamic Link', + options: 'doctype', hidden: 1, onchange: function() { - me.get_applicable_doctype(dialog).then(applicable => { - me.get_multi_select_options(dialog, applicable).then(options => { - me.on_docname_change(dialog, options, applicable); + if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ + me.get_applicable_doctype(dialog).then(applicable => { + me.get_multi_select_options(dialog, applicable).then(options => { + me.on_docname_change(dialog, options, applicable); + }); }); - }); + } } }, { @@ -196,29 +197,7 @@ frappe.listview_settings['User Permission'] = { }); }, - get_docname_options: function(dialog) { - return new Promise(resolve => { - var options = []; - if(dialog.fields_dict.doctype.value){ - frappe.call({ - method:"frappe.client.get_list", - async: false, - args: { - doctype: dialog.fields_dict.doctype.value, - }, - callback: function(r) { - for(var d in r.message) { - options.push(r.message[d].name); - } - resolve(options); - } - }); - } - }); - }, - - on_doctype_change: function(options, dialog) { - dialog.set_df_property("docname", "options", options); + on_doctype_change: function(dialog) { dialog.set_df_property("docname", "hidden", 0); dialog.set_df_property("docname", "reqd", 1); dialog.set_df_property("apply_to_all_doctypes", "hidden", 0); From 515d2628819ab312c5a5b743cd14880b400b096c Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 6 Feb 2019 11:12:39 +0530 Subject: [PATCH 19/47] Added inner button --- frappe/core/doctype/user_permission/user_permission_list.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 140d7f093f..d25e9be674 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -2,7 +2,7 @@ frappe.listview_settings['User Permission'] = { onload: function(list_view) { var me = this; - list_view.page.add_menu_item(__("Create/Update User Permissions"), function() { + list_view.page.add_inner_button( __("Create/Update User Permissions"), function() { var dialog =new frappe.ui.Dialog({ title : __('Add User Permissions'), fields: [ @@ -95,8 +95,7 @@ frappe.listview_settings['User Permission'] = { }); dialog.show(); }); - - list_view.page.add_menu_item(__("Clear User Permissions"), () => { + list_view.page.add_inner_button( __("Clear User Permissions"), function() { const dialog = new frappe.ui.Dialog({ title: __('Clear User Permissions'), fields: [ From 86f37dc0ea4e02d811e062401428894228ec50ca Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 6 Feb 2019 12:34:10 +0530 Subject: [PATCH 20/47] Code refractor --- .../user_permission/test_user_permission.py | 85 ++++++++----------- .../user_permission/user_permission_list.js | 4 +- 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/frappe/core/doctype/user_permission/test_user_permission.py b/frappe/core/doctype/user_permission/test_user_permission.py index a974aadb19..f002664eea 100644 --- a/frappe/core/doctype/user_permission/test_user_permission.py +++ b/frappe/core/doctype/user_permission/test_user_permission.py @@ -10,40 +10,19 @@ import unittest class TestUserPermission(unittest.TestCase): def test_apply_to_all(self): user = get_user() - created = add_user_permissions({ - "user": user.name, - "doctype":"User", - "docname":user.name , - "apply_to_all_doctypes":1}) + param = get_params(user, apply = 1) + created = add_user_permissions(param) self.assertEquals(created, 1) def test_for_applicables_on_update_from_apply_to_all(self): user = get_user() - create = add_user_permissions({ - "user": user.name, - "doctype":"User", - "docname":user.name , - "apply_to_all_doctypes":0, - "applicable_doctypes":["Chat Room","Chat Message"]}) + param = get_params(user, applicable = ["Chat Room", "Chat Message"]) + create = add_user_permissions(param) frappe.db.commit() - removed_apply_to_all = frappe.db.exists("User Permission", { - "user": user.name, - "allow": "User", - "for_value": user.name, - "apply_to_all_doctypes": 1}) - created_applicable_first = frappe.db.exists("User Permission", { - "user": user.name, - "allow": "User", - "for_value": user.name, - "apply_to_all_doctypes": 0, - "applicable_for": "Chat Room"}) - created_applicable_second = frappe.db.exists("User Permission", { - "user": user.name, - "allow": "User", - "for_value": user.name, - "apply_to_all_doctypes": 0, - "applicable_for": "Chat Message"}) + removed_apply_to_all = frappe.db.exists("User Permission", get_exists_param(user)) + created_applicable_first = frappe.db.exists("User Permission", get_exists_param(user, applicable = "Chat Room")) + created_applicable_second = frappe.db.exists("User Permission", get_exists_param(user, applicable = "Chat Message")) self.assertIsNone(removed_apply_to_all) self.assertIsNotNone(created_applicable_first) @@ -52,27 +31,11 @@ class TestUserPermission(unittest.TestCase): def test_for_apply_to_all_on_update_from_applicables(self): user = get_user() - created = add_user_permissions({ - "user": user.name, - "doctype":"User", - "docname":user.name , - "apply_to_all_doctypes":1}) - created_apply_to_all = frappe.db.exists("User Permission", { - "user": user.name, - "allow": "User", - "for_value": user.name, - "apply_to_all_doctypes": 1}) - removed_applicable_first = frappe.db.exists("User Permission", { - "user": user.name, - "allow": "User", - "for_value": user.name, - "apply_to_all_doctypes": 0, - "applicable_for": "Chat Room"}) - removed_applicable_second = frappe.db.exists("User Permission", { - "user": user.name, "allow": "User", - "for_value": user.name, - "apply_to_all_doctypes": 0, - "applicable_for": "Chat Message"}) + param = get_params(user, apply = 1) + created = add_user_permissions(param) + created_apply_to_all = frappe.db.exists("User Permission", get_exists_param(user)) + removed_applicable_first = frappe.db.exists("User Permission", get_exists_param(user, applicable = "Chat Room")) + removed_applicable_second = frappe.db.exists("User Permission", get_exists_param(user, applicable = "Chat Message")) self.assertIsNotNone(created_apply_to_all) @@ -90,4 +53,28 @@ def get_user(): user.add_roles("System Manager") return user +def get_params(user, apply = None , applicable= None): + param = { + "user": user.name, + "doctype":"User", + "docname":user.name + } + if apply: + param.update({"apply_to_all_doctypes": 1}) + param.update({"applicable_doctypes": []}) + if applicable: + param.update({"apply_to_all_doctypes": 0}) + param.update({"applicable_doctypes": applicable}) + return param +def get_exists_param(user, applicable = None): + param = { + "user": user.name, + "allow": "User", + "for_value": user.name, + } + if applicable: + param.update({"applicable_for": applicable}) + else: + param.update({"apply_to_all_doctypes": 1}) + return param diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index d25e9be674..b5b94891a0 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -3,7 +3,7 @@ frappe.listview_settings['User Permission'] = { onload: function(list_view) { var me = this; list_view.page.add_inner_button( __("Create/Update User Permissions"), function() { - var dialog =new frappe.ui.Dialog({ + let dialog =new frappe.ui.Dialog({ title : __('Add User Permissions'), fields: [ { @@ -208,7 +208,7 @@ frappe.listview_settings['User Permission'] = { dialog.set_primary_action("Update"); dialog.set_title("Update User Permissions"); dialog.set_df_property("applicable_doctypes", "options", options); - if(dialog.fields_dict.applicable_doctypes.get_checked_options().length == options.length){ + if(dialog.fields_dict.applicable_doctypes.get_checked_options().length == options.length) { dialog.set_df_property("applicable_doctypes", "hidden", 1); dialog.set_value("apply_to_all_doctypes", "checked", 1); } else { From 1bb4c6275f9b4d119b5a8dedb3b0d96eab8e6412 Mon Sep 17 00:00:00 2001 From: Saif Date: Wed, 6 Feb 2019 12:18:41 +0500 Subject: [PATCH 21/47] fix: Don't send attachment/download header with PDF files (#6881) --- frappe/utils/print_format.py | 4 ++-- frappe/utils/response.py | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/frappe/utils/print_format.py b/frappe/utils/print_format.py index a254f0b8d1..084f4f381c 100644 --- a/frappe/utils/print_format.py +++ b/frappe/utils/print_format.py @@ -90,13 +90,13 @@ def download_pdf(doctype, name, format=None, doc=None, no_letterhead=0): html = frappe.get_print(doctype, name, format, doc=doc, no_letterhead=no_letterhead) frappe.local.response.filename = "{name}.pdf".format(name=name.replace(" ", "-").replace("/", "-")) frappe.local.response.filecontent = get_pdf(html) - frappe.local.response.type = "download" + frappe.local.response.type = "pdf" @frappe.whitelist() def report_to_pdf(html, orientation="Landscape"): frappe.local.response.filename = "report.pdf" frappe.local.response.filecontent = get_pdf(html, {"orientation": orientation}) - frappe.local.response.type = "download" + frappe.local.response.type = "pdf" @frappe.whitelist() def print_by_server(doctype, name, print_format=None, doc=None, no_letterhead=0): diff --git a/frappe/utils/response.py b/frappe/utils/response.py index 8b19fc4607..b1f0ddb42d 100644 --- a/frappe/utils/response.py +++ b/frappe/utils/response.py @@ -42,6 +42,7 @@ def build_response(response_type=None): 'txt': as_txt, 'download': as_raw, 'json': as_json, + 'pdf': as_pdf, 'page': as_page, 'redirect': redirect, 'binary': as_binary @@ -84,6 +85,13 @@ def as_json(): response.data = json.dumps(frappe.local.response, default=json_handler, separators=(',',':')) return response +def as_pdf(): + response = Response() + response.mimetype = "application/pdf" + response.headers["Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8") + response.data = frappe.response['filecontent'] + return response + def as_binary(): response = Response() response.mimetype = 'application/octet-stream' From 5d84aa781327e9a9773830ce83e05b884e91aa3e Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 6 Feb 2019 14:57:19 +0530 Subject: [PATCH 22/47] inner button label --- frappe/core/doctype/user_permission/user_permission_list.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index b5b94891a0..d9c04c34ac 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -2,7 +2,7 @@ frappe.listview_settings['User Permission'] = { onload: function(list_view) { var me = this; - list_view.page.add_inner_button( __("Create/Update User Permissions"), function() { + list_view.page.add_inner_button( __("Add / Update"), function() { let dialog =new frappe.ui.Dialog({ title : __('Add User Permissions'), fields: [ @@ -95,7 +95,7 @@ frappe.listview_settings['User Permission'] = { }); dialog.show(); }); - list_view.page.add_inner_button( __("Clear User Permissions"), function() { + list_view.page.add_inner_button( __("Bulk Delete"), function() { const dialog = new frappe.ui.Dialog({ title: __('Clear User Permissions'), fields: [ @@ -140,7 +140,7 @@ frappe.listview_settings['User Permission'] = { }); }, - primary_action_label: __('Clear') + primary_action_label: __('Delete') }); dialog.show(); From 8b860a8ce75dda342e8d8efa2a3c941e7acc8cf7 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 6 Feb 2019 16:10:39 +0530 Subject: [PATCH 23/47] Fix: onchange of Docname --- .../doctype/user_permission/user_permission_list.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index d9c04c34ac..8f6379f78d 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -37,12 +37,15 @@ frappe.listview_settings['User Permission'] = { options: 'doctype', hidden: 1, onchange: function() { - if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ - me.get_applicable_doctype(dialog).then(applicable => { - me.get_multi_select_options(dialog, applicable).then(options => { - me.on_docname_change(dialog, options, applicable); + let field = dialog.fields_dict["docname"]; + if(field.value != field.last_value) { + if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ + me.get_applicable_doctype(dialog).then(applicable => { + me.get_multi_select_options(dialog, applicable).then(options => { + me.on_docname_change(dialog, options, applicable); + }); }); - }); + } } } }, From 73c67481dec25b9f7deb4ed69cdf2d04baf59f59 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 6 Feb 2019 16:27:46 +0530 Subject: [PATCH 24/47] test: Change total post length --- frappe/tests/test_permissions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/tests/test_permissions.py b/frappe/tests/test_permissions.py index 52e42a8900..32eca81fcd 100644 --- a/frappe/tests/test_permissions.py +++ b/frappe/tests/test_permissions.py @@ -372,7 +372,7 @@ class TestPermissions(unittest.TestCase): posts = frappe.get_all('Blog Post', fields=['name', 'blogger']) # Get all posts for admin - self.assertEqual(len(posts), 5) + self.assertEqual(len(posts), 4) frappe.set_user('test2@example.com') From 5c14f2c256660bf8f15db09d876b098ff859a53c Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Wed, 6 Feb 2019 21:04:20 +0530 Subject: [PATCH 25/47] remove distinct from count We shouldn't do a distinct count on primary key, as it is not required, and is also slow. See below query run times. MariaDB [c6b2c772b91fd3d8]> select count(distinct name) from `tabStock Ledger Entry`; +----------------------+ | count(distinct name) | +----------------------+ | 3268372 | +----------------------+ 1 row in set (14.65 sec) MariaDB [c6b2c772b91fd3d8]> select count(name) from `tabStock Ledger Entry`; +-------------+ | count(name) | +-------------+ | 3268372 | +-------------+ 1 row in set (0.24 sec) --- frappe/public/js/frappe/list/list_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 29bdbd1b92..7a34bb3cb5 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -597,7 +597,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { args: { doctype: this.doctype, filters: this.get_filters_for_args(), - fields: [`count(distinct ${frappe.model.get_full_column_name('name', this.doctype)}) as total_count`], + fields: [`count(${frappe.model.get_full_column_name('name', this.doctype)}) as total_count`], } }).then(r => { this.total_count = r.message.values[0][0] || current_count; From 53930a12ebe42200b0743179a7fff86b73dcc55a Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Wed, 6 Feb 2019 22:32:26 +0530 Subject: [PATCH 26/47] Close read_only db connection Close read only db connection, else one might end up with 'Too many connections' error from mysql. --- frappe/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/__init__.py b/frappe/__init__.py index c540652c8c..d4a4a231ff 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -501,6 +501,7 @@ def read_only(): retval = fn(*args, **get_newargs(fn, kwargs)) if local and hasattr(local, 'master_db'): + local.db.close() local.db = local.master_db return retval From 06892149a997006a3b35e3984ef0d20bd7378a75 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 7 Feb 2019 17:48:05 +0530 Subject: [PATCH 27/47] Show permission failure message based on passed user - only if user passed is equal to session user or if no user is passed --- frappe/permissions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index 7553cb5dc5..e53608468c 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -24,8 +24,10 @@ def print_has_permission_check_logs(func): def inner(*args, **kwargs): frappe.flags['has_permission_check_logs'] = [] result = func(*args, **kwargs) + self_perm_check = True if not kwargs['user'] else kwargs['user'] == frappe.session.user # print only if access denied - if not result: + # and if user is checking his own permission + if not result and self_perm_check: msgprint(('
').join(frappe.flags['has_permission_check_logs'])) frappe.flags.pop('has_permission_check_logs', None) return result From 5ed640eb32c938e80f312328c9780e4379466402 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Thu, 7 Feb 2019 18:07:45 +0530 Subject: [PATCH 28/47] fix: requested changes --- .../doctype/user_permission/user_permission_list.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 8f6379f78d..1f0fe20bda 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -42,6 +42,7 @@ frappe.listview_settings['User Permission'] = { if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ me.get_applicable_doctype(dialog).then(applicable => { me.get_multi_select_options(dialog, applicable).then(options => { + me.applicable_options = options; me.on_docname_change(dialog, options, applicable); }); }); @@ -51,17 +52,13 @@ frappe.listview_settings['User Permission'] = { }, { fieldname: 'apply_to_all_doctypes', - label: __('Apply to all Documents Type'), + label: __('Apply to all Documents Types'), fieldtype: 'Check', checked: 1, hidden: 1, onchange: function() { if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ - me.get_applicable_doctype(dialog).then(applicable => { - me.get_multi_select_options(dialog, applicable).then(options => { - me.on_apply_to_all_doctypes_change(dialog,options); - }); - }); + me.on_apply_to_all_doctypes_change(dialog, me.applicable_options); } } }, @@ -213,7 +210,6 @@ frappe.listview_settings['User Permission'] = { dialog.set_df_property("applicable_doctypes", "options", options); if(dialog.fields_dict.applicable_doctypes.get_checked_options().length == options.length) { dialog.set_df_property("applicable_doctypes", "hidden", 1); - dialog.set_value("apply_to_all_doctypes", "checked", 1); } else { dialog.set_df_property("applicable_doctypes", "hidden", 0); dialog.set_df_property("apply_to_all_doctypes", "checked", 0); @@ -221,7 +217,6 @@ frappe.listview_settings['User Permission'] = { } else { dialog.set_primary_action("Submit"); dialog.set_title("Add User Permissions"); - dialog.set_value("apply_to_all_doctypes", "checked",1); dialog.set_df_property("applicable_doctypes", "options", options); dialog.set_df_property("applicable_doctypes", "hidden", 1); } @@ -232,8 +227,8 @@ frappe.listview_settings['User Permission'] = { dialog.set_df_property("applicable_doctypes", "hidden", 0); dialog.set_df_property("applicable_doctypes", "options", options); } else { - dialog.set_df_property("applicable_doctypes", "hidden", 1); dialog.set_df_property("applicable_doctypes", "options", options); + dialog.set_df_property("applicable_doctypes", "hidden", 1); } } }; \ No newline at end of file From 1d5310166d72ca4b05609e64b13b9def3e13403a Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 7 Feb 2019 18:18:01 +0530 Subject: [PATCH 29/47] fix: Set default print language in Notification --- frappe/email/doctype/notification/notification.py | 11 +++++++++-- frappe/email/queue.py | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/frappe/email/doctype/notification/notification.py b/frappe/email/doctype/notification/notification.py index a3f43f716d..acddf36777 100644 --- a/frappe/email/doctype/notification/notification.py +++ b/frappe/email/doctype/notification/notification.py @@ -212,8 +212,15 @@ def get_context(context): please enable Allow Print For {0} in Print Settings""".format(status)), title=_("Error in Notification")) else: - return [{"print_format_attachment":1, "doctype":doc.doctype, "name": doc.name, - "print_format":self.print_format, "print_letterhead": print_settings.with_letterhead}] + return [{ + "print_format_attachment": 1, + "doctype": doc.doctype, + "name": doc.name, + "print_format": self.print_format, + "print_letterhead": print_settings.with_letterhead, + "lang": frappe.db.get_value('Print Format', self.print_format, 'default_print_language') + if self.print_format else 'en' + }] def get_template(self): diff --git a/frappe/email/queue.py b/frappe/email/queue.py index 0ed4044586..e62e7ca674 100755 --- a/frappe/email/queue.py +++ b/frappe/email/queue.py @@ -175,7 +175,8 @@ def get_email_queue(recipients, sender, subject, **kwargs): if att.get('fid'): _attachments.append(att) elif att.get("print_format_attachment") == 1: - att['lang'] = frappe.local.lang + if not att.get('lang', None): + att['lang'] = frappe.local.lang att['print_letterhead'] = kwargs.get('print_letterhead') _attachments.append(att) e.attachments = json.dumps(_attachments) From 23e934c67b2f7ef431d141bce47e17579a9d5e0c Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Thu, 7 Feb 2019 18:19:28 +0530 Subject: [PATCH 30/47] fix: requested changes --- .../doctype/user_permission/test_user_permission.py | 11 ++++++++--- .../core/doctype/user_permission/user_permission.py | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/user_permission/test_user_permission.py b/frappe/core/doctype/user_permission/test_user_permission.py index f002664eea..b83d103013 100644 --- a/frappe/core/doctype/user_permission/test_user_permission.py +++ b/frappe/core/doctype/user_permission/test_user_permission.py @@ -9,12 +9,14 @@ import unittest class TestUserPermission(unittest.TestCase): def test_apply_to_all(self): + ''' Create User permission for User having access to all applicable Doctypes''' user = get_user() param = get_params(user, apply = 1) created = add_user_permissions(param) self.assertEquals(created, 1) - def test_for_applicables_on_update_from_apply_to_all(self): + def test_for_applicable_on_update_from_apply_to_all(self): + ''' Update User Permission from all to some applicable Doctypes''' user = get_user() param = get_params(user, applicable = ["Chat Room", "Chat Message"]) create = add_user_permissions(param) @@ -29,7 +31,8 @@ class TestUserPermission(unittest.TestCase): self.assertIsNotNone(created_applicable_second) self.assertEquals(create, 1) - def test_for_apply_to_all_on_update_from_applicables(self): + def test_for_apply_to_all_on_update_from_applicable(self): + ''' Update User Permission from some to all applicable Doctypes''' user = get_user() param = get_params(user, apply = 1) created = add_user_permissions(param) @@ -53,7 +56,8 @@ def get_user(): user.add_roles("System Manager") return user -def get_params(user, apply = None , applicable= None): +def get_params(user, apply = None , applicable = None): + ''' Return param to insert ''' param = { "user": user.name, "doctype":"User", @@ -68,6 +72,7 @@ def get_params(user, apply = None , applicable= None): return param def get_exists_param(user, applicable = None): + ''' param to check existing Document ''' param = { "user": user.name, "allow": "User", diff --git a/frappe/core/doctype/user_permission/user_permission.py b/frappe/core/doctype/user_permission/user_permission.py index 016e5a8a07..bb7e7db405 100644 --- a/frappe/core/doctype/user_permission/user_permission.py +++ b/frappe/core/doctype/user_permission/user_permission.py @@ -148,6 +148,7 @@ def clear_user_permissions(user, for_doctype): @frappe.whitelist() def add_user_permissions(data): + ''' Add and update the user permissions ''' frappe.only_for('System Manager') if isinstance(data, frappe.string_types): data = json.loads(data) From 7b45ca5fef15229aab9ba0ee3e1378f95f6b9372 Mon Sep 17 00:00:00 2001 From: Kenneth Sequeira Date: Thu, 7 Feb 2019 19:23:24 +0530 Subject: [PATCH 31/47] Fix Typo: Exection Time -> Execution Time --- frappe/public/js/frappe/views/reports/query_report.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 8a73bf8d83..d77b43bd48 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -992,7 +992,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList { show_footer_message() { const message = __('For comparison, use >5, <10 or =324. For ranges, use 5:10 (for values between 5 & 10).'); - const execution_time_msg = __('Exection Time: {0} sec', [this.execution_time || 0.1]); + const execution_time_msg = __('Execution Time: {0} sec', [this.execution_time || 0.1]); this.page.footer.removeClass('hide').addClass('text-muted col-md-12') .html(`${message}${execution_time_msg}`); From 192cba460ed6faa1760274769ac9f11ad668b500 Mon Sep 17 00:00:00 2001 From: Sahil Khan Date: Fri, 8 Feb 2019 18:22:01 +0530 Subject: [PATCH 32/47] fix(email_group): show correct total_subscribers after inserting or deleting email group members --- .../doctype/email_group_member/email_group_member.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frappe/email/doctype/email_group_member/email_group_member.py b/frappe/email/doctype/email_group_member/email_group_member.py index d0968425d0..8bdff4e516 100644 --- a/frappe/email/doctype/email_group_member/email_group_member.py +++ b/frappe/email/doctype/email_group_member/email_group_member.py @@ -7,7 +7,15 @@ import frappe from frappe.model.document import Document class EmailGroupMember(Document): - pass + def after_delete(self): + print("*"*50, "delete") + email_group = frappe.get_doc('Email Group', self.email_group) + email_group.update_total_subscribers() + + def after_insert(self): + print("*"*50, "add") + email_group = frappe.get_doc('Email Group', self.email_group) + email_group.update_total_subscribers() def after_doctype_insert(): - frappe.db.add_unique("Email Group Member", ("email_group", "email")) \ No newline at end of file + frappe.db.add_unique("Email Group Member", ("email_group", "email")) From 91ac1608db9eb71c74a1bd1471d3174a950dceeb Mon Sep 17 00:00:00 2001 From: Sahil Khan Date: Fri, 8 Feb 2019 18:26:04 +0530 Subject: [PATCH 33/47] fix: remove print statements --- frappe/email/doctype/email_group_member/email_group_member.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/frappe/email/doctype/email_group_member/email_group_member.py b/frappe/email/doctype/email_group_member/email_group_member.py index 8bdff4e516..23b279e755 100644 --- a/frappe/email/doctype/email_group_member/email_group_member.py +++ b/frappe/email/doctype/email_group_member/email_group_member.py @@ -8,12 +8,10 @@ from frappe.model.document import Document class EmailGroupMember(Document): def after_delete(self): - print("*"*50, "delete") email_group = frappe.get_doc('Email Group', self.email_group) email_group.update_total_subscribers() def after_insert(self): - print("*"*50, "add") email_group = frappe.get_doc('Email Group', self.email_group) email_group.update_total_subscribers() From e7390b701b8422a8ce392e22eb1e7fe901a98be5 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Fri, 8 Feb 2019 19:41:55 +0530 Subject: [PATCH 34/47] fix: Currency symbol in list view (#6900) * fix: Currency fix in list view * fix(list_view): Added missing semicolon --- frappe/public/js/frappe/list/list_view.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 7a34bb3cb5..8dd6f67209 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -137,6 +137,13 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { ); fields.forEach(f => this._add_field(f)); + + this.fields.forEach(f => { + const df = frappe.meta.get_docfield(f[1], f[0]); + if (df && df.fieldtype === 'Currency' && df.options && !df.options.includes(':')) { + this._add_field(df.options); + } + }); } patch_refresh_and_load_lib() { From 42c7fffee4cbb5327e58fbcea0684d104fa30e64 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Sat, 9 Feb 2019 12:01:15 +0530 Subject: [PATCH 35/47] fix: don't send read receipt by default' --- frappe/public/js/frappe/views/communication.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/communication.js b/frappe/public/js/frappe/views/communication.js index 371af5a514..027f1fd1b7 100755 --- a/frappe/public/js/frappe/views/communication.js +++ b/frappe/public/js/frappe/views/communication.js @@ -92,7 +92,7 @@ frappe.views.CommunicationComposer = Class.extend({ {label:__("Send me a copy"), fieldtype:"Check", fieldname:"send_me_a_copy", 'default': frappe.boot.user.send_me_a_copy}, {label:__("Send Read Receipt"), fieldtype:"Check", - fieldname:"send_read_receipt", default: 1}, + fieldname:"send_read_receipt"}, {label:__("Attach Document Print"), fieldtype:"Check", fieldname:"attach_document_print"}, {label:__("Select Print Format"), fieldtype:"Select", From 1978c33a150294e72f6b7d33ee8c54f91a207f1d Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 9 Feb 2019 17:28:52 +0530 Subject: [PATCH 36/47] fix: Create Kanban Cards with current filters If you are in a Kanban Board and you create new cards, it will be added according to the filters fine, but if you change the filters it still sets the old filters. --- frappe/public/js/frappe/views/kanban/kanban_board.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/kanban/kanban_board.js b/frappe/public/js/frappe/views/kanban/kanban_board.js index 276f696189..6c22b14030 100644 --- a/frappe/public/js/frappe/views/kanban/kanban_board.js +++ b/frappe/public/js/frappe/views/kanban/kanban_board.js @@ -97,7 +97,7 @@ frappe.provide("frappe.views"); var doc_fields = {}; doc_fields[field.fieldname] = card_title; doc_fields[this.board.field_name] = column_title; - this.board.filters_array.forEach(function(f) { + this.cur_list.filter_area.get().forEach(function(f) { if (f[2] !== "=") return; doc_fields[f[1]] = f[3]; }); From 63446380f698a278e5ae7ab9ecf013efc9561310 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 9 Feb 2019 19:13:05 +0530 Subject: [PATCH 37/47] fix: Kanban UX - When adding new card, add them directly and then update it later again from the updated doc from server - Update card order when a new card is added --- .../js/frappe/views/kanban/kanban_board.js | 57 ++++++++++++------- .../js/frappe/views/kanban/kanban_card.html | 2 +- frappe/public/less/common.less | 4 ++ 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/frappe/public/js/frappe/views/kanban/kanban_board.js b/frappe/public/js/frappe/views/kanban/kanban_board.js index 6c22b14030..bf777a9b7c 100644 --- a/frappe/public/js/frappe/views/kanban/kanban_board.js +++ b/frappe/public/js/frappe/views/kanban/kanban_board.js @@ -38,7 +38,8 @@ frappe.provide("frappe.views"); cards: cards, columns: columns, cur_list: opts.cur_list, - empty_state: false + empty_state: false, + wrapper: opts.wrapper }); }, update_cards: function(updater, cards) { @@ -104,14 +105,26 @@ frappe.provide("frappe.views"); $.extend(doc, doc_fields); + // add the card directly + // for better ux + const card = prepare_card(doc, state); + card._disable_click = true; + const cards = [...state.cards, card]; + // remember the name which we will override later + const old_name = doc.name; + updater.set({ cards }); + if (field && !quick_entry) { return insert_doc(doc) .then(function(r) { - var updated_doc = r.message; - var card = prepare_card(doc, state, updated_doc); - var cards = state.cards.slice(); - cards.push(card); - updater.set({ cards: cards }); + // update the card in place with the updated doc + const updated_doc = r.message; + const index = state.cards.findIndex(card => card.name === old_name); + const card = prepare_card(updated_doc, state); + const new_cards = state.cards.slice(); + new_cards[index] = card; + updater.set({ cards: new_cards }); + fluxify.doAction('update_order'); }); } else { frappe.new_doc(this.doctype, doc); @@ -142,11 +155,22 @@ frappe.provide("frappe.views"); fluxify.doAction('update_card', updated_card); }); }, - update_order: function(updater, order) { + update_order: function(updater) { // cache original order const _cards = this.cards.slice(); const _columns = this.columns.slice(); + const order = {}; + this.wrapper.find('.kanban-column[data-column-value]') + .each(function() { + var col_name = $(this).data().columnValue; + order[col_name] = []; + $(this).find('.kanban-card-wrapper').each(function() { + var card_name = $(this).data().name; + order[col_name].push(card_name); + }); + }); + frappe.call({ method: method_prefix + "update_order", args: { @@ -431,17 +455,7 @@ frappe.provide("frappe.views"); wrapper.find('.kanban-card.add-card').fadeIn(100); wrapper.find('.kanban-cards').height('auto'); // update order - var order = {}; - wrapper.find('.kanban-column[data-column-value]') - .each(function() { - var col_name = $(this).data().columnValue; - order[col_name] = []; - $(this).find('.kanban-card-wrapper').each(function() { - var card_name = $(this).data().name; - order[col_name].push(card_name); - }); - }); - fluxify.doAction('update_order', order); + fluxify.doAction('update_order'); }, onAdd: function() { }, @@ -470,11 +484,11 @@ frappe.provide("frappe.views"); // not already working -- double entry e.preventDefault(); var card_title = $textarea.val(); + $new_card_area.hide(); + $textarea.val(''); fluxify.doAction('add_card', card_title, column.title) .then(() => { $btn_add.show(); - $new_card_area.hide(); - $textarea.val(''); }); } } @@ -531,7 +545,8 @@ frappe.provide("frappe.views"); function make_dom() { var opts = { name: card.name, - title: remove_img_tags(card.title) + title: remove_img_tags(card.title), + disable_click: card._disable_click ? 'disable-click' : '' }; self.$card = $(frappe.render_template('kanban_card', opts)) .appendTo(wrapper); diff --git a/frappe/public/js/frappe/views/kanban/kanban_card.html b/frappe/public/js/frappe/views/kanban/kanban_card.html index 94b6054e1c..8d749132ce 100644 --- a/frappe/public/js/frappe/views/kanban/kanban_card.html +++ b/frappe/public/js/frappe/views/kanban/kanban_card.html @@ -1,4 +1,4 @@ -
+
{{ title }} diff --git a/frappe/public/less/common.less b/frappe/public/less/common.less index 8ab34dfa6d..17c475d76f 100644 --- a/frappe/public/less/common.less +++ b/frappe/public/less/common.less @@ -304,3 +304,7 @@ a.no-decoration& { .text-small { font-size: @text-small; } + +.disable-click { + pointer-events: none; +} From 66179ab86270302644aa8a33c57813e595006338 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sun, 10 Feb 2019 12:54:37 +0530 Subject: [PATCH 38/47] fix: Use .get() to avoid key error --- frappe/permissions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index e53608468c..46924331f4 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -24,7 +24,7 @@ def print_has_permission_check_logs(func): def inner(*args, **kwargs): frappe.flags['has_permission_check_logs'] = [] result = func(*args, **kwargs) - self_perm_check = True if not kwargs['user'] else kwargs['user'] == frappe.session.user + self_perm_check = True if not kwargs.get('user') else kwargs.get('user') == frappe.session.user # print only if access denied # and if user is checking his own permission if not result and self_perm_check: From de958bdac54be686f90069ed63ca734def22919d Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Mon, 11 Feb 2019 13:52:18 +0530 Subject: [PATCH 39/47] added select all and unselect all button --- frappe/core/doctype/user_permission/user_permission_list.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 1f0fe20bda..4682c05670 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -44,6 +44,7 @@ frappe.listview_settings['User Permission'] = { me.get_multi_select_options(dialog, applicable).then(options => { me.applicable_options = options; me.on_docname_change(dialog, options, applicable); + dialog.fields_dict.applicable_doctypes.setup_select_all() }); }); } @@ -59,6 +60,7 @@ frappe.listview_settings['User Permission'] = { onchange: function() { if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ me.on_apply_to_all_doctypes_change(dialog, me.applicable_options); + dialog.fields_dict.applicable_doctypes.setup_select_all() } } }, From 33552408225019c82d183f8dcb10c5812804f34b Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Mon, 11 Feb 2019 14:32:15 +0530 Subject: [PATCH 40/47] select all only if options are greater than 5 --- .../core/doctype/user_permission/user_permission_list.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index 4682c05670..bdf65a6244 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -44,7 +44,9 @@ frappe.listview_settings['User Permission'] = { me.get_multi_select_options(dialog, applicable).then(options => { me.applicable_options = options; me.on_docname_change(dialog, options, applicable); - dialog.fields_dict.applicable_doctypes.setup_select_all() + if(options.length > 5){ + dialog.fields_dict.applicable_doctypes.setup_select_all() + } }); }); } @@ -60,7 +62,9 @@ frappe.listview_settings['User Permission'] = { onchange: function() { if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ me.on_apply_to_all_doctypes_change(dialog, me.applicable_options); - dialog.fields_dict.applicable_doctypes.setup_select_all() + if(me.applicable_options.length > 5){ + dialog.fields_dict.applicable_doctypes.setup_select_all() + } } } }, From ec8ed9d50a805d8e8fafb15128488d38543c8f14 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Mon, 11 Feb 2019 14:45:25 +0530 Subject: [PATCH 41/47] fix: codacy --- frappe/core/doctype/user_permission/user_permission_list.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/user_permission/user_permission_list.js b/frappe/core/doctype/user_permission/user_permission_list.js index bdf65a6244..00d829b2a0 100644 --- a/frappe/core/doctype/user_permission/user_permission_list.js +++ b/frappe/core/doctype/user_permission/user_permission_list.js @@ -45,7 +45,7 @@ frappe.listview_settings['User Permission'] = { me.applicable_options = options; me.on_docname_change(dialog, options, applicable); if(options.length > 5){ - dialog.fields_dict.applicable_doctypes.setup_select_all() + dialog.fields_dict.applicable_doctypes.setup_select_all(); } }); }); @@ -63,7 +63,7 @@ frappe.listview_settings['User Permission'] = { if(dialog.fields_dict.doctype.value && dialog.fields_dict.docname.value && dialog.fields_dict.user.value){ me.on_apply_to_all_doctypes_change(dialog, me.applicable_options); if(me.applicable_options.length > 5){ - dialog.fields_dict.applicable_doctypes.setup_select_all() + dialog.fields_dict.applicable_doctypes.setup_select_all(); } } } From e9bc64029316b9ac181e6411b8d73be41bee5d2f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Mon, 11 Feb 2019 16:50:49 +0530 Subject: [PATCH 42/47] fix: Print Preview UX - Show footer on bottom - Show message indicating that print may go into multiple pages --- frappe/public/js/frappe/dom.js | 10 ++++++++ frappe/public/js/frappe/form/print.js | 24 ++++++++++++++++--- .../frappe/form/templates/print_layout.html | 3 ++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/dom.js b/frappe/public/js/frappe/dom.js index d91d7e38b0..a13b8754fd 100644 --- a/frappe/public/js/frappe/dom.js +++ b/frappe/public/js/frappe/dom.js @@ -220,6 +220,16 @@ frappe.dom = { }; reader.readAsDataURL(file_obj); }); + }, + pixel_to_inches(pixels) { + const div = $('
'); + div.appendTo(document.body); + + const dpi_x = document.getElementById('dpi').offsetWidth; + const inches = pixels / dpi_x; + div.remove(); + + return inches; } } diff --git a/frappe/public/js/frappe/form/print.js b/frappe/public/js/frappe/form/print.js index aa6be540ab..f0a4226444 100644 --- a/frappe/public/js/frappe/form/print.js +++ b/frappe/public/js/frappe/form/print.js @@ -136,22 +136,40 @@ frappe.ui.form.PrintPreview = Class.extend({ preview: function () { var me = this; this.get_print_html(function (out) { - me.wrapper.find(".print-format").html(out.html); + const $print_format = me.wrapper.find(".print-format"); + $print_format.html(out.html); me.show_footer(); me.set_style(out.style); + + const print_height = $print_format.get(0).offsetHeight; + const $message = me.wrapper.find(".page-break-message"); + + const print_height_inches = frappe.dom.pixel_to_inches(print_height); + // if contents are large enough, indicate that it will get printed on multiple pages + // Maximum height for an A4 document is 11.69 inches + if (print_height_inches > 11.69) { + $message.text(__('This may get printed on multiple pages')); + } else { + $message.text(''); + } }); }, show_footer: function() { // footer is hidden by default as reqd by pdf generation // simple hack to show it in print preview + this.wrapper.find('.print-format').css({ + display: 'flex', + flexDirection: 'column' + }); this.wrapper.find('.page-break').css({ 'display': 'flex', - 'flex-direction': 'column' + 'flex-direction': 'column', + 'flex': '1' }); this.wrapper.find('#footer-html').attr('style', ` display: block !important; order: 1; - margin-top: 20px; + margin-top: auto; `); }, printit: function () { diff --git a/frappe/public/js/frappe/form/templates/print_layout.html b/frappe/public/js/frappe/form/templates/print_layout.html index bbdf415b17..b2abd11099 100644 --- a/frappe/public/js/frappe/form/templates/print_layout.html +++ b/frappe/public/js/frappe/form/templates/print_layout.html @@ -31,6 +31,7 @@ +
From 850e9e6d0b17ac5787ca23f222ec7784e12551ee Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Mon, 11 Feb 2019 18:41:11 +0530 Subject: [PATCH 43/47] fix: Skip get_open_count during migrate or install --- frappe/desk/notifications.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frappe/desk/notifications.py b/frappe/desk/notifications.py index 59c783c524..eb56c458ce 100644 --- a/frappe/desk/notifications.py +++ b/frappe/desk/notifications.py @@ -249,6 +249,11 @@ def get_open_count(doctype, name, items=[]): :param transactions: List of transactions (json/dict) :param filters: optional filters (json/list)''' + if frappe.flags.in_migrate or frappe.flags.in_install: + return { + 'count': [] + } + frappe.has_permission(doc=frappe.get_doc(doctype, name), throw=True) meta = frappe.get_meta(doctype) From 507945096ad1db11968c505c5f8561aaae86afd7 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Mon, 11 Feb 2019 23:22:42 +0530 Subject: [PATCH 44/47] fix(base_list): keeping a promise --- frappe/public/js/frappe/ui/filters/filter.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frappe/public/js/frappe/ui/filters/filter.js b/frappe/public/js/frappe/ui/filters/filter.js index e8220bd07c..b4c550a297 100644 --- a/frappe/public/js/frappe/ui/filters/filter.js +++ b/frappe/public/js/frappe/ui/filters/filter.js @@ -115,10 +115,14 @@ frappe.ui.Filter = class { } update_filter_tag() { - return this._filter_value_set.then(() => { - !this.$filter_tag ? this.make_tag() : this.set_filter_button_text(); - this.filter_edit_area.hide(); - }); + if (this._filter_value_set) { + return this._filter_value_set.then(() => { + !this.$filter_tag ? this.make_tag() : this.set_filter_button_text(); + this.filter_edit_area.hide(); + }); + } else { + return Promise.resolve(); + } } remove() { From 73c9cbec60c345de2c622fe1795d8faa039c740d Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 12 Feb 2019 10:54:19 +0530 Subject: [PATCH 45/47] fix(typo): vale -> value --- frappe/model/document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/document.py b/frappe/model/document.py index c635db45a5..b2b68b2f62 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -989,7 +989,7 @@ class Document(BaseDocument): frappe.db.commit() def db_get(self, fieldname): - '''get database vale for this fieldname''' + '''get database value for this fieldname''' return frappe.db.get_value(self.doctype, self.name, fieldname) def check_no_back_links_exist(self): From ea82d6b485a7b395f6c8d58f62d75d910cacd305 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 12 Feb 2019 16:14:38 +0530 Subject: [PATCH 46/47] fix: unfreeze oauthlib, requests-oauthlib (#6922) --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7c4f0d2962..cc94f7cc5c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -34,8 +34,8 @@ ndg-httpsclient pyasn1 zxcvbn-python unittest-xml-reporting -oauthlib==3.0.0 -requests-oauthlib==1.2.0 +oauthlib +requests-oauthlib pdfkit PyJWT PyPDF2 From ead9bde39d69174b3b50e938d873ea39bd17deb1 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 12 Feb 2019 16:38:43 +0550 Subject: [PATCH 47/47] bumped to version 11.1.5 --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index d4a4a231ff..1be882ab35 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -23,7 +23,7 @@ if sys.version[0] == '2': reload(sys) sys.setdefaultencoding("utf-8") -__version__ = '11.1.4' +__version__ = '11.1.5' __title__ = "Frappe Framework" local = Local()