diff --git a/frappe/__init__.py b/frappe/__init__.py index c8147401dd..427d747072 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.0' +__version__ = '11.1.1' __title__ = "Frappe Framework" local = Local() diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 3346079208..50fe23fe1e 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -686,5 +686,7 @@ commands = [ watch, _bulk_rename, add_to_email_queue, + setup_global_help, + setup_help, rebuild_global_search ] diff --git a/frappe/core/doctype/report/report.json b/frappe/core/doctype/report/report.json index ce7b4b7d51..4c8b77de5f 100644 --- a/frappe/core/doctype/report/report.json +++ b/frappe/core/doctype/report/report.json @@ -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", diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py index 8699549870..3f9162ffd7 100644 --- a/frappe/core/doctype/report/report.py +++ b/frappe/core/doctype/report/report.py @@ -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 diff --git a/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.js b/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.js index 02fcf94a7b..fa807792fa 100644 --- a/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.js +++ b/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.js @@ -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') diff --git a/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.json b/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.json index 0c21a5748b..8a5393b872 100644 --- a/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.json +++ b/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.json @@ -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 } \ No newline at end of file diff --git a/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.py b/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.py index f05e187972..d7462d1d95 100644 --- a/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.py +++ b/frappe/core/doctype/role_permission_for_page_and_report/role_permission_for_page_and_report.py @@ -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() diff --git a/frappe/core/doctype/system_settings/system_settings.json b/frappe/core/doctype/system_settings/system_settings.json index 1da13ee88b..cf317edc42 100644 --- a/frappe/core/doctype/system_settings/system_settings.json +++ b/frappe/core/doctype/system_settings/system_settings.json @@ -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", diff --git a/frappe/custom/doctype/customize_form/test_customize_form.py b/frappe/custom/doctype/customize_form/test_customize_form.py index 7df3eedb5e..7da63f4d5d 100644 --- a/frappe/custom/doctype/customize_form/test_customize_form.py +++ b/frappe/custom/doctype/customize_form/test_customize_form.py @@ -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") diff --git a/frappe/desk/query_report.py b/frappe/desk/query_report.py index 107ed38544..d33c341a9b 100644 --- a/frappe/desk/query_report.py +++ b/frappe/desk/query_report.py @@ -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) diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index b306692739..5ab3cd1630 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -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", diff --git a/frappe/hooks.py b/frappe/hooks.py index e9a5326810..960badcbab 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -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", diff --git a/frappe/integrations/doctype/ldap_settings/ldap_settings.json b/frappe/integrations/doctype/ldap_settings/ldap_settings.json index f317f43070..6eb44a2db8 100644 --- a/frappe/integrations/doctype/ldap_settings/ldap_settings.json +++ b/frappe/integrations/doctype/ldap_settings/ldap_settings.json @@ -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", diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 3ce9e7f854..3617b81ba8 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -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: diff --git a/frappe/public/js/frappe/views/reports/query_report.js b/frappe/public/js/frappe/views/reports/query_report.js index 06038d1856..8a73bf8d83 100644 --- a/frappe/public/js/frappe/views/reports/query_report.js +++ b/frappe/public/js/frappe/views/reports/query_report.js @@ -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 = $(`
`) .hide().insertAfter(page_form); - this.show_tip(); this.$chart = $('
').hide().appendTo(this.page.main); this.$report = $('
').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(`

${message}

`); + 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(`${message}${execution_time_msg}`); } message_div(message) { diff --git a/frappe/tests/test_global_search.py b/frappe/tests/test_global_search.py index 4cae44060b..7f7dc0ed78 100644 --- a/frappe/tests/test_global_search.py +++ b/frappe/tests/test_global_search.py @@ -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): diff --git a/frappe/utils/global_search.py b/frappe/utils/global_search.py index 1c078a1691..581a75cdaf 100644 --- a/frappe/utils/global_search.py +++ b/frappe/utils/global_search.py @@ -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): """ diff --git a/frappe/utils/redis_wrapper.py b/frappe/utils/redis_wrapper.py index 1ac3667138..cb92ced5c6 100644 --- a/frappe/utils/redis_wrapper.py +++ b/frappe/utils/redis_wrapper.py @@ -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