Merge branch 'develop' of github.com:frappe/frappe into fix-base-path-restore

This commit is contained in:
Gavin D'souza 2020-12-04 18:17:59 +05:30
commit 3ce680a5f9
5 changed files with 44 additions and 9 deletions

View file

@ -4,6 +4,8 @@
from __future__ import unicode_literals
import ast
import frappe
from frappe.model.document import Document
from frappe.utils.safe_exec import safe_exec
@ -11,9 +13,9 @@ from frappe import _
class ServerScript(Document):
@staticmethod
def validate():
def validate(self):
frappe.only_for('Script Manager', True)
ast.parse(self.script)
@staticmethod
def on_update():

View file

@ -45,6 +45,15 @@ frappe.response['message'] = 'hello'
allow_guest = 1,
script = '''
frappe.flags = 'hello'
'''
),
dict(
name='test_invalid_namespace_method',
script_type = 'DocType Event',
doctype_event = 'Before Insert',
reference_doctype = 'Note',
script = '''
frappe.method_that_doesnt_exist("do some magic")
'''
)
]
@ -85,3 +94,8 @@ class TestServerScript(unittest.TestCase):
def test_api_return(self):
self.assertEqual(frappe.get_doc('Server Script', 'test_return_value').execute_method(), 'hello')
def test_attribute_error(self):
"""Raise AttributeError if method not found in Namespace"""
note = frappe.get_doc({"doctype": "Note", "title": "Test Note: Server Script"})
self.assertRaises(AttributeError, note.insert)

View file

@ -15,7 +15,9 @@ frappe.report_utils = {
if (raw_data.add_total_row) {
labels = labels.slice(0, -1);
datasets[0].values = datasets[0].values.slice(0, -1);
datasets.forEach(dataset => {
dataset.values = dataset.values.slice(0, -1);
});
}
return {

View file

@ -66,9 +66,14 @@ def get_email_address(user=None):
def get_formatted_email(user, mail=None):
"""get Email Address of user formatted as: `John Doe <johndoe@example.com>`"""
fullname = get_fullname(user)
if not mail:
mail = get_email_address(user)
return cstr(make_header(decode_header(formataddr((fullname, mail)))))
mail = get_email_address(user) or validate_email_address(user)
if not mail:
return ''
else:
return cstr(make_header(decode_header(formataddr((fullname, mail)))))
def extract_email_id(email):
"""fetch only the email part of the Email Address"""

View file

@ -13,7 +13,19 @@ from frappe.www.printview import get_visible_columns
import frappe.exceptions
import frappe.integrations.utils
class ServerScriptNotEnabled(frappe.PermissionError): pass
class ServerScriptNotEnabled(frappe.PermissionError):
pass
class NamespaceDict(frappe._dict):
"""Raise AttributeError if function not found in namespace"""
def __getattr__(self, key):
ret = self.get(key)
if (not ret and key.startswith("__")) or (key not in self):
def default_function(*args, **kwargs):
raise AttributeError(f"module has no attribute '{key}'")
return default_function
return ret
def safe_exec(script, _globals=None, _locals=None):
# script reports must be enabled via site_config.json
@ -46,13 +58,13 @@ def get_safe_globals():
user = getattr(frappe.local, "session", None) and frappe.local.session.user or "Guest"
out = frappe._dict(
out = NamespaceDict(
# make available limited methods of frappe
json=json,
dict=dict,
log=frappe.log,
_dict=frappe._dict,
frappe=frappe._dict(
frappe=NamespaceDict(
flags=frappe._dict(),
format=frappe.format_value,
format_value=frappe.format_value,
@ -112,7 +124,7 @@ def get_safe_globals():
out.get_visible_columns = get_visible_columns
out.frappe.date_format = date_format
out.frappe.time_format = time_format
out.frappe.db = frappe._dict(
out.frappe.db = NamespaceDict(
get_list = frappe.get_list,
get_all = frappe.get_all,
get_value = frappe.db.get_value,