From 64ae24f0741111edb49a0a0327098c2b91e455ff Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 18 Dec 2018 13:17:04 +0530 Subject: [PATCH 01/11] fix(Kanban): Fix for New Kanban DDL issue --- .../desk/doctype/kanban_board/kanban_board.py | 12 +--- .../js/frappe/views/kanban/kanban_view.js | 55 +++++++++---------- 2 files changed, 28 insertions(+), 39 deletions(-) diff --git a/frappe/desk/doctype/kanban_board/kanban_board.py b/frappe/desk/doctype/kanban_board/kanban_board.py index a1df694f6e..b63d446d6d 100644 --- a/frappe/desk/doctype/kanban_board/kanban_board.py +++ b/frappe/desk/doctype/kanban_board/kanban_board.py @@ -8,7 +8,6 @@ import json from frappe import _ from frappe.model.document import Document from six import iteritems -from frappe.custom.doctype.custom_field.custom_field import create_custom_field class KanbanBoard(Document): @@ -130,17 +129,8 @@ def update_order(board_name, order): @frappe.whitelist() def quick_kanban_board(doctype, board_name, field_name, project=None): '''Create new KanbanBoard quickly with default options''' + doc = frappe.new_doc('Kanban Board') - - if field_name == 'kanban_column': - create_custom_field(doctype, { - 'label': 'Kanban Column', - 'fieldname': 'kanban_column', - 'fieldtype': 'Select', - 'hidden': 1, - 'owner': 'Administrator' - }) - meta = frappe.get_meta(doctype) options = '' diff --git a/frappe/public/js/frappe/views/kanban/kanban_view.js b/frappe/public/js/frappe/views/kanban/kanban_view.js index 74dc283326..0f85875233 100644 --- a/frappe/public/js/frappe/views/kanban/kanban_view.js +++ b/frappe/public/js/frappe/views/kanban/kanban_view.js @@ -225,21 +225,18 @@ frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown) const fields = get_fields_for_dialog(); + let primary_action_label = fields.length > 1 ? __('Save') : ''; + let primary_action = fields.length > 1 ? + ({ board_name, field_name, project }) => { + make_kanban_board(board_name, field_name, project) + .then(() => dialog.hide(), (err) => frappe.msgprint(err)); + } : null; + dialog = new frappe.ui.Dialog({ title: __('New Kanban Board'), - fields: fields, - - primary_action_label: __('Save'), - primary_action(values) { - const custom_column = - values.custom_column !== undefined ? - values.custom_column : 1; - - let field_name = custom_column ? 'kanban_column' : values.field_name; - - make_kanban_board(values.board_name, field_name, values.project) - .then(() => dialog.hide(), (err) => frappe.msgprint(err)); - } + fields, + primary_action_label, + primary_action }); return dialog; } @@ -272,26 +269,28 @@ frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown) }); if (select_fields.length > 0) { - fields = fields.concat([{ + fields.push({ fieldtype: 'Select', fieldname: 'field_name', label: __('Columns based on'), options: select_fields.map(df => ({label: df.label, value: df.fieldname})), default: select_fields[0], - depends_on: 'eval:doc.custom_column===0', - reqd: 1 - }, - - { - fieldtype: 'Check', - fieldname: 'custom_column', - label: __('Custom Column'), - default: 0, - onchange() { - const value = this.get_value(); - this.layout.set_df_property('field_name', 'reqd', !value); - } - }]); + reqd: 1, + }); + } else { + fields = [{ + fieldtype: 'HTML', + options: ` +
+

+ ${__('No fields found that can be used as a Kanban Column. Use the Customize Form to add a Custom Field of type "Select".')} +

+ + ${__('Customize Form')} + +
+ ` + }] } return fields; From ccea2e2b0076e085999cc7d902b5ba03787107cf Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sat, 22 Dec 2018 00:22:10 +0530 Subject: [PATCH 02/11] style: Add semicolon --- frappe/public/js/frappe/views/kanban/kanban_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/kanban/kanban_view.js b/frappe/public/js/frappe/views/kanban/kanban_view.js index 0f85875233..edf3061b43 100644 --- a/frappe/public/js/frappe/views/kanban/kanban_view.js +++ b/frappe/public/js/frappe/views/kanban/kanban_view.js @@ -290,7 +290,7 @@ frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown) ` - }] + }]; } return fields; From 3ada55f9f8cdb644f8ad0d00954b7de231ea5f30 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Thu, 27 Dec 2018 19:53:15 +0530 Subject: [PATCH 03/11] fix assets for css for mobile build --- frappe/www/desk.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frappe/www/desk.py b/frappe/www/desk.py index 4387beb596..8de09b3720 100644 --- a/frappe/www/desk.py +++ b/frappe/www/desk.py @@ -70,8 +70,13 @@ def get_desk_assets(build_version): pass for path in data["include_css"]: - with open(os.path.join(frappe.local.sites_path, path) ,"r") as f: - assets[1]["data"] = assets[1]["data"] + "\n" + frappe.safe_decode(f.read(), "utf-8") + if path.startswith('/assets/'): + path = path.replace('/assets/', 'assets/') + try: + with open(os.path.join(frappe.local.sites_path, path) ,"r") as f: + assets[1]["data"] = assets[1]["data"] + "\n" + frappe.safe_decode(f.read(), "utf-8") + except IOError: + pass return { "build_version": data["build_version"], From 4239a56e5c06655b1250db5d461cf75317bba239 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 27 Dec 2018 20:28:27 +0530 Subject: [PATCH 04/11] Fix: default not found issue (fixes "in user permission" check) Also rename a badly named function --- frappe/public/js/frappe/defaults.js | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/frappe/public/js/frappe/defaults.js b/frappe/public/js/frappe/defaults.js index a2df90e5b4..6115afb784 100644 --- a/frappe/public/js/frappe/defaults.js +++ b/frappe/public/js/frappe/defaults.js @@ -8,9 +8,11 @@ frappe.defaults = { if(!d && frappe.defaults.is_a_user_permission_key(key)) d = defaults[frappe.model.scrub(key)]; if($.isArray(d)) d = d[0]; - if(frappe.defaults.not_in_user_permission(key, d)) { + + if(!frappe.defaults.in_user_permission(key, d)) { return; } + return d; }, get_user_defaults: function(key) { @@ -29,7 +31,7 @@ frappe.defaults = { // filter out values which are not permitted to the user d.filter(item => { - if(!frappe.defaults.not_in_user_permission(key, item)) { + if(frappe.defaults.in_user_permission(key, item)) { return item; } }); @@ -73,7 +75,7 @@ frappe.defaults = { } } - if(frappe.defaults.not_in_user_permission(key, value)) { + if(!frappe.defaults.in_user_permission(key, value)) { return; } @@ -90,14 +92,22 @@ frappe.defaults = { return key.indexOf(":")===-1 && key !== frappe.model.scrub(key); }, - not_in_user_permission: function(key, value) { - let user_permission = this.get_user_permissions()[frappe.model.unscrub(key)] || []; + in_user_permission: function(key, value) { + let user_permission = this.get_user_permissions()[frappe.model.unscrub(key)]; - let doc_found = user_permission.some(perm => { - return perm.doc === value; - }); + if (user_permission && user_permission.length) { + + let doc_found = user_permission.some(perm => { + return perm.doc === value; + }); + return doc_found; + + } else { + // there is no user permission for this doctype + // so we can allow this doc i.e., value + return true; + } - return !doc_found; }, get_user_permissions: function() { From dfb725fe7f8af895c6ba142b8c2c73a9ebbcf6cd Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Fri, 28 Dec 2018 18:28:05 +0530 Subject: [PATCH 05/11] fix: Currency formatting fix in report view (#6691) * Currency formatting fix in report view * Minor Fix * (Codacy Fix) Missing semicolon --- frappe/public/js/frappe/views/reports/report_view.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index 1668d4a25d..eeb0385a57 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -833,7 +833,13 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { editable, align, format: (value, row, column, data) => { - return frappe.format(value, column.docfield, { always_show_decimals: true }, data); + const d = row.reduce((acc, curr) => { + if (!curr.column.docfield) return acc; + acc[curr.column.docfield.fieldname] = curr.content; + return acc; + }, {}); + + return frappe.format(value, column.docfield, { always_show_decimals: true }, d); } }; } @@ -1055,7 +1061,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { for (let cdt in values) { fields = fields.concat(values[cdt].map(f => [f, cdt])); } - + // always keep name (ID) column this.fields = [["name", this.doctype], ...fields]; From ae57e75b0e2214e82b455e2a14eb08c92e425914 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Sun, 30 Dec 2018 22:43:21 +0530 Subject: [PATCH 06/11] fix(is_html): Return false if text is not string --- frappe/utils/data.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frappe/utils/data.py b/frappe/utils/data.py index 83e4082426..73458b5952 100644 --- a/frappe/utils/data.py +++ b/frappe/utils/data.py @@ -568,6 +568,8 @@ def in_words(integer, in_million=True): return ret.replace('-', ' ') def is_html(text): + if not isinstance(text, frappe.string_types): + return False return re.search('<[^>]+>', text) def is_image(filepath): From ffa0a1821c5ecac46276e6d42fdde3f1d1ddc318 Mon Sep 17 00:00:00 2001 From: Zarrar Date: Mon, 31 Dec 2018 11:34:48 +0530 Subject: [PATCH 07/11] fix: Delete View Logs when deleting a document (#6695) --- frappe/model/delete_doc.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frappe/model/delete_doc.py b/frappe/model/delete_doc.py index 6348f66b55..c1711e5118 100644 --- a/frappe/model/delete_doc.py +++ b/frappe/model/delete_doc.py @@ -214,7 +214,7 @@ def check_if_doc_is_linked(doc, method="Delete"): def check_if_doc_is_dynamically_linked(doc, method="Delete"): '''Raise `frappe.LinkExistsError` if the document is dynamically linked''' for df in get_dynamic_link_map().get(doc.doctype, []): - if df.parent in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", "Activity Log", 'File', 'Version'): + if df.parent in ("Communication", "ToDo", "DocShare", "Email Unsubscribe", "Activity Log", 'File', 'Version', 'View log'): # don't check for communication and todo! continue @@ -280,6 +280,10 @@ def delete_dynamic_links(doctype, name): communication_type = 'Comment' and reference_doctype=%s and reference_name=%s""", (doctype, name)) + # delete view logs + frappe.db.sql("""delete from `tabView log` + where reference_doctype=%s and reference_name=%s""", (doctype, name)) + # unlink communications frappe.db.sql("""update `tabCommunication` set reference_doctype=null, reference_name=null From ba72414a3dde2f5b3f70e1ab7e5cc93719fb58cc Mon Sep 17 00:00:00 2001 From: Zarrar Date: Mon, 31 Dec 2018 11:35:59 +0530 Subject: [PATCH 08/11] fix: Hide dialog after assignment (#6696) * dialog hide fix after assigning * fix: remove console statement --- frappe/public/js/frappe/form/footer/assign_to.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/footer/assign_to.js b/frappe/public/js/frappe/form/footer/assign_to.js index af23855110..b7056fd745 100644 --- a/frappe/public/js/frappe/form/footer/assign_to.js +++ b/frappe/public/js/frappe/form/footer/assign_to.js @@ -150,7 +150,7 @@ frappe.ui.form.AssignToDialog = Class.extend({ {value:'High', label:__('High')}], 'default':'Medium'}, ], - primary_action: function() { frappe.ui.add_assignment(opts, me) }, + primary_action: function() { frappe.ui.add_assignment(opts, this) }, primary_action_label: __("Add") }) $.extend(me, dialog); From 825b0120fa2261571e00ecb95e0220f693da162f Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Mon, 31 Dec 2018 08:16:55 +0000 Subject: [PATCH 09/11] fix(login): redirect user from login page if already logged in (#6689) * fix(login): redirect user from login page if already logged in the user should not be able to access the login page if a user session already exists. closes #6500. Signed-off-by: Chinmay Pai * fix(test-website): fix website test what is the point in writing tests if they don't really work/function as intended? Signed-off-by: Chinmay Pai * fix(regex): do not replace '\' in rules that defeats the entire purpose of creating rules, wtf? Signed-off-by: Chinmay Pai * fix(test_website): change user using set_user() Signed-off-by: Chinmay Pai * redirect: prefix string with r to escape string literals Signed-off-by: Chinmay Pai --- frappe/tests/test_website.py | 24 +++++++++++++----------- frappe/website/context.py | 2 +- frappe/website/redirect.py | 5 +++-- frappe/website/render.py | 3 +++ frappe/www/login.py | 4 ++-- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/frappe/tests/test_website.py b/frappe/tests/test_website.py index 28b8021aff..583bed6409 100644 --- a/frappe/tests/test_website.py +++ b/frappe/tests/test_website.py @@ -13,45 +13,47 @@ def set_request(**kwargs): class TestWebsite(unittest.TestCase): def test_page_load(self): + frappe.set_user('Guest') set_request(method='POST', path='login') response = render.render() - self.assertTrue(response.status_code, 200) + self.assertEquals(response.status_code, 200) html = frappe.safe_decode(response.get_data()) self.assertTrue('/* login-css */' in html) self.assertTrue('// login.js' in html) self.assertTrue('' in html) + frappe.set_user('Administrator') def test_redirect(self): import frappe.hooks frappe.hooks.website_redirects = [ - dict(source='/testfrom', target='://testto1'), - dict(source='/testfromregex.*', target='://testto2'), - dict(source='/testsub/(.*)', target='://testto3/\1') + dict(source=r'/testfrom', target=r'://testto1'), + dict(source=r'/testfromregex.*', target=r'://testto2'), + dict(source=r'/testsub/(.*)', target=r'://testto3/\1') ] frappe.cache().delete_key('app_hooks') frappe.cache().delete_key('website_redirects') set_request(method='GET', path='/testfrom') response = render.render() - self.assertTrue(response.status_code, 301) - self.assertTrue(response.headers.get('Location'), '://testto1') + self.assertEquals(response.status_code, 301) + self.assertEquals(response.headers.get('Location'), r'://testto1') set_request(method='GET', path='/testfromregex/test') response = render.render() - self.assertTrue(response.status_code, 301) - self.assertTrue(response.headers.get('Location'), '://testto2') + self.assertEquals(response.status_code, 301) + self.assertEquals(response.headers.get('Location'), r'://testto2') set_request(method='GET', path='/testsub/me') response = render.render() - self.assertTrue(response.status_code, 301) - self.assertTrue(response.headers.get('Location'), '://testto3/me') + self.assertEquals(response.status_code, 301) + self.assertEquals(response.headers.get('Location'), r'://testto3/me') set_request(method='GET', path='/test404') response = render.render() - self.assertTrue(response.status_code, 404) + self.assertEquals(response.status_code, 404) delattr(frappe.hooks, 'website_redirects') frappe.cache().delete_key('app_hooks') diff --git a/frappe/website/context.py b/frappe/website/context.py index f971fa0dcb..81962d7fec 100644 --- a/frappe/website/context.py +++ b/frappe/website/context.py @@ -48,7 +48,7 @@ def update_controller_context(context, controller): ret = module.get_context(context) if ret: context.update(ret) - except (frappe.PermissionError, frappe.DoesNotExistError): + except (frappe.PermissionError, frappe.DoesNotExistError, frappe.Redirect): raise except: if not frappe.flags.in_migrate: diff --git a/frappe/website/redirect.py b/frappe/website/redirect.py index b40e7cc658..8006ebaed7 100644 --- a/frappe/website/redirect.py +++ b/frappe/website/redirect.py @@ -16,7 +16,8 @@ def resolve_redirect(path): {"source": "/from", "target": "/main"}, # use regex - {"source": "/from/(.*)", "target": "/main/\1"} + {"source": r"/from/(.*)", "target": r"/main/\1"} + # use r as a string prefix if you use regex groups or want to escape any string literal ] ''' redirects = frappe.get_hooks('website_redirects') @@ -31,7 +32,7 @@ def resolve_redirect(path): for rule in redirects: pattern = rule['source'].strip('/ ') + '$' if re.match(pattern, path): - redirect_to = re.sub(pattern, rule['target'].replace('\\', '\\\\'), path) + redirect_to = re.sub(pattern, rule['target'], path) frappe.flags.redirect_location = redirect_to frappe.cache().hset('website_redirects', path, redirect_to) raise frappe.Redirect diff --git a/frappe/website/render.py b/frappe/website/render.py index a5006abae7..88e0eb235d 100644 --- a/frappe/website/render.py +++ b/frappe/website/render.py @@ -67,6 +67,9 @@ def render(path=None, http_status_code=None): except frappe.PermissionError as e: data, http_status_code = render_403(e, path) + except frappe.Redirect as e: + raise e + except Exception: path = "error" data = render_page(path) diff --git a/frappe/www/login.py b/frappe/www/login.py index e14dd85cf0..c2f83e45c3 100644 --- a/frappe/www/login.py +++ b/frappe/www/login.py @@ -15,8 +15,8 @@ from frappe.utils.html_utils import get_icon_html no_cache = True def get_context(context): - if frappe.session.user != "Guest" and frappe.session.data.user_type=="System User": - frappe.local.flags.redirect_location = "/desk" + if frappe.session.user != "Guest": + frappe.local.flags.redirect_location = "/" if frappe.session.data.user_type=="Website User" else "/desk" raise frappe.Redirect # get settings from site config From eacaea6a0dffff76f22af6b16d1f4be4646cdbf5 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Mon, 31 Dec 2018 20:07:13 +0530 Subject: [PATCH 10/11] Add accidently removed match filters (#6701) - Fixes "No user permission applied for Reports" issue --- frappe/model/db_query.py | 1 + 1 file changed, 1 insertion(+) diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index 6174d01939..ca7558c77a 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -552,6 +552,7 @@ class DatabaseQuery(object): ) match_conditions.append("({condition})".format(condition=condition)) + match_filters[df.get('options')] = docs if match_conditions: self.match_conditions.append(" and ".join(match_conditions)) From e9a1ad50814744b615b71fde746fa85980a2d6fd Mon Sep 17 00:00:00 2001 From: Saurabh Date: Tue, 1 Jan 2019 14:56:16 +0600 Subject: [PATCH 11/11] bumped to version 11.0.3-beta.46 --- frappe/hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/hooks.py b/frappe/hooks.py index c928418a02..1c25ee7ec4 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -12,7 +12,7 @@ source_link = "https://github.com/frappe/frappe" app_license = "MIT" develop_version = '12.x.x-develop' -staging_version = '11.0.3-beta.45' +staging_version = '11.0.3-beta.46' app_email = "info@frappe.io"