From 40603a89c559e63bdf79f19db39fa4772f7bb28f Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Mon, 5 Jun 2023 15:14:45 -0400 Subject: [PATCH 1/7] fix: multiple input element's in a single control --- frappe/public/js/frappe/form/grid_row.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index d4fdd47a11..dffe83cb45 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -963,7 +963,15 @@ export default class GridRow { } var col = this; let first_input_field = $(col).find('input[type="Text"]:first'); - first_input_field.trigger("focus"); + let input_in_focus = false; + + $(col).find("input[type='Text']").each(function () { + if($(this).is(":focus")) { + input_in_focus = true; + } + }); + + !input_in_focus && first_input_field.trigger("focus"); if (event.pointerType == "touch") { first_input_field.length && on_input_focus(first_input_field); From fc7069fb492e366b0971ba675f59a40a6859b6bf Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Tue, 6 Jun 2023 10:27:13 -0400 Subject: [PATCH 2/7] chore: linter --- frappe/public/js/frappe/form/grid_row.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index dffe83cb45..f42a1e88f4 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -965,8 +965,10 @@ export default class GridRow { let first_input_field = $(col).find('input[type="Text"]:first'); let input_in_focus = false; - $(col).find("input[type='Text']").each(function () { - if($(this).is(":focus")) { + $(col) + .find("input[type='Text']") + .each(function () { + if ($(this).is(":focus")) { input_in_focus = true; } }); From eed61e64855e2d4d575bf2eb12cf4057f99bf30e Mon Sep 17 00:00:00 2001 From: Devin Slauenwhite Date: Tue, 13 Jun 2023 11:14:35 -0400 Subject: [PATCH 3/7] fix: text to lowercase Co-authored-by: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> --- frappe/public/js/frappe/form/grid_row.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index f42a1e88f4..356c5f4d1d 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -966,7 +966,7 @@ export default class GridRow { let input_in_focus = false; $(col) - .find("input[type='Text']") + .find("input[type='text']") .each(function () { if ($(this).is(":focus")) { input_in_focus = true; From 23dd8e92482c24ef0351462249e3ffb464e01e3e Mon Sep 17 00:00:00 2001 From: David Arnold Date: Tue, 13 Jun 2023 10:36:06 -0500 Subject: [PATCH 4/7] refactor: normalize redis invocation and unblock unix domain socket conn (#21309) Prior to this change, given tat a unix domain socket string was passed ad `frappe.conf.redis_queue`, then the url split would have failed. With this change, the upstream API for `from_url` is invoked transparently. passing none values for username and password is inocuous; [proof](https://github.com/redis/redis-py/blob/d95d8a24ed2af3eae80b7b0f14cbccc9dbe86e96/redis/connection.py#L604) and [proof](https://github.com/redis/redis-py/blob/d95d8a24ed2af3eae80b7b0f14cbccc9dbe86e96/redis/connection.py#L594) The [entrypoint](https://github.com/redis/redis-py/blob/d95d8a24ed2af3eae80b7b0f14cbccc9dbe86e96/redis/client.py#L868) passes these parameters on transparently. --- frappe/utils/redis_queue.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frappe/utils/redis_queue.py b/frappe/utils/redis_queue.py index 89f8fe16f3..b045be3ab1 100644 --- a/frappe/utils/redis_queue.py +++ b/frappe/utils/redis_queue.py @@ -17,10 +17,7 @@ class RedisQueue: @classmethod def get_connection(cls, username=None, password=None): - rq_url = frappe.local.conf.redis_queue - domain = rq_url.split("redis://", 1)[-1] - url = (username and f"redis://{username}:{password or ''}@{domain}") or rq_url - conn = redis.from_url(url) + conn = redis.from_url(frappe.conf.redis_queue, username=username, password=password) conn.ping() return conn From 5d074f3237ac24c09366c66e7ef31fc554e0b5a3 Mon Sep 17 00:00:00 2001 From: David Arnold Date: Tue, 13 Jun 2023 22:26:09 -0500 Subject: [PATCH 5/7] ci: fix patch workflow (#21363) --- .github/workflows/patch-mariadb-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/patch-mariadb-tests.yml b/.github/workflows/patch-mariadb-tests.yml index c8fe91d287..066173af25 100644 --- a/.github/workflows/patch-mariadb-tests.yml +++ b/.github/workflows/patch-mariadb-tests.yml @@ -141,8 +141,8 @@ jobs: update_to_version 14 echo "Updating to last commit" - git checkout -q -f "$GITHUB_SHA" rm -rf ~/frappe-bench/env + git checkout -q -f "$GITHUB_SHA" bench -v setup env bench --site test_site migrate From 039be73af4bba125f1a70a47b689e0830f6bf7f6 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 14 Jun 2023 10:46:25 +0530 Subject: [PATCH 6/7] refactor: Consider singles for dynamic set_value usage (#21367) Found all usage using this semgrep rule: ```yaml - pattern: frappe.db.set_value($DOCTYPE, ...) - pattern-not: frappe.db.set_value("$STR", ...) ``` --- frappe/core/doctype/doctype/doctype.json | 2 +- frappe/core/doctype/file/file.py | 19 +++++++++----- frappe/desk/doctype/todo/todo.py | 22 ++++++++++------ frappe/desk/like.py | 5 +++- frappe/model/base_document.py | 5 +++- frappe/model/document.py | 32 ++++++++++++++++-------- frappe/tests/test_assign.py | 13 +++++++--- frappe/tests/test_document.py | 7 ++++++ 8 files changed, 75 insertions(+), 30 deletions(-) diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json index 842898d064..5209a408eb 100644 --- a/frappe/core/doctype/doctype/doctype.json +++ b/frappe/core/doctype/doctype/doctype.json @@ -755,4 +755,4 @@ "states": [], "track_changes": 1, "translated_doctype": 1 -} \ No newline at end of file +} diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index c4cefc7271..7770226e79 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -236,12 +236,19 @@ class File(Document): ): return - frappe.db.set_value( - self.attached_to_doctype, - self.attached_to_name, - self.attached_to_field, - self.file_url, - ) + if frappe.get_meta(self.attached_to_doctype).issingle: + frappe.db.set_single_value( + self.attached_to_doctype, + self.attached_to_field, + self.file_url, + ) + else: + frappe.db.set_value( + self.attached_to_doctype, + self.attached_to_name, + self.attached_to_field, + self.file_url, + ) def fetch_attached_to_field(self, old_file_url): if self.attached_to_field: diff --git a/frappe/desk/doctype/todo/todo.py b/frappe/desk/doctype/todo/todo.py index e076f3384a..46a826688a 100644 --- a/frappe/desk/doctype/todo/todo.py +++ b/frappe/desk/doctype/todo/todo.py @@ -81,13 +81,21 @@ class ToDo(Document): ) assignments.reverse() - frappe.db.set_value( - self.reference_type, - self.reference_name, - "_assign", - json.dumps(assignments), - update_modified=False, - ) + if frappe.get_meta(self.reference_type).issingle: + frappe.db.set_single_value( + self.reference_type, + "_assign", + json.dumps(assignments), + update_modified=False, + ) + else: + frappe.db.set_value( + self.reference_type, + self.reference_name, + "_assign", + json.dumps(assignments), + update_modified=False, + ) except Exception as e: if frappe.db.is_table_missing(e) and frappe.flags.in_install: diff --git a/frappe/desk/like.py b/frappe/desk/like.py index 0f297455e7..60eea3c525 100644 --- a/frappe/desk/like.py +++ b/frappe/desk/like.py @@ -52,7 +52,10 @@ def _toggle_like(doctype, name, add, user=None): liked_by.remove(user) remove_like(doctype, name) - frappe.db.set_value(doctype, name, "_liked_by", json.dumps(liked_by), update_modified=False) + if frappe.get_meta(doctype).issingle: + frappe.db.set_single_value(doctype, "_liked_by", json.dumps(liked_by), update_modified=False) + else: + frappe.db.set_value(doctype, name, "_liked_by", json.dumps(liked_by), update_modified=False) except frappe.db.ProgrammingError as e: if frappe.db.is_column_missing(e): diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 63188e749d..609bfa4b9e 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -646,7 +646,10 @@ class BaseDocument: def update_modified(self): """Update modified timestamp""" self.set("modified", now()) - frappe.db.set_value(self.doctype, self.name, "modified", self.modified, update_modified=False) + if getattr(self.meta, "issingle", False): + frappe.db.set_single_value(self.doctype, "modified", self.modified, update_modified=False) + else: + frappe.db.set_value(self.doctype, self.name, "modified", self.modified, update_modified=False) def _fix_numeric_types(self): for df in self.meta.get("fields"): diff --git a/frappe/model/document.py b/frappe/model/document.py index 9496c09077..e2a55065bb 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -1123,7 +1123,7 @@ class Document(BaseDocument): def reset_seen(self): """Clear _seen property and set current user as seen""" - if getattr(self.meta, "track_seen", False): + if getattr(self.meta, "track_seen", False) and not getattr(self.meta, "issingle", False): frappe.db.set_value( self.doctype, self.name, "_seen", json.dumps([frappe.session.user]), update_modified=False ) @@ -1182,15 +1182,25 @@ class Document(BaseDocument): if self.name is None: return - frappe.db.set_value( - self.doctype, - self.name, - fieldname, - value, - self.modified, - self.modified_by, - update_modified=update_modified, - ) + if self.meta.issingle: + frappe.db.set_single_value( + self.doctype, + fieldname, + value, + modified=self.modified, + modified_by=self.modified_by, + update_modified=update_modified, + ) + else: + frappe.db.set_value( + self.doctype, + self.name, + fieldname, + value, + self.modified, + self.modified_by, + update_modified=update_modified, + ) self.run_method("on_change") @@ -1375,7 +1385,7 @@ class Document(BaseDocument): if not user: user = frappe.session.user - if self.meta.track_seen and not frappe.flags.read_only: + if self.meta.track_seen and not frappe.flags.read_only and not self.meta.issingle: _seen = self.get("_seen") or [] _seen = frappe.parse_json(_seen) diff --git a/frappe/tests/test_assign.py b/frappe/tests/test_assign.py index 4243bd080a..c299d235dc 100644 --- a/frappe/tests/test_assign.py +++ b/frappe/tests/test_assign.py @@ -23,16 +23,23 @@ class TestAssign(FrappeTestCase): if not frappe.db.exists("User", "test@example.com"): frappe.get_doc({"doctype": "User", "email": "test@example.com", "first_name": "Test"}).insert() - added = assign(todo, "test@example.com") + self._test_basic_assign_on_document(todo) + + def _test_basic_assign_on_document(self, doc): + added = assign(doc, "test@example.com") self.assertTrue("test@example.com" in [d.owner for d in added]) - frappe.desk.form.assign_to.remove(todo.doctype, todo.name, "test@example.com") + frappe.desk.form.assign_to.remove(doc.doctype, doc.name, "test@example.com") # assignment is cleared - assignments = frappe.desk.form.assign_to.get(dict(doctype=todo.doctype, name=todo.name)) + assignments = frappe.desk.form.assign_to.get(dict(doctype=doc.doctype, name=doc.name)) self.assertEqual(len(assignments), 0) + def test_assign_single(self): + c = frappe.get_doc("Contact Us Settings") + self._test_basic_assign_on_document(c) + def test_assignment_count(self): frappe.db.delete("ToDo") diff --git a/frappe/tests/test_document.py b/frappe/tests/test_document.py index 4e575528ab..cdd1d08c62 100644 --- a/frappe/tests/test_document.py +++ b/frappe/tests/test_document.py @@ -452,6 +452,13 @@ class TestDocument(FrappeTestCase): frappe.exceptions.InvalidDates, doc.validate_from_to_dates, "start_date", "end_date" ) + def test_db_set_singles(self): + c = frappe.get_doc("Contact Us Settings") + key, val = "email_id", "admin1@example.com" + c.db_set(key, val) + changed_val = frappe.db.get_single_value(c.doctype, key) + self.assertEqual(val, changed_val) + class TestDocumentWebView(FrappeTestCase): def get(self, path, user="Guest"): From c2a562b82e842fcb4e74d861765ae0bcac44d38c Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 14 Jun 2023 11:45:03 +0530 Subject: [PATCH 7/7] ci: debug patch workflow failure (#21369) --- .github/workflows/patch-mariadb-tests.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/patch-mariadb-tests.yml b/.github/workflows/patch-mariadb-tests.yml index 066173af25..864661ef54 100644 --- a/.github/workflows/patch-mariadb-tests.yml +++ b/.github/workflows/patch-mariadb-tests.yml @@ -148,4 +148,11 @@ jobs: - name: Show bench output if: ${{ always() }} - run: cat ~/frappe-bench/bench_start.log || true + run: | + cd ~/frappe-bench + cat bench_start.log || true + cd logs + for f in ./*.log*; do + echo "Printing log: $f"; + cat $f + done