Merge branch 'master' into develop
This commit is contained in:
commit
2e46b1d70c
6 changed files with 111 additions and 25 deletions
|
|
@ -14,7 +14,7 @@ import os, sys, importlib, inspect, json
|
|||
from .exceptions import *
|
||||
from .utils.jinja import get_jenv, get_template, render_template, get_email_from_template
|
||||
|
||||
__version__ = '9.2.23'
|
||||
__version__ = '9.2.24'
|
||||
__title__ = "Frappe Framework"
|
||||
|
||||
local = Local()
|
||||
|
|
|
|||
|
|
@ -778,6 +778,8 @@ def reset_password(user):
|
|||
|
||||
try:
|
||||
user = frappe.get_doc("User", user)
|
||||
if not user.enabled:
|
||||
return 'disabled'
|
||||
user.validate_reset_password()
|
||||
user.reset_password(send_email=True)
|
||||
|
||||
|
|
|
|||
|
|
@ -255,3 +255,36 @@ frappe.is_mobile = function() {
|
|||
return $(document).width() < 768;
|
||||
}
|
||||
|
||||
frappe.utils.xss_sanitise = function (string, options) {
|
||||
// Reference - https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
|
||||
let sanitised = string; // un-sanitised string.
|
||||
const DEFAULT_OPTIONS = {
|
||||
strategies: ['html', 'js'] // use all strategies.
|
||||
}
|
||||
const HTML_ESCAPE_MAP = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/'
|
||||
};
|
||||
const REGEX_SCRIPT = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi; // used in jQuery 1.7.2 src/ajax.js Line 14
|
||||
options = Object.assign({ }, DEFAULT_OPTIONS, options); // don't deep copy, immutable beauty.
|
||||
|
||||
// Rule 1
|
||||
if ( options.strategies.includes('html') ) {
|
||||
// By far, the best thing that has ever happened to JS - Object.keys
|
||||
Object.keys(HTML_ESCAPE_MAP).map((char, escape) => {
|
||||
const regex = new RegExp(char, "g");
|
||||
sanitised = sanitised.replace(regex, escape);
|
||||
});
|
||||
}
|
||||
|
||||
// Rule 3 - TODO: Check event handlers?
|
||||
if ( options.strategies.includes('js') ) {
|
||||
sanitised = sanitised.replace(REGEX_SCRIPT, "");
|
||||
}
|
||||
|
||||
return sanitised;
|
||||
}
|
||||
|
|
@ -17,8 +17,8 @@ login.bind_events = function() {
|
|||
event.preventDefault();
|
||||
var args = {};
|
||||
args.cmd = "login";
|
||||
args.usr = ($("#login_email").val() || "").trim();
|
||||
args.pwd = $("#login_password").val();
|
||||
args.usr = frappe.utils.xss_sanitise(($("#login_email").val() || "").trim());
|
||||
args.pwd = frappe.utils.xss_sanitise($("#login_password").val());
|
||||
args.device = "desktop";
|
||||
if(!args.usr || !args.pwd) {
|
||||
frappe.msgprint("{{ _("Both login and password required") }}");
|
||||
|
|
@ -184,6 +184,8 @@ login.login_handlers = (function() {
|
|||
login.set_indicator("{{ _("Not a valid user") }}", 'red');
|
||||
} else if (data.message=='not allowed') {
|
||||
login.set_indicator("{{ _("Not Allowed") }}", 'red');
|
||||
} else if (data.message=='disabled') {
|
||||
login.set_indicator("{{ _("Not Allowed: Disabled User") }}", 'red');
|
||||
} else {
|
||||
login.set_indicator("{{ _("Instructions Emailed") }}", 'green');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,12 @@ from frappe.utils import cint, strip_html_tags
|
|||
from frappe.model.base_document import get_controller
|
||||
from six import text_type
|
||||
|
||||
|
||||
def setup_global_search_table():
|
||||
'''Creates __global_seach table'''
|
||||
"""
|
||||
Creates __global_seach table
|
||||
:return:
|
||||
"""
|
||||
if not '__global_search' in frappe.db.get_tables():
|
||||
frappe.db.sql('''create table __global_search(
|
||||
doctype varchar(100),
|
||||
|
|
@ -26,12 +30,21 @@ def setup_global_search_table():
|
|||
ENGINE=MyISAM
|
||||
CHARACTER SET=utf8mb4''')
|
||||
|
||||
|
||||
def reset():
|
||||
'''Deletes all data in __global_search'''
|
||||
"""
|
||||
Deletes all data in __global_search
|
||||
:return:
|
||||
"""
|
||||
frappe.db.sql('delete from __global_search')
|
||||
|
||||
|
||||
def get_doctypes_with_global_search(with_child_tables=True):
|
||||
'''Return doctypes with global search fields'''
|
||||
"""
|
||||
Return doctypes with global search fields
|
||||
:param with_child_tables:
|
||||
:return:
|
||||
"""
|
||||
def _get():
|
||||
global_search_doctypes = []
|
||||
filters = {}
|
||||
|
|
@ -43,17 +56,25 @@ def get_doctypes_with_global_search(with_child_tables=True):
|
|||
global_search_doctypes.append(d)
|
||||
|
||||
installed_apps = frappe.get_installed_apps()
|
||||
module_app = frappe.local.module_app
|
||||
|
||||
doctypes = [
|
||||
d.name for d in global_search_doctypes
|
||||
if module_app.get(frappe.scrub(d.module))
|
||||
and module_app[frappe.scrub(d.module)] in installed_apps
|
||||
]
|
||||
|
||||
doctypes = [d.name for d in global_search_doctypes
|
||||
if frappe.local.module_app[frappe.scrub(d.module)] in installed_apps]
|
||||
return doctypes
|
||||
|
||||
return frappe.cache().get_value('doctypes_with_global_search', _get)
|
||||
|
||||
|
||||
def rebuild_for_doctype(doctype):
|
||||
'''Rebuild entries of doctype's documents in __global_search on change of
|
||||
searchable fields
|
||||
:param doctype: Doctype '''
|
||||
"""
|
||||
Rebuild entries of doctype's documents in __global_search on change of
|
||||
searchable fields
|
||||
:param doctype: Doctype
|
||||
"""
|
||||
|
||||
def _get_filters():
|
||||
filters = frappe._dict({ "docstatus": ["!=", 2] })
|
||||
|
|
@ -127,6 +148,7 @@ def rebuild_for_doctype(doctype):
|
|||
if all_contents:
|
||||
insert_values_for_multiple_docs(all_contents)
|
||||
|
||||
|
||||
def delete_global_search_records_for_doctype(doctype):
|
||||
frappe.db.sql('''
|
||||
delete
|
||||
|
|
@ -134,6 +156,7 @@ def delete_global_search_records_for_doctype(doctype):
|
|||
where
|
||||
doctype = %s''', doctype, as_dict=True)
|
||||
|
||||
|
||||
def get_selected_fields(meta, global_search_fields):
|
||||
fieldnames = [df.fieldname for df in global_search_fields]
|
||||
if meta.istable==1:
|
||||
|
|
@ -146,6 +169,7 @@ def get_selected_fields(meta, global_search_fields):
|
|||
|
||||
return fieldnames
|
||||
|
||||
|
||||
def get_children_data(doctype, meta):
|
||||
"""
|
||||
Get all records from all the child tables of a doctype
|
||||
|
|
@ -182,6 +206,7 @@ def get_children_data(doctype, meta):
|
|||
|
||||
return all_children, child_search_fields
|
||||
|
||||
|
||||
def insert_values_for_multiple_docs(all_contents):
|
||||
values = []
|
||||
for content in all_contents:
|
||||
|
|
@ -201,9 +226,11 @@ 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
|
||||
:param doc: Document to be added to global search'''
|
||||
"""
|
||||
Add values marked with `in_global_search` to
|
||||
`frappe.flags.update_global_search` from given doc
|
||||
:param doc: Document to be added to global search
|
||||
"""
|
||||
|
||||
if doc.docstatus > 1 or (doc.meta.has_field("enabled") and not doc.get("enabled")) \
|
||||
or doc.get("disabled"):
|
||||
|
|
@ -235,6 +262,7 @@ def update_global_search(doc):
|
|||
published=published, title=doc.get_title(), route=doc.get('route')))
|
||||
enqueue_global_search()
|
||||
|
||||
|
||||
def enqueue_global_search():
|
||||
if frappe.flags.update_global_search:
|
||||
try:
|
||||
|
|
@ -246,21 +274,32 @@ def enqueue_global_search():
|
|||
|
||||
frappe.flags.update_global_search = []
|
||||
|
||||
|
||||
def get_formatted_value(value, field):
|
||||
'''Prepare field from raw data'''
|
||||
"""
|
||||
Prepare field from raw data
|
||||
:param value:
|
||||
:param field:
|
||||
:return:
|
||||
"""
|
||||
|
||||
from six.moves.html_parser import HTMLParser
|
||||
|
||||
if(getattr(field, 'fieldtype', None) in ["Text", "Text Editor"]):
|
||||
if getattr(field, 'fieldtype', None) in ["Text", "Text Editor"]:
|
||||
h = HTMLParser()
|
||||
value = h.unescape(value)
|
||||
value = (re.subn(r'<[\s]*(script|style).*?</\1>(?s)', '', text_type(value))[0])
|
||||
value = ' '.join(value.split())
|
||||
return field.label + " : " + strip_html_tags(text_type(value))
|
||||
|
||||
|
||||
def sync_global_search(flags=None):
|
||||
'''Add values from `flags` (frappe.flags.update_global_search) to __global_search.
|
||||
This is called internally at the end of the request.'''
|
||||
"""
|
||||
Add values from `flags` (frappe.flags.update_global_search) to __global_search.
|
||||
This is called internally at the end of the request.
|
||||
:param flags:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if not flags:
|
||||
flags = frappe.flags.update_global_search
|
||||
|
|
@ -278,10 +317,13 @@ def sync_global_search(flags=None):
|
|||
|
||||
frappe.flags.update_global_search = []
|
||||
|
||||
|
||||
def delete_for_document(doc):
|
||||
'''Delete the __global_search entry of a document that has
|
||||
been deleted
|
||||
:param doc: Deleted document'''
|
||||
"""
|
||||
Delete the __global_search entry of a document that has
|
||||
been deleted
|
||||
:param doc: Deleted document
|
||||
"""
|
||||
|
||||
frappe.db.sql('''
|
||||
delete
|
||||
|
|
@ -290,13 +332,16 @@ def delete_for_document(doc):
|
|||
doctype = %s and
|
||||
name = %s''', (doc.doctype, doc.name), as_dict=True)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def search(text, start=0, limit=20, doctype=""):
|
||||
'''Search for given text in __global_search
|
||||
"""
|
||||
Search for given text in __global_search
|
||||
:param text: phrase to be searched
|
||||
:param start: start results at, default 0
|
||||
:param limit: number of results to return, default 20
|
||||
:return: Array of result objects'''
|
||||
:return: Array of result objects
|
||||
"""
|
||||
|
||||
text = "+" + text + "*"
|
||||
if not doctype:
|
||||
|
|
@ -328,13 +373,16 @@ def search(text, start=0, limit=20, doctype=""):
|
|||
|
||||
return results
|
||||
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def web_search(text, start=0, limit=20):
|
||||
'''Search for given text in __global_search where published = 1
|
||||
"""
|
||||
Search for given text in __global_search where published = 1
|
||||
:param text: phrase to be searched
|
||||
:param start: start results at, default 0
|
||||
:param limit: number of results to return, default 20
|
||||
:return: Array of result objects'''
|
||||
:return: Array of result objects
|
||||
"""
|
||||
|
||||
text = "+" + text + "*"
|
||||
results = frappe.db.sql('''
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ $.extend(frappe, {
|
|||
if($.isArray(html)) {
|
||||
html = html.join("<hr>")
|
||||
}
|
||||
|
||||
return frappe.get_modal(title || "Message", html).modal("show");
|
||||
},
|
||||
send_message: function(opts, btn) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue