Merge branch 'hotfix'

This commit is contained in:
Saurabh 2019-01-30 12:29:38 +05:30
commit 5f817ed5df
18 changed files with 269 additions and 84 deletions

View file

@ -23,7 +23,7 @@ if sys.version[0] == '2':
reload(sys)
sys.setdefaultencoding("utf-8")
__version__ = '11.1.0'
__version__ = '11.1.1'
__title__ = "Frappe Framework"
local = Local()

View file

@ -686,5 +686,7 @@ commands = [
watch,
_bulk_rename,
add_to_email_queue,
setup_global_help,
setup_help,
rebuild_global_search
]

View file

@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@ -42,7 +43,7 @@
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
"unique": 1
},
{
"allow_bulk_edit": 0,
@ -562,7 +563,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "prepared_report",
"fieldname": "disable_prepared_report",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@ -571,15 +572,47 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Disable Prepared Report",
"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": "prepared_report",
"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": "Prepared Report",
"length": 0,
"no_copy": 0,
"options": "Yes\nNo",
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@ -600,7 +633,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-06-27 14:48:49.989952",
"modified": "2019-01-25 12:04:50.833264",
"modified_by": "Administrator",
"module": "Core",
"name": "Report",

View file

@ -193,3 +193,8 @@ class Report(Document):
@Document.whitelist
def toggle_disable(self, disable):
self.db_set("disabled", cint(disable))
@frappe.whitelist()
def is_prepared_report_disabled(report):
return frappe.db.get_value('Report',
report, 'disable_prepared_report') or 0

View file

@ -9,10 +9,14 @@ frappe.ui.form.on('Role Permission for Page and Report', {
refresh: function(frm) {
frm.disable_save();
frm.role_area.hide();
frm.add_custom_button(__("Reset to defaults"),
function(){ frm.trigger("reset_roles") });
frm.add_custom_button(__("Update"),
function(){ frm.trigger("update_roles") }).addClass('btn-primary');
frm.add_custom_button(__("Reset to defaults"), function() {
frm.trigger("reset_roles");
});
frm.add_custom_button(__("Update"), function() {
frm.trigger("update_report_page_data");
}).addClass('btn-primary');
},
onload: function(frm) {
@ -45,22 +49,22 @@ frappe.ui.form.on('Role Permission for Page and Report', {
page: function(frm) {
if(frm.doc.page) {
frm.trigger("get_roles")
frm.trigger("set_report_page_data");
}
},
report: function(frm){
if(frm.doc.report) {
frm.trigger("get_roles")
frm.trigger("set_report_page_data");
}
},
get_roles: function(frm) {
set_report_page_data: function(frm) {
frm.toggle_display('roles_html', true)
frm.role_area.show();
return frm.call({
method:"get_custom_roles",
method:"set_report_page_data",
doc: frm.doc,
callback: function(r) {
refresh_field('roles')
@ -69,14 +73,14 @@ frappe.ui.form.on('Role Permission for Page and Report', {
})
},
update_roles: function(frm) {
update_report_page_data: function(frm) {
frm.trigger("validate_mandatory_fields")
if(frm.roles_editor) {
frm.roles_editor.set_roles_in_table()
}
return frm.call({
method:"set_custom_roles",
method:"update_report_page_data",
doc: frm.doc,
callback: function(r) {
refresh_field('roles')

View file

@ -1,5 +1,6 @@
{
"allow_copy": 1,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@ -13,6 +14,8 @@
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@ -24,7 +27,7 @@
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Set Role For",
"length": 0,
@ -40,9 +43,12 @@
"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,
@ -71,9 +77,12 @@
"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,
@ -102,9 +111,77 @@
"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": "column_break_4",
"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,
"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": "report",
"fetch_from": "",
"fieldname": "disable_prepared_report",
"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": "Disable Prepared Report",
"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,
@ -131,9 +208,12 @@
"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,
@ -161,9 +241,12 @@
"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,
@ -191,6 +274,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
@ -204,7 +288,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-03-11 02:35:32.369043",
"modified": "2019-01-25 12:08:57.250719",
"modified_by": "Administrator",
"module": "Core",
"name": "Role Permission for Page and Report",
@ -213,7 +297,6 @@
"permissions": [
{
"amend": 0,
"apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 1,
@ -239,5 +322,6 @@
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0
"track_seen": 0,
"track_views": 0
}

View file

@ -4,10 +4,15 @@
from __future__ import unicode_literals
import frappe
from frappe.core.doctype.report.report import is_prepared_report_disabled
from frappe.model.document import Document
class RolePermissionforPageandReport(Document):
def get_custom_roles(self):
def set_report_page_data(self):
self.set_custom_roles()
self.check_prepared_report_disabled()
def set_custom_roles(self):
args = self.get_args()
self.set('roles', [])
@ -19,7 +24,11 @@ class RolePermissionforPageandReport(Document):
roles = self.get_standard_roles()
self.set('roles', roles)
def check_prepared_report_disabled(self):
if self.report:
self.disable_prepared_report = is_prepared_report_disabled(self.report)
def get_standard_roles(self):
doctype = self.set_role_for
docname = self.page if self.set_role_for == 'Page' else self.report
@ -29,9 +38,14 @@ class RolePermissionforPageandReport(Document):
def reset_roles(self):
roles = self.get_standard_roles()
self.set('roles', roles)
self.set_custom_roles()
self.update_custom_roles()
self.update_disable_prepared_report()
def set_custom_roles(self):
def update_report_page_data(self):
self.update_custom_roles()
self.update_disable_prepared_report()
def update_custom_roles(self):
args = self.get_args()
name = frappe.db.get_value('Custom Role', args, "name")
@ -50,6 +64,10 @@ class RolePermissionforPageandReport(Document):
else:
frappe.get_doc(args).insert()
def update_disable_prepared_report(self):
if self.report:
frappe.db.set_value('Report', self.report, 'disable_prepared_report', self.disable_prepared_report)
def get_args(self, row=None):
name = self.page if self.set_role_for == 'Page' else self.report
check_for_field = self.set_role_for.replace(" ","_").lower()

View file

@ -1624,7 +1624,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2018-10-01 17:35:13.043855",
"modified": "2019-01-30 11:02:41.011412",
"modified_by": "Administrator",
"module": "Core",
"name": "System Settings",

View file

@ -46,7 +46,7 @@ class TestCustomizeForm(unittest.TestCase):
d = self.get_customize_form("Event")
self.assertEquals(d.doc_type, "Event")
self.assertEquals(len(d.get("fields")), 30)
self.assertEquals(len(d.get("fields")), 28)
d = self.get_customize_form("Event")
self.assertEquals(d.doc_type, "Event")

View file

@ -58,7 +58,7 @@ def generate_report_result(report, filters=None, user=None):
module = report.module or frappe.db.get_value("DocType", report.ref_doctype, "module")
if report.is_standard == "Yes":
method_name = get_report_module_dotted_path(module, report.name) + ".execute"
threshold = 60
threshold = 30
res = []
start_time = datetime.datetime.now()
@ -67,9 +67,13 @@ def generate_report_result(report, filters=None, user=None):
end_time = datetime.datetime.now()
if (end_time - start_time).seconds > threshold and not report.prepared_report:
execution_time = (end_time - start_time).seconds
if execution_time > threshold and not report.prepared_report:
report.db_set('prepared_report', 1)
frappe.cache().hset('report_execution_time', report.name, execution_time)
columns, result = res[0], res[1]
if len(res) > 2:
message = res[2]
@ -90,7 +94,8 @@ def generate_report_result(report, filters=None, user=None):
"message": message,
"chart": chart,
"data_to_be_printed": data_to_be_printed,
"status": status
"status": status,
"execution_time": frappe.cache().hget('report_execution_time', report.name) or 0
}
@frappe.whitelist()
@ -148,7 +153,8 @@ def get_script(report_name):
return {
"script": render_include(script),
"html_format": html_format
"html_format": html_format,
"execution_time": frappe.cache().hget('report_execution_time', report_name) or 0
}
@ -165,7 +171,7 @@ def run(report_name, filters=None, user=None):
result = None
if report.prepared_report:
if report.prepared_report and not report.disable_prepared_report:
if filters:
if isinstance(filters, string_types):
filters = json.loads(filters)

View file

@ -1563,7 +1563,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-01 19:37:43.234891",
"modified": "2019-01-30 11:02:41.011412",
"modified_by": "Administrator",
"module": "Email",
"name": "Email Account",

View file

@ -147,7 +147,8 @@ scheduler_events = {
"frappe.integrations.doctype.razorpay_settings.razorpay_settings.capture_payment",
"frappe.twofactor.delete_all_barcodes_for_users",
"frappe.integrations.doctype.gcalendar_settings.gcalendar_settings.sync",
"frappe.website.doctype.web_page.web_page.check_publish_status"
"frappe.website.doctype.web_page.web_page.check_publish_status",
'frappe.utils.global_search.sync_global_search'
],
"hourly": [
"frappe.model.utils.link_count.update_link_count",

View file

@ -397,7 +397,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2017-03-08 17:16:01.087365",
"modified": "2019-01-30 11:02:41.011412",
"modified_by": "Administrator",
"module": "Integrations",
"name": "LDAP Settings",

View file

@ -754,7 +754,7 @@ class BaseDocument(object):
ref_doc = frappe.new_doc(self.doctype)
else:
# get values from old doc
if self.parent:
if self.get('parent_doc'):
self.parent_doc.get_latest()
ref_doc = [d for d in self.parent_doc.get(self.parentfield) if d.name == self.name][0]
else:

View file

@ -51,7 +51,13 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
this.primary_action = null;
this.secondary_action = {
label: __('Refresh'),
action: () => this.refresh()
action: () => {
if(this.execution_time > 2) {
this.setup_progress_bar();
}
this.refresh();
}
};
// throttle refresh for 300ms
@ -84,7 +90,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
return;
}
if (this.report_name !== frappe.get_route()[1]) {
this.toggle_loading(true);
// this.toggle_loading(true);
// different report
this.load_report();
} else {
@ -106,6 +112,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
frappe.run_serially([
() => this.get_report_doc(),
() => this.get_report_settings(),
() => this.setup_progress_bar(),
() => this.setup_page_head(),
() => this.refresh_report(),
() => this.add_make_chart_button()
@ -155,12 +162,24 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
return frappe.after_ajax(() => {
this.report_settings = frappe.query_reports[this.report_name];
this.report_settings.html_format = r.message.html_format;
this.report_settings.execution_time = r.message.execution_time || 0;
});
});
return this._load_script;
}
setup_progress_bar() {
let seconds_elapsed = 0;
const execution_time = this.report_settings.execution_time < 10
? 10 : this.report_settings.execution_time;
this.interval = setInterval(function() {
seconds_elapsed += 1;
frappe.show_progress(__('Preparing Report'), seconds_elapsed, execution_time);
}, 1000);
}
setup_filters() {
this.clear_filters();
const { filters = [] } = this.report_settings;
@ -272,8 +291,10 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
})
}).then(r => {
let data = r.message;
this.hide_status();
clearInterval(this.interval);
this.execution_time = data.execution_time || 0.1;
if (data.prepared_report) {
this.prepared_report = true;
@ -308,6 +329,9 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
} else {
this.toggle_nothing_to_show(true);
}
this.show_footer_message();
frappe.hide_progress();
});
}
@ -953,7 +977,6 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
this.$status = $(`<div class="form-message text-muted small"></div>`)
.hide().insertAfter(page_form);
this.show_tip();
this.$chart = $('<div class="chart-wrapper">').hide().appendTo(this.page.main);
this.$report = $('<div class="report-wrapper">').appendTo(this.page.main);
this.$message = $(this.message_div('')).hide().appendTo(this.page.main);
@ -967,9 +990,12 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
this.$status.hide();
}
show_tip() {
show_footer_message() {
const message = __('For comparison, use >5, <10 or =324. For ranges, use 5:10 (for values between 5 & 10).');
this.page.footer.removeClass('hide').addClass('text-muted text-center').html(`<p>${message}</p>`);
const execution_time_msg = __('Exection Time: {0} sec', [this.execution_time || 0.1]);
this.page.footer.removeClass('hide').addClass('text-muted col-md-12')
.html(`<span class="text-left col-md-6">${message}</span><span class="text-right col-md-6">${execution_time_msg}</span>`);
}
message_div(message) {

View file

@ -42,8 +42,10 @@ class TestGlobalSearch(unittest.TestCase):
repeat_on='Every Month',
starts_on=frappe.utils.now_datetime())).insert()
global_search.sync_global_search()
frappe.db.commit()
def test_search(self):
self.insert_test_events()
results = global_search.search('awakens')
@ -61,7 +63,7 @@ class TestGlobalSearch(unittest.TestCase):
event.subject = test_subject
event.save()
frappe.db.commit()
global_search.sync_global_search()
results = global_search.search('testing global search')
self.assertTrue('testing global search' in results[0].content)
@ -87,6 +89,7 @@ class TestGlobalSearch(unittest.TestCase):
self.assertEqual(len(results), 1)
frappe.delete_doc('Event', event_name)
global_search.sync_global_search()
results = global_search.search(test_subject)
self.assertEqual(len(results), 0)
@ -111,6 +114,7 @@ class TestGlobalSearch(unittest.TestCase):
})
doc.insert()
global_search.sync_global_search()
frappe.db.commit()
def test_get_field_value(self):

View file

@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe
import re
import redis
import json
from frappe.utils import cint, strip_html_tags
from frappe.model.base_document import get_controller
from frappe.model.db_schema import varchar_len
@ -76,6 +77,9 @@ def rebuild_for_doctype(doctype):
:param doctype: Doctype
"""
if frappe.local.conf.get('disable_global_search'):
return
def _get_filters():
filters = frappe._dict({ "docstatus": ["!=", 2] })
if meta.has_field("enabled"):
@ -228,17 +232,17 @@ def insert_values_for_multiple_docs(all_contents):
def update_global_search(doc):
"""
Add values marked with `in_global_search` to
`frappe.flags.update_global_search` from given doc
`global_search_queue` from given doc
:param doc: Document to be added to global search
"""
if frappe.local.conf.get('disable_global_search'):
return
if doc.docstatus > 1 or (doc.meta.has_field("enabled") and not doc.get("enabled")) \
or doc.get("disabled"):
return
if frappe.flags.update_global_search==None:
frappe.flags.update_global_search = []
content = []
for field in doc.meta.get_global_search_fields():
if doc.get(field.fieldname) and field.fieldtype != "Table":
@ -264,30 +268,21 @@ def update_global_search(doc):
title = (doc.get_title() or '')[:int(varchar_len)]
route = doc.get('route') if doc else ''
frappe.flags.update_global_search.append(
dict(
doctype=doc.doctype,
name=doc.name,
content=' ||| '.join(content or ''),
published=published,
title=title,
route=route
)
value = dict(
doctype=doc.doctype,
name=doc.name,
content=' ||| '.join(content or ''),
published=published,
title=title,
route=route
)
enqueue_global_search()
def enqueue_global_search():
if frappe.flags.update_global_search:
try:
frappe.enqueue('frappe.utils.global_search.sync_global_search',
now=frappe.flags.in_test or frappe.flags.in_install or frappe.flags.in_migrate,
flags=frappe.flags.update_global_search, enqueue_after_commit=True)
# append to search queue if connected
frappe.cache().lpush('global_search_queue', json.dumps(value))
except redis.exceptions.ConnectionError:
sync_global_search()
frappe.flags.update_global_search = []
# not connected, sync directly
sync_value(value)
def get_formatted_value(value, field):
@ -308,30 +303,30 @@ def get_formatted_value(value, field):
return field.label + " : " + strip_html_tags(text_type(value))
def sync_global_search(flags=None):
def sync_global_search():
"""
Add values from `flags` (frappe.flags.update_global_search) to __global_search.
This is called internally at the end of the request.
Inserts / updates values from `global_search_queue` to __global_search.
This is called via job scheduler
:param flags:
:return:
"""
while frappe.cache().llen('global_search_queue') > 0:
value = json.loads(frappe.cache().lpop('global_search_queue'))
sync_value(value)
if not flags:
flags = frappe.flags.update_global_search
# Can pass flags manually as frappe.flags.update_global_search isn't reliable at a later time,
# when syncing is enqueued
for value in flags:
frappe.db.sql('''
insert into __global_search
(doctype, name, content, published, title, route)
values
(%(doctype)s, %(name)s, %(content)s, %(published)s, %(title)s, %(route)s)
on duplicate key update
content = %(content)s''', value)
frappe.flags.update_global_search = []
def sync_value(value):
'''
Sync a given document to global search
:param value: dict of { doctype, name, content, published, title, route }
'''
frappe.db.sql('''
insert into __global_search
(doctype, name, content, published, title, route)
values
(%(doctype)s, %(name)s, %(content)s, %(published)s, %(title)s, %(route)s)
on duplicate key update
content = %(content)s''', value)
def delete_for_document(doc):
"""

View file

@ -10,6 +10,13 @@ from six import iteritems
class RedisWrapper(redis.Redis):
"""Redis client that will automatically prefix conf.db_name"""
def connected(self):
try:
self.ping()
return True
except redis.exceptions.ConnectionError:
return False
def make_key(self, key, user=None, shared=False):
if shared:
return key