From 6624f3a1af1c6328279c1d74303d479fd4ae41ba Mon Sep 17 00:00:00 2001 From: Saurabh Date: Fri, 3 Apr 2020 18:12:32 +0530 Subject: [PATCH 1/2] enhancement: provision to scheduled server scripts execution --- .../scheduled_job_type.json | 9 +++++++- .../scheduled_job_type/scheduled_job_type.py | 7 +++++- .../doctype/server_script/server_script.json | 14 +++++++++--- .../doctype/server_script/server_script.py | 22 +++++++++++++++++++ .../server_script/server_script_utils.py | 3 ++- frappe/utils/safe_exec.py | 3 +++ 6 files changed, 52 insertions(+), 6 deletions(-) diff --git a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json index e2ec921679..48c98c0bc4 100644 --- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json +++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json @@ -12,6 +12,7 @@ "engine": "InnoDB", "field_order": [ "stopped", + "execute_via_server_script", "method", "frequency", "cron_format", @@ -63,6 +64,12 @@ "options": "All\nHourly\nHourly Long\nDaily\nDaily Long\nWeekly\nWeekly Long\nMonthly\nMonthly Long\nCron\nYearly\nAnnual", "read_only": 1, "reqd": 1 + }, + { + "default": "0", + "fieldname": "execute_via_server_script", + "fieldtype": "Check", + "label": "Execute Via Server Script" } ], "in_create": 1, @@ -72,7 +79,7 @@ "link_fieldname": "scheduled_job_type" } ], - "modified": "2019-12-09 11:10:21.259929", + "modified": "2020-04-03 17:14:13.899031", "modified_by": "Administrator", "module": "Core", "name": "Scheduled Job Type", diff --git a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py index 3cd994ebfa..b1b867d527 100644 --- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py +++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py @@ -70,7 +70,12 @@ class ScheduledJobType(Document): self.scheduler_log = None try: self.log_status('Start') - frappe.get_attr(self.method)() + if self.execute_via_server_script: + script_name = frappe.db.get_value("Server Script", {'api_method': self.method}) + if script_name: + frappe.get_doc('Server Script', script_name).execute_scheduled_method() + else: + frappe.get_attr(self.method)() frappe.db.commit() self.log_status('Complete') except Exception: diff --git a/frappe/core/doctype/server_script/server_script.json b/frappe/core/doctype/server_script/server_script.json index 36c297cc26..aeed982162 100644 --- a/frappe/core/doctype/server_script/server_script.json +++ b/frappe/core/doctype/server_script/server_script.json @@ -11,6 +11,7 @@ "column_break_3", "reference_doctype", "doctype_event", + "scheduler_event", "api_method", "allow_guest", "section_break_8", @@ -22,7 +23,7 @@ "fieldtype": "Select", "in_list_view": 1, "label": "Script Type", - "options": "DocType Event\nAPI", + "options": "DocType Event\nScheduler Event\nAPI", "reqd": 1 }, { @@ -47,7 +48,7 @@ "options": "Before Insert\nBefore Save\nAfter Save\nBefore Submit\nAfter Submit\nBefore Cancel\nAfter Cancel\nBefore Delete\nAfter Delete\nBefore Save (Submitted Document)\nAfter Save (Submitted Document)" }, { - "depends_on": "eval:doc.script_type==='API'", + "depends_on": "eval:doc.script_type==='API' || doc.script_type==='Scheduler Event'", "fieldname": "api_method", "fieldtype": "Data", "label": "API Method" @@ -72,10 +73,17 @@ { "fieldname": "section_break_8", "fieldtype": "Section Break" + }, + { + "depends_on": "eval:doc.script_type==='Scheduler Event'", + "fieldname": "scheduler_event", + "fieldtype": "Select", + "label": "Scheduler Event", + "options": "All\nHourly\nHourly Long\nDaily\nDaily Long\nWeekly\nWeekly Long\nMonthly\nMonthly Long\nCron\nYearly\nAnnual" } ], "links": [], - "modified": "2019-12-17 12:55:07.389775", + "modified": "2020-04-03 16:33:08.765621", "modified_by": "Administrator", "module": "Core", "name": "Server Script", diff --git a/frappe/core/doctype/server_script/server_script.py b/frappe/core/doctype/server_script/server_script.py index e2c6d3b7b0..c651da2269 100644 --- a/frappe/core/doctype/server_script/server_script.py +++ b/frappe/core/doctype/server_script/server_script.py @@ -8,6 +8,7 @@ import frappe from frappe.model.document import Document from frappe.utils.safe_exec import safe_exec + class ServerScript(Document): @staticmethod def validate(): @@ -15,6 +16,7 @@ class ServerScript(Document): @staticmethod def on_update(): + setup_scheduler_events() frappe.cache().delete_value('server_script_map') def execute_method(self): @@ -31,3 +33,23 @@ class ServerScript(Document): # execute event safe_exec(self.script, None, dict(doc = doc)) + def execute_scheduled_method(self): + if self.script_type == 'Scheduler Event': + safe_exec(self.script) + else: + # wrong report type! + raise frappe.DoesNotExistError + +def setup_scheduler_events(): + enabled_server_scripts = frappe.get_all('Server Script', + fields=('name', 'doctype_event','api_method', 'scheduler_event'), + filters={'disabled': 0, 'script_type': 'Scheduler Event'}) + + for script in enabled_server_scripts: + if not frappe.db.exists('Scheduled Job Type', dict(method=script.api_method)): + frappe.get_doc(dict( + doctype = 'Scheduled Job Type', + method = script.api_method, + frequency = script.scheduler_event, + has_server_script=1 + )).insert() \ No newline at end of file diff --git a/frappe/core/doctype/server_script/server_script_utils.py b/frappe/core/doctype/server_script/server_script_utils.py index 2e1a5ae8bb..e03504f30b 100644 --- a/frappe/core/doctype/server_script/server_script_utils.py +++ b/frappe/core/doctype/server_script/server_script_utils.py @@ -66,6 +66,7 @@ def get_server_script_map(): script_map.setdefault(script.reference_doctype, {}).setdefault(script.doctype_event, []).append(script.name) else: script_map.setdefault('_api', {})[script.api_method] = script.name + frappe.cache().set_value('server_script_map', script_map) - return script_map + return script_map \ No newline at end of file diff --git a/frappe/utils/safe_exec.py b/frappe/utils/safe_exec.py index 62d0286e03..ed949d8a01 100644 --- a/frappe/utils/safe_exec.py +++ b/frappe/utils/safe_exec.py @@ -11,6 +11,7 @@ from frappe.website.utils import (get_shade, get_toc, get_next_link) from frappe.modules import scrub from frappe.www.printview import get_visible_columns import frappe.exceptions +import frappe.integrations.utils class ServerScriptNotEnabled(frappe.PermissionError): pass @@ -79,6 +80,8 @@ def get_safe_globals(): user=user, csrf_token=frappe.local.session.data.csrf_token if getattr(frappe.local, "session", None) else '' ), + make_get_request = frappe.integrations.utils.make_get_request, + make_post_request = frappe.integrations.utils.make_post_request, socketio_port=frappe.conf.socketio_port, get_hooks=frappe.get_hooks, ), From 30e7d9e1512c2d9d774844c15dd30b41beee5797 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 6 Apr 2020 12:05:48 +0530 Subject: [PATCH 2/2] feat: link server scripts in scheduler --- .../scheduled_job_type.json | 14 ++++--- .../scheduled_job_type/scheduled_job_type.py | 4 +- .../doctype/server_script/server_script.js | 42 ++++++++++++++++++- .../doctype/server_script/server_script.json | 12 +----- .../doctype/server_script/server_script.py | 42 +++++++++++++------ 5 files changed, 81 insertions(+), 33 deletions(-) diff --git a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json index 48c98c0bc4..2a9c1a4573 100644 --- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json +++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json @@ -12,8 +12,8 @@ "engine": "InnoDB", "field_order": [ "stopped", - "execute_via_server_script", "method", + "server_script", "frequency", "cron_format", "last_execution", @@ -66,10 +66,12 @@ "reqd": 1 }, { - "default": "0", - "fieldname": "execute_via_server_script", - "fieldtype": "Check", - "label": "Execute Via Server Script" + "fieldname": "server_script", + "fieldtype": "Link", + "label": "Server Script", + "options": "Server Script", + "read_only": 1, + "search_index": 1 } ], "in_create": 1, @@ -79,7 +81,7 @@ "link_fieldname": "scheduled_job_type" } ], - "modified": "2020-04-03 17:14:13.899031", + "modified": "2020-04-05 17:27:33.480562", "modified_by": "Administrator", "module": "Core", "name": "Scheduled Job Type", diff --git a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py index b1b867d527..c179054550 100644 --- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py +++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py @@ -70,8 +70,8 @@ class ScheduledJobType(Document): self.scheduler_log = None try: self.log_status('Start') - if self.execute_via_server_script: - script_name = frappe.db.get_value("Server Script", {'api_method': self.method}) + if self.server_script: + script_name = frappe.db.get_value("Server Script", self.server_script) if script_name: frappe.get_doc('Server Script', script_name).execute_scheduled_method() else: diff --git a/frappe/core/doctype/server_script/server_script.js b/frappe/core/doctype/server_script/server_script.js index eea8558456..d7f4c3e536 100644 --- a/frappe/core/doctype/server_script/server_script.js +++ b/frappe/core/doctype/server_script/server_script.js @@ -2,7 +2,45 @@ // For license information, please see license.txt frappe.ui.form.on('Server Script', { - // refresh: function(frm) { + refresh: function(frm) { + if(frm.doc.script_type === 'Scheduler Event' && !frm.doc.disabled){ + frm.add_custom_button('Schedule Script', function() { + var d = new frappe.ui.Dialog({ + title: "Schedule Script Execution", + fields: [ + { + fieldname: "event_type", + label: __('Select Event Type'), + fieldtype: "Select", + options: "All\nHourly\nDaily\nWeekly\nMonthly\nYearly\nHourly Long\nDaily Long\nWeekly Long\nMonthly Long" + }, + ], + primary_action_label: __('Schedule Script'), + primary_action: () => { + d.get_primary_btn().attr('disabled', true); + var data = d.get_values(); + d.hide(); + if(data) { + frm.events.schedule_script(frm, data); + } + + } + }); + + d.show(); + + }); + } + }, + + schedule_script(frm, data){ + frm.call({ + method: "frappe.core.doctype.server_script.server_script.setup_scheduler_events", + args: { + 'script_name': frm.doc.name, + 'frequency': data.event_type + } + }) + } - // } }); diff --git a/frappe/core/doctype/server_script/server_script.json b/frappe/core/doctype/server_script/server_script.json index aeed982162..bef3dfc60c 100644 --- a/frappe/core/doctype/server_script/server_script.json +++ b/frappe/core/doctype/server_script/server_script.json @@ -11,7 +11,6 @@ "column_break_3", "reference_doctype", "doctype_event", - "scheduler_event", "api_method", "allow_guest", "section_break_8", @@ -48,7 +47,7 @@ "options": "Before Insert\nBefore Save\nAfter Save\nBefore Submit\nAfter Submit\nBefore Cancel\nAfter Cancel\nBefore Delete\nAfter Delete\nBefore Save (Submitted Document)\nAfter Save (Submitted Document)" }, { - "depends_on": "eval:doc.script_type==='API' || doc.script_type==='Scheduler Event'", + "depends_on": "eval:doc.script_type==='API'", "fieldname": "api_method", "fieldtype": "Data", "label": "API Method" @@ -73,17 +72,10 @@ { "fieldname": "section_break_8", "fieldtype": "Section Break" - }, - { - "depends_on": "eval:doc.script_type==='Scheduler Event'", - "fieldname": "scheduler_event", - "fieldtype": "Select", - "label": "Scheduler Event", - "options": "All\nHourly\nHourly Long\nDaily\nDaily Long\nWeekly\nWeekly Long\nMonthly\nMonthly Long\nCron\nYearly\nAnnual" } ], "links": [], - "modified": "2020-04-03 16:33:08.765621", + "modified": "2020-04-06 11:24:38.161555", "modified_by": "Administrator", "module": "Core", "name": "Server Script", diff --git a/frappe/core/doctype/server_script/server_script.py b/frappe/core/doctype/server_script/server_script.py index c651da2269..9522b77b4b 100644 --- a/frappe/core/doctype/server_script/server_script.py +++ b/frappe/core/doctype/server_script/server_script.py @@ -7,6 +7,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document from frappe.utils.safe_exec import safe_exec +from frappe import _ class ServerScript(Document): @@ -16,7 +17,6 @@ class ServerScript(Document): @staticmethod def on_update(): - setup_scheduler_events() frappe.cache().delete_value('server_script_map') def execute_method(self): @@ -40,16 +40,32 @@ class ServerScript(Document): # wrong report type! raise frappe.DoesNotExistError -def setup_scheduler_events(): - enabled_server_scripts = frappe.get_all('Server Script', - fields=('name', 'doctype_event','api_method', 'scheduler_event'), - filters={'disabled': 0, 'script_type': 'Scheduler Event'}) +@frappe.whitelist() +def setup_scheduler_events(script_name, frequency): + method = frappe.scrub(script_name) + '_' + frequency.lower() + scheduled_script = frappe.db.get_value('Scheduled Job Type', + dict(method=method)) - for script in enabled_server_scripts: - if not frappe.db.exists('Scheduled Job Type', dict(method=script.api_method)): - frappe.get_doc(dict( - doctype = 'Scheduled Job Type', - method = script.api_method, - frequency = script.scheduler_event, - has_server_script=1 - )).insert() \ No newline at end of file + if not scheduled_script: + doc = frappe.get_doc(dict( + doctype = 'Scheduled Job Type', + method = method, + frequency = frequency, + server_script = script_name + )) + + doc.insert() + + frappe.msgprint(_('Enabled scheduled execution for script {0}').format(script_name)) + + else: + doc = frappe.get_doc('Scheduled Job Type', scheduled_script) + doc.update(dict( + doctype = 'Scheduled Job Type', + method = method, + frequency = frequency, + server_script = script_name + )) + doc.save() + + frappe.msgprint(_('Scheduled execution for script {0} has updated').format(script_name))