fix(security): use restricted python

This commit is contained in:
Rushabh Mehta 2019-10-11 09:45:36 +05:30
parent 6108c2ce33
commit 9d615f7f12
12 changed files with 383 additions and 878 deletions

View file

@ -1,777 +1,204 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:report_name",
"beta": 0,
"creation": "2013-03-09 15:45:57",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
"editable_grid": 0,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "report_name",
"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": "Report Name",
"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": 1
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "ref_doctype",
"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": "Ref DocType",
"length": 0,
"no_copy": 0,
"options": "DocType",
"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,
"fetch_if_empty": 0,
"fieldname": "reference_report",
"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": "Reference 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,
"fetch_if_empty": 0,
"fieldname": "is_standard",
"fieldtype": "Select",
"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": "Is Standard",
"length": 0,
"no_copy": 0,
"options": "No\nYes",
"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,
"fetch_if_empty": 0,
"fieldname": "module",
"fieldtype": "Link",
"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": "Module",
"length": 0,
"no_copy": 0,
"options": "Module Def",
"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_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "add_total_row",
"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": "Add Total Row",
"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_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 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,
"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,
"fetch_if_empty": 0,
"fieldname": "report_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": "Report Type",
"length": 0,
"no_copy": 0,
"options": "Report Builder\nQuery Report\nScript Report\nCustom Report",
"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,
"fetch_if_empty": 0,
"fieldname": "disabled",
"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": "Disabled",
"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_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_if_empty": 0,
"fieldname": "icon",
"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": "Icon",
"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,
"fetch_if_empty": 0,
"fieldname": "color",
"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": "Color",
"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.is_standard == \"No\"",
"fetch_if_empty": 0,
"fieldname": "letter_head",
"fieldtype": "Link",
"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": "Letter Head",
"length": 0,
"no_copy": 0,
"options": "Letter Head",
"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,
"fetch_if_empty": 0,
"fieldname": "section_break_6",
"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_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.report_type==\"Query Report\"",
"fetch_if_empty": 0,
"fieldname": "query",
"fieldtype": "Code",
"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": "Query",
"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_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "",
"description": "JavaScript Format: frappe.query_reports['REPORTNAME'] = {}",
"fetch_if_empty": 0,
"fieldname": "javascript",
"fieldtype": "Code",
"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": "Javascript",
"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_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.report_type==\"Report Builder\" || \"Custom Report\"",
"fetch_if_empty": 0,
"fieldname": "json",
"fieldtype": "Code",
"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": "JSON",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"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,
"fetch_if_empty": 0,
"fieldname": "permission_rules",
"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,
"label": "",
"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.is_standard == 'Yes'",
"fetch_if_empty": 0,
"fieldname": "roles",
"fieldtype": "Table",
"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": "Roles",
"length": 0,
"no_copy": 0,
"options": "Has Role",
"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,
"fetch_if_empty": 0,
"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,
"columns": 0,
"fetch_if_empty": 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": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_toolbar": 0,
"icon": "",
"idx": 1,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2019-04-12 15:53:14.194591",
"modified_by": "Administrator",
"module": "Core",
"name": "Report",
"owner": "Administrator",
"permissions": [
{
"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": "Administrator",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"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": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"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": "Report Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
},
{
"amend": 0,
"cancel": 0,
"create": 0,
"delete": 0,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"set_user_permissions": 0,
"share": 0,
"submit": 0,
"write": 0
}
],
"quick_entry": 0,
"read_only": 0,
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}
"autoname": "field:report_name",
"creation": "2013-03-09 15:45:57",
"doctype": "DocType",
"document_type": "System",
"engine": "InnoDB",
"field_order": [
"report_name",
"ref_doctype",
"reference_report",
"is_standard",
"module",
"column_break_4",
"report_type",
"letter_head",
"add_total_row",
"disabled",
"disable_prepared_report",
"prepared_report",
"section_break_6",
"query",
"javascript",
"report_script",
"json",
"permission_rules",
"roles"
],
"fields": [
{
"fieldname": "report_name",
"fieldtype": "Data",
"label": "Report Name",
"reqd": 1,
"unique": 1
},
{
"fieldname": "ref_doctype",
"fieldtype": "Link",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Ref DocType",
"options": "DocType",
"reqd": 1
},
{
"fieldname": "reference_report",
"fieldtype": "Data",
"label": "Reference Report"
},
{
"fieldname": "is_standard",
"fieldtype": "Select",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Is Standard",
"options": "No\nYes",
"reqd": 1
},
{
"fieldname": "module",
"fieldtype": "Link",
"label": "Module",
"options": "Module Def"
},
{
"default": "0",
"fieldname": "add_total_row",
"fieldtype": "Check",
"label": "Add Total Row"
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
},
{
"fieldname": "report_type",
"fieldtype": "Select",
"label": "Report Type",
"options": "Report Builder\nQuery Report\nScript Report\nCustom Report",
"reqd": 1
},
{
"default": "0",
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disabled"
},
{
"depends_on": "eval: doc.is_standard == \"No\"",
"fieldname": "letter_head",
"fieldtype": "Link",
"label": "Letter Head",
"options": "Letter Head"
},
{
"fieldname": "section_break_6",
"fieldtype": "Section Break"
},
{
"depends_on": "eval:doc.report_type==\"Query Report\"",
"fieldname": "query",
"fieldtype": "Code",
"label": "Query"
},
{
"depends_on": "eval:doc.report_type==\"Script Report\" && doc.is_standard===\"No\"",
"description": "JavaScript Format: frappe.query_reports['REPORTNAME'] = {}",
"fieldname": "javascript",
"fieldtype": "Code",
"label": "Javascript"
},
{
"depends_on": "eval:doc.report_type==\"Report Builder\" || \"Custom Report\"",
"fieldname": "json",
"fieldtype": "Code",
"label": "JSON",
"read_only": 1
},
{
"fieldname": "permission_rules",
"fieldtype": "Section Break"
},
{
"depends_on": "eval:doc.is_standard == 'Yes'",
"fieldname": "roles",
"fieldtype": "Table",
"label": "Roles",
"options": "Has Role"
},
{
"default": "0",
"fieldname": "disable_prepared_report",
"fieldtype": "Check",
"label": "Disable Prepared Report"
},
{
"default": "0",
"fieldname": "prepared_report",
"fieldtype": "Check",
"hidden": 1,
"label": "Prepared Report",
"read_only": 1
},
{
"depends_on": "eval:doc.report_type==\"Script Report\" && doc.is_standard===\"No\"",
"description": "output in the form of `data = [columns, result]`",
"fieldname": "report_script",
"fieldtype": "Code",
"label": "Script"
}
],
"idx": 1,
"modified": "2019-10-09 15:43:08.577610",
"modified_by": "Administrator",
"module": "Core",
"name": "Report",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Administrator",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Report Manager",
"share": 1,
"write": 1
},
{
"email": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "All"
}
],
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View file

@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
import json
import json, datetime
from frappe import _
import frappe.desk.query_report
from frappe.utils import cint
@ -27,16 +27,15 @@ class Report(Document):
if frappe.session.user=="Administrator" and getattr(frappe.local.conf, 'developer_mode',0)==1:
self.is_standard = "Yes"
if self.is_standard == "No" and frappe.db.get_value("Report", self.name, "is_standard") == "Yes":
frappe.throw(_("Cannot edit a standard report. Please duplicate and create a new report"))
if self.is_standard == "No":
frappe.only_for('Script Manager')
if frappe.db.get_value("Report", self.name, "is_standard") == "Yes":
frappe.throw(_("Cannot edit a standard report. Please duplicate and create a new report"))
if self.is_standard == "Yes" and frappe.session.user!="Administrator":
frappe.throw(_("Only Administrator can save a standard report. Please rename and save."))
if self.report_type in ("Query Report", "Script Report") \
and frappe.session.user!="Administrator":
frappe.throw(_("Only Administrator allowed to create Query / Script Reports"))
if self.report_type == "Report Builder":
self.update_report_json()
@ -92,6 +91,35 @@ class Report(Document):
make_boilerplate("controller.py", self, {"name": self.name})
make_boilerplate("controller.js", self, {"name": self.name})
def execute_script_report(self, filters):
threshold = 30
res = []
start_time = datetime.datetime.now()
# The JOB
if self.is_standard == 'Yes':
module = self.module or frappe.db.get_value("DocType", self.ref_doctype, "module")
method_name = get_report_module_dotted_path(module, report.name) + ".execute"
res = frappe.get_attr(method_name)(frappe._dict(filters))
else:
if not frappe.conf.server_script_enabled:
raise ServerScriptNotEnabled
loc = {"filters": frappe._dict(filters), 'data':[]}
exec(self.report_script, globals(), loc)
res = loc['data']
end_time = datetime.datetime.now()
execution_time = (end_time - start_time).seconds
if execution_time > threshold and not self.prepared_report:
self.db_set('prepared_report', 1)
frappe.cache().hset('report_execution_time', self.name, execution_time)
return res
def get_data(self, filters=None, limit=None, user=None, as_dict=False):
columns = []
out = []

View file

@ -68,3 +68,6 @@ class TestReport(unittest.TestCase):
self.assertEqual(columns[1].get('label'), 'User Type')
self.assertTrue('Administrator' in [d[0] for d in data])
frappe.delete_doc('Report', 'User Activity Report Without Sort')
def test_non_standard_script_report(self):
pass

View file

@ -6,11 +6,13 @@
"engine": "InnoDB",
"field_order": [
"script_type",
"disabled",
"column_break_3",
"reference_doctype",
"doctype_event",
"frequency",
"api_method",
"allow_guest",
"section_break_8",
"script"
],
"fields": [
@ -33,7 +35,7 @@
"fieldname": "reference_doctype",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Reference DocType",
"label": "Reference Document Type",
"options": "DocType"
},
{
@ -41,14 +43,7 @@
"fieldname": "doctype_event",
"fieldtype": "Select",
"label": "DocType Event",
"options": "Before Insert\nBefore Save\nAfter Save\nBefore Submit\nBefore Cancel\nBefore Delete"
},
{
"depends_on": "eval:doc.script_type==='Scheduled Job'",
"fieldname": "frequency",
"fieldtype": "Select",
"label": "Frequency",
"options": "Hourly\nDaily\nWeekly\nMonthly"
"options": "Before Insert\nBefore Save\nAfter Save\nBefore Submit\nAfter Submit\nBefore Cancel\nAfter Cancel\nBefore Delete\nAfter Delete"
},
{
"depends_on": "eval:doc.script_type==='API'",
@ -62,9 +57,23 @@
"fieldname": "allow_guest",
"fieldtype": "Check",
"label": "Allow Guest"
},
{
"default": "0",
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disabled"
},
{
"fieldname": "column_break_3",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_8",
"fieldtype": "Section Break"
}
],
"modified": "2019-10-04 15:51:57.995877",
"modified": "2019-10-09 15:08:40.085059",
"modified_by": "Administrator",
"module": "Core",
"name": "Server Script",
@ -78,7 +87,7 @@
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"role": "Script Manager",
"share": 1,
"write": 1
}

View file

@ -6,13 +6,13 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe.utils.safe_globals import get_safe_globals
from frappe.utils.safe_exec import safe_exec
class ServerScriptNotEnabled(frappe.PermissionError): pass
class ServerScript(Document):
def validate(self):
frappe.only_for('System Manager')
frappe.only_for('Script Manager')
def on_update(self):
frappe.cache().delete_value('server_script_map')
@ -23,14 +23,13 @@ class ServerScript(Document):
if self.script_type == 'API':
if frappe.session.user == 'Guest' and not self.allow_guest:
raise frappe.PermissionError
exec(self.script, globals(), None)
safe_exec(self.script)
else:
raise frappe.DoesNotExistError
def execute_doc(self, doc):
if not frappe.conf.server_script_enabled:
raise ServerScriptNotEnabled
context = doc.as_dict()
context.doc = doc
exec(self.script, globals(), context)
context = dict(doc = doc)
safe_exec(self.script, None, context)

View file

@ -6,8 +6,11 @@ EVENT_MAP = {
'validate': 'Before Save',
'on_update': 'After Save',
'before_submit': 'Before Submit',
'on_submit': 'After Submit',
'before_cancel': 'Before Cancel',
'before_delete': 'Before Delete'
'on_cancel': 'After Cancel',
'on_trash': 'Before Delete',
'after_delete': 'After Delete',
}
def run_server_script_api(method):
@ -23,9 +26,10 @@ def run_server_script_for_doc_event(doc, event):
if frappe.flags.in_install:
return
script_name = get_server_script_map().get(doc.doctype, {}).get(EVENT_MAP[event], None)
if script_name:
frappe.get_doc('Server Script', script_name).execute_doc(doc)
scripts = get_server_script_map().get(doc.doctype, {}).get(EVENT_MAP[event], None)
if scripts:
for script_name in scripts:
frappe.get_doc('Server Script', script_name).execute_doc(doc)
def get_server_script_map():
script_map = frappe.cache().get_value('server_script_map')
@ -34,7 +38,7 @@ def get_server_script_map():
for script in frappe.get_all('Server Script', ('name', 'reference_doctype', 'doctype_event',
'api_method', 'script_type')):
if script.script_type == 'DocType Event':
script_map.setdefault(script.reference_doctype, {})[script.doctype_event] = script.name
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)

View file

@ -9,46 +9,67 @@ import requests
from frappe.utils import get_site_url
from frappe.core.doctype.server_script.server_script_utils import get_server_script_map
scripts = [
dict(
name='test_todo',
script_type = 'DocType Event',
doctype_event = 'Before Insert',
reference_doctype = 'ToDo',
script = '''
if "test" in doc.description:
doc.status = 'Closed'
'''
),
dict(
name='test_todo_validate',
script_type = 'DocType Event',
doctype_event = 'Before Insert',
reference_doctype = 'ToDo',
script = '''
if "validate" in doc.description:
raise frappe.ValidationError
'''
),
dict(
name='test_api',
script_type = 'API',
api_method = 'test_server_script',
allow_guest = 1,
script = '''
frappe.response['message'] = 'hello'
'''
)
]
class TestServerScript(unittest.TestCase):
@classmethod
def setUpClass(cls):
frappe.db.commit()
frappe.db.sql('truncate `tabServer Script`')
frappe.get_doc('User', 'Administrator').add_roles('Script Manager')
for script in scripts:
script_doc = frappe.get_doc(doctype ='Server Script')
script_doc.update(script)
script_doc.insert()
frappe.db.commit()
# @classmethod
# def tearDownClass(cls):
# frappe.db.sql('truncate `tabServer Script`')
def setUp(self):
frappe.cache().delete_value('server_script_map')
def test_doctype_event(self):
script = get_server_script()
script.script_type = 'DocType Event'
script.script = 'frappe.flags._ping = True'
script.reference_doctype = 'ToDo'
script.doctype_event = 'Before Save'
script.save()
frappe.db.commit()
todo = frappe.get_doc(dict(doctype='ToDo', description='hello')).insert()
self.assertEqual(todo.status, 'Open')
frappe.flags._ping = False
frappe.get_doc(dict(doctype='ToDo', description='test todo')).insert()
self.assertTrue(frappe.flags._ping)
todo = frappe.get_doc(dict(doctype='ToDo', description='test todo')).insert()
self.assertEqual(todo.status, 'Closed')
self.assertRaises(frappe.ValidationError, frappe.get_doc(dict(doctype='ToDo', description='validate me')).insert)
def test_api(self):
script = get_server_script()
script.script_type = 'API'
script.api_method = 'test_server_script'
script.allow_guest = 1
script.script = 'frappe.response["message"] = "hello"'
script.save()
frappe.db.commit()
response = requests.post(get_site_url(frappe.local.site) + "/api/method/test_server_script")
self.assertEqual(response.status_code, 200)
self.assertEqual("hello", response.json()["message"])
def get_server_script():
if frappe.db.exists('Server Script', 'Test Server Script'):
return frappe.get_doc('Server Script', 'Test Server Script')
else:
script = frappe.get_doc(dict(
doctype = 'Server Script',
name = 'Test Server Script',
script = '# nothing',
script_type = 'DocType Event'
)).insert()
return script

View file

@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
import os, json, datetime
import os, json
from frappe import _
from frappe.modules import scrub, get_module_path
@ -63,38 +63,21 @@ def generate_report_result(report, filters=None, user=None):
result = [list(t) for t in frappe.db.sql(report.query, filters)]
columns = [cstr(c[0]) for c in frappe.db.get_description()]
else:
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 = 30
res = []
start_time = datetime.datetime.now()
# The JOB
res = frappe.get_attr(method_name)(frappe._dict(filters))
elif report.report_type == 'Script Report':
res = report.execute_script_report(filters)
end_time = datetime.datetime.now()
columns, result = res[0], res[1]
if len(res) > 2:
message = res[2]
if len(res) > 3:
chart = res[3]
if len(res) > 4:
data_to_be_printed = res[4]
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]
if len(res) > 3:
chart = res[3]
if len(res) > 4:
data_to_be_printed = res[4]
if report.custom_columns:
columns = json.loads(report.custom_columns)
result = add_data_to_custom_columns(columns, result)
if report.custom_columns:
columns = json.loads(report.custom_columns)
result = add_data_to_custom_columns(columns, result)
if result:
result = get_filtered_data(report.ref_doctype, columns, result, user)

View file

@ -0,0 +1,11 @@
from __future__ import unicode_literals
import unittest
import frappe
from frappe.utils.safe_exec import safe_exec
class TestSafeExec(unittest.TestCase):
def test_import_fails(self):
self.assertRaises(ImportError, safe_exec, 'import os')
def test_internal_attributes(self):
self.assertRaises(SyntaxError, safe_exec, '().__class__.__call__')

View file

@ -4,7 +4,7 @@ from __future__ import unicode_literals
def get_jenv():
import frappe
from frappe.utils.safe_globals import get_safe_globals
from frappe.utils.safe_exec import get_safe_globals
if not getattr(frappe.local, 'jenv', None):
from jinja2 import DebugUndefined

View file

@ -1,7 +1,12 @@
import os, json
import os, json, inspect
import mimetypes
from html2text import html2text
from RestrictedPython import compile_restricted, safe_globals
def safe_exec(script, _globals=None, _locals=None):
if not _globals: _globals = get_safe_globals()
exec(compile_restricted(script), _globals, _locals)
def get_safe_globals():
import frappe
@ -11,6 +16,7 @@ def get_safe_globals():
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
datautils = {}
if frappe.db:
@ -18,14 +24,7 @@ def get_safe_globals():
else:
date_format = 'yyyy-mm-dd'
for key, obj in frappe.utils.data.__dict__.items():
if key.startswith("_"):
# ignore
continue
if hasattr(obj, "__call__"):
# only allow functions
datautils[key] = obj
add_module_properties(frappe.utils.data, datautils, lambda obj: hasattr(obj, "__call__"))
if "_" in getattr(frappe.local, 'form_dict', {}):
del frappe.local.form_dict["_"]
@ -77,6 +76,8 @@ def get_safe_globals():
dev_server = 1 if os.environ.get('DEV_SERVER', False) else 0
)
add_module_properties(frappe.exceptions, out.frappe, lambda obj: inspect.isclass(obj) and issubclass(obj, Exception))
if not frappe.flags.in_setup_help:
out.get_visible_columns = get_visible_columns
out.frappe.date_format = date_format
@ -87,4 +88,22 @@ def get_safe_globals():
escape = frappe.db.escape,
)
if frappe.response:
out.frappe.response = frappe.response
out.update(safe_globals)
# default writer allows write access
out._write_ = lambda obj: obj
return out
def add_module_properties(module, data, filter_method):
for key, obj in module.__dict__.items():
if key.startswith("_"):
# ignore
continue
if filter_method(obj):
# only allow functions
data[key] = obj

View file

@ -65,3 +65,4 @@ Pygments==2.2.0
frontmatter
PyYAML==3.13
xlrd
RestrictedPython==5.0