From 1014fc621ef60301911e7efbd5d48dc44f1cdbb2 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Mon, 14 Jan 2019 12:54:19 +0530 Subject: [PATCH 001/330] Don't assume async value If async was passed in it was being set as true even if the paased value is false. This commit fixes the same. --- frappe/utils/background_jobs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index f1194edaf4..46a1546a55 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -37,7 +37,7 @@ def enqueue(method, queue='default', timeout=None, event=None, ''' # To handle older implementations if 'async' in kwargs: - is_async = True + is_async = kwargs.get('async') del kwargs['async'] if now or frappe.flags.in_migrate: From 3587edd484549513f6fd8323a95f18078dab96d0 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Mon, 14 Jan 2019 13:15:12 +0530 Subject: [PATCH 002/330] Use pop instead of condition --- frappe/utils/background_jobs.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index 46a1546a55..a65d1d8e03 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -36,10 +36,8 @@ def enqueue(method, queue='default', timeout=None, event=None, :param kwargs: keyword arguments to be passed to the method ''' # To handle older implementations - if 'async' in kwargs: - is_async = kwargs.get('async') - del kwargs['async'] - + is_async = kwargs.pop('async', is_async) + if now or frappe.flags.in_migrate: return frappe.call(method, **kwargs) From c111040373b0fabda8a848bfb22e00d42a1b9df1 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Wed, 23 Jan 2019 14:34:56 +0530 Subject: [PATCH 003/330] 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 004/330] 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 005/330] 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 006/330] 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 3121a60292cf42d57f2bfeb5c185d39e48b4b4e8 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 29 Jan 2019 11:00:04 +0530 Subject: [PATCH 007/330] fix: remove trailing whitespace. --- frappe/utils/background_jobs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/background_jobs.py b/frappe/utils/background_jobs.py index a65d1d8e03..99e24bdf44 100755 --- a/frappe/utils/background_jobs.py +++ b/frappe/utils/background_jobs.py @@ -37,7 +37,7 @@ def enqueue(method, queue='default', timeout=None, event=None, ''' # To handle older implementations is_async = kwargs.pop('async', is_async) - + if now or frappe.flags.in_migrate: return frappe.call(method, **kwargs) From f780b42cfb6a5fbf69d31f63a32a826e9be2cb9d Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Tue, 29 Jan 2019 16:13:56 +0530 Subject: [PATCH 008/330] 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 009/330] 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 010/330] 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 011/330] 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 57196a8bbed57022be4bd3930cf69516f899e958 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Thu, 31 Jan 2019 13:54:42 +0530 Subject: [PATCH 012/330] fix(website): Enable socketio on website (for file upload) (#6866) --- frappe/templates/base.html | 1 + frappe/utils/jinja.py | 1 + frappe/website/js/website.js | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/templates/base.html b/frappe/templates/base.html index 5e8f3b3396..9c68254e2f 100644 --- a/frappe/templates/base.html +++ b/frappe/templates/base.html @@ -32,6 +32,7 @@ frappe.ready_events.push(fn); } window.dev_server = {{ dev_server }}; + window.socketio_port = {{ frappe.socketio_port }}; {% block body %} diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index 16755e8d28..d0a2c34a6e 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -134,6 +134,7 @@ def get_allowed_functions_for_jenv(): 'user': user, 'csrf_token': frappe.local.session.data.csrf_token if getattr(frappe.local, "session", None) else '' }, + "socketio_port": frappe.conf.socketio_port, }, 'style': { 'border_color': '#d1d8dd' diff --git a/frappe/website/js/website.js b/frappe/website/js/website.js index 7fa29991d0..a980955971 100644 --- a/frappe/website/js/website.js +++ b/frappe/website/js/website.js @@ -427,5 +427,6 @@ frappe.ready(function() { }); } } - }) + }); + frappe.socketio.init(window.socketio_port); }); From 88364f764fd9e28411e96d73492a18c94d2fe314 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 31 Jan 2019 14:01:08 +0530 Subject: [PATCH 013/330] fix: Validate length for int and bigint column types (#6804) * fix: Validate length for int and bigint column types * fix: skip standard fields * fix: Skip Check fields as well Value of Check fields can be True or False, which are casted to 0 or 1 explicitly --- frappe/model/base_document.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 3617b81ba8..bc5e772627 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -547,10 +547,20 @@ class BaseDocument(object): # single doctype value type is mediumtext return + column_types_to_check_length = ('varchar', 'int', 'bigint') + for fieldname, value in iteritems(self.get_valid_dict()): df = self.meta.get_field(fieldname) - if df and df.fieldtype in type_map and type_map[df.fieldtype][0]=="varchar": - max_length = cint(df.get("length")) or cint(varchar_len) + + if not df or df.fieldtype == 'Check': + # skip standard fields and Check fields + continue + + column_type = type_map[df.fieldtype][0] or None + default_column_max_length = type_map[df.fieldtype][1] or None + + if df and df.fieldtype in type_map and column_type in column_types_to_check_length: + max_length = cint(df.get("length")) or cint(default_column_max_length) if len(cstr(value)) > max_length: if self.parentfield and self.idx: From 9873c042311c029d21e977ddd1f6be5feea234dc Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Thu, 31 Jan 2019 09:46:48 +0000 Subject: [PATCH 014/330] fix(sync_global_search): decode json object as str (#6867) --- frappe/utils/global_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/global_search.py b/frappe/utils/global_search.py index 581a75cdaf..b4d2d2f0f3 100644 --- a/frappe/utils/global_search.py +++ b/frappe/utils/global_search.py @@ -311,7 +311,7 @@ def sync_global_search(): :return: """ while frappe.cache().llen('global_search_queue') > 0: - value = json.loads(frappe.cache().lpop('global_search_queue')) + value = json.loads(frappe.cache().lpop('global_search_queue').decode('utf-8')) sync_value(value) def sync_value(value): From c62f3155f2107f1cc9ccf296957571a9811ebc7e Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Fri, 25 Jan 2019 18:31:52 +0530 Subject: [PATCH 015/330] 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 9acfebc0aed9995d0f4cf42ce9228368c5e44bd0 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 31 Jan 2019 19:20:01 +0530 Subject: [PATCH 016/330] Return doctype field as well from get_communcation method Co-authored-by: Chinmay Pai --- frappe/desk/form/load.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/desk/form/load.py b/frappe/desk/form/load.py index 0566a4d14b..c64cc6cfab 100644 --- a/frappe/desk/form/load.py +++ b/frappe/desk/form/load.py @@ -142,7 +142,7 @@ def get_communication_data(doctype, name, start=0, limit=20, after=None, fields= `communication_date`, `content`, `sender`, `sender_full_name`, `creation`, `subject`, `delivery_status`, `_liked_by`, `timeline_doctype`, `timeline_name`, `reference_doctype`, `reference_name`, - `link_doctype`, `link_name`, `read_by_recipient`, `rating` ''' + `link_doctype`, `link_name`, `read_by_recipient`, `rating`, 'Communication' AS `doctype`''' conditions = '''communication_type in ('Communication', 'Comment', 'Feedback') and ( From c79abc6d7734fa2ed6c672d0d41fa52c2f79b2a4 Mon Sep 17 00:00:00 2001 From: britlog Date: Thu, 31 Jan 2019 22:34:15 +0100 Subject: [PATCH 017/330] 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 018/330] 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 5d85379e8b867afbe033c4d7237a6a1c5c550315 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Tue, 29 Jan 2019 11:52:16 +0530 Subject: [PATCH 019/330] feat: override treeview buttons with sasme labelled button in tree file --- frappe/public/js/frappe/views/treeview.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/public/js/frappe/views/treeview.js b/frappe/public/js/frappe/views/treeview.js index dda728cff5..c42546f6e4 100644 --- a/frappe/public/js/frappe/views/treeview.js +++ b/frappe/public/js/frappe/views/treeview.js @@ -219,6 +219,9 @@ frappe.views.TreeView = Class.extend({ ] if(this.opts.toolbar && this.opts.extend_toolbar) { + toolbar = toolbar.filter(btn => { + return !me.opts.toolbar.find(d => d["label"]==btn["label"]); + }); return toolbar.concat(this.opts.toolbar) } else if (this.opts.toolbar && !this.opts.extend_toolbar) { return this.opts.toolbar From af35ae8fc81b37cef0690829b52e091f8c70e6a3 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Tue, 29 Jan 2019 11:53:18 +0530 Subject: [PATCH 020/330] feat: ability to pass selected node while overriding a button --- frappe/public/js/frappe/views/treeview.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/views/treeview.js b/frappe/public/js/frappe/views/treeview.js index c42546f6e4..94daa22f8e 100644 --- a/frappe/public/js/frappe/views/treeview.js +++ b/frappe/public/js/frappe/views/treeview.js @@ -229,9 +229,9 @@ frappe.views.TreeView = Class.extend({ return toolbar } }, - new_node: function() { + new_node: function(node) { var me = this; - var node = me.tree.get_selected_node(); + var node = node || me.tree.get_selected_node(); if(!(node && node.expandable)) { frappe.msgprint(__("Select a group node first.")); From c079646556fa0431d45ff8356218d20f0d26a0ff Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Tue, 29 Jan 2019 11:55:46 +0530 Subject: [PATCH 021/330] feat: ability to provide custom onchange for filter and to disable onchange completely --- frappe/public/js/frappe/views/treeview.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/frappe/public/js/frappe/views/treeview.js b/frappe/public/js/frappe/views/treeview.js index 94daa22f8e..472741fc56 100644 --- a/frappe/public/js/frappe/views/treeview.js +++ b/frappe/public/js/frappe/views/treeview.js @@ -100,17 +100,20 @@ frappe.views.TreeView = Class.extend({ filter.default = frappe.route_options[filter.fieldname] } - filter.change = function() { - var val = this.get_value(); - me.args[filter.fieldname] = val; - if (val) { - me.root_label = val; - me.page.set_title(val); - } else { - me.root_label = me.opts.root_label; - me.set_title(); + if(!filter.disable_onchange) { + filter.change = function() { + filter.on_change && filter.on_change(); + var val = this.get_value(); + me.args[filter.fieldname] = val; + if (val) { + me.root_label = val; + me.page.set_title(val); + } else { + me.root_label = me.opts.root_label; + me.set_title(); + } + me.make_tree(); } - me.make_tree(); } me.page.add_field(filter); From e6b94e764bc4f413ff10fbec6787ac60304ece15 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Tue, 29 Jan 2019 12:38:07 +0530 Subject: [PATCH 022/330] fix: codacy fix --- frappe/public/js/frappe/views/treeview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/treeview.js b/frappe/public/js/frappe/views/treeview.js index 472741fc56..d4d32eba40 100644 --- a/frappe/public/js/frappe/views/treeview.js +++ b/frappe/public/js/frappe/views/treeview.js @@ -234,7 +234,7 @@ frappe.views.TreeView = Class.extend({ }, new_node: function(node) { var me = this; - var node = node || me.tree.get_selected_node(); + node = node || me.tree.get_selected_node(); if(!(node && node.expandable)) { frappe.msgprint(__("Select a group node first.")); From eb2a0942e0294037b3f1cecb04430035ad664194 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 30 Jan 2019 10:32:16 +0530 Subject: [PATCH 023/330] feat: post_render function added to be triggered after treeview is successfully built --- frappe/public/js/frappe/views/treeview.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frappe/public/js/frappe/views/treeview.js b/frappe/public/js/frappe/views/treeview.js index d4d32eba40..64c1696fe0 100644 --- a/frappe/public/js/frappe/views/treeview.js +++ b/frappe/public/js/frappe/views/treeview.js @@ -156,6 +156,12 @@ frappe.views.TreeView = Class.extend({ }); cur_tree = this.tree; + this.post_render(); + }, + + post_render: function() { + var me = this; + me.opts.post_render && me.opts.post_render(me); }, select_node: function(node) { From a7e127e4981edc5872e4f30f010a344ba42e3fac Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 30 Jan 2019 10:48:43 +0530 Subject: [PATCH 024/330] fix: get ancestors for a node with more filters --- frappe/utils/nestedset.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/utils/nestedset.py b/frappe/utils/nestedset.py index 8bef19cedb..f5400318a7 100644 --- a/frappe/utils/nestedset.py +++ b/frappe/utils/nestedset.py @@ -15,7 +15,7 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import now +from frappe.utils import now, cint class NestedSetRecursionError(frappe.ValidationError): pass class NestedSetMultipleRootsError(frappe.ValidationError): pass @@ -256,9 +256,10 @@ def get_root_of(doctype): and t1.rgt > t1.lft""".format(doctype, doctype)) return result[0][0] if result else None -def get_ancestors_of(doctype, name): +def get_ancestors_of(doctype, name, order_by="lft desc", limit=None): """Get ancestor elements of a DocType with a tree structure""" lft, rgt = frappe.db.get_value(doctype, name, ["lft", "rgt"]) + limit = "limit %s" % cint(limit) if limit else "" result = frappe.db.sql_list("""select name from `tab{0}` - where lft<%s and rgt>%s order by lft desc""".format(doctype), (lft, rgt)) + where lft<%s and rgt>%s order by {1} {2}""".format(doctype, order_by, limit), (lft, rgt)) return result or [] From c5ed692e1c3160bb8639b3875a5add1aa48c1dd7 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 30 Jan 2019 11:07:16 +0530 Subject: [PATCH 025/330] fix: minor revert change to new_node function --- frappe/public/js/frappe/views/treeview.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/views/treeview.js b/frappe/public/js/frappe/views/treeview.js index 64c1696fe0..2b76e135cf 100644 --- a/frappe/public/js/frappe/views/treeview.js +++ b/frappe/public/js/frappe/views/treeview.js @@ -238,9 +238,9 @@ frappe.views.TreeView = Class.extend({ return toolbar } }, - new_node: function(node) { + new_node: function() { var me = this; - node = node || me.tree.get_selected_node(); + var node = me.tree.get_selected_node(); if(!(node && node.expandable)) { frappe.msgprint(__("Select a group node first.")); From 04b3a5cabc60241c8f8bbd3f447ea22919389d57 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Wed, 30 Jan 2019 16:31:00 +0530 Subject: [PATCH 026/330] feat: added a utility method to get all the descendants of a node --- frappe/utils/nestedset.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frappe/utils/nestedset.py b/frappe/utils/nestedset.py index f5400318a7..021425bab2 100644 --- a/frappe/utils/nestedset.py +++ b/frappe/utils/nestedset.py @@ -263,3 +263,11 @@ def get_ancestors_of(doctype, name, order_by="lft desc", limit=None): result = frappe.db.sql_list("""select name from `tab{0}` where lft<%s and rgt>%s order by {1} {2}""".format(doctype, order_by, limit), (lft, rgt)) return result or [] + +def get_descendants_of(doctype, name, order_by="lft desc", limit=None): + '''Return descendants of the current record''' + lft, rgt = frappe.db.get_value(doctype, name, ['lft', 'rgt']) + limit = "limit %s" % cint(limit) if limit else "" + result = frappe.db.sql_list("""select name from `tab{0}` + where lft>%s and rgt<%s order by {1} {2}""".format(doctype, order_by, limit), (lft, rgt)) + return result or [] From ff1b2b1297966eff4fe533843a5d95051e06e109 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Fri, 1 Feb 2019 13:10:15 +0530 Subject: [PATCH 027/330] 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 1d8f35ce979c6c02a091b42e08176401d9a8a317 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Fri, 1 Feb 2019 12:14:34 +0530 Subject: [PATCH 028/330] fix: use orm instead of query --- frappe/utils/nestedset.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frappe/utils/nestedset.py b/frappe/utils/nestedset.py index 021425bab2..777dd7aba7 100644 --- a/frappe/utils/nestedset.py +++ b/frappe/utils/nestedset.py @@ -15,7 +15,7 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import now, cint +from frappe.utils import now class NestedSetRecursionError(frappe.ValidationError): pass class NestedSetMultipleRootsError(frappe.ValidationError): pass @@ -259,15 +259,17 @@ def get_root_of(doctype): def get_ancestors_of(doctype, name, order_by="lft desc", limit=None): """Get ancestor elements of a DocType with a tree structure""" lft, rgt = frappe.db.get_value(doctype, name, ["lft", "rgt"]) - limit = "limit %s" % cint(limit) if limit else "" - result = frappe.db.sql_list("""select name from `tab{0}` - where lft<%s and rgt>%s order by {1} {2}""".format(doctype, order_by, limit), (lft, rgt)) + + result = [d["name"] for d in frappe.db.get_list(doctype, {"lft": ["<", lft], "rgt": [">", rgt]}, + "name", order_by=order_by, limit_page_length=limit)] + return result or [] def get_descendants_of(doctype, name, order_by="lft desc", limit=None): '''Return descendants of the current record''' lft, rgt = frappe.db.get_value(doctype, name, ['lft', 'rgt']) - limit = "limit %s" % cint(limit) if limit else "" - result = frappe.db.sql_list("""select name from `tab{0}` - where lft>%s and rgt<%s order by {1} {2}""".format(doctype, order_by, limit), (lft, rgt)) + + result = [d["name"] for d in frappe.db.get_list(doctype, {"lft": [">", lft], "rgt": ["<", rgt]}, + "name", order_by=order_by, limit_page_length=limit)] + return result or [] From a67cecf9813e9e2a4f5361fabeeffb491e28c76d Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 1 Feb 2019 17:34:12 +0530 Subject: [PATCH 029/330] fix(test): Use single quotes for empty string (constant) (#6871) * Use single quotes for empty string since value inside double quotes is considered as Identifier in postgres * Do not show change log modal when in test * Revert "Do not show change log modal when in test" This reverts commit 6c2c3fd80cad3ff491b7d3b60a2b756ba6823bf8. * Do not show change log modal when in test - To check it is test environment we are checking if Cypress is loaded on window object --- frappe/model/db_query.py | 2 +- frappe/public/js/frappe/desk.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index 178bc427eb..66238dd4b0 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -458,7 +458,7 @@ class DatabaseQuery(object): f.operator = '=' value = "" - fallback = '""' + fallback = "''" can_be_null = True if 'ifnull' not in column_name: diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index 68ff55efe5..5313f64b41 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -72,7 +72,7 @@ frappe.Application = Class.extend({ frappe.msgprint(frappe.boot.messages); } - if (frappe.boot.change_log && frappe.boot.change_log.length) { + if (frappe.boot.change_log && frappe.boot.change_log.length && !window.Cypress) { this.show_change_log(); } else { this.show_notes(); From 94cd6ce59b816b1b4151ef1fb667cd8f771d387f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Sat, 2 Feb 2019 22:07:12 +0530 Subject: [PATCH 030/330] fix: Order by param in report builder (#6877) --- frappe/core/doctype/report/report.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py index 3f9162ffd7..789c989439 100644 --- a/frappe/core/doctype/report/report.py +++ b/frappe/core/doctype/report/report.py @@ -150,6 +150,8 @@ class Report(Document): if params.get('sort_by'): order_by = _format(params.get('sort_by').split('.')) + ' ' + params.get('sort_order') + elif params.get('order_by'): + order_by = params.get('order_by') else: order_by = _format([self.ref_doctype, 'modified']) + ' desc' From c50ad322254cc417018358390656e5b5716b70a9 Mon Sep 17 00:00:00 2001 From: Saif Ur Rehman Date: Sun, 3 Feb 2019 05:20:30 +0500 Subject: [PATCH 031/330] 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 032/330] 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 033/330] 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 ff3ee03f11966962e775b2a5fb4b8c77790e56e3 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 4 Feb 2019 14:30:29 +0530 Subject: [PATCH 034/330] fix: Download read-only fields from grid --- frappe/public/js/frappe/form/grid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js index a535d0b35a..cdd3b6fb69 100644 --- a/frappe/public/js/frappe/form/grid.js +++ b/frappe/public/js/frappe/form/grid.js @@ -684,7 +684,7 @@ export default class Grid { data.push(["------"]); $.each(frappe.get_meta(me.df.options).fields, function(i, df) { // don't include the read-only field in the template - if(frappe.model.is_value_type(df.fieldtype) && !df.read_only) { + if(frappe.model.is_value_type(df.fieldtype)) { data[1].push(df.label); data[2].push(df.fieldname); let description = (df.description || "") + ' '; From b38c018c3779ea4017b035539be9113e9e142be3 Mon Sep 17 00:00:00 2001 From: Anurag Mishra Date: Mon, 4 Feb 2019 15:37:49 +0530 Subject: [PATCH 035/330] 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 cac2ca53f2702b3e4274377141746572a7f3fb54 Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Tue, 5 Feb 2019 10:50:16 +0530 Subject: [PATCH 036/330] fix(chat_profile): rename chat profile when email is renamed (#6885) chat profile should be renamed when user renames their email id, else the chat profile won't be found Signed-off-by: Chinmay Pai Co-authored-by: Suraj Shetty --- frappe/core/doctype/user/user.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index 5a08f51df1..e746914399 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -358,6 +358,9 @@ class User(Document): where `%s`=%s""" % \ (tab[0], field, '%s', field, '%s'), (new_name, old_name)) + if frappe.db.exists("Chat Profile", old_name): + frappe.rename_doc("Chat Profile", old_name, new_name, force=True) + # set email frappe.db.sql("""\ update `tabUser` set email=%s From 96bff3cd9e5a34bbae48f33a200e3a19c5687604 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 5 Feb 2019 10:52:00 +0530 Subject: [PATCH 037/330] fix: jinja local.conf data leak (#6884) --- frappe/templates/includes/blog/hero.html | 2 +- frappe/utils/jinja.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/templates/includes/blog/hero.html b/frappe/templates/includes/blog/hero.html index 8ec47f3ac0..b8a39e5c9c 100644 --- a/frappe/templates/includes/blog/hero.html +++ b/frappe/templates/includes/blog/hero.html @@ -1,4 +1,4 @@ -{% if blog_title and not (frappe.local.form_dict.txt or frappe.local.form_dict.by) %} +{% if blog_title and not (form_dict.txt or form_dict.by) %}

diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index d0a2c34a6e..86b586667d 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -56,7 +56,7 @@ def render_template(template, context, is_path=None, safe_render=True): :param template: path or HTML containing the jinja template :param context: dict of properties to pass to the template :param is_path: (optional) assert that the `template` parameter is a path - :param safe_render: (optional) prevent server side scripting via jinja templating + :param safe_render: (optional) prevent server side scripting via jinja templating ''' from frappe import throw @@ -117,7 +117,6 @@ def get_allowed_functions_for_jenv(): 'date_format': date_format, "format_date": frappe.utils.data.global_date_format, "form_dict": getattr(frappe.local, 'form_dict', {}), - "local": frappe.local, "get_hooks": frappe.get_hooks, "get_meta": frappe.get_meta, "get_doc": frappe.get_doc, @@ -130,6 +129,7 @@ def get_allowed_functions_for_jenv(): "get_gravatar": frappe.utils.get_gravatar_url, "full_name": frappe.local.session.data.full_name if getattr(frappe.local, "session", None) else "Guest", "render_template": frappe.render_template, + "request": getattr(frappe.local, 'request', {}), 'session': { 'user': user, 'csrf_token': frappe.local.session.data.csrf_token if getattr(frappe.local, "session", None) else '' From 9373125c0a9b59a2c6bb16e5bcc5214a72e1c531 Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Tue, 5 Feb 2019 10:52:54 +0530 Subject: [PATCH 038/330] fix(reportview): cast docname to string (#6876) * fix(reportview): cast docname to string explicitly cast docnames to string to fix sorting in reportview.py:217 Signed-off-by: Chinmay Pai * fix: codacy changes i hate codacy. * fix(reportview): remove redundant safe_decode call --- frappe/desk/reportview.py | 2 +- frappe/public/js/frappe/views/reports/reportview.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index fef0db9f74..4df25fb1e8 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -214,7 +214,7 @@ def delete_items(): """delete selected items""" import json - il = sorted(json.loads(frappe.form_dict.get('items')), reverse=True, key=frappe.safe_decode) + il = sorted(json.loads(frappe.form_dict.get('items')), reverse=True) doctype = frappe.form_dict.get('doctype') failed = [] diff --git a/frappe/public/js/frappe/views/reports/reportview.js b/frappe/public/js/frappe/views/reports/reportview.js index b3b454afee..f10e0922af 100644 --- a/frappe/public/js/frappe/views/reports/reportview.js +++ b/frappe/public/js/frappe/views/reports/reportview.js @@ -801,7 +801,9 @@ frappe.views.ReportView = frappe.ui.BaseList.extend({ }); this.page.add_menu_item(__("Delete"), function() { - var delete_list = $.map(me.get_checked_items(), function(d) { return d.name; }); + var delete_list = $.map(me.get_checked_items(), function(d) { + return d.name.toString(); + }); if(!delete_list.length) return; if(frappe.confirm(__("This is PERMANENT action and you cannot undo. Continue?"), From 6377bdf6db5b49927ab3d4b12e09bf7ee64a1cf6 Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Tue, 5 Feb 2019 10:53:31 +0530 Subject: [PATCH 039/330] fix(data_import): use absolute url (#6875) there is no need to prepend the sitename to the url, since browsers/html are/is smart enough to handle absolute urls. Signed-off-by: Chinmay Pai --- frappe/core/doctype/data_import/importer.py | 12 ++++++------ frappe/utils/data.py | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frappe/core/doctype/data_import/importer.py b/frappe/core/doctype/data_import/importer.py index 4ab7c3a10c..99c29be76f 100644 --- a/frappe/core/doctype/data_import/importer.py +++ b/frappe/core/doctype/data_import/importer.py @@ -16,7 +16,7 @@ from frappe.utils.csvutils import getlink from frappe.utils.dateutils import parse_date from frappe.utils.file_manager import save_url -from frappe.utils import cint, cstr, flt, getdate, get_datetime, get_url, get_url_to_form +from frappe.utils import cint, cstr, flt, getdate, get_datetime, get_url, get_absolute_url from six import text_type, string_types @@ -411,16 +411,16 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, # log errors if parentfield: log(**{"row": doc.idx, "title": 'Inserted row for "%s"' % (as_link(parenttype, doc.parent)), - "link": get_url_to_form(parenttype, doc.parent), "message": 'Document successfully saved', "indicator": "green"}) + "link": get_absolute_url(parenttype, doc.parent), "message": 'Document successfully saved', "indicator": "green"}) elif submit_after_import: log(**{"row": row_idx + 1, "title":'Submitted row for "%s"' % (as_link(doc.doctype, doc.name)), - "message": "Document successfully submitted", "link": get_url_to_form(doc.doctype, doc.name), "indicator": "blue"}) + "message": "Document successfully submitted", "link": get_absolute_url(doc.doctype, doc.name), "indicator": "blue"}) elif original: log(**{"row": row_idx + 1,"title":'Updated row for "%s"' % (as_link(doc.doctype, doc.name)), - "message": "Document successfully updated", "link": get_url_to_form(doc.doctype, doc.name), "indicator": "green"}) + "message": "Document successfully updated", "link": get_absolute_url(doc.doctype, doc.name), "indicator": "green"}) elif not update_only: log(**{"row": row_idx + 1, "title":'Inserted row for "%s"' % (as_link(doc.doctype, doc.name)), - "message": "Document successfully saved", "link": get_url_to_form(doc.doctype, doc.name), "indicator": "green"}) + "message": "Document successfully saved", "link": get_absolute_url(doc.doctype, doc.name), "indicator": "green"}) else: log(**{"row": row_idx + 1, "title":'Ignored row for %s' % (row[1]), "link": None, "message": "Document updation ignored", "indicator": "orange"}) @@ -437,7 +437,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, error_trace = frappe.get_traceback() if error_trace: error_log_doc = frappe.log_error(error_trace) - error_link = get_url_to_form("Error Log", error_log_doc.name) + error_link = get_absolute_url("Error Log", error_log_doc.name) else: error_link = None diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 3e92d3e5b9..8e5b89f1ef 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -745,6 +745,9 @@ def get_link_to_form(doctype, name, label=None): return """{1}""".format(get_url_to_form(doctype, name), label) +def get_absolute_url(doctype, name): + return "desk#Form/{0}/{1}".format(quoted(doctype), quoted(name)) + def get_url_to_form(doctype, name): return get_url(uri = "desk#Form/{0}/{1}".format(quoted(doctype), quoted(name))) From 228522b555d4e6f740f6fa4ab326374bf3f13c33 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 5 Feb 2019 18:43:18 +0550 Subject: [PATCH 040/330] bumped to version 11.1.4 --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 666c51aea0..c540652c8c 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.3' +__version__ = '11.1.4' __title__ = "Frappe Framework" local = Local() From a7a4679a09221100d64d66be9b2b41310f138ad6 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 5 Feb 2019 18:41:19 +0530 Subject: [PATCH 041/330] 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 042/330] 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 043/330] 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 044/330] 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 045/330] 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 046/330] 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 65d21675516e76ec483fcf6f4a56cdc0eb6136e3 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 6 Feb 2019 11:12:18 +0530 Subject: [PATCH 047/330] feat: various fixes to Web Form and content type selection for Web Page and Blog Post --- .../public/js/frappe/form/controls/check.js | 20 +- frappe/public/js/frappe/ui/messages.js | 7 +- .../public/js/frappe/ui/toolbar/navbar.html | 4 +- frappe/public/less/desk.less | 2 +- frappe/public/less/navbar.less | 8 + frappe/templates/base.html | 6 + frappe/templates/styles/standard.css | 4 +- frappe/website/css/web_form.css | 8 +- .../website/doctype/blog_post/blog_post.json | 858 ++--- frappe/website/doctype/blog_post/blog_post.py | 7 +- .../doctype/web_form/templates/web_form.html | 4 +- frappe/website/doctype/web_form/web_form.json | 2757 +++++++++-------- .../web_form_field/web_form_field.json | 1070 +++---- .../website/doctype/web_page/test_web_page.py | 34 +- frappe/website/doctype/web_page/web_page.json | 166 +- frappe/website/doctype/web_page/web_page.py | 9 +- frappe/website/js/web_form_class.js | 13 +- frappe/website/router.py | 5 + frappe/website/utils.py | 16 + frappe/website/website_generator.py | 3 + 20 files changed, 2697 insertions(+), 2304 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/check.js b/frappe/public/js/frappe/form/controls/check.js index b54571b166..a9d2e78264 100644 --- a/frappe/public/js/frappe/form/controls/check.js +++ b/frappe/public/js/frappe/form/controls/check.js @@ -1,16 +1,16 @@ frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({ input_type: "checkbox", make_wrapper: function() { - this.$wrapper = $('
\ -
\ - \ -

\ -
\ -
').appendTo(this.parent); + this.$wrapper = $(`
+
+ +

+
+
`).appendTo(this.parent); }, set_input_areas: function() { this.label_area = this.label_span = this.$wrapper.find(".label-area").get(0); diff --git a/frappe/public/js/frappe/ui/messages.js b/frappe/public/js/frappe/ui/messages.js index ed3d4c1f64..5231e5a449 100644 --- a/frappe/public/js/frappe/ui/messages.js +++ b/frappe/public/js/frappe/ui/messages.js @@ -100,12 +100,7 @@ frappe.msgprint = function(msg, title) { if(data.message instanceof Array) { data.message.forEach(function(m) { - const msg = { - message: m, - indicator: data.indicator, - title: data.title - } - frappe.msgprint(msg); + frappe.msgprint(m); }); return; } diff --git a/frappe/public/js/frappe/ui/toolbar/navbar.html b/frappe/public/js/frappe/ui/toolbar/navbar.html index 12e4c5beaa..729365f53a 100644 --- a/frappe/public/js/frappe/ui/toolbar/navbar.html +++ b/frappe/public/js/frappe/ui/toolbar/navbar.html @@ -4,7 +4,9 @@ - +

diff --git a/frappe/public/less/desk.less b/frappe/public/less/desk.less index a5a9fa0fa5..9bcb0d1565 100644 --- a/frappe/public/less/desk.less +++ b/frappe/public/less/desk.less @@ -761,7 +761,7 @@ li.user-progress { } .checkbox label { - padding-left: 0px; + padding-left: 2px; } .checkbox input[type=checkbox] { diff --git a/frappe/public/less/navbar.less b/frappe/public/less/navbar.less index d044a730fd..01398042c7 100644 --- a/frappe/public/less/navbar.less +++ b/frappe/public/less/navbar.less @@ -33,6 +33,14 @@ .badge { font-weight: normal; } + + .navbar-home { + img { + width: 24px; + margin-right: 0px; + margin-top: -3px; + } + } } .navbar-icon-home { diff --git a/frappe/templates/base.html b/frappe/templates/base.html index 9c68254e2f..fd427bedff 100644 --- a/frappe/templates/base.html +++ b/frappe/templates/base.html @@ -16,9 +16,15 @@ {% endblock %} {%- block head -%} {% block meta_block %}{% endblock %} + {% if head_html is defined -%} {{ head_html or "" }} {%- endif %} + + {% for key in meta %} + {% if meta[key] %}{% endif %} + {% endfor %} + {%- for link in web_include_css %} {%- endfor -%} diff --git a/frappe/templates/styles/standard.css b/frappe/templates/styles/standard.css index e8c14210f9..39ea31a805 100644 --- a/frappe/templates/styles/standard.css +++ b/frappe/templates/styles/standard.css @@ -1,7 +1,7 @@ @media screen { .print-format-gutter { - background-color: #ddd; - padding: 15px 0px; + background-color: #d1d8dd; + padding: 30px 0px; } .print-format { background-color: white; diff --git a/frappe/website/css/web_form.css b/frappe/website/css/web_form.css index 266f0332af..c9f9c87adf 100644 --- a/frappe/website/css/web_form.css +++ b/frappe/website/css/web_form.css @@ -11,8 +11,8 @@ font-weight: normal; } -input[type='checkbox'] { - margin-top: 3px; +.checkbox .label-area { + padding-left: 3px; } .page-header-actions-block .btn-delete { @@ -32,10 +32,6 @@ input[type='checkbox'] { display: none; } -.checkbox label { - font-size: 12px; -} - .web-form-page, .web-form-page .section { padding: 20px 0px; } diff --git a/frappe/website/doctype/blog_post/blog_post.json b/frappe/website/doctype/blog_post/blog_post.json index 21be444dce..dbd665bbf1 100644 --- a/frappe/website/doctype/blog_post/blog_post.json +++ b/frappe/website/doctype/blog_post/blog_post.json @@ -1,394 +1,528 @@ { - "allow_copy": 0, - "allow_guest_to_view": 1, - "allow_import": 1, - "allow_rename": 0, - "beta": 0, - "creation": "2013-03-28 10:35:30", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, - "engine": "InnoDB", + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 1, + "allow_import": 1, + "allow_rename": 0, + "beta": 0, + "creation": "2013-03-28 10:35:30", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 0, + "engine": "InnoDB", "fields": [ { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "title", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Title", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "title", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 1, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Title", + "length": 0, + "no_copy": 1, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "published_on", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Published On", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "published_on", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Published On", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "published", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Published", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "published", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Published", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "blog_category", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Blog Category", - "length": 0, - "no_copy": 0, - "options": "Blog Category", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "blog_category", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Blog Category", + "length": 0, + "no_copy": 0, + "options": "Blog Category", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "blogger", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Blogger", - "length": 0, - "no_copy": 0, - "options": "Blogger", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "blogger", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Blogger", + "length": 0, + "no_copy": 0, + "options": "Blogger", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "route", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Route", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "route", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Route", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 1 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_5", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_5", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Description for listing page, in plain text, only a couple of lines. (max 140 characters)", - "fieldname": "blog_intro", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Blog Intro", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "description": "Description for listing page, in plain text, only a couple of lines. (max 140 characters)", + "fieldname": "blog_intro", + "fieldtype": "Small Text", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Blog Intro", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "content", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Content", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Rich Text", + "fieldname": "content_type", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Content Type", + "length": 0, + "no_copy": 0, + "options": "Rich Text\nMarkdown\nHTML", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "email_sent", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Email Sent", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.content_type === 'Rich Text'", + "fieldname": "content", + "fieldtype": "Text Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 1, + "in_filter": 0, + "in_global_search": 1, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Content", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.content_type === 'Markdown'", + "fieldname": "content_md", + "fieldtype": "Markdown Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Content (Markdown)", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:doc.content_type === 'HTML'", + "fieldname": "content_html", + "fieldtype": "HTML Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Content (HTML)", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "email_sent", + "fieldtype": "Check", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Email Sent", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 } - ], - "has_web_view": 1, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-quote-left", - "idx": 1, - "image_view": 0, - "in_create": 0, - "is_published_field": "published", - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 5, - "modified": "2017-03-06 16:25:33.410910", - "modified_by": "Administrator", - "module": "Website", - "name": "Blog Post", - "owner": "Administrator", + ], + "has_web_view": 1, + "hide_heading": 0, + "hide_toolbar": 0, + "icon": "fa fa-quote-left", + "idx": 1, + "image_view": 0, + "in_create": 0, + "is_published_field": "published", + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 5, + "modified": "2019-02-01 16:34:03.418705", + "modified_by": "Administrator", + "module": "Website", + "name": "Blog Post", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Website Manager", - "set_user_permissions": 1, - "share": 1, - "submit": 0, + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Website Manager", + "set_user_permissions": 1, + "share": 1, + "submit": 0, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Blogger", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Blogger", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "route": "/blog", - "show_name_in_global_search": 0, - "sort_order": "ASC", - "title_field": "title", - "track_changes": 1, - "track_seen": 0 + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "route": "/blog", + "show_name_in_global_search": 0, + "sort_order": "ASC", + "title_field": "title", + "track_changes": 1, + "track_seen": 0, + "track_views": 0 } \ No newline at end of file diff --git a/frappe/website/doctype/blog_post/blog_post.py b/frappe/website/doctype/blog_post/blog_post.py index c2d1bf26d6..7943ead3bc 100644 --- a/frappe/website/doctype/blog_post/blog_post.py +++ b/frappe/website/doctype/blog_post/blog_post.py @@ -8,7 +8,7 @@ from frappe import _ from frappe.website.website_generator import WebsiteGenerator from frappe.website.render import clear_cache from frappe.utils import today, cint, global_date_format, get_fullname, strip_html_tags, markdown -from frappe.website.utils import find_first_image, get_comment_list +from frappe.website.utils import (find_first_image, get_comment_list, get_html_content_based_on_type) class BlogPost(WebsiteGenerator): website = frappe._dict( @@ -58,14 +58,13 @@ class BlogPost(WebsiteGenerator): context.description = self.blog_intro or self.content[:140] + context.content = get_html_content_based_on_type(self, 'content', self.content_type) + context.metatags = { "name": self.title, "description": context.description, } - if "" in context.content: - context.content = markdown(context.content) - image = find_first_image(self.content) if image: context.metatags["image"] = image diff --git a/frappe/website/doctype/web_form/templates/web_form.html b/frappe/website/doctype/web_form/templates/web_form.html index f3377f8366..b3bf648038 100644 --- a/frappe/website/doctype/web_form/templates/web_form.html +++ b/frappe/website/doctype/web_form/templates/web_form.html @@ -22,7 +22,7 @@ {%- endif %} {% if not is_list %} + {{ _(button_label or "Save") }} {% endif %}
{% endif %} @@ -152,7 +152,7 @@ {% if (loop.index == layout|len or frappe.form_dict.new) %} {% if not read_only %} + {{ _(button_label or "Save") }} {% endif %} {% elif layout|len > 1 %} @@ -140,6 +141,10 @@ export default { this.last_fetched = new Date(); }); }, + clear: function() { + frappe.call("frappe.www.recorder.erase_requests"); + this.refresh(); + }, record: function(should_record) { frappe.call({ method: "frappe.www.recorder.set_recorder_state", diff --git a/frappe/www/recorder.py b/frappe/www/recorder.py index 3d50d65f42..30d7b836da 100644 --- a/frappe/www/recorder.py +++ b/frappe/www/recorder.py @@ -50,6 +50,12 @@ def get_requests(): return requests +@frappe.whitelist() +def erase_requests(): + do_not_record() + frappe.cache().delete_value("recorder-requests") + + @frappe.whitelist() def get_request_data(uuid): do_not_record() From d0b8d0fa0f6f17ee32e3e755e329dc607668665b Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Sat, 19 Jan 2019 22:51:05 +0530 Subject: [PATCH 277/330] feat(recorder): Show duration field in request list --- frappe/public/js/frappe/recorder/RecorderDetail.vue | 3 +++ frappe/recorder.py | 1 + 2 files changed, 4 insertions(+) diff --git a/frappe/public/js/frappe/recorder/RecorderDetail.vue b/frappe/public/js/frappe/recorder/RecorderDetail.vue index fe5efbe7e5..a7c67dbe68 100644 --- a/frappe/public/js/frappe/recorder/RecorderDetail.vue +++ b/frappe/public/js/frappe/recorder/RecorderDetail.vue @@ -14,6 +14,7 @@ Index Time + Duration Method Path CMD @@ -21,6 +22,7 @@ + @@ -30,6 +32,7 @@ {{ request.index }} {{ request.time }} + {{ request.duration }} {{ request.method }} {{ request.path | elipsize }} {{ request.cmd | elipsize }} diff --git a/frappe/recorder.py b/frappe/recorder.py index 31e7722a37..606a5aac51 100644 --- a/frappe/recorder.py +++ b/frappe/recorder.py @@ -102,6 +102,7 @@ class Recorder(): "path": self.path, "cmd": self.cmd, "time": self.time, + "duration": float("{:0.3f}".format((datetime.datetime.now() - self.time).total_seconds() * 1000)), "method": self.method, }, default=lambda x: str(x)) ) From 9fe6fa63394e14106130c3610fd8a7dbe3c9a8de Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Sat, 19 Jan 2019 23:05:15 +0530 Subject: [PATCH 278/330] fix(recorder): Improve Table styling --- .../js/frappe/recorder/RecorderDetail.vue | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/frappe/public/js/frappe/recorder/RecorderDetail.vue b/frappe/public/js/frappe/recorder/RecorderDetail.vue index a7c67dbe68..99e80da4b1 100644 --- a/frappe/public/js/frappe/recorder/RecorderDetail.vue +++ b/frappe/public/js/frappe/recorder/RecorderDetail.vue @@ -12,12 +12,12 @@ - - - - - - + + + + + + @@ -25,9 +25,9 @@ - - - + + + From 10f8fad12db0a6c810d411b3d8ac1d905ec86c15 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Sat, 19 Jan 2019 23:14:00 +0530 Subject: [PATCH 279/330] fix(recorder): Sort based on cmd correctly --- frappe/recorder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/recorder.py b/frappe/recorder.py index 606a5aac51..49b3017dc7 100644 --- a/frappe/recorder.py +++ b/frappe/recorder.py @@ -82,7 +82,7 @@ class Recorder(): self.time = datetime.datetime.now() self.calls = [] self.path = frappe.request.path - self.cmd = frappe.local.form_dict.cmd + self.cmd = frappe.local.form_dict.cmd or "" self.method = frappe.request.method self.request = { From b0faf643868e12f7fd0e813cd8cdcd16c866aa39 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Sat, 19 Jan 2019 23:14:52 +0530 Subject: [PATCH 280/330] style: Linting fixes --- frappe/app.py | 1 - .../public/js/frappe/recorder/RecorderDetail.vue | 2 +- frappe/public/js/frappe/recorder/recorder.js | 14 +++++++------- frappe/recorder.py | 16 +++++++++------- frappe/www/recorder.py | 1 - 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/frappe/app.py b/frappe/app.py index 747464944f..9da7ea71a0 100644 --- a/frappe/app.py +++ b/frappe/app.py @@ -3,7 +3,6 @@ # MIT License. See license.txt from __future__ import unicode_literals -import json import os from six import iteritems import logging diff --git a/frappe/public/js/frappe/recorder/RecorderDetail.vue b/frappe/public/js/frappe/recorder/RecorderDetail.vue index 99e80da4b1..b3391e4201 100644 --- a/frappe/public/js/frappe/recorder/RecorderDetail.vue +++ b/frappe/public/js/frappe/recorder/RecorderDetail.vue @@ -9,7 +9,7 @@ -
IndexTimeDurationMethodPathCMDIndexTimeDurationMethodPathCMD
{{ request.index }}
+
diff --git a/frappe/public/js/frappe/recorder/recorder.js b/frappe/public/js/frappe/recorder/recorder.js index 7ddaefe330..3bae466aad 100644 --- a/frappe/public/js/frappe/recorder/recorder.js +++ b/frappe/public/js/frappe/recorder/recorder.js @@ -1,11 +1,11 @@ -import Vue from 'vue/dist/vue.js' -import VueRouter from 'vue-router/dist/vue-router.js' +import Vue from 'vue/dist/vue.js'; +import VueRouter from 'vue-router/dist/vue-router.js'; -import RecorderRoot from "./RecorderRoot.vue" +import RecorderRoot from "./RecorderRoot.vue"; -import RecorderDetail from "./RecorderDetail.vue" -import RequestDetail from "./RequestDetail.vue" -import SQLDetail from "./SQLDetail.vue" +import RecorderDetail from "./RecorderDetail.vue"; +import RequestDetail from "./RequestDetail.vue"; +import SQLDetail from "./SQLDetail.vue"; frappe.ready(function() { Vue.use(VueRouter) @@ -25,7 +25,7 @@ frappe.ready(function() { path: '/request/:request_uuid/sql/:call_index', component: SQLDetail, }, - ] + ]; const router = new VueRouter({ mode: 'hash', diff --git a/frappe/recorder.py b/frappe/recorder.py index 49b3017dc7..d3b9f36ef1 100644 --- a/frappe/recorder.py +++ b/frappe/recorder.py @@ -89,7 +89,7 @@ class Recorder(): "headers": dict(frappe.local.request.headers), "data": frappe.local.form_dict, } - self._patch() + _patch() def register(self, data): self.calls.append(data) @@ -104,17 +104,19 @@ class Recorder(): "time": self.time, "duration": float("{:0.3f}".format((datetime.datetime.now() - self.time).total_seconds() * 1000)), "method": self.method, - }, default=lambda x: str(x)) + }, default=str) ) frappe.cache().set( "recorder-request-{}".format(self.uuid), - json.dumps(self.calls, default=lambda x: str(x)) + json.dumps(self.calls, default=str) ) - def _patch(self): - frappe.db._sql = frappe.db.sql - frappe.db.sql = sql - frappe.db._sql("SET PROFILING = 1") + +def _patch(): + frappe.db._sql = frappe.db.sql + frappe.db.sql = sql + frappe.db._sql("SET PROFILING = 1") + def compress(data): if data: diff --git a/frappe/www/recorder.py b/frappe/www/recorder.py index 30d7b836da..91515dbd2f 100644 --- a/frappe/www/recorder.py +++ b/frappe/www/recorder.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import frappe import json -import redis from pygments.formatters import HtmlFormatter def do_not_record(): From 874dedc0670301f1407350339362b69f3dba9fbd Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Sat, 19 Jan 2019 23:32:13 +0530 Subject: [PATCH 281/330] feat(recorder): Add First and Last button in pagination --- .../js/frappe/recorder/RecorderDetail.vue | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/recorder/RecorderDetail.vue b/frappe/public/js/frappe/recorder/RecorderDetail.vue index b3391e4201..8c6823f34b 100644 --- a/frappe/public/js/frappe/recorder/RecorderDetail.vue +++ b/frappe/public/js/frappe/recorder/RecorderDetail.vue @@ -12,10 +12,10 @@
Index
- - + + - + @@ -87,7 +87,11 @@ export default { const current_page = this.query.pagination.page; const total_pages = this.query.pagination.total; return [{ - label:"Previous", + label: "First", + number: 1, + status: (current_page == 1) ? "disabled" : "", + },{ + label: "Previous", number: Math.max(current_page - 1, 1), status: (current_page == 1) ? "disabled" : "", }, { @@ -95,9 +99,13 @@ export default { number: current_page, status: "active", }, { - label:"Next", + label: "Next", number: Math.min(current_page + 1, total_pages), status: (current_page == total_pages) ? "disabled" : "", + }, { + label: "Last", + number: total_pages, + status: (current_page == total_pages) ? "disabled" : "", }]; } }, From 5b4ec4dc221bcd55eac9e1b35493b5d5846b0ec8 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Sat, 19 Jan 2019 23:45:32 +0530 Subject: [PATCH 282/330] fix(recorder): Show query execution time in ms --- frappe/recorder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/recorder.py b/frappe/recorder.py index d3b9f36ef1..3eadfdd6d1 100644 --- a/frappe/recorder.py +++ b/frappe/recorder.py @@ -56,7 +56,7 @@ def sql(*args, **kwargs): "time": { "start": start_time, "end": end_time, - "total": end_time - start_time, + "total": float("{:.3f}".format((end_time - start_time) * 1000)), }, } From d9c2fab8923a69133d45fd691ba6b9abea442bdb Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Sun, 20 Jan 2019 00:03:19 +0530 Subject: [PATCH 283/330] feat(recorder): Interactive table for sql list --- .../js/frappe/recorder/RequestDetail.vue | 56 ++++++++++++++++--- frappe/recorder.py | 7 +-- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/frappe/public/js/frappe/recorder/RequestDetail.vue b/frappe/public/js/frappe/recorder/RequestDetail.vue index 60c0d8adf0..409397f148 100644 --- a/frappe/public/js/frappe/recorder/RequestDetail.vue +++ b/frappe/public/js/frappe/recorder/RequestDetail.vue @@ -1,19 +1,22 @@
IndexTimeIndexTime DurationMethodMethod Path CMD