From 861ff16ac8d045f5a35191c2f15a182d9e46a183 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sat, 5 Mar 2022 19:53:45 +0100 Subject: [PATCH 01/38] refactor: `frappe.db.exists` --- frappe/database/database.py | 50 +++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index dc9f20d8c2..9b1828f811 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -884,27 +884,39 @@ class Database(object): return self.sql("select name from `tab{doctype}` limit 1".format(doctype=doctype)) def exists(self, dt, dn=None, cache=False): - """Returns true if document exists. + """Return the document name of a matching document, or None. - :param dt: DocType name. - :param dn: Document name or filter dict.""" - if isinstance(dt, str): - if dt!="DocType" and dt==dn: - return True # single always exists (!) - try: - return self.get_value(dt, dn, "name", cache=cache) - except Exception: - return None + Note: `cache` only works if `dt` and `dn` are of type `str`. - elif isinstance(dt, dict) and dt.get('doctype'): - try: - conditions = [] - for d in dt: - if d == 'doctype': continue - conditions.append([d, '=', dt[d]]) - return self.get_all(dt['doctype'], filters=conditions, as_list=1) - except Exception: - return None + ## Examples + + Pass doctype and docname (only in this case we can cache the result) + + ``` + exists("User", "jane@example.org", cache=True) + ``` + + Pass a dict of filters including the `"doctype"` key: + + ``` + exists({"doctype": "User", "full_name": "Jane Doe"}) + ``` + + Pass the doctype and a dict of filters: + + ``` + exists("User", {"full_name": "Jane Doe"}) + ``` + """ + if dt == dn: + # single always exists (!) + return dn + + if isinstance(dt, dict): + _dt = dt.pop("doctype") + dt, dn = _dt, dt + + return self.get_value(dt, dn, ignore=True, cache=cache) def count(self, dt, filters=None, debug=False, cache=False): """Returns `COUNT(*)` for given DocType and filters.""" From e6261f15cca054868f10596d1ec70921193d1a34 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 8 Mar 2022 12:36:18 +0530 Subject: [PATCH 02/38] fix: web form list button --- frappe/public/js/frappe/web_form/web_form_list.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/web_form/web_form_list.js b/frappe/public/js/frappe/web_form/web_form_list.js index f4d41c2a0b..272c65cf69 100644 --- a/frappe/public/js/frappe/web_form/web_form_list.js +++ b/frappe/public/js/frappe/web_form/web_form_list.js @@ -212,8 +212,7 @@ export default class WebFormList { "btn", "btn-secondary", "btn-sm", - "ml-2", - "text-white" + "ml-2" ); } else if (type == "danger") { From 067e842e01d6425671b048a9bf5f745a053416dc Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Wed, 9 Mar 2022 09:58:44 +0530 Subject: [PATCH 03/38] fix: web form list empty state --- .../js/frappe/web_form/web_form_list.js | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/web_form/web_form_list.js b/frappe/public/js/frappe/web_form/web_form_list.js index f4d41c2a0b..42cc10142f 100644 --- a/frappe/public/js/frappe/web_form/web_form_list.js +++ b/frappe/public/js/frappe/web_form/web_form_list.js @@ -16,7 +16,8 @@ export default class WebFormList { if (this.table) { Array.from(this.table.tBodies).forEach(tbody => tbody.remove()); let check = document.getElementById('select-all'); - check.checked = false; + if (check) + check.checked = false; } this.rows = []; this.page_length = 20; @@ -131,9 +132,33 @@ export default class WebFormList { this.make_table_head(); } - this.append_rows(this.data); + if (this.data.length) { + this.append_rows(this.data); + this.wrapper.appendChild(this.table); + } + else { + let new_button = ""; + let empty_state = document.createElement("div"); + empty_state.classList.add("no-result", "text-muted", "flex", "justify-center", "align-center"); + + frappe.has_permission(this.doctype, "", "create", () => { + new_button = `

`; + }); + + empty_state.innerHTML = `
+
+ Generic Empty State +
+

${__("No {0} found", [__(this.doctype)])}

+ ${new_button}`; + + this.wrapper.appendChild(empty_state); + } - this.wrapper.appendChild(this.table); } make_table_head() { From 428de40dcef5b2a903153b353d956408d07d5880 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Wed, 9 Mar 2022 14:39:44 +0530 Subject: [PATCH 04/38] fix: formatting --- frappe/public/js/frappe/web_form/web_form_list.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/web_form/web_form_list.js b/frappe/public/js/frappe/web_form/web_form_list.js index 42cc10142f..b7e92052a4 100644 --- a/frappe/public/js/frappe/web_form/web_form_list.js +++ b/frappe/public/js/frappe/web_form/web_form_list.js @@ -135,8 +135,7 @@ export default class WebFormList { if (this.data.length) { this.append_rows(this.data); this.wrapper.appendChild(this.table); - } - else { + } else { let new_button = ""; let empty_state = document.createElement("div"); empty_state.classList.add("no-result", "text-muted", "flex", "justify-center", "align-center"); From 734d0b4fe8f6ee0e810d7e5bb205329ad9acf80a Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 17 Mar 2022 01:35:46 +0100 Subject: [PATCH 05/38] test: frappe.db.exists --- frappe/tests/test_db.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index bbd09590be..504a1eb3b8 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -301,6 +301,14 @@ class TestDB(unittest.TestCase): # recover transaction to continue other tests raise Exception + def test_exists(self): + dt, dn = "User", "Administrator" + self.assertEqual(frappe.db.exists(dt, dn, cache=True), dn) + self.assertEqual(frappe.db.exists(dt, dn), dn) + self.assertEqual(frappe.db.exists(dt, {"name": ("=", dn)}), dn) + self.assertEqual(frappe.db.exists({"doctype": dt, "name": ("like", "Admin%")}), dn) + self.assertEqual(frappe.db.exists(dt, [["name", "=", dn]]), dn) + @run_only_if(db_type_is.MARIADB) class TestDDLCommandsMaria(unittest.TestCase): From 7e550e919ca51d5986314db9a6227cb988f5644f Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 17 Mar 2022 02:07:23 +0100 Subject: [PATCH 06/38] revert: don't check for doctype (861ff16) --- frappe/database/database.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index 9b1828f811..5d91e0b4f1 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -908,7 +908,7 @@ class Database(object): exists("User", {"full_name": "Jane Doe"}) ``` """ - if dt == dn: + if dt != "DocType" and dt == dn: # single always exists (!) return dn From c26cf2547885b7b9c6d608a23c273d1501dd2f07 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Thu, 17 Mar 2022 02:46:00 +0100 Subject: [PATCH 07/38] fix: avoid invalid call to frappe.db.exists --- frappe/model/base_document.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 8a81aa5610..c251325bcb 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -963,7 +963,7 @@ class BaseDocument(object): from frappe.model.meta import get_default_df df = get_default_df(fieldname) - if not currency and df: + if df.fieldtype == "Currency" and not currency: currency = self.get(df.get("options")) if not frappe.db.exists('Currency', currency, cache=True): currency = None From d68187ab9679d3cc0fc95129716625154c5712db Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 17 Mar 2022 16:42:45 +0530 Subject: [PATCH 08/38] fix: empty state height --- .../public/js/frappe/web_form/web_form_list.js | 18 ++++++++---------- frappe/public/scss/website/index.scss | 13 +++++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/frappe/public/js/frappe/web_form/web_form_list.js b/frappe/public/js/frappe/web_form/web_form_list.js index b7e92052a4..1f3628ac38 100644 --- a/frappe/public/js/frappe/web_form/web_form_list.js +++ b/frappe/public/js/frappe/web_form/web_form_list.js @@ -141,23 +141,21 @@ export default class WebFormList { empty_state.classList.add("no-result", "text-muted", "flex", "justify-center", "align-center"); frappe.has_permission(this.doctype, "", "create", () => { - new_button = `

`; - empty_state.innerHTML = `
+ empty_state.innerHTML = `
- Generic Empty State + Generic Empty State
-

${__("No {0} found", [__(this.doctype)])}

+

${__("No {0} found", [__(this.doctype)])}

${new_button}`; - this.wrapper.appendChild(empty_state); + this.wrapper.appendChild(empty_state); + }); } - } make_table_head() { diff --git a/frappe/public/scss/website/index.scss b/frappe/public/scss/website/index.scss index 2cc0f64f76..e36e649eb7 100644 --- a/frappe/public/scss/website/index.scss +++ b/frappe/public/scss/website/index.scss @@ -311,3 +311,16 @@ h5.modal-title { .empty-list-icon { height: 70px; } + +.null-state { + height: 60px; + width: auto; + margin-bottom: var(--margin-md); + img { + fill: var(--fg-color); + } +} + +.no-result { + min-height: #{"calc(100vh - 284px)"}; +} From bbcb99d65d9e560d101b810918724b02e47d3ed2 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 17 Mar 2022 16:55:14 +0530 Subject: [PATCH 09/38] fix: removed console --- frappe/public/js/frappe/web_form/web_form_list.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/public/js/frappe/web_form/web_form_list.js b/frappe/public/js/frappe/web_form/web_form_list.js index 1f3628ac38..09127a9f7f 100644 --- a/frappe/public/js/frappe/web_form/web_form_list.js +++ b/frappe/public/js/frappe/web_form/web_form_list.js @@ -141,7 +141,6 @@ export default class WebFormList { empty_state.classList.add("no-result", "text-muted", "flex", "justify-center", "align-center"); frappe.has_permission(this.doctype, "", "create", () => { - console.log(this) new_button = ``; From 5187663d7370df3f548e0d83583a2f88220232fa Mon Sep 17 00:00:00 2001 From: hrwx Date: Sat, 19 Mar 2022 23:50:30 +0000 Subject: [PATCH 10/38] chore: prefix test for parse_email --- frappe/core/doctype/communication/test_communication.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/communication/test_communication.py b/frappe/core/doctype/communication/test_communication.py index d933c2f494..8012d8facf 100644 --- a/frappe/core/doctype/communication/test_communication.py +++ b/frappe/core/doctype/communication/test_communication.py @@ -4,8 +4,8 @@ import unittest from urllib.parse import quote import frappe -from frappe.email.doctype.email_queue.email_queue import EmailQueue from frappe.core.doctype.communication.communication import get_emails +from frappe.email.doctype.email_queue.email_queue import EmailQueue test_records = frappe.get_test_records('Communication') @@ -202,7 +202,7 @@ class TestCommunication(unittest.TestCase): self.assertIn(("Note", note.name), doc_links) - def parse_emails(self): + def test_parse_emails(self): emails = get_emails( [ 'comm_recipient+DocType+DocName@example.com', From 1934340a1b81313b191381206c3dc6aa3fdedac1 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 01:46:27 +0100 Subject: [PATCH 11/38] refactor: don't assign variable to itself --- frappe/handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 frappe/handler.py diff --git a/frappe/handler.py b/frappe/handler.py old mode 100755 new mode 100644 index 3fd1c096e4..07c7d7a30c --- a/frappe/handler.py +++ b/frappe/handler.py @@ -250,7 +250,7 @@ def run_doc_method(method, docs=None, dt=None, dn=None, arg=None, args=None): try: args = json.loads(args) except ValueError: - args = args + pass method_obj = getattr(doc, method) fn = getattr(method_obj, '__func__', method_obj) From 687ca6972d63a7505211b89ba4dc6b7f4efc174e Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 01:53:30 +0100 Subject: [PATCH 12/38] refactor: remove unused fallback --- frappe/public/js/frappe/views/reports/report_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index f80d59350f..2747a2723d 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -1026,7 +1026,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { } if (!docfield || docfield.report_hide) return; - let title = __(docfield ? docfield.label : toTitle(fieldname)); + let title = __(docfield.label); if (doctype !== this.doctype) { title += ` (${__(doctype)})`; } From 0d8733c462b99063a70eb50c3de2538608f613ba Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 02:19:07 +0100 Subject: [PATCH 13/38] refactor: remove unused import --- frappe/utils/backups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py index 3a0c337042..de7ce2e38b 100644 --- a/frappe/utils/backups.py +++ b/frappe/utils/backups.py @@ -15,7 +15,7 @@ import click # imports - module imports import frappe -from frappe import _, conf +from frappe import conf from frappe.utils import get_file_size, get_url, now, now_datetime, cint from frappe.utils.password import get_encryption_key From 4b8efc5ebd4e62a45aa6a4fecd68f607ab35d127 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 02:19:41 +0100 Subject: [PATCH 14/38] fix: typo in parameter name --- frappe/utils/backups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py index de7ce2e38b..dc5cdf43a2 100644 --- a/frappe/utils/backups.py +++ b/frappe/utils/backups.py @@ -505,7 +505,7 @@ download only after 24 hours.""" % { datetime_str.strftime("%d/%m/%Y %H:%M:%S") + """ - Backup ready to be downloaded""" ) - frappe.sendmail(recipients=recipient_list, msg=msg, subject=subject) + frappe.sendmail(recipients=recipient_list, message=msg, subject=subject) return recipient_list From 1d3ec4297402c4a6769af7731bf88e14d38999fb Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 02:20:27 +0100 Subject: [PATCH 15/38] fix: send_email doesn't take arguments --- frappe/utils/backups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/backups.py b/frappe/utils/backups.py index dc5cdf43a2..5197b20bd3 100644 --- a/frappe/utils/backups.py +++ b/frappe/utils/backups.py @@ -779,7 +779,7 @@ if __name__ == "__main__": db_type=db_type, db_port=db_port, ) - odb.send_email("abc.sql.gz") + odb.send_email() if cmd == "delete_temp_backups": delete_temp_backups() From 8a4f316ec5c3492b4f692f60079c2d299c5ff29d Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 02:35:35 +0100 Subject: [PATCH 16/38] refactor: remove useless pass, log error --- frappe/core/doctype/user/user.py | 4 ++-- frappe/translate.py | 2 -- frappe/utils/nestedset.py | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py index d08755f9a8..1ad977547c 100644 --- a/frappe/core/doctype/user/user.py +++ b/frappe/core/doctype/user/user.py @@ -253,8 +253,8 @@ class User(Document): self.email_new_password(new_password) except frappe.OutgoingEmailError: - print(frappe.get_traceback()) - pass # email server not set, don't send email + # email server not set, don't send email + frappe.log_error(frappe.get_traceback()) @Document.hook def validate_reset_password(self): diff --git a/frappe/translate.py b/frappe/translate.py index 292adc71c7..0367d33d3b 100644 --- a/frappe/translate.py +++ b/frappe/translate.py @@ -650,8 +650,6 @@ def extract_messages_from_code(code): if isinstance(e, InvalidIncludePath): frappe.clear_last_message() - pass - messages = [] pattern = r"_\(([\"']{,3})(?P((?!\1).)*)\1(\s*,\s*context\s*=\s*([\"'])(?P((?!\5).)*)\5)*(\s*,\s*(.)*?\s*(,\s*([\"'])(?P((?!\11).)*)\11)*)*\)" diff --git a/frappe/utils/nestedset.py b/frappe/utils/nestedset.py index 98ad337043..2517761c45 100644 --- a/frappe/utils/nestedset.py +++ b/frappe/utils/nestedset.py @@ -227,7 +227,6 @@ class NestedSet(Document): update_nsm(self) except frappe.DoesNotExistError: if self.flags.on_rollback: - pass frappe.message_log.pop() else: raise From 9a2a2e7abea43d5854b92ea994cd62ac3f2f64f6 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 03:08:23 +0100 Subject: [PATCH 17/38] fix: assign result of concat --- frappe/public/js/frappe/list/list_settings.js | 2 +- frappe/public/js/frappe/utils/utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/list/list_settings.js b/frappe/public/js/frappe/list/list_settings.js index 782a077a78..186a4370bc 100644 --- a/frappe/public/js/frappe/list/list_settings.js +++ b/frappe/public/js/frappe/list/list_settings.js @@ -375,7 +375,7 @@ export default class ListSettings { let me = this; if (me.removed_fields) { - me.removed_fields.concat(fields); + me.removed_fields = me.removed_fields.concat(fields); } else { me.removed_fields = fields; } diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index a944af523d..0514576380 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -231,7 +231,7 @@ Object.assign(frappe.utils, { if (tt && (tt.substr(0, 1)===">" || tt.substr(0, 4)===">")) { part.push(t); } else { - out.concat(part); + out = out.concat(part); out.push(t); part = []; } From f650408daa0da57d0ce9072eb4a5b2f244b0e4bd Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 20 Mar 2022 18:02:44 +0100 Subject: [PATCH 18/38] refactor: use frappe.parse_json --- frappe/handler.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/frappe/handler.py b/frappe/handler.py index 07c7d7a30c..ebc72da937 100644 --- a/frappe/handler.py +++ b/frappe/handler.py @@ -225,11 +225,10 @@ def ping(): def run_doc_method(method, docs=None, dt=None, dn=None, arg=None, args=None): """run a whitelisted controller method""" - import json - import inspect + from inspect import getfullargspec - if not args: - args = arg or "" + if not args and arg: + args = arg if dt: # not called from a doctype (from a page) if not dn: @@ -237,9 +236,7 @@ def run_doc_method(method, docs=None, dt=None, dn=None, arg=None, args=None): doc = frappe.get_doc(dt, dn) else: - if isinstance(docs, str): - docs = json.loads(docs) - + docs = frappe.parse_json(docs) doc = frappe.get_doc(docs) doc._original_modified = doc.modified doc.check_if_latest() @@ -248,7 +245,7 @@ def run_doc_method(method, docs=None, dt=None, dn=None, arg=None, args=None): throw_permission_error() try: - args = json.loads(args) + args = frappe.parse_json(args) except ValueError: pass @@ -257,7 +254,7 @@ def run_doc_method(method, docs=None, dt=None, dn=None, arg=None, args=None): is_whitelisted(fn) is_valid_http_method(fn) - fnargs = inspect.getfullargspec(method_obj).args + fnargs = getfullargspec(method_obj).args if not fnargs or (len(fnargs)==1 and fnargs[0]=="self"): response = doc.run_method(method) From afd5956e31836634c6d63a6b3b68d30234588a91 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Mon, 21 Mar 2022 10:39:52 +0530 Subject: [PATCH 19/38] style: Fix formatting --- .../js/frappe/web_form/web_form_list.js | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/frappe/public/js/frappe/web_form/web_form_list.js b/frappe/public/js/frappe/web_form/web_form_list.js index 09127a9f7f..8d2959e49f 100644 --- a/frappe/public/js/frappe/web_form/web_form_list.js +++ b/frappe/public/js/frappe/web_form/web_form_list.js @@ -141,16 +141,26 @@ export default class WebFormList { empty_state.classList.add("no-result", "text-muted", "flex", "justify-center", "align-center"); frappe.has_permission(this.doctype, "", "create", () => { - new_button = ``; - - empty_state.innerHTML = `
-
- Generic Empty State -
-

${__("No {0} found", [__(this.doctype)])}

- ${new_button}`; + new_button = ` + + `; + + empty_state.innerHTML = ` +
+
+ Generic Empty State +
+

${__("No {0} found", [__(this.doctype)])}

+ ${new_button} +
+ `; this.wrapper.appendChild(empty_state); }); From b97cfed6d7678409019bdf02a48f3c8b8abdb770 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 19 Mar 2022 20:46:53 +0530 Subject: [PATCH 20/38] perf: limit rows to 1 for get_value and exists --- frappe/database/database.py | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index a3476c9538..099c9f1fde 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -384,7 +384,7 @@ class Database(object): """ ret = self.get_values(doctype, filters, fieldname, ignore, as_dict, debug, - order_by, cache=cache, for_update=for_update, run=run, pluck=pluck, distinct=distinct) + order_by, cache=cache, for_update=for_update, run=run, pluck=pluck, distinct=distinct, limit=1) if not run: return ret @@ -393,7 +393,7 @@ class Database(object): def get_values(self, doctype, filters=None, fieldname="name", ignore=None, as_dict=False, debug=False, order_by="KEEP_DEFAULT_ORDERING", update=None, cache=False, for_update=False, - run=True, pluck=False, distinct=False): + run=True, pluck=False, distinct=False, limit=None): """Returns multiple document properties. :param doctype: DocType name. @@ -423,14 +423,15 @@ class Database(object): if isinstance(filters, list): out = self._get_value_for_many_names( - doctype, - filters, - fieldname, - order_by, + doctype=doctype, + names=filters, + field=fieldname, + order_by=order_by, debug=debug, run=run, pluck=pluck, distinct=distinct, + limit=limit, ) else: @@ -444,17 +445,18 @@ class Database(object): if order_by: order_by = "modified" if order_by == "KEEP_DEFAULT_ORDERING" else order_by out = self._get_values_from_table( - fields, - filters, - doctype, - as_dict, - debug, - order_by, - update, + fields=fields, + filters=filters, + doctype=doctype, + as_dict=as_dict, + debug=debug, + order_by=order_by, + update=update, for_update=for_update, run=run, pluck=pluck, - distinct=distinct + distinct=distinct, + limit=limit, ) except Exception as e: if ignore and (frappe.db.is_missing_column(e) or frappe.db.is_table_missing(e)): @@ -623,6 +625,7 @@ class Database(object): run=True, pluck=False, distinct=False, + limit=None, ): field_objects = [] @@ -641,6 +644,7 @@ class Database(object): field_objects=field_objects, fields=fields, distinct=distinct, + limit=limit, ) if ( fields == "*" @@ -654,7 +658,7 @@ class Database(object): ) return r - def _get_value_for_many_names(self, doctype, names, field, order_by, debug=False, run=True, pluck=False, distinct=False): + def _get_value_for_many_names(self, doctype, names, field, order_by, debug=False, run=True, pluck=False, distinct=False, limit=None): names = list(filter(None, names)) if names: return self.get_all( @@ -667,6 +671,7 @@ class Database(object): as_list=1, run=run, distinct=distinct, + limit_page_length=limit ) else: return {} From 85428e817d2c2034b10ea6d18eb30d65555b3240 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 21 Mar 2022 11:16:10 +0530 Subject: [PATCH 21/38] test: get_value(s) with limits --- frappe/tests/test_db.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 235211b6b8..1cd9287ec3 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -14,7 +14,7 @@ from frappe.database.database import Database from frappe.query_builder import Field from frappe.query_builder.functions import Concat_ws from frappe.tests.test_query_builder import db_type_is, run_only_if -from frappe.utils import add_days, now, random_string +from frappe.utils import add_days, now, random_string, cint from frappe.utils.testutils import clear_custom_fields @@ -84,6 +84,27 @@ class TestDB(unittest.TestCase): ), ) + def test_get_value_limits(self): + + # check both dict and list style filters + filters = [{"enabled": 1}, [["enabled", "=", 1]]] + for filter in filters: + self.assertEqual(1, len(frappe.db.get_values("User", filters=filter, limit=1))) + # count of last touched rows as per DB-API 2.0 https://peps.python.org/pep-0249/#rowcount + self.assertGreaterEqual(1, cint(frappe.db._cursor.rowcount)) + self.assertEqual(2, len(frappe.db.get_values("User", filters=filter, limit=2))) + self.assertGreaterEqual(2, cint(frappe.db._cursor.rowcount)) + + # without limits length == count + self.assertEqual(len(frappe.db.get_values("User", filters=filter)), + frappe.db.count("User", filter)) + + frappe.db.get_value("User", filters=filter) + self.assertGreaterEqual(1, cint(frappe.db._cursor.rowcount)) + + frappe.db.exists("User", filter) + self.assertGreaterEqual(1, cint(frappe.db._cursor.rowcount)) + def test_escape(self): frappe.db.escape("香港濟生堂製藥有限公司 - IT".encode("utf-8")) From 10fbb4330ac3c10839d8f32672fc2c563d6b549a Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 10 Mar 2022 12:58:13 +0530 Subject: [PATCH 22/38] fix: setting permissions to any role of some doctypes is not working (cherry picked from commit 6612232babd61852e90ccfc2ca836397d80506cf) # Conflicts: # frappe/permissions.py --- frappe/permissions.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frappe/permissions.py b/frappe/permissions.py index af17faba01..985d398749 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -7,7 +7,11 @@ import frappe.share from frappe import _, msgprint from frappe.utils import cint from frappe.query_builder import DocType +<<<<<<< HEAD +======= +import frappe.share +>>>>>>> 6612232bab (fix: setting permissions to any role of some doctypes is not working) rights = ("select", "read", "write", "create", "delete", "submit", "cancel", "amend", "print", "email", "report", "import", "export", "set_user_permissions", "share") @@ -466,6 +470,12 @@ def update_permission_property(doctype, role, permlevel, ptype, value=None, vali table = DocType("Custom DocPerm") frappe.qb.update(table).set(ptype, value).where(table.name == name).run() +<<<<<<< HEAD +======= + table = DocType("Custom DocPerm") + frappe.qb.update(table).set(ptype, value).where(table.name == name).run() + +>>>>>>> 6612232bab (fix: setting permissions to any role of some doctypes is not working) if validate: validate_permissions_for_doctype(doctype) From b2c0bf7a4ee491a9f871b8cd62d40be25b642214 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 17 Mar 2022 13:19:50 +0530 Subject: [PATCH 23/38] fix: remove tab \t and newlines \n from start of query and remove from middle (cherry picked from commit ac5effc7dd4d876d06daf945f0b8b77ecdd0c05f) # Conflicts: # frappe/database/database.py --- frappe/database/database.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frappe/database/database.py b/frappe/database/database.py index a3476c9538..f9a230b25c 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -116,8 +116,14 @@ class Database(object): """ query = str(query) +<<<<<<< HEAD if not run: return query +======= + + # remove \n \t from start of query and replace them with space anywhere in middle + query = re.sub(r'\s', ' ', query).lstrip() +>>>>>>> ac5effc7dd (fix: remove tab \t and newlines \n from start of query and remove from middle) if re.search(r'ifnull\(', query, flags=re.IGNORECASE): # replaces ifnull in query with coalesce From fbac6fbfb40e9e03aa67dc0df32328bdb96cd7a1 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Thu, 17 Mar 2022 15:06:20 +0530 Subject: [PATCH 24/38] fix: only remove \n\t from start and end (cherry picked from commit 7bb172365f2c9ae6cca98ccc4dfee7714b9c3f0c) # Conflicts: # frappe/database/database.py --- frappe/database/database.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frappe/database/database.py b/frappe/database/database.py index f9a230b25c..3ce2b32fc8 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -121,9 +121,14 @@ class Database(object): return query ======= +<<<<<<< HEAD # remove \n \t from start of query and replace them with space anywhere in middle query = re.sub(r'\s', ' ', query).lstrip() >>>>>>> ac5effc7dd (fix: remove tab \t and newlines \n from start of query and remove from middle) +======= + # remove \n \t from start and end of query + query = re.sub(r'^\s*|\s*$', '', query) +>>>>>>> 7bb172365f (fix: only remove \n\t from start and end) if re.search(r'ifnull\(', query, flags=re.IGNORECASE): # replaces ifnull in query with coalesce From a832aa27af79e20b5ec47d21d0f8fffb8cf84f0f Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 21 Mar 2022 11:26:36 +0530 Subject: [PATCH 25/38] chore: whitespace --- frappe/public/js/frappe/web_form/web_form_list.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/web_form/web_form_list.js b/frappe/public/js/frappe/web_form/web_form_list.js index 076f2f266d..1ad332e3c2 100644 --- a/frappe/public/js/frappe/web_form/web_form_list.js +++ b/frappe/public/js/frappe/web_form/web_form_list.js @@ -142,8 +142,8 @@ export default class WebFormList { frappe.has_permission(this.doctype, "", "create", () => { new_button = ` - @@ -152,9 +152,9 @@ export default class WebFormList { empty_state.innerHTML = `
- Generic Empty State

${__("No {0} found", [__(this.doctype)])}

From 1054a1203e0d3a79025b561d88cb342c6fdd6d10 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 21 Mar 2022 12:09:31 +0530 Subject: [PATCH 26/38] fix: assinging thread locals to global variables --- frappe/email/doctype/auto_email_report/auto_email_report.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/email/doctype/auto_email_report/auto_email_report.py b/frappe/email/doctype/auto_email_report/auto_email_report.py index 5ffde0c37b..abeb681a25 100644 --- a/frappe/email/doctype/auto_email_report/auto_email_report.py +++ b/frappe/email/doctype/auto_email_report/auto_email_report.py @@ -15,8 +15,6 @@ from frappe.utils.csvutils import to_csv from frappe.utils.xlsxutils import make_xlsx from frappe.desk.query_report import build_xlsx_data -max_reports_per_user = frappe.local.conf.max_reports_per_user or 3 - class AutoEmailReport(Document): def autoname(self): @@ -46,6 +44,8 @@ class AutoEmailReport(Document): def validate_report_count(self): '''check that there are only 3 enabled reports per user''' count = frappe.db.sql('select count(*) from `tabAuto Email Report` where user=%s and enabled=1', self.user)[0][0] + max_reports_per_user = frappe.local.conf.max_reports_per_user or 3 + if count > max_reports_per_user + (-1 if self.flags.in_insert else 0): frappe.throw(_('Only {0} emailed reports are allowed per user').format(max_reports_per_user)) From dbb622fce177491a2d8d7ee92d1abbebeeba0333 Mon Sep 17 00:00:00 2001 From: Isaiah Galorport <86836253+icecliff@users.noreply.github.com> Date: Mon, 21 Mar 2022 16:43:06 +0800 Subject: [PATCH 27/38] fix: Other user must not able to delete other user's comment except System Manager (#16018) * fix: Other user must not able to delete other user's comment except Admin * Update frappe/public/js/frappe/form/footer/form_timeline.js Co-authored-by: Sagar Vora * fix: Close condition scope Co-authored-by: Sagar Vora Co-authored-by: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> (cherry picked from commit e4137ca8a1bea4e35358e0ba9844042c3e4d334a) # Conflicts: # frappe/public/js/frappe/form/footer/form_timeline.js --- frappe/public/js/frappe/form/footer/form_timeline.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/frappe/public/js/frappe/form/footer/form_timeline.js b/frappe/public/js/frappe/form/footer/form_timeline.js index d440874f36..7182aa667d 100644 --- a/frappe/public/js/frappe/form/footer/form_timeline.js +++ b/frappe/public/js/frappe/form/footer/form_timeline.js @@ -453,6 +453,7 @@ class FormTimeline extends BaseTimeline { let edit_wrapper = $(`
`).hide(); let edit_box = this.make_editable(edit_wrapper); let content_wrapper = comment_wrapper.find('.content'); +<<<<<<< HEAD let more_actions_wrapper = comment_wrapper.find('.more-actions'); if (frappe.model.can_delete("Comment")) { const delete_option = $(` @@ -461,6 +462,15 @@ class FormTimeline extends BaseTimeline { ${__("Delete")} +======= + + let delete_button = $(); + if (frappe.model.can_delete("Comment") && (frappe.session.user == doc.owner || frappe.user.has_role("System Manager"))) { + delete_button = $(` + +>>>>>>> e4137ca8a1 (fix: Other user must not able to delete other user's comment except System Manager (#16018)) `).click(() => this.delete_comment(doc.name)); more_actions_wrapper.find('.dropdown-menu').append(delete_option); } From 810867a0d53d35eec27cc7599c4e2ed980e61967 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Mon, 21 Mar 2022 14:18:58 +0530 Subject: [PATCH 28/38] fix: merge conflict --- .../public/js/frappe/form/footer/form_timeline.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/frappe/public/js/frappe/form/footer/form_timeline.js b/frappe/public/js/frappe/form/footer/form_timeline.js index 7182aa667d..0070d384d7 100644 --- a/frappe/public/js/frappe/form/footer/form_timeline.js +++ b/frappe/public/js/frappe/form/footer/form_timeline.js @@ -453,24 +453,17 @@ class FormTimeline extends BaseTimeline { let edit_wrapper = $(`
`).hide(); let edit_box = this.make_editable(edit_wrapper); let content_wrapper = comment_wrapper.find('.content'); -<<<<<<< HEAD let more_actions_wrapper = comment_wrapper.find('.more-actions'); - if (frappe.model.can_delete("Comment")) { + if (frappe.model.can_delete("Comment") && ( + frappe.session.user == doc.owner || + frappe.user.has_role("System Manager") + )) { const delete_option = $(`
  • ${__("Delete")}
  • -======= - - let delete_button = $(); - if (frappe.model.can_delete("Comment") && (frappe.session.user == doc.owner || frappe.user.has_role("System Manager"))) { - delete_button = $(` - ->>>>>>> e4137ca8a1 (fix: Other user must not able to delete other user's comment except System Manager (#16018)) `).click(() => this.delete_comment(doc.name)); more_actions_wrapper.find('.dropdown-menu').append(delete_option); } From 880832671aec005d2f0f5bb256ec1a430416eaa6 Mon Sep 17 00:00:00 2001 From: Karthikeyan Singaravelan Date: Mon, 21 Mar 2022 11:03:59 +0000 Subject: [PATCH 29/38] fix: use assertEqual instead of assertEquals for Python 3.11 compatibility --- frappe/core/doctype/file/test_file.py | 6 +++--- frappe/email/doctype/notification/test_notification.py | 2 +- frappe/tests/test_base_document.py | 6 +++--- frappe/tests/test_db.py | 4 ++-- frappe/tests/test_document.py | 6 +++--- frappe/tests/test_search.py | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/frappe/core/doctype/file/test_file.py b/frappe/core/doctype/file/test_file.py index d8e748a518..fb98a18d6e 100644 --- a/frappe/core/doctype/file/test_file.py +++ b/frappe/core/doctype/file/test_file.py @@ -382,7 +382,7 @@ class TestFile(unittest.TestCase): }).insert(ignore_permissions=True) test_file.make_thumbnail() - self.assertEquals(test_file.thumbnail_url, '/files/image_small.jpg') + self.assertEqual(test_file.thumbnail_url, '/files/image_small.jpg') # test web image without extension test_file = frappe.get_doc({ @@ -399,7 +399,7 @@ class TestFile(unittest.TestCase): test_file.reload() test_file.file_url = "/files/image_small.jpg" test_file.make_thumbnail(suffix="xs", crop=True) - self.assertEquals(test_file.thumbnail_url, '/files/image_small_xs.jpg') + self.assertEqual(test_file.thumbnail_url, '/files/image_small_xs.jpg') frappe.clear_messages() test_file.db_set('thumbnail_url', None) @@ -407,7 +407,7 @@ class TestFile(unittest.TestCase): test_file.file_url = frappe.utils.get_url('unknown.jpg') test_file.make_thumbnail(suffix="xs") self.assertEqual(json.loads(frappe.message_log[0]).get("message"), f"File '{frappe.utils.get_url('unknown.jpg')}' not found") - self.assertEquals(test_file.thumbnail_url, None) + self.assertEqual(test_file.thumbnail_url, None) def test_file_unzip(self): file_path = frappe.get_app_path('frappe', 'www/_test/assets/file.zip') diff --git a/frappe/email/doctype/notification/test_notification.py b/frappe/email/doctype/notification/test_notification.py index f05d35be3e..f6f216ada2 100644 --- a/frappe/email/doctype/notification/test_notification.py +++ b/frappe/email/doctype/notification/test_notification.py @@ -240,7 +240,7 @@ class TestNotification(unittest.TestCase): self.assertTrue(email_queue) # check if description is changed after alert since set_property_after_alert is set - self.assertEquals(todo.description, 'Changed by Notification') + self.assertEqual(todo.description, 'Changed by Notification') recipients = [d.recipient for d in email_queue.recipients] self.assertTrue('test2@example.com' in recipients) diff --git a/frappe/tests/test_base_document.py b/frappe/tests/test_base_document.py index 7e165e9045..fda795b5b6 100644 --- a/frappe/tests/test_base_document.py +++ b/frappe/tests/test_base_document.py @@ -7,12 +7,12 @@ class TestBaseDocument(unittest.TestCase): def test_docstatus(self): doc = BaseDocument({"docstatus": 0}) self.assertTrue(doc.docstatus.is_draft()) - self.assertEquals(doc.docstatus, 0) + self.assertEqual(doc.docstatus, 0) doc.docstatus = 1 self.assertTrue(doc.docstatus.is_submitted()) - self.assertEquals(doc.docstatus, 1) + self.assertEqual(doc.docstatus, 1) doc.docstatus = 2 self.assertTrue(doc.docstatus.is_cancelled()) - self.assertEquals(doc.docstatus, 2) + self.assertEqual(doc.docstatus, 2) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 1cd9287ec3..19b683aa75 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -386,7 +386,7 @@ class TestDDLCommandsMaria(unittest.TestCase): WHERE Key_name = '{index_name}'; """ ) - self.assertEquals(len(indexs_in_table), 2) + self.assertEqual(len(indexs_in_table), 2) class TestDBSetValue(unittest.TestCase): @@ -590,7 +590,7 @@ class TestDDLCommandsPost(unittest.TestCase): AND indexname = '{index_name}' ; """, ) - self.assertEquals(len(indexs_in_table), 1) + self.assertEqual(len(indexs_in_table), 1) @run_only_if(db_type_is.POSTGRES) def test_modify_query(self): diff --git a/frappe/tests/test_document.py b/frappe/tests/test_document.py index 55dbf001f9..169d1ebb2c 100644 --- a/frappe/tests/test_document.py +++ b/frappe/tests/test_document.py @@ -260,15 +260,15 @@ class TestDocument(unittest.TestCase): 'doctype': 'Test Formatted', 'currency': 100000 }) - self.assertEquals(d.get_formatted('currency', currency='INR', format="#,###.##"), '₹ 100,000.00') + self.assertEqual(d.get_formatted('currency', currency='INR', format="#,###.##"), '₹ 100,000.00') def test_limit_for_get(self): doc = frappe.get_doc("DocType", "DocType") # assuming DocType has more than 3 Data fields - self.assertEquals(len(doc.get("fields", limit=3)), 3) + self.assertEqual(len(doc.get("fields", limit=3)), 3) # limit with filters - self.assertEquals(len(doc.get("fields", filters={"fieldtype": "Data"}, limit=3)), 3) + self.assertEqual(len(doc.get("fields", filters={"fieldtype": "Data"}, limit=3)), 3) def test_virtual_fields(self): """Virtual fields are accessible via API and Form views, whenever .as_dict is invoked diff --git a/frappe/tests/test_search.py b/frappe/tests/test_search.py index f644f2dfcc..38a00f689a 100644 --- a/frappe/tests/test_search.py +++ b/frappe/tests/test_search.py @@ -70,10 +70,10 @@ class TestSearch(unittest.TestCase): result = frappe.response['results'] # Check whether the result is sorted or not - self.assertEquals(self.parent_doctype_name, result[0]['value']) + self.assertEqual(self.parent_doctype_name, result[0]['value']) # Check whether searching for parent also list out children - self.assertEquals(len(result), len(self.child_doctypes_names) + 1) + self.assertEqual(len(result), len(self.child_doctypes_names) + 1) #Search for the word "pay", part of the word "pays" (country) in french. def test_link_search_in_foreign_language(self): From aa0d10fe0ecc4df770f2f77a4e05db7880384ed8 Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Mon, 21 Mar 2022 17:24:18 +0530 Subject: [PATCH 30/38] fix: First set in model then save attachment --- frappe/public/js/frappe/form/controls/attach.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/attach.js b/frappe/public/js/frappe/form/controls/attach.js index bd66225171..01af3bbc89 100644 --- a/frappe/public/js/frappe/form/controls/attach.js +++ b/frappe/public/js/frappe/form/controls/attach.js @@ -110,9 +110,9 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro return this.value || null; } - on_upload_complete(attachment) { + async on_upload_complete(attachment) { if(this.frm) { - this.parse_validate_and_set_in_model(attachment.file_url); + await this.parse_validate_and_set_in_model(attachment.file_url); this.frm.attachments.update_attachment(attachment); this.frm.doc.docstatus == 1 ? this.frm.save('Update') : this.frm.save(); } From d97c7e7cafcebb79840b9bc9a584ce9955ac70fd Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Mon, 21 Mar 2022 18:05:01 +0530 Subject: [PATCH 31/38] fix: resolved conflicts in permissions.py --- frappe/permissions.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/frappe/permissions.py b/frappe/permissions.py index 985d398749..a6c17fb59f 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -7,11 +7,7 @@ import frappe.share from frappe import _, msgprint from frappe.utils import cint from frappe.query_builder import DocType -<<<<<<< HEAD -======= -import frappe.share ->>>>>>> 6612232bab (fix: setting permissions to any role of some doctypes is not working) rights = ("select", "read", "write", "create", "delete", "submit", "cancel", "amend", "print", "email", "report", "import", "export", "set_user_permissions", "share") @@ -470,12 +466,6 @@ def update_permission_property(doctype, role, permlevel, ptype, value=None, vali table = DocType("Custom DocPerm") frappe.qb.update(table).set(ptype, value).where(table.name == name).run() -<<<<<<< HEAD -======= - table = DocType("Custom DocPerm") - frappe.qb.update(table).set(ptype, value).where(table.name == name).run() - ->>>>>>> 6612232bab (fix: setting permissions to any role of some doctypes is not working) if validate: validate_permissions_for_doctype(doctype) @@ -604,4 +594,4 @@ def is_parent_valid(child_doctype, parent_doctype): from frappe.core.utils import find parent_meta = frappe.get_meta(parent_doctype) child_table_field_exists = find(parent_meta.get_table_fields(), lambda d: d.options == child_doctype) - return not parent_meta.istable and child_table_field_exists \ No newline at end of file + return not parent_meta.istable and child_table_field_exists From 5c6c9bb5c461fcdde9cdfda664451b8332a7fc8c Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Mon, 21 Mar 2022 18:16:54 +0530 Subject: [PATCH 32/38] fix: resolved conflicts in database.py --- frappe/database/database.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index 3ce2b32fc8..7bf3b46bf0 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -116,19 +116,11 @@ class Database(object): """ query = str(query) -<<<<<<< HEAD if not run: return query -======= -<<<<<<< HEAD - # remove \n \t from start of query and replace them with space anywhere in middle - query = re.sub(r'\s', ' ', query).lstrip() ->>>>>>> ac5effc7dd (fix: remove tab \t and newlines \n from start of query and remove from middle) -======= # remove \n \t from start and end of query query = re.sub(r'^\s*|\s*$', '', query) ->>>>>>> 7bb172365f (fix: only remove \n\t from start and end) if re.search(r'ifnull\(', query, flags=re.IGNORECASE): # replaces ifnull in query with coalesce From 512c62248769ce3a92cf433ded2bb53db58f281c Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 21 Mar 2022 20:51:35 +0100 Subject: [PATCH 33/38] test: make sure `exists` doesn't eat the doctype key --- frappe/tests/test_db.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frappe/tests/test_db.py b/frappe/tests/test_db.py index 19b683aa75..10c601db00 100644 --- a/frappe/tests/test_db.py +++ b/frappe/tests/test_db.py @@ -327,7 +327,13 @@ class TestDB(unittest.TestCase): self.assertEqual(frappe.db.exists(dt, dn, cache=True), dn) self.assertEqual(frappe.db.exists(dt, dn), dn) self.assertEqual(frappe.db.exists(dt, {"name": ("=", dn)}), dn) - self.assertEqual(frappe.db.exists({"doctype": dt, "name": ("like", "Admin%")}), dn) + + filters = {"doctype": dt, "name": ("like", "Admin%")} + self.assertEqual(frappe.db.exists(filters), dn) + self.assertEqual( + filters["doctype"], dt + ) # make sure that doctype was not removed from filters + self.assertEqual(frappe.db.exists(dt, [["name", "=", dn]]), dn) From 44a7c0dd9318d984b20ae95180f5cf35eb146c28 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 21 Mar 2022 20:51:59 +0100 Subject: [PATCH 34/38] fix: copy dict before popping keys --- frappe/database/database.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index b1b5abffca..82a7e6f919 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -919,8 +919,8 @@ class Database(object): return dn if isinstance(dt, dict): - _dt = dt.pop("doctype") - dt, dn = _dt, dt + dt = dt.copy() # don't modify the original dict + dt, dn = dt.pop("doctype"), dt return self.get_value(dt, dn, ignore=True, cache=cache) From 179c9f117c7ecf8c9c2882ecf192031331294bbf Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 21 Mar 2022 21:12:05 +0100 Subject: [PATCH 35/38] perf: exists is already called in delete_doc --- frappe/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 86f8be35ea..80dd2f5f15 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -978,8 +978,7 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa def delete_doc_if_exists(doctype, name, force=0): """Delete document if exists.""" - if db.exists(doctype, name): - delete_doc(doctype, name, force=force) + delete_doc(doctype, name, force=force, ignore_missing=True) def reload_doctype(doctype, force=False, reset_permissions=False): """Reload DocType from model (`[module]/[doctype]/[name]/[name].json`) files.""" From 8cf2bf89534039b5b23a32177b469c1ddb1bd521 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Mon, 21 Mar 2022 23:09:58 +0100 Subject: [PATCH 36/38] refactor: call getfullargspec only once --- frappe/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/__init__.py b/frappe/__init__.py index 86f8be35ea..1501fda81a 100644 --- a/frappe/__init__.py +++ b/frappe/__init__.py @@ -1252,9 +1252,10 @@ def get_newargs(fn, kwargs): if hasattr(fn, 'fnargs'): fnargs = fn.fnargs else: - fnargs = inspect.getfullargspec(fn).args - fnargs.extend(inspect.getfullargspec(fn).kwonlyargs) - varkw = inspect.getfullargspec(fn).varkw + fullargspec = inspect.getfullargspec(fn) + fnargs = fullargspec.args + fnargs.extend(fullargspec.kwonlyargs) + varkw = fullargspec.varkw newargs = {} for a in kwargs: From 7a9536332eb862d359e5bf0d0b9819b758dc45d7 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 22 Mar 2022 09:16:39 +0530 Subject: [PATCH 37/38] feat: Hide page head while scrolling down - To create more reading area in the form --- frappe/public/js/frappe/ui/page.js | 14 +++++++++----- frappe/public/scss/desk/page.scss | 1 + 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/frappe/public/js/frappe/ui/page.js b/frappe/public/js/frappe/ui/page.js index 91a2390cdb..e3134b1f38 100644 --- a/frappe/public/js/frappe/ui/page.js +++ b/frappe/public/js/frappe/ui/page.js @@ -47,13 +47,17 @@ frappe.ui.Page = class Page { } setup_scroll_handler() { - window.addEventListener('scroll', () => { - if (document.documentElement.scrollTop) { - $('.page-head').toggleClass('drop-shadow', true); + let last_scroll = 0; + window.addEventListener('scroll', frappe.utils.throttle(() => { + $('.page-head').toggleClass('drop-shadow', !!document.documentElement.scrollTop); + let current_scroll = document.documentElement.scrollTop; + if (current_scroll > 0 && last_scroll <= current_scroll) { + $('.page-head').css("top", "-15px"); } else { - $('.page-head').removeClass('drop-shadow'); + $('.page-head').css("top", "var(--navbar-height)"); } - }); + last_scroll = current_scroll; + }), 500); } get_empty_state(title, message, primary_action) { diff --git a/frappe/public/scss/desk/page.scss b/frappe/public/scss/desk/page.scss index f0a9152cfb..2df349cb6c 100644 --- a/frappe/public/scss/desk/page.scss +++ b/frappe/public/scss/desk/page.scss @@ -88,6 +88,7 @@ top: var(--navbar-height); background: var(--bg-color); margin-bottom: 5px; + transition: 0.5s top; .page-head-content { height: var(--page-head-height); } From d30f9e1d78b5e2e02ae9b7afedccd5451ab3d94f Mon Sep 17 00:00:00 2001 From: Shariq Ansari Date: Tue, 22 Mar 2022 11:23:43 +0530 Subject: [PATCH 38/38] fix: wait until attach is cleared before saving --- frappe/public/js/frappe/form/controls/attach.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/attach.js b/frappe/public/js/frappe/form/controls/attach.js index 01af3bbc89..a91058a208 100644 --- a/frappe/public/js/frappe/form/controls/attach.js +++ b/frappe/public/js/frappe/form/controls/attach.js @@ -37,8 +37,8 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro if(this.frm) { me.parse_validate_and_set_in_model(null); me.refresh(); - me.frm.attachments.remove_attachment_by_filename(me.value, function() { - me.parse_validate_and_set_in_model(null); + me.frm.attachments.remove_attachment_by_filename(me.value, async () => { + await me.parse_validate_and_set_in_model(null); me.refresh(); me.frm.doc.docstatus == 1 ? me.frm.save('Update') : me.frm.save(); });