From e4e6d2796c786635c782f8638bb4e0c0225b638d Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 16 Feb 2019 16:15:20 +0530 Subject: [PATCH 01/11] Add custom get_value to get repective value in the option list instead of label selected by user --- .../js/frappe/form/controls/multiselect.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/frappe/public/js/frappe/form/controls/multiselect.js b/frappe/public/js/frappe/form/controls/multiselect.js index ae6a7a124e..03d0a580ae 100644 --- a/frappe/public/js/frappe/form/controls/multiselect.js +++ b/frappe/public/js/frappe/form/controls/multiselect.js @@ -32,6 +32,33 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({ }); }, + get_value() { + let data = this._super(); + // find value of label from option list and return actual value string + if (this.df.options[0].label) { + data = data.split(',').map(op => op.trim()); + data = data.map(val => { + let option = this.df.options.find(op => op.label === val); + if(option) { + return option.value; + } + }).filter(n => n != null).join(', '); + } + return data; + }, + + set_formatted_input(value) { + if (!value) return + // find label of value from option list and set from it as input + if (this.df.options[0].label) { + value = value.split(',').map(d => d.trim()).map(val => { + let option = this.df.options.find(op => op.value === val); + return option ? option.label : val; + }).filter(n => n != null).join(', '); + } + this._super(value); + }, + get_values() { const value = this.get_value() || ''; const values = value.split(/\s*,\s*/).filter(d => d); From 58e19de1ce17d7675ec5e5e62737ac38ec1e2fa7 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 16 Feb 2019 16:19:13 +0530 Subject: [PATCH 02/11] Remove extra code --- frappe/public/js/frappe/form/controls/multiselect.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/multiselect.js b/frappe/public/js/frappe/form/controls/multiselect.js index 03d0a580ae..783c3af731 100644 --- a/frappe/public/js/frappe/form/controls/multiselect.js +++ b/frappe/public/js/frappe/form/controls/multiselect.js @@ -39,9 +39,7 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({ data = data.split(',').map(op => op.trim()); data = data.map(val => { let option = this.df.options.find(op => op.label === val); - if(option) { - return option.value; - } + return option ? option.value : null; }).filter(n => n != null).join(', '); } return data; From 178c553b5d30ef38e6eb02a4b4e779a83ec5eda2 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 16 Feb 2019 15:46:10 +0530 Subject: [PATCH 03/11] fix: Dont cache get_hooks in developer_mode --- frappe/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index bdd534bc62..d566c43d15 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -918,11 +918,15 @@ def get_hooks(hook=None, default=None, app_name=None): append_hook(hooks, key, getattr(app_hooks, key)) return hooks + no_cache = conf.developer_mode or False if app_name: hooks = _dict(load_app_hooks(app_name)) else: - hooks = _dict(cache().get_value("app_hooks", load_app_hooks)) + if no_cache: + hooks = _dict(load_app_hooks()) + else: + hooks = _dict(cache().get_value("app_hooks", load_app_hooks)) if hook: return hooks.get(hook) or (default if default is not None else []) From 7984036ca44a8dd259d574db137e8693a8788b57 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sat, 16 Feb 2019 21:03:17 +0530 Subject: [PATCH 04/11] Fix codacy --- frappe/public/js/frappe/form/controls/multiselect.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/controls/multiselect.js b/frappe/public/js/frappe/form/controls/multiselect.js index 783c3af731..fc5cb05010 100644 --- a/frappe/public/js/frappe/form/controls/multiselect.js +++ b/frappe/public/js/frappe/form/controls/multiselect.js @@ -46,7 +46,7 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({ }, set_formatted_input(value) { - if (!value) return + if (!value) return; // find label of value from option list and set from it as input if (this.df.options[0].label) { value = value.split(',').map(d => d.trim()).map(val => { From 8e06d1a894e7143198322731d4c1ba95a0e8edb4 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sun, 17 Feb 2019 15:45:53 +0530 Subject: [PATCH 05/11] Fix listview load --- frappe/public/js/frappe/list/list_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 8dd6f67209..5399f30f92 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -863,7 +863,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { } return return_value; }); - + this.toggle_result_area(); this.render(); }); }); From 5e5c9f103dfd866ad5b6c1b99e1fcb049d11d189 Mon Sep 17 00:00:00 2001 From: Himanshu Date: Mon, 18 Feb 2019 19:23:19 +0530 Subject: [PATCH 06/11] fix(router): Router Fix if Doc Name contains '?' (#6945) - Router Show Page Not Found when there is a '?' in the doc name as it considers everything after '?' as argument - When the name of doc is 'New' it considers as you are creating a new doc every time you visit it. - After the fix, it checks if there is an '=' in name to check if there is an argument passed in the URL - _Doesn't break the 'New' functionality_ --- frappe/public/js/frappe/router.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js index e79080cb3b..59bad0655d 100644 --- a/frappe/public/js/frappe/router.js +++ b/frappe/public/js/frappe/router.js @@ -77,8 +77,15 @@ frappe.get_route = function(route) { // for app route = frappe.get_raw_route_str(route).split('/'); route = $.map(route, frappe._decode_str); - var parts = route[route.length - 1].split("?"); - route[route.length - 1] = parts[0]; + var parts = null; + var doc_name = route[route.length - 1]; + // if the last part contains ? then check if it is valid query string + if(doc_name.indexOf("?") < doc_name.indexOf("=")){ + parts = doc_name.split("?"); + route[route.length - 1] = parts[0]; + } else { + parts = doc_name; + } if (parts.length > 1) { var query_params = frappe.utils.get_query_params(parts[1]); frappe.route_options = $.extend(frappe.route_options || {}, query_params); From 4b4d59026ff3e5a1e9c04654267c8ba1350901ff Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Tue, 19 Feb 2019 14:19:51 +0530 Subject: [PATCH 07/11] fix: Jinja template error (#6957) Errors in Custom Print Format are not framework errors and should not have a "Report Issue" button --- frappe/__init__.py | 3 ++- frappe/utils/jinja.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index d566c43d15..481b74023c 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -274,7 +274,8 @@ def errprint(msg): if not request or (not "cmd" in local.form_dict) or conf.developer_mode: print(msg.encode('utf-8')) - error_log.append({"exc": msg, "locals": get_frame_locals()}) + from .utils import escape_html + error_log.append({"exc": escape_html(msg), "locals": get_frame_locals()}) def log(msg): """Add to `debug_log`. diff --git a/frappe/utils/jinja.py b/frappe/utils/jinja.py index 86b586667d..b8a41e53cc 100644 --- a/frappe/utils/jinja.py +++ b/frappe/utils/jinja.py @@ -59,7 +59,9 @@ def render_template(template, context, is_path=None, safe_render=True): :param safe_render: (optional) prevent server side scripting via jinja templating ''' - from frappe import throw + from frappe import get_traceback, throw + from frappe.utils import escape_html + from jinja2 import TemplateError if not template: return "" @@ -72,7 +74,11 @@ def render_template(template, context, is_path=None, safe_render=True): else: if safe_render and ".__" in template: throw("Illegal template") - return get_jenv().from_string(template).render(context) + try: + return get_jenv().from_string(template).render(context) + except TemplateError: + throw(title="Jinja Template Error", msg="
{template}
{tb}
".format(template=template, tb=escape_html(get_traceback()))) + def get_allowed_functions_for_jenv(): import os, json From 953f2c466f73525fb5d93f2626168a8b0d7bd1d9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Tue, 19 Feb 2019 14:23:39 +0530 Subject: [PATCH 08/11] fix: Doctypes not showing in data export (#6956) The maximum length for a `GET` request is 4096 bytes which is crossed in this case. --- frappe/public/js/frappe/form/controls/link.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/controls/link.js b/frappe/public/js/frappe/form/controls/link.js index 1d413b83f8..86a99c970f 100644 --- a/frappe/public/js/frappe/form/controls/link.js +++ b/frappe/public/js/frappe/form/controls/link.js @@ -157,7 +157,7 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({ me.set_custom_query(args); frappe.call({ - type: "GET", + type: "POST", method:'frappe.desk.search.search_link', no_spinner: true, args: args, From 572edb08ba3b394b203f2a9d41d45adfd6a8760b Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 19 Feb 2019 14:28:14 +0530 Subject: [PATCH 09/11] fix(email): default UIDVALIDITY to 0 --- frappe/email/receive.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/frappe/email/receive.py b/frappe/email/receive.py index 900456e37f..94b7da74f1 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -190,12 +190,10 @@ class EmailServer: # compare the UIDVALIDITY of email account and imap server uid_validity = self.settings.uid_validity - responce, message = self.imap.status("Inbox", "(UIDVALIDITY UIDNEXT)") - current_uid_validity = self.parse_imap_responce("UIDVALIDITY", message[0]) - if not current_uid_validity: - frappe.throw(_("Can not find UIDVALIDITY in imap status response")) + response, message = self.imap.status("Inbox", "(UIDVALIDITY UIDNEXT)") + current_uid_validity = self.parse_imap_response("UIDVALIDITY", message[0]) or 0 - uidnext = int(self.parse_imap_responce("UIDNEXT", message[0]) or "1") + uidnext = int(self.parse_imap_response("UIDNEXT", message[0]) or "1") frappe.db.set_value("Email Account", self.settings.email_account, "uidnext", uidnext) if not uid_validity or uid_validity != current_uid_validity: @@ -223,9 +221,9 @@ class EmailServer: elif uid_validity == current_uid_validity: return - def parse_imap_responce(self, cmd, responce): + def parse_imap_response(self, cmd, response): pattern = r"(?<={cmd} )[0-9]*".format(cmd=cmd) - match = re.search(pattern, responce.decode('utf-8'), re.U | re.I) + match = re.search(pattern, response.decode('utf-8'), re.U | re.I) if match: return match.group(0) else: From 308fa1318fe26c4021745b62a92ae42d0a520b4d Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 19 Feb 2019 14:30:06 +0530 Subject: [PATCH 10/11] fix: Ignore duplicate entry for Chat Profile (#6959) ![image](https://user-images.githubusercontent.com/9355208/52956076-55e96600-33b4-11e9-9580-6e5173f1fbe2.png) --- .../chat/doctype/chat_profile/chat_profile.py | 128 +++++++++--------- 1 file changed, 61 insertions(+), 67 deletions(-) diff --git a/frappe/chat/doctype/chat_profile/chat_profile.py b/frappe/chat/doctype/chat_profile/chat_profile.py index b5ec9a8be9..ca33751519 100644 --- a/frappe/chat/doctype/chat_profile/chat_profile.py +++ b/frappe/chat/doctype/chat_profile/chat_profile.py @@ -9,99 +9,93 @@ import frappe from frappe.core.doctype.version.version import get_diff from frappe.chat.doctype.chat_room import chat_room from frappe.chat.util import ( - safe_json_loads, - filter_dict, - dictify + safe_json_loads, + filter_dict, + dictify ) session = frappe.session class ChatProfile(Document): - def before_save(self): - if not self.is_new(): - self.get_doc_before_save() + def before_save(self): + if not self.is_new(): + self.get_doc_before_save() - def on_update(self): - if not self.is_new(): - b, a = self.get_doc_before_save(), self - diff = dictify(get_diff(a, b)) - if diff: - user = session.user + def on_update(self): + if not self.is_new(): + b, a = self.get_doc_before_save(), self + diff = dictify(get_diff(a, b)) + if diff: + user = session.user - fields = [changed[0] for changed in diff.changed] + fields = [changed[0] for changed in diff.changed] - if 'status' in fields: - rooms = chat_room.get(user, filters = ['Chat Room', 'type', '=', 'Direct']) - update = dict(user = user, data = dict(status = self.status)) + if 'status' in fields: + rooms = chat_room.get(user, filters = ['Chat Room', 'type', '=', 'Direct']) + update = dict(user = user, data = dict(status = self.status)) - for room in rooms: - frappe.publish_realtime('frappe.chat.profile:update', update, room = room.name, after_commit = True) + for room in rooms: + frappe.publish_realtime('frappe.chat.profile:update', update, room = room.name, after_commit = True) - if 'enable_chat' in fields: - update = dict(user = user, data = dict(enable_chat = bool(self.enable_chat))) - frappe.publish_realtime('frappe.chat.profile:update', update, user = user, after_commit = True) + if 'enable_chat' in fields: + update = dict(user = user, data = dict(enable_chat = bool(self.enable_chat))) + frappe.publish_realtime('frappe.chat.profile:update', update, user = user, after_commit = True) def authenticate(user): - if user != session.user: - frappe.throw(_("Sorry, you're not authorized.")) + if user != session.user: + frappe.throw(_("Sorry, you're not authorized.")) @frappe.whitelist() def get(user, fields = None): - duser = frappe.get_doc('User', user) - dprof = frappe.get_doc('Chat Profile', user) + duser = frappe.get_doc('User', user) + dprof = frappe.get_doc('Chat Profile', user) - # If you're adding something here, make sure the client recieves it. - profile = dict( - # User - name = duser.name, - email = duser.email, - first_name = duser.first_name, - last_name = duser.last_name, - username = duser.username, - avatar = duser.user_image, - bio = duser.bio, - # Chat Profile - status = dprof.status, - chat_background = dprof.chat_background, - message_preview = bool(dprof.message_preview), - notification_tones = bool(dprof.notification_tones), - conversation_tones = bool(dprof.conversation_tones), - enable_chat = bool(dprof.enable_chat) - ) - profile = filter_dict(profile, fields) + # If you're adding something here, make sure the client recieves it. + profile = dict( + # User + name = duser.name, + email = duser.email, + first_name = duser.first_name, + last_name = duser.last_name, + username = duser.username, + avatar = duser.user_image, + bio = duser.bio, + # Chat Profile + status = dprof.status, + chat_background = dprof.chat_background, + message_preview = bool(dprof.message_preview), + notification_tones = bool(dprof.notification_tones), + conversation_tones = bool(dprof.conversation_tones), + enable_chat = bool(dprof.enable_chat) + ) + profile = filter_dict(profile, fields) - return dictify(profile) + return dictify(profile) @frappe.whitelist() def create(user, exists_ok = False, fields = None): - authenticate(user) + authenticate(user) - exists_ok, fields = safe_json_loads(exists_ok, fields) + exists_ok, fields = safe_json_loads(exists_ok, fields) - result = frappe.db.sql(""" - SELECT * - FROM `tabChat Profile` - WHERE user = "{user}" - """.format(user = user)) + try: + dprof = frappe.new_doc('Chat Profile') + dprof.user = user + dprof.save(ignore_permissions = True) + except frappe.DuplicateEntryError: + if not exists_ok: + frappe.throw(_('Chat Profile for User {0} exists.').format(user)) - if result: - if not exists_ok: - frappe.throw(_('Chat Profile for User {0} exists.').format(user)) - else: - dprof = frappe.new_doc('Chat Profile') - dprof.user = user - dprof.save(ignore_permissions = True) + profile = get(user, fields = fields) - profile = get(user, fields = fields) - - return profile + return profile @frappe.whitelist() def update(user, data): - authenticate(user) + authenticate(user) - data = safe_json_loads(data) + data = safe_json_loads(data) - dprof = frappe.get_doc('Chat Profile', user) - dprof.update(data) - dprof.save(ignore_permissions = True) \ No newline at end of file + dprof = frappe.get_doc('Chat Profile', user) + dprof.update(data) + dprof.save(ignore_permissions = True) \ No newline at end of file From 94a61b40fe8505e80ab803288fd6d026f2e9b7b3 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 19 Feb 2019 18:10:39 +0550 Subject: [PATCH 11/11] bumped to version 11.1.7 --- frappe/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 481b74023c..d9cb285387 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -24,7 +24,7 @@ if sys.version[0] == '2': reload(sys) sys.setdefaultencoding("utf-8") -__version__ = '11.1.6' +__version__ = '11.1.7' __title__ = "Frappe Framework" local = Local()