From db35431b8cd78513b36137d055696eaeacfe5fa7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 20 Dec 2022 13:16:56 +0530 Subject: [PATCH 1/7] fix(postgres): psql with remote databases If you dont use unix socket psql command doesn't work. --- frappe/commands/utils.py | 8 +++++++- frappe/contacts/doctype/contact/contact.py | 4 ++-- frappe/tests/test_commands.py | 9 ++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index e5c6c406eb..4b5a04ea33 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -548,7 +548,13 @@ def _mariadb(): def _psql(): psql = which("psql") - subprocess.run([psql, "-d", frappe.conf.db_name]) + + host = frappe.conf.db_host or "127.0.0.1" + port = frappe.conf.db_port or "5432" + env = os.environ.copy() + env["PGPASSWORD"] = frappe.conf.db_password + conn_string = f"postgresql://{frappe.conf.db_name}@{host}:{port}/{frappe.conf.db_name}" + subprocess.run([psql, conn_string], check=True, env=env) @click.command("jupyter") diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py index 36e7629173..e7d250148b 100644 --- a/frappe/contacts/doctype/contact/contact.py +++ b/frappe/contacts/doctype/contact/contact.py @@ -133,7 +133,7 @@ class Contact(Document): def get_default_contact(doctype, name): """Returns default contact for the given doctype, name""" out = frappe.db.sql( - '''select parent, + """select parent, IFNULL((select is_primary_contact from tabContact c where c.name = dl.parent), 0) as is_primary_contact from @@ -141,7 +141,7 @@ def get_default_contact(doctype, name): where dl.link_doctype=%s and dl.link_name=%s and - dl.parenttype = 'Contact' ''', + dl.parenttype = 'Contact' """, (doctype, name), as_dict=True, ) diff --git a/frappe/tests/test_commands.py b/frappe/tests/test_commands.py index 6582b29b7e..7af66f6c62 100644 --- a/frappe/tests/test_commands.py +++ b/frappe/tests/test_commands.py @@ -29,7 +29,7 @@ import frappe.recorder from frappe.installer import add_to_installed_apps, remove_app from frappe.query_builder.utils import db_type_is from frappe.tests.test_query_builder import run_only_if -from frappe.tests.utils import FrappeTestCase +from frappe.tests.utils import FrappeTestCase, timeout from frappe.utils import add_to_date, get_bench_path, get_bench_relative_path, now from frappe.utils.backups import BackupGenerator, fetch_latest_backups from frappe.utils.jinja_globals import bundled_asset @@ -763,3 +763,10 @@ class TestCommandUtils(FrappeTestCase): app_groups = get_app_groups() self.assertIn("frappe", app_groups) self.assertIsInstance(app_groups["frappe"], click.Group) + + +class TestDBCli(BaseTestCommands): + @timeout(10) + def test_db_cli(self): + self.execute("bench --site {site} db-console", kwargs={"cmd_input": rb"\q"}) + self.assertEqual(self.returncode, 0) From 3ff49ec0adf6b59f8a343c8e24b52c2ce128e323 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 20 Dec 2022 15:13:16 +0530 Subject: [PATCH 2/7] fix: mariadb convert port to string for os.execv --- frappe/commands/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 4b5a04ea33..bb943c7223 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -532,7 +532,7 @@ def _mariadb(): command = [ mysql, "--port", - frappe.conf.db_port or MariaDBDatabase.default_port, + str(frappe.conf.db_port or MariaDBDatabase.default_port), "-u", frappe.conf.db_name, f"-p{frappe.conf.db_password}", From 272d9e008544ca1c3624f88f05a20fb02637e658 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 20 Dec 2022 16:06:46 +0530 Subject: [PATCH 3/7] fix: shift-select checkboxes ranges (#19367) This doesn't work if document names have spaces in them. This is because data props are urlencoded while we are comparing it with raw data. --- frappe/public/js/frappe/list/list_view.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 272be5ea0f..76c99652c6 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -1256,8 +1256,8 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { // shift select checkboxes if (e.shiftKey && this.$checkbox_cursor && !$target.is(this.$checkbox_cursor)) { - const name_1 = this.$checkbox_cursor.data().name; - const name_2 = $target.data().name; + const name_1 = decodeURIComponent(this.$checkbox_cursor.data().name); + const name_2 = decodeURIComponent($target.data().name); const index_1 = this.data.findIndex((d) => d.name === name_1); const index_2 = this.data.findIndex((d) => d.name === name_2); let [min_index, max_index] = [index_1, index_2]; @@ -1268,7 +1268,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { let docnames = this.data.slice(min_index + 1, max_index).map((d) => d.name); const selector = docnames - .map((name) => `.list-row-checkbox[data-name="${name}"]`) + .map((name) => `.list-row-checkbox[data-name="${encodeURIComponent(name)}"]`) .join(","); this.$result.find(selector).prop("checked", true); } From bb5e21de5fbd2d6dfe338a821de2c93f1ddb1293 Mon Sep 17 00:00:00 2001 From: Ahmed Hasanin <52963581+AHasanin@users.noreply.github.com> Date: Tue, 20 Dec 2022 14:22:48 +0200 Subject: [PATCH 4/7] fix(error snapshot): fix seen update qeury in error snapshot to work with postgres (#19373) [skip ci] --- frappe/core/doctype/error_snapshot/error_snapshot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frappe/core/doctype/error_snapshot/error_snapshot.py b/frappe/core/doctype/error_snapshot/error_snapshot.py index 6966cf0aca..acc49c78cd 100644 --- a/frappe/core/doctype/error_snapshot/error_snapshot.py +++ b/frappe/core/doctype/error_snapshot/error_snapshot.py @@ -12,10 +12,10 @@ class ErrorSnapshot(Document): def onload(self): if not self.parent_error_snapshot: - self.db_set("seen", True, update_modified=False) + self.db_set("seen", 1, update_modified=False) for relapsed in frappe.get_all("Error Snapshot", filters={"parent_error_snapshot": self.name}): - frappe.db.set_value("Error Snapshot", relapsed.name, "seen", True, update_modified=False) + frappe.db.set_value("Error Snapshot", relapsed.name, "seen", 1, update_modified=False) frappe.local.flags.commit = True @@ -32,7 +32,7 @@ class ErrorSnapshot(Document): self.update({"parent_error_snapshot": parent["name"]}) frappe.db.set_value("Error Snapshot", parent["name"], "relapses", parent["relapses"] + 1) if parent["seen"]: - frappe.db.set_value("Error Snapshot", parent["name"], "seen", False) + frappe.db.set_value("Error Snapshot", parent["name"], "seen", 0) @staticmethod def clear_old_logs(days=30): From 1ab85a66c5434b1411bf22e827b6d1b1ed63b197 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 21 Dec 2022 12:11:34 +0530 Subject: [PATCH 5/7] ci: better release notes generation (#19380) [skip ci] --- .github/workflows/release_notes.yml | 38 +++++++++++++++++++++++++++++ .releaserc | 4 +-- 2 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/release_notes.yml diff --git a/.github/workflows/release_notes.yml b/.github/workflows/release_notes.yml new file mode 100644 index 0000000000..bf761f23ba --- /dev/null +++ b/.github/workflows/release_notes.yml @@ -0,0 +1,38 @@ +# This action: +# +# 1. Generates release notes using github API. +# 2. Strips unnecessary info like chore/style etc from notes. +# 3. Updates release info. + +# This action needs to be maintained on all branches that do releases. + +name: 'Release Notes' + +on: + workflow_dispatch: + inputs: + tag_name: + description: 'Tag of release like v13.0.0' + required: true + type: string + release: + types: [released] + +permissions: + contents: read + +jobs: + regen-notes: + name: 'Regenerate release notes' + runs-on: ubuntu-latest + + steps: + - name: Update notes + run: | + NEW_NOTES=$(gh api --method POST -H "Accept: application/vnd.github+json" /repos/frappe/frappe/releases/generate-notes -f tag_name=$RELEASE_TAG | jq -r '.body' | sed -E '/^\* (chore|ci|test|docs|style)/d' ) + RELEASE_ID=$(gh api -H "Accept: application/vnd.github+json" /repos/frappe/frappe/releases/tags/$RELEASE_TAG | jq -r '.id') + gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/frappe/frappe/releases/$RELEASE_ID -f body=$NEW_NOTES + + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} + RELEASE_TAG: ${{ github.event.inputs.tag_name || github.event.release.tag_name }} diff --git a/.releaserc b/.releaserc index c9ca71bbf5..86f4f3cda0 100644 --- a/.releaserc +++ b/.releaserc @@ -13,9 +13,9 @@ [ "@semantic-release/git", { "assets": ["frappe/__init__.py"], - "message": "chore(release): Bumped to Version ${nextRelease.version}\n\n${nextRelease.notes}" + "message": "chore(release): Bumped to Version ${nextRelease.version}" } ], "@semantic-release/github" ] -} \ No newline at end of file +} From 211880d693513143b6f8a80f05df97697d4014bf Mon Sep 17 00:00:00 2001 From: Bread Genie <63963181+BreadGenie@users.noreply.github.com> Date: Wed, 21 Dec 2022 12:39:00 +0530 Subject: [PATCH 6/7] fix(boilerplate): add redis services in GHA (#19376) * feat(boilerplate): add redis services * chore: bump all action versions [skip ci] Co-authored-by: Ankush Menat --- frappe/utils/boilerplate.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/frappe/utils/boilerplate.py b/frappe/utils/boilerplate.py index 002e1de8f2..5c792208b3 100644 --- a/frappe/utils/boilerplate.py +++ b/frappe/utils/boilerplate.py @@ -429,6 +429,18 @@ jobs: name: Server services: + redis-cache: + image: redis:alpine + ports: + - 13000:6379 + redis-queue: + image: redis:alpine + ports: + - 11000:6379 + redis-socketio: + image: redis:alpine + ports: + - 12000:6379 mariadb: image: mariadb:10.6 env: @@ -439,17 +451,17 @@ jobs: steps: - name: Clone - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: '3.10' - name: Setup Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: - node-version: 14 + node-version: 16 check-latest: true - name: Cache pip @@ -465,7 +477,7 @@ jobs: id: yarn-cache-dir-path run: 'echo "::set-output name=dir::$(yarn cache dir)"' - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: yarn-cache with: path: ${{{{ steps.yarn-cache-dir-path.outputs.dir }}}} From a18e63ef9288b6ac9716fc74c756f9536716de3e Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 21 Dec 2022 15:10:50 +0530 Subject: [PATCH 7/7] fix: Allow emailing disabled user (#19382) Not sure why we need to validate this. A disabled user can still exist outside of system with same active email address. --- frappe/core/doctype/communication/mixins.py | 14 ++++---------- .../doctype/communication/test_communication.py | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/frappe/core/doctype/communication/mixins.py b/frappe/core/doctype/communication/mixins.py index 85de33841f..7b6427d1c2 100644 --- a/frappe/core/doctype/communication/mixins.py +++ b/frappe/core/doctype/communication/mixins.py @@ -59,10 +59,7 @@ class CommunicationEmailMixin: * if email copy is requested by sender, then add sender to CC. * If this doc is created through inbound mail, then add doc owner to cc list * remove all the thread_notify disabled users. - * Make sure that all users enabled in the system - * Remove admin from email list - - * FixMe: Removed adding TODO owners to cc list. Check if that is needed. + * Remove standard users from email list """ if hasattr(self, "_final_cc"): return self._final_cc @@ -80,13 +77,12 @@ class CommunicationEmailMixin: cc = set(cc) - set(self.filter_thread_notification_disbled_users(cc)) cc = cc - set(self.mail_recipients(is_inbound_mail_communcation=is_inbound_mail_communcation)) - cc = cc - set(self.filter_disabled_users(cc)) # # Incase of inbound mail, to and cc already received the mail, no need to send again. if is_inbound_mail_communcation: cc = cc - set(self.cc_list() + self.to_list()) - self._final_cc = list(filter(lambda id: id != "Administrator", cc)) + self._final_cc = [m for m in cc if m not in frappe.STANDARD_USERS] return self._final_cc def get_mail_cc_with_displayname(self, is_inbound_mail_communcation=False, include_sender=False): @@ -99,8 +95,7 @@ class CommunicationEmailMixin: """ * Thread_notify check * Email unsubscribe list - * User must be enabled in the system - * remove_administrator_from_email_list + * remove standard users. """ if hasattr(self, "_final_bcc"): return self._final_bcc @@ -110,13 +105,12 @@ class CommunicationEmailMixin: bcc = bcc - {self.sender_mailid} bcc = bcc - set(self.filter_thread_notification_disbled_users(bcc)) bcc = bcc - set(self.mail_recipients(is_inbound_mail_communcation=is_inbound_mail_communcation)) - bcc = bcc - set(self.filter_disabled_users(bcc)) # Incase of inbound mail, to and cc & bcc already received the mail, no need to send again. if is_inbound_mail_communcation: bcc = bcc - set(self.bcc_list() + self.to_list()) - self._final_bcc = list(filter(lambda id: id != "Administrator", bcc)) + self._final_bcc = [m for m in bcc if m not in frappe.STANDARD_USERS] return self._final_bcc def get_mail_bcc_with_displayname(self, is_inbound_mail_communcation=False): diff --git a/frappe/core/doctype/communication/test_communication.py b/frappe/core/doctype/communication/test_communication.py index 7c032a926d..5b208eaeb7 100644 --- a/frappe/core/doctype/communication/test_communication.py +++ b/frappe/core/doctype/communication/test_communication.py @@ -343,7 +343,7 @@ class TestCommunicationEmailMixin(FrappeTestCase): user = self.new_user(email="bcc+2@test.com", enabled=0) comm = self.new_communication(bcc=bcc_list) res = comm.get_mail_bcc_with_displayname() - self.assertCountEqual(res, ["bcc+1@test.com"]) + self.assertCountEqual(res, bcc_list) user.delete() comm.delete()