From 2e577aa64e22d36bd2c643461eab7a76f77385b2 Mon Sep 17 00:00:00 2001 From: chillaranand Date: Thu, 14 Jul 2022 16:47:59 +0530 Subject: [PATCH 01/48] fix: Check for file url before validating remote file --- frappe/core/doctype/file/file.py | 2 +- frappe/core/doctype/file/test_file.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index 7a66d45c73..e1faf331d6 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -262,7 +262,7 @@ class File(Document): def validate_remote_file(self): """Validates if file uploaded using URL already exist""" site_url = get_url() - if "/files/" in self.file_url and self.file_url.startswith(site_url): + if self.file_url and "/files/" in self.file_url and self.file_url.startswith(site_url): self.file_url = self.file_url.split(site_url, 1)[1] def set_folder_name(self): diff --git a/frappe/core/doctype/file/test_file.py b/frappe/core/doctype/file/test_file.py index a9d40b35b1..d849a2de4d 100644 --- a/frappe/core/doctype/file/test_file.py +++ b/frappe/core/doctype/file/test_file.py @@ -510,6 +510,16 @@ class TestFile(FrappeTestCase): ).insert(ignore_permissions=True) self.assertRaisesRegex(ValidationError, "not a zip file", test_file.unzip) + def test_create_file_without_file_url(self): + test_file = frappe.get_doc( + { + "doctype": "File", + "file_name": "logo", + "content": "frappe", + } + ).insert() + assert test_file is not None + class TestAttachment(unittest.TestCase): test_doctype = "Test For Attachment" From d23705f60ccf142e40448d3a4f267daccd0b3387 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 25 Jul 2022 12:50:49 +0530 Subject: [PATCH 02/48] ci: Cleanup install.sh --- .github/helper/install.sh | 66 ++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/.github/helper/install.sh b/.github/helper/install.sh index 21d4a7b972..1a2c62c973 100644 --- a/.github/helper/install.sh +++ b/.github/helper/install.sh @@ -5,55 +5,63 @@ cd ~ || exit echo "Setting Up Bench..." pip install frappe-bench - bench -v init frappe-bench --skip-assets --python "$(which python)" --frappe-path "${GITHUB_WORKSPACE}" +cd ./frappe-bench || exit + +bench -v setup requirements --dev +if [ "$TYPE" == "ui" ]; then + bench -v setup requirements --node; +fi + +echo "Setting Up Sites & Database..." mkdir ~/frappe-bench/sites/test_site cp "${GITHUB_WORKSPACE}/.github/helper/consumer_db/$DB.json" ~/frappe-bench/sites/test_site/site_config.json if [ "$TYPE" == "server" ]; then - mkdir ~/frappe-bench/sites/test_site_producer; - cp "${GITHUB_WORKSPACE}/.github/helper/producer_db/$DB.json" ~/frappe-bench/sites/test_site_producer/site_config.json; + mkdir ~/frappe-bench/sites/test_site_producer; + cp "${GITHUB_WORKSPACE}/.github/helper/producer_db/$DB.json" ~/frappe-bench/sites/test_site_producer/site_config.json; fi - if [ "$DB" == "mariadb" ];then - mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL character_set_server = 'utf8mb4'"; - mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL character_set_server = 'utf8mb4'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"; - mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_consumer"; - mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_consumer'@'localhost' IDENTIFIED BY 'test_frappe_consumer'"; - mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_consumer\`.* TO 'test_frappe_consumer'@'localhost'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_consumer"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_consumer'@'localhost' IDENTIFIED BY 'test_frappe_consumer'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_consumer\`.* TO 'test_frappe_consumer'@'localhost'"; - mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_producer"; - mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_producer'@'localhost' IDENTIFIED BY 'test_frappe_producer'"; - mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_producer\`.* TO 'test_frappe_producer'@'localhost'"; - - mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "FLUSH PRIVILEGES"; - fi + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE DATABASE test_frappe_producer"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "CREATE USER 'test_frappe_producer'@'localhost' IDENTIFIED BY 'test_frappe_producer'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "GRANT ALL PRIVILEGES ON \`test_frappe_producer\`.* TO 'test_frappe_producer'@'localhost'"; + mariadb --host 127.0.0.1 --port 3306 -u root -ptravis -e "FLUSH PRIVILEGES"; +fi if [ "$DB" == "postgres" ];then - echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe_consumer" -U postgres; - echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE USER test_frappe_consumer WITH PASSWORD 'test_frappe'" -U postgres; + echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe_consumer" -U postgres; + echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE USER test_frappe_consumer WITH PASSWORD 'test_frappe'" -U postgres; - echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe_producer" -U postgres; - echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE USER test_frappe_producer WITH PASSWORD 'test_frappe'" -U postgres; + echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE DATABASE test_frappe_producer" -U postgres; + echo "travis" | psql -h 127.0.0.1 -p 5432 -c "CREATE USER test_frappe_producer WITH PASSWORD 'test_frappe'" -U postgres; fi -cd ./frappe-bench || exit +echo "Setting Up Procfile..." sed -i 's/^watch:/# watch:/g' Procfile sed -i 's/^schedule:/# schedule:/g' Procfile +if [ "$TYPE" == "server" ]; then + sed -i 's/^socketio:/# socketio:/g' Procfile; + sed -i 's/^redis_socketio:/# redis_socketio:/g' Procfile; +fi +if [ "$TYPE" == "ui" ]; then + sed -i 's/^web: bench serve/web: bench serve --with-coverage/g' Procfile; +fi -if [ "$TYPE" == "server" ]; then sed -i 's/^socketio:/# socketio:/g' Procfile; fi -if [ "$TYPE" == "server" ]; then sed -i 's/^redis_socketio:/# redis_socketio:/g' Procfile; fi - -if [ "$TYPE" == "ui" ]; then bench -v setup requirements --node; fi -bench -v setup requirements --dev - -if [ "$TYPE" == "ui" ]; then sed -i 's/^web: bench serve/web: bench serve --with-coverage/g' Procfile; fi +echo "Starting Bench..." bench start &> bench_start.log & bench --site test_site reinstall --yes -if [ "$TYPE" == "server" ]; then bench --site test_site_producer reinstall --yes; fi -if [ "$TYPE" == "server" ]; then CI=Yes bench build --app frappe; fi +if [ "$TYPE" == "server" ]; then + bench --site test_site_producer reinstall --yes; + CI=Yes bench build --app frappe; +fi From 31658e5241b7822bd42a73fdd393c91531f47619 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 25 Jul 2022 13:07:53 +0530 Subject: [PATCH 03/48] ci: Install wkhtmltopdf in the background --- .github/helper/install_dependencies.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/helper/install_dependencies.sh b/.github/helper/install_dependencies.sh index f16bd61a53..694b0a9504 100644 --- a/.github/helper/install_dependencies.sh +++ b/.github/helper/install_dependencies.sh @@ -3,8 +3,11 @@ set -e echo "Setting Up System Dependencies..." -wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb -sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb +install_wkhtmltopdf() { + wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb + sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb +} +install_wkhtmltopdf & curl -LsS -O https://downloads.mariadb.com/MariaDB/mariadb_repo_setup sudo bash mariadb_repo_setup --mariadb-server-version=10.6 From 4289e7c7ea24757b51a966a98d6753af00c1acff Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 25 Jul 2022 14:33:30 +0530 Subject: [PATCH 04/48] ci: Merge PR linter checks * Combine jobs to be triggered at pull_request events: commit-lint, docs-required, linter * PY310-ize helper scripts --- .github/helper/documentation.py | 2 +- .github/helper/translation.py | 15 ++----- .github/workflows/docs-checker.yml | 28 ------------- .github/workflows/linters.yml | 57 ++++++++++++++++++++++---- .github/workflows/semantic-commits.yml | 30 -------------- 5 files changed, 55 insertions(+), 77 deletions(-) delete mode 100644 .github/workflows/docs-checker.yml delete mode 100644 .github/workflows/semantic-commits.yml diff --git a/.github/helper/documentation.py b/.github/helper/documentation.py index aece5f543b..eb0b373acd 100644 --- a/.github/helper/documentation.py +++ b/.github/helper/documentation.py @@ -30,7 +30,7 @@ def docs_link_exists(body): if __name__ == "__main__": pr = sys.argv[1] - response = requests.get("https://api.github.com/repos/frappe/frappe/pulls/{}".format(pr)) + response = requests.get(f"https://api.github.com/repos/frappe/frappe/pulls/{pr}") if response.ok: payload = response.json() diff --git a/.github/helper/translation.py b/.github/helper/translation.py index 9146b3b32b..72f661d3e1 100644 --- a/.github/helper/translation.py +++ b/.github/helper/translation.py @@ -20,19 +20,12 @@ for _file in files_to_scan: if 'frappe-lint: disable-translate' in line: continue - start_matches = start_pattern.search(line) - if start_matches: - starts_with_f = starts_with_f_pattern.search(line) - - if starts_with_f: - has_f_string = f_string_pattern.search(line) - if has_f_string: + if start_matches := start_pattern.search(line): + if starts_with_f := starts_with_f_pattern.search(line): + if has_f_string := f_string_pattern.search(line): errors_encounter += 1 print(f'\nF-strings are not supported for translations at line number {line_number}\n{line.strip()[:100]}') - continue - else: - continue - + continue match = pattern.search(line) error_found = False diff --git a/.github/workflows/docs-checker.yml b/.github/workflows/docs-checker.yml deleted file mode 100644 index e61ee6355a..0000000000 --- a/.github/workflows/docs-checker.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: 'Documentation Check' -on: - pull_request: - types: [ opened, synchronize, reopened, edited ] - -permissions: - contents: read - -jobs: - docs-required: - name: 'Documentation Required' - runs-on: ubuntu-latest - - steps: - - name: 'Setup Environment' - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - - name: 'Clone repo' - uses: actions/checkout@v3 - - - name: Validate Docs - env: - PR_NUMBER: ${{ github.event.number }} - run: | - pip install requests --quiet - python $GITHUB_WORKSPACE/.github/helper/documentation.py $PR_NUMBER diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 6d1029d51d..e3f71455cd 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -1,12 +1,56 @@ name: Linters on: - pull_request: { } + pull_request: + +permissions: + contents: read + +concurrency: + group: commitcheck-frappe-${{ github.event.number }} + cancel-in-progress: true jobs: + commit-lint: + name: 'Semantic Commits' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 200 - linters: - name: Frappe Linter + - uses: actions/setup-node@v3 + with: + node-version: 16 + check-latest: true + + - name: Check commit titles + run: | + npm install @commitlint/cli @commitlint/config-conventional + npx commitlint --verbose --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} + + docs-required: + name: 'Documentation Required' + runs-on: ubuntu-latest + + steps: + - name: 'Setup Environment' + uses: actions/setup-python@v4 + with: + python-version: '3.10' + + - name: 'Clone repo' + uses: actions/checkout@v3 + + - name: Validate Docs + env: + PR_NUMBER: ${{ github.event.number }} + run: | + pip install requests --quiet + python $GITHUB_WORKSPACE/.github/helper/documentation.py $PR_NUMBER + + linter: + name: 'Frappe Linter' runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -22,8 +66,7 @@ jobs: - name: Download Semgrep rules run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules - - name: Download semgrep - run: pip install semgrep==0.97.0 - - name: Run Semgrep rules - run: semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness + run: | + pip install semgrep==0.97.0 + semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness diff --git a/.github/workflows/semantic-commits.yml b/.github/workflows/semantic-commits.yml deleted file mode 100644 index 7afa02d1b9..0000000000 --- a/.github/workflows/semantic-commits.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Semantic Commits - -on: - pull_request: {} - -permissions: - contents: read - -concurrency: - group: commitcheck-frappe-${{ github.event.number }} - cancel-in-progress: true - -jobs: - commitlint: - name: Check Commit Titles - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 200 - - - uses: actions/setup-node@v3 - with: - node-version: 16 - check-latest: true - - - name: Check commit titles - run: | - npm install @commitlint/cli @commitlint/config-conventional - npx commitlint --verbose --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} From a7ab78bde1439672fe49fe6a544a5baf372a3dcb Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 25 Jul 2022 14:35:16 +0530 Subject: [PATCH 05/48] ci(minor): Actions * Rename CI actions to add database_type * Add workflow_dispatch to assets build action on develop * Rename unit test jobs for better labelling on PR check titles * Rename Patch action for consistency --- .github/workflows/patch-mariadb-tests.yml | 10 +++++----- .github/workflows/publish-assets-develop.yml | 1 + .github/workflows/server-mariadb-tests.yml | 5 ++--- .github/workflows/server-postgres-tests.yml | 5 ++--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/workflows/patch-mariadb-tests.yml b/.github/workflows/patch-mariadb-tests.yml index e18cbf53ba..3412fe7503 100644 --- a/.github/workflows/patch-mariadb-tests.yml +++ b/.github/workflows/patch-mariadb-tests.yml @@ -1,7 +1,8 @@ -name: Patch - -on: [pull_request, workflow_dispatch] +name: Server (MariaDB) +on: + pull_request: + workflow_dispatch: concurrency: group: patch-mariadb-develop-${{ github.event.number }} @@ -12,11 +13,10 @@ permissions: jobs: test: + name: Patch runs-on: ubuntu-latest timeout-minutes: 60 - name: Patch Test - services: mariadb: image: mariadb:10.6 diff --git a/.github/workflows/publish-assets-develop.yml b/.github/workflows/publish-assets-develop.yml index 467922e766..12bf9eca55 100644 --- a/.github/workflows/publish-assets-develop.yml +++ b/.github/workflows/publish-assets-develop.yml @@ -1,6 +1,7 @@ name: 'Frappe Assets' on: + workflow_dispatch: push: branches: [ develop ] diff --git a/.github/workflows/server-mariadb-tests.yml b/.github/workflows/server-mariadb-tests.yml index 9e7cffba5d..c8ccfa7862 100644 --- a/.github/workflows/server-mariadb-tests.yml +++ b/.github/workflows/server-mariadb-tests.yml @@ -1,4 +1,4 @@ -name: Server +name: Server (MariaDB) on: pull_request: @@ -16,6 +16,7 @@ permissions: jobs: test: + name: Unit Tests runs-on: ubuntu-latest timeout-minutes: 60 @@ -24,8 +25,6 @@ jobs: matrix: container: [1, 2] - name: Python Unit Tests (MariaDB) - services: mariadb: image: mariadb:10.6 diff --git a/.github/workflows/server-postgres-tests.yml b/.github/workflows/server-postgres-tests.yml index 1741752e6b..9760067197 100644 --- a/.github/workflows/server-postgres-tests.yml +++ b/.github/workflows/server-postgres-tests.yml @@ -1,4 +1,4 @@ -name: Server +name: Server (Postgres) on: pull_request: @@ -15,6 +15,7 @@ permissions: jobs: test: + name: Unit Tests runs-on: ubuntu-latest timeout-minutes: 60 @@ -23,8 +24,6 @@ jobs: matrix: container: [1, 2] - name: Python Unit Tests (Postgres) - services: postgres: image: postgres:12.4 From de97eaf603aea9e25fbed365c5091a30e0719034 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 25 Jul 2022 15:00:16 +0530 Subject: [PATCH 06/48] ci: Merge vulnerable dependency check to linter action --- .github/workflows/deps-checker.yml | 22 -------------------- .github/workflows/linters.yml | 32 ++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 32 deletions(-) delete mode 100644 .github/workflows/deps-checker.yml diff --git a/.github/workflows/deps-checker.yml b/.github/workflows/deps-checker.yml deleted file mode 100644 index d3fa8c80fb..0000000000 --- a/.github/workflows/deps-checker.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: 'Python Dependency Check' -on: - pull_request: - workflow_dispatch: - push: - branches: [ develop ] - -permissions: - contents: read - -jobs: - deps-vulnerable-check: - name: 'Vulnerable Dependency' - runs-on: ubuntu-latest - - steps: - - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - uses: actions/checkout@v3 - - run: pip install pip-audit - - run: pip-audit ${GITHUB_WORKSPACE} diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index e3f71455cd..c0c44ffe56 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -2,6 +2,9 @@ name: Linters on: pull_request: + workflow_dispatch: + push: + branches: [ develop ] permissions: contents: read @@ -14,11 +17,12 @@ jobs: commit-lint: name: 'Semantic Commits' runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: - uses: actions/checkout@v3 with: fetch-depth: 200 - - uses: actions/setup-node@v3 with: node-version: 16 @@ -32,15 +36,14 @@ jobs: docs-required: name: 'Documentation Required' runs-on: ubuntu-latest + if: github.event_name == 'pull_request' steps: - name: 'Setup Environment' uses: actions/setup-python@v4 with: python-version: '3.10' - - - name: 'Clone repo' - uses: actions/checkout@v3 + - uses: actions/checkout@v3 - name: Validate Docs env: @@ -54,14 +57,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - - name: Set up Python - uses: actions/setup-python@v4 + - uses: actions/setup-python@v4 with: python-version: '3.10' - - - name: Install and Run Pre-commit - uses: pre-commit/action@v3.0.0 + - uses: pre-commit/action@v3.0.0 - name: Download Semgrep rules run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules @@ -70,3 +69,16 @@ jobs: run: | pip install semgrep==0.97.0 semgrep ci --config ./frappe-semgrep-rules/rules --config r/python.lang.correctness + + deps-vulnerable-check: + name: 'Vulnerable Dependency Check' + runs-on: ubuntu-latest + + steps: + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - uses: actions/checkout@v3 + - run: | + pip install pip-audit + pip-audit ${GITHUB_WORKSPACE} From 1e40b32ebf3ddec6aac755e2fc1ef6b096b01349 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 25 Jul 2022 15:01:13 +0530 Subject: [PATCH 07/48] ci: Combine actions to be triggered 'on release' * Trigger static asset building & updating release assets * Trigger Docker release build --- .github/workflows/docker-release.yml | 20 ------------------- ...ish-assets-releases.yml => on_release.yml} | 20 +++++++++++++++++-- 2 files changed, 18 insertions(+), 22 deletions(-) delete mode 100644 .github/workflows/docker-release.yml rename .github/workflows/{publish-assets-releases.yml => on_release.yml} (71%) diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml deleted file mode 100644 index 988c2dcc6c..0000000000 --- a/.github/workflows/docker-release.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: 'Trigger Docker build on release' -on: - release: - types: [released] -permissions: - contents: read - -jobs: - curl: - permissions: - contents: none - name: 'Trigger Docker build on release' - runs-on: ubuntu-latest - container: - image: alpine:latest - steps: - - name: curl - run: | - apk add curl bash - curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.CI_PAT }}" https://api.github.com/repos/frappe/frappe_docker/actions/workflows/build_stable.yml/dispatches -d '{"ref":"main"}' diff --git a/.github/workflows/publish-assets-releases.yml b/.github/workflows/on_release.yml similarity index 71% rename from .github/workflows/publish-assets-releases.yml rename to .github/workflows/on_release.yml index ff1656e55d..59e14a8c4d 100644 --- a/.github/workflows/publish-assets-releases.yml +++ b/.github/workflows/on_release.yml @@ -1,8 +1,11 @@ -name: 'Frappe Assets' +name: 'Release' on: release: - types: [ created ] + types: [released] + +permissions: + contents: read env: GITHUB_TOKEN: ${{ github.token }} @@ -47,3 +50,16 @@ jobs: asset_path: build/assets.tar.gz asset_name: assets.tar.gz asset_content_type: application/octet-stream + + docker-release: + name: 'Trigger Docker build on release' + runs-on: ubuntu-latest + permissions: + contents: none + container: + image: alpine:latest + steps: + - name: curl + run: | + apk add curl bash + curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: Bearer ${{ secrets.CI_PAT }}" https://api.github.com/repos/frappe/frappe_docker/actions/workflows/build_stable.yml/dispatches -d '{"ref":"main"}' From 590e983a7f68a1fc131590d0c3f37bb7d129ffa9 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 25 Jul 2022 15:03:06 +0530 Subject: [PATCH 08/48] ci: Rename release action release.yml was a bit ambiguous given we have separate action configs related to release event or intent. --- .github/workflows/{release.yml => create-release.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{release.yml => create-release.yml} (100%) diff --git a/.github/workflows/release.yml b/.github/workflows/create-release.yml similarity index 100% rename from .github/workflows/release.yml rename to .github/workflows/create-release.yml From d2a5b8b00212aa5d25c02bf410dccc0671694f60 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Mon, 25 Jul 2022 16:30:11 +0530 Subject: [PATCH 09/48] ci: Skip pre-commit on branch builds --- .github/workflows/linters.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index c0c44ffe56..f56c108f6b 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -55,6 +55,8 @@ jobs: linter: name: 'Frappe Linter' runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 From 3216529deb6a49c66584d0987e230b7e9e833e6b Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Mon, 25 Jul 2022 17:46:27 +0530 Subject: [PATCH 10/48] fix: Letter head image not working (#17608) --- frappe/printing/doctype/letter_head/letter_head.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/printing/doctype/letter_head/letter_head.py b/frappe/printing/doctype/letter_head/letter_head.py index 9edd84a425..c48fd1fe25 100644 --- a/frappe/printing/doctype/letter_head/letter_head.py +++ b/frappe/printing/doctype/letter_head/letter_head.py @@ -61,9 +61,12 @@ class LetterHead(Document): # To preserve the aspect ratio of the image, apply constraints only on # the greater dimension and allow the other to scale accordingly - dimension = "width" if width > height else "height" + dimension = "width" if self.get(width) > self.get(height) else "height" dimension_value = self.get(f"{dimension_prefix}{dimension}") + if not dimension_value: + dimension_value = "" + self.set( html_field, f"""
From dd767bd6878ce0ff6c90538ccecd2bd222ebff8f Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 25 Jul 2022 17:47:52 +0530 Subject: [PATCH 11/48] refactor: move get_involved_users to form Involved users is a property of the form and doesn't have much to do with reviews. --- frappe/public/js/frappe/form/form.js | 23 +++++++++++++++++++ .../public/js/frappe/form/sidebar/review.js | 23 +------------------ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 4e38a5ee7e..854a1723d9 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1873,6 +1873,29 @@ frappe.ui.form.Form = class FrappeForm { get_active_tab() { return this.active_tab_map && this.active_tab_map[this.docname]; } + + get_involved_users() { + const user_fields = this.meta.fields + .filter(d => d.fieldtype === 'Link' && d.options === 'User') + .map(d => d.fieldname); + + user_fields.push('owner'); + let involved_users = user_fields.map(field => this.doc[field]); + + const docinfo = this.get_docinfo(); + + involved_users = involved_users.concat( + docinfo.communications.map(d => d.sender && d.delivery_status === 'sent'), + docinfo.comments.map(d => d.owner), + docinfo.versions.map(d => d.owner), + docinfo.assignments.map(d => d.owner) + ); + + return involved_users + .uniqBy(u => u) + .filter(user => !['Administrator', frappe.session.user].includes(user)) + .filter(Boolean); + } }; frappe.validated = 0; diff --git a/frappe/public/js/frappe/form/sidebar/review.js b/frappe/public/js/frappe/form/sidebar/review.js index 2d54ad4329..242f6f0435 100644 --- a/frappe/public/js/frappe/form/sidebar/review.js +++ b/frappe/public/js/frappe/form/sidebar/review.js @@ -38,30 +38,9 @@ frappe.ui.form.Review = class Review { review_button.click(() => this.show_review_dialog()); } } - get_involved_users() { - const user_fields = this.frm.meta.fields - .filter(d => d.fieldtype === 'Link' && d.options === 'User') - .map(d => d.fieldname); - user_fields.push('owner'); - let involved_users = user_fields.map(field => this.frm.doc[field]); - - const docinfo = this.frm.get_docinfo(); - - involved_users = involved_users.concat( - docinfo.communications.map(d => d.sender && d.delivery_status === 'sent'), - docinfo.comments.map(d => d.owner), - docinfo.versions.map(d => d.owner), - docinfo.assignments.map(d => d.owner) - ); - - return involved_users - .uniqBy(u => u) - .filter(user => !['Administrator', frappe.session.user].includes(user)) - .filter(Boolean); - } show_review_dialog() { - const user_options = this.get_involved_users(); + const user_options = this.frm.get_involved_users(); const review_dialog = new frappe.ui.Dialog({ 'title': __('Add Review'), 'fields': [{ From 5a2b5001009ba8273a9044a678b31931fe49da96 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Mon, 25 Jul 2022 18:31:12 +0530 Subject: [PATCH 12/48] fix(UX): mentions - prioritize invovled users --- .../public/js/frappe/form/controls/text_editor.js | 14 +++++++++++++- frappe/public/js/frappe/form/form.js | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/text_editor.js b/frappe/public/js/frappe/form/controls/text_editor.js index 50b625f248..be0983fc73 100644 --- a/frappe/public/js/frappe/form/controls/text_editor.js +++ b/frappe/public/js/frappe/form/controls/text_editor.js @@ -195,7 +195,9 @@ frappe.ui.form.ControlTextEditor = class ControlTextEditor extends frappe.ui.for let values = await frappe.xcall(method, { search_term }); - renderList(values, search_term); + + let sorted_values = me.prioritize_involved_users_in_mention(values); + renderList(sorted_values, search_term); }, 300), renderItem(item) { let value = item.value; @@ -204,6 +206,16 @@ frappe.ui.form.ControlTextEditor = class ControlTextEditor extends frappe.ui.for }; } + prioritize_involved_users_in_mention(values) { + const involved_users = this.frm?.get_involved_users() // input on form + || cur_frm?.get_involved_users() // comment box / dialog on active form + || []; + + return values + .filter(val => involved_users.includes(val.id)) + .concat(values.filter(val => !involved_users.includes(val.id))); + } + get_toolbar_options() { return [ [{ header: [1, 2, 3, false] }], diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 854a1723d9..ea37c80e5e 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1875,11 +1875,11 @@ frappe.ui.form.Form = class FrappeForm { } get_involved_users() { - const user_fields = this.meta.fields + let user_fields = this.meta.fields .filter(d => d.fieldtype === 'Link' && d.options === 'User') .map(d => d.fieldname); - user_fields.push('owner'); + user_fields = [...user_fields, "owner", "modified_by"]; let involved_users = user_fields.map(field => this.doc[field]); const docinfo = this.get_docinfo(); From df30f47f4e922b7fe582df70faa7248e506eeddb Mon Sep 17 00:00:00 2001 From: phot0n Date: Wed, 9 Mar 2022 12:23:34 +0530 Subject: [PATCH 13/48] chore: remove razorpay.js --- frappe/public/js/integrations/razorpay.js | 148 ---------------------- 1 file changed, 148 deletions(-) delete mode 100644 frappe/public/js/integrations/razorpay.js diff --git a/frappe/public/js/integrations/razorpay.js b/frappe/public/js/integrations/razorpay.js deleted file mode 100644 index eda4ac1894..0000000000 --- a/frappe/public/js/integrations/razorpay.js +++ /dev/null @@ -1,148 +0,0 @@ -/* HOW-TO - -Razorpay Payment - -1. Include checkout script in your code - {{ include_script('checkout.bundle.js) }} - -2. Create the Order controller in your backend - def get_razorpay_order(self): - controller = get_payment_gateway_controller("Razorpay") - - payment_details = { - "amount": 300, - ... - "reference_doctype": "Conference Participant", - "reference_docname": self.name, - ... - "receipt": self.name - } - - return controller.create_order(**payment_details) - -3. Inititate the payment in client using checkout API - function make_payment(ticket) { - var options = { - "name": "", - "description": "", - "image": "", - "prefill": { - "name": "", - "email": "", - "contact": "" - }, - "theme": { - "color": "" - }, - "doctype": "", - "docname": " { - - -{% endblock %} - -{%- block page_content -%} -
-
- -
-
- -
-
- -
-
-
-
-
-
- - -
- -
-
- - -{% endblock %} diff --git a/frappe/templates/pages/integrations/braintree_checkout.py b/frappe/templates/pages/integrations/braintree_checkout.py deleted file mode 100644 index c4c79ea74f..0000000000 --- a/frappe/templates/pages/integrations/braintree_checkout.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors -# License: MIT. See LICENSE - -import json - -import frappe -from frappe import _ -from frappe.integrations.doctype.braintree_settings.braintree_settings import ( - get_client_token, - get_gateway_controller, -) -from frappe.utils import flt - -no_cache = 1 - -expected_keys = ( - "amount", - "title", - "description", - "reference_doctype", - "reference_docname", - "payer_name", - "payer_email", - "order_id", - "currency", -) - - -def get_context(context): - context.no_cache = 1 - - # all these keys exist in form_dict - if not (set(expected_keys) - set(list(frappe.form_dict))): - for key in expected_keys: - context[key] = frappe.form_dict[key] - - context.client_token = get_client_token(context.reference_docname) - - context["amount"] = flt(context["amount"]) - - gateway_controller = get_gateway_controller(context.reference_docname) - context["header_img"] = frappe.db.get_value( - "Braintree Settings", gateway_controller, "header_img" - ) - - else: - frappe.redirect_to_message( - _("Some information is missing"), - _("Looks like someone sent you to an incomplete URL. Please ask them to look into it."), - ) - frappe.local.flags.redirect_location = frappe.local.response.location - raise frappe.Redirect - - -@frappe.whitelist(allow_guest=True) -def make_payment(payload_nonce, data, reference_doctype, reference_docname): - data = json.loads(data) - - data.update({"payload_nonce": payload_nonce}) - - gateway_controller = get_gateway_controller(reference_docname) - data = frappe.get_doc("Braintree Settings", gateway_controller).create_payment_request(data) - frappe.db.commit() - return data diff --git a/frappe/templates/pages/integrations/payment-cancel.html b/frappe/templates/pages/integrations/payment-cancel.html deleted file mode 100644 index a7c327508f..0000000000 --- a/frappe/templates/pages/integrations/payment-cancel.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "templates/web.html" %} - -{% block title %}{{ _("Payment Cancelled") }}{% endblock %} - -{%- block page_content -%} -
-
- - {{ _("Payment Cancelled") }} -
-

{{ _("Your payment is cancelled.") }}

- -
- - -{% endblock %} diff --git a/frappe/templates/pages/integrations/payment-failed.html b/frappe/templates/pages/integrations/payment-failed.html deleted file mode 100644 index 8f416b563a..0000000000 --- a/frappe/templates/pages/integrations/payment-failed.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "templates/web.html" %} - -{% block title %}{{ _("Payment Failed") }}{% endblock %} - -{%- block page_content -%} -
-
- - {{ _("Payment Failed") }} -
-

{{ _("Your payment has failed.") }}

- -
- - -{% endblock %} diff --git a/frappe/templates/pages/integrations/payment-success.html b/frappe/templates/pages/integrations/payment-success.html deleted file mode 100644 index 76c5db93bf..0000000000 --- a/frappe/templates/pages/integrations/payment-success.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends "templates/web.html" %} - -{% block title %}{{ _("Payment Success") }}{% endblock %} - -{%- block page_content -%} -
-
- - {{ _("Success") }} -
-

{{ payment_message or _("Your payment was successfully accepted") }}

- {% if not payment_message %} - - {% endif %} -
- - -{% endblock %} diff --git a/frappe/templates/pages/integrations/payment_cancel.py b/frappe/templates/pages/integrations/payment_cancel.py deleted file mode 100644 index cf2a10f8c7..0000000000 --- a/frappe/templates/pages/integrations/payment_cancel.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: MIT. See LICENSE - -import frappe - - -def get_context(context): - token = frappe.local.form_dict.token - - if token: - frappe.db.set_value("Integration Request", token, "status", "Cancelled") - frappe.db.commit() diff --git a/frappe/templates/pages/integrations/payment_success.py b/frappe/templates/pages/integrations/payment_success.py deleted file mode 100644 index 8985850a81..0000000000 --- a/frappe/templates/pages/integrations/payment_success.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: MIT. See LICENSE - -import frappe - -no_cache = True - - -def get_context(context): - token = frappe.local.form_dict.token - doc = frappe.get_doc(frappe.local.form_dict.doctype, frappe.local.form_dict.docname) - - context.payment_message = "" - if hasattr(doc, "get_payment_success_message"): - context.payment_message = doc.get_payment_success_message() diff --git a/frappe/templates/pages/integrations/paytm_checkout.html b/frappe/templates/pages/integrations/paytm_checkout.html deleted file mode 100644 index 168f6597e5..0000000000 --- a/frappe/templates/pages/integrations/paytm_checkout.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends "templates/web.html" %} - -{% block title %} Payment {% endblock %} - -{%- block header -%} - - Merchant Checkout Page - -{% endblock %} - -{% block script %} - -{% endblock %} - -{%- block page_content -%} - -
-

Please do not refresh this page...

- -
- {% for name, value in payment_details.items() %} - - {% endfor %} -
-
- -{% endblock %} - -{% block style %} - -{% endblock %} \ No newline at end of file diff --git a/frappe/templates/pages/integrations/paytm_checkout.py b/frappe/templates/pages/integrations/paytm_checkout.py deleted file mode 100644 index 93097e038b..0000000000 --- a/frappe/templates/pages/integrations/paytm_checkout.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors -# License: MIT. See LICENSE -import json - -import frappe -from frappe import _ -from frappe.integrations.doctype.paytm_settings.paytm_settings import ( - get_paytm_config, - get_paytm_params, -) - - -def get_context(context): - context.no_cache = 1 - paytm_config = get_paytm_config() - - try: - doc = frappe.get_doc("Integration Request", frappe.form_dict["order_id"]) - - context.payment_details = get_paytm_params(json.loads(doc.data), doc.name, paytm_config) - - context.url = paytm_config.url - - except Exception: - frappe.log_error() - frappe.redirect_to_message( - _("Invalid Token"), - _("Seems token you are using is invalid!"), - http_status_code=400, - indicator_color="red", - ) - - frappe.local.flags.redirect_location = frappe.local.response.location - raise frappe.Redirect diff --git a/frappe/templates/pages/integrations/razorpay_checkout.html b/frappe/templates/pages/integrations/razorpay_checkout.html deleted file mode 100644 index fa1101c216..0000000000 --- a/frappe/templates/pages/integrations/razorpay_checkout.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "templates/web.html" %} - -{% block title %} Payment {% endblock %} - -{%- block header -%}{% endblock %} - -{% block script %} - - -{% endblock %} - -{%- block page_content -%} - -

- Loading Payment System - -

- -{% endblock %} - -{% block style %} - -{% endblock %} \ No newline at end of file diff --git a/frappe/templates/pages/integrations/razorpay_checkout.py b/frappe/templates/pages/integrations/razorpay_checkout.py deleted file mode 100644 index d0e77f6d8a..0000000000 --- a/frappe/templates/pages/integrations/razorpay_checkout.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors -# License: MIT. See LICENSE -import json - -import frappe -from frappe import _ -from frappe.utils import cint, flt - -no_cache = 1 - -expected_keys = ( - "amount", - "title", - "description", - "reference_doctype", - "reference_docname", - "payer_name", - "payer_email", - "order_id", - "currency", -) - - -def get_context(context): - context.no_cache = 1 - context.api_key = get_api_key() - - try: - doc = frappe.get_doc("Integration Request", frappe.form_dict["token"]) - payment_details = json.loads(doc.data) - - for key in expected_keys: - context[key] = payment_details[key] - - context["token"] = frappe.form_dict["token"] - context["amount"] = flt(context["amount"]) - context["subscription_id"] = ( - payment_details["subscription_id"] if payment_details.get("subscription_id") else "" - ) - - except Exception as e: - frappe.redirect_to_message( - _("Invalid Token"), - _("Seems token you are using is invalid!"), - http_status_code=400, - indicator_color="red", - ) - - frappe.local.flags.redirect_location = frappe.local.response.location - raise frappe.Redirect - - -def get_api_key(): - api_key = frappe.db.get_single_value("Razorpay Settings", "api_key") - if cint(frappe.form_dict.get("use_sandbox")): - api_key = frappe.conf.sandbox_api_key - - return api_key - - -@frappe.whitelist(allow_guest=True) -def make_payment(razorpay_payment_id, options, reference_doctype, reference_docname, token): - data = {} - - if isinstance(options, str): - data = json.loads(options) - - data.update( - { - "razorpay_payment_id": razorpay_payment_id, - "reference_docname": reference_docname, - "reference_doctype": reference_doctype, - "token": token, - } - ) - - data = frappe.get_doc("Razorpay Settings").create_request(data) - frappe.db.commit() - return data diff --git a/frappe/templates/pages/integrations/stripe_checkout.css b/frappe/templates/pages/integrations/stripe_checkout.css deleted file mode 100644 index a42808aa7f..0000000000 --- a/frappe/templates/pages/integrations/stripe_checkout.css +++ /dev/null @@ -1,113 +0,0 @@ -.StripeElement { - background-color: white; - height: 40px; - padding: 10px 12px; - border-radius: 4px; - border: 1px solid transparent; - box-shadow: 0 1px 3px 0 #e6ebf1; - -webkit-transition: box-shadow 150ms ease; - transition: box-shadow 150ms ease; -} - -.StripeElement--focus { - box-shadow: 0 1px 3px 0 #cfd7df; -} - -.StripeElement--invalid { - border-color: #fa755a; -} - -.StripeElement--webkit-autofill { - background-color: #fefde5; -} - -.stripe #payment-form { - margin-top: 80px; -} - -.stripe button { - float: right; - display: block; - background: #5e64ff; - color: white; - box-shadow: 0 7px 14px 0 rgba(49, 49, 93, 0.10), 0 3px 6px 0 rgba(0, 0, 0, 0.08); - border-radius: 4px; - border: 0; - margin-top: 20px; - font-size: 15px; - font-weight: 400; - max-width: 40%; - height: 40px; - line-height: 38px; - outline: none; -} - -.stripe button:hover, .stripe button:focus { - background: #2b33ff; - border-color: #0711ff; -} - -.stripe button:active { - background: #5e64ff; -} - -.stripe button:disabled { - background: #515e80; -} - -.stripe .group { - background: white; - box-shadow: 2px 7px 14px 2px rgba(49, 49, 93, 0.10), 0 3px 6px 0 rgba(0, 0, 0, 0.08); - border-radius: 4px; - margin-bottom: 20px; -} - -.stripe label { - position: relative; - color: #8898AA; - font-weight: 300; - height: 40px; - line-height: 40px; - margin-left: 20px; - display: block; -} - -.stripe .group label:not(:last-child) { - border-bottom: 1px solid #F0F5FA; -} - -.stripe label>span { - width: 20%; - text-align: right; - float: left; -} - -.current-card { - margin-left: 20px; -} - -.field { - background: transparent; - font-weight: 300; - border: 0; - color: #31325F; - outline: none; - padding-right: 10px; - padding-left: 10px; - cursor: text; - width: 70%; - height: 40px; - float: right; -} - -.field::-webkit-input-placeholder { - color: #CFD7E0; -} - -.field::-moz-placeholder { - color: #CFD7E0; -} - -.field:-ms-input-placeholder { - color: #CFD7E0; -} diff --git a/frappe/templates/pages/integrations/stripe_checkout.html b/frappe/templates/pages/integrations/stripe_checkout.html deleted file mode 100644 index ec3d9783c5..0000000000 --- a/frappe/templates/pages/integrations/stripe_checkout.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends "templates/web.html" %} - -{% block title %} Payment {% endblock %} - -{%- block header -%} -{% endblock %} - -{% block script %} - - -{% endblock %} - -{%- block page_content -%} - -
-
- {% if image %} - - {% endif %} -

{{description}}

-
-
-
-
- -
-
-
-
- -
-
-
- -
- -
- -
- - -
-
-
-
- - -{% endblock %} diff --git a/frappe/templates/pages/integrations/stripe_checkout.py b/frappe/templates/pages/integrations/stripe_checkout.py deleted file mode 100644 index 1c0e20c631..0000000000 --- a/frappe/templates/pages/integrations/stripe_checkout.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors -# License: MIT. See LICENSE -import json - -import frappe -from frappe import _ -from frappe.integrations.doctype.stripe_settings.stripe_settings import get_gateway_controller -from frappe.utils import cint, fmt_money - -no_cache = 1 - -expected_keys = ( - "amount", - "title", - "description", - "reference_doctype", - "reference_docname", - "payer_name", - "payer_email", - "order_id", - "currency", -) - - -def get_context(context): - context.no_cache = 1 - - # all these keys exist in form_dict - if not (set(expected_keys) - set(list(frappe.form_dict))): - for key in expected_keys: - context[key] = frappe.form_dict[key] - - gateway_controller = get_gateway_controller(context.reference_doctype, context.reference_docname) - context.publishable_key = get_api_key(context.reference_docname, gateway_controller) - context.image = get_header_image(context.reference_docname, gateway_controller) - - context["amount"] = fmt_money(amount=context["amount"], currency=context["currency"]) - - if is_a_subscription(context.reference_doctype, context.reference_docname): - payment_plan = frappe.db.get_value( - context.reference_doctype, context.reference_docname, "payment_plan" - ) - recurrence = frappe.db.get_value("Payment Plan", payment_plan, "recurrence") - - context["amount"] = context["amount"] + " " + _(recurrence) - - else: - frappe.redirect_to_message( - _("Some information is missing"), - _("Looks like someone sent you to an incomplete URL. Please ask them to look into it."), - ) - frappe.local.flags.redirect_location = frappe.local.response.location - raise frappe.Redirect - - -def get_api_key(doc, gateway_controller): - publishable_key = frappe.db.get_value("Stripe Settings", gateway_controller, "publishable_key") - if cint(frappe.form_dict.get("use_sandbox")): - publishable_key = frappe.conf.sandbox_publishable_key - - return publishable_key - - -def get_header_image(doc, gateway_controller): - header_image = frappe.db.get_value("Stripe Settings", gateway_controller, "header_img") - - return header_image - - -@frappe.whitelist(allow_guest=True) -def make_payment(stripe_token_id, data, reference_doctype=None, reference_docname=None): - data = json.loads(data) - - data.update({"stripe_token_id": stripe_token_id}) - - gateway_controller = get_gateway_controller(reference_doctype, reference_docname) - - if is_a_subscription(reference_doctype, reference_docname): - reference = frappe.get_doc(reference_doctype, reference_docname) - data = reference.create_subscription("stripe", gateway_controller, data) - else: - data = frappe.get_doc("Stripe Settings", gateway_controller).create_request(data) - - frappe.db.commit() - return data - - -def is_a_subscription(reference_doctype, reference_docname): - if not frappe.get_meta(reference_doctype).has_field("is_a_subscription"): - return False - return frappe.db.get_value(reference_doctype, reference_docname, "is_a_subscription") From 725b8fb13a1b7eaf97df59b4614d6761b5f76abc Mon Sep 17 00:00:00 2001 From: phot0n Date: Tue, 29 Mar 2022 13:38:54 +0530 Subject: [PATCH 18/48] chore: remove payments card from integration workspace --- .../workspace/integrations/integrations.json | 152 ++++++------------ 1 file changed, 45 insertions(+), 107 deletions(-) diff --git a/frappe/integrations/workspace/integrations/integrations.json b/frappe/integrations/workspace/integrations/integrations.json index bbd2e1199f..8d1dfd64af 100644 --- a/frappe/integrations/workspace/integrations/integrations.json +++ b/frappe/integrations/workspace/integrations/integrations.json @@ -1,6 +1,6 @@ { "charts": [], - "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Backup\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Google Services\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Authentication\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Payments\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]", + "content": "[{\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Backup\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Google Services\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Authentication\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]", "creation": "2020-03-02 15:16:18.714190", "docstatus": 0, "doctype": "Workspace", @@ -106,11 +106,52 @@ { "hidden": 0, "is_query_report": 0, - "label": "Authentication", + "label": "Settings", "link_count": 0, "onboard": 0, "type": "Card Break" }, + { + "dependencies": "", + "hidden": 0, + "is_query_report": 0, + "label": "Webhook", + "link_count": 0, + "link_to": "Webhook", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "dependencies": "", + "hidden": 0, + "is_query_report": 0, + "label": "Slack Webhook URL", + "link_count": 0, + "link_to": "Slack Webhook URL", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "dependencies": "", + "hidden": 0, + "is_query_report": 0, + "label": "SMS Settings", + "link_count": 0, + "link_to": "SMS Settings", + "link_type": "DocType", + "onboard": 0, + "type": "Link" + }, + { + "hidden": 0, + "is_query_report": 0, + "label": "Authentication", + "link_count": 4, + "onboard": 0, + "type": "Card Break" + }, { "dependencies": "", "hidden": 0, @@ -154,119 +195,16 @@ "link_type": "DocType", "onboard": 0, "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Payments", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Braintree Settings", - "link_count": 0, - "link_to": "Braintree Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "PayPal Settings", - "link_count": 0, - "link_to": "PayPal Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Razorpay Settings", - "link_count": 0, - "link_to": "Razorpay Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Stripe Settings", - "link_count": 0, - "link_to": "Stripe Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Paytm Settings", - "link_count": 0, - "link_to": "Paytm Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Settings", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Webhook", - "link_count": 0, - "link_to": "Webhook", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Slack Webhook URL", - "link_count": 0, - "link_to": "Slack Webhook URL", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "SMS Settings", - "link_count": 0, - "link_to": "SMS Settings", - "link_type": "DocType", - "onboard": 0, - "type": "Link" } ], - "modified": "2022-01-13 17:39:01.292154", + "modified": "2022-07-23 18:00:28.805405", "modified_by": "Administrator", "module": "Integrations", "name": "Integrations", "owner": "Administrator", "parent_page": "", "public": 1, + "quick_lists": [], "restrict_to_domain": "", "roles": [], "sequence_id": 15.0, From f3473b059e7ae1b15967dacc3243966c390f1682 Mon Sep 17 00:00:00 2001 From: phot0n Date: Tue, 5 Apr 2022 23:30:59 +0530 Subject: [PATCH 19/48] chore: remove payment gateway and integration request doctype --- .../core/doctype/payment_gateway/__init__.py | 0 .../payment_gateway/payment_gateway.js | 8 - .../payment_gateway/payment_gateway.json | 55 ------- .../payment_gateway/payment_gateway.py | 8 - .../payment_gateway/test_payment_gateway.py | 9 - .../doctype/integration_request/__init__.py | 0 .../integration_request.js | 8 - .../integration_request.json | 154 ------------------ .../integration_request.py | 37 ----- .../test_integration_request.py | 11 -- 10 files changed, 290 deletions(-) delete mode 100644 frappe/core/doctype/payment_gateway/__init__.py delete mode 100644 frappe/core/doctype/payment_gateway/payment_gateway.js delete mode 100644 frappe/core/doctype/payment_gateway/payment_gateway.json delete mode 100644 frappe/core/doctype/payment_gateway/payment_gateway.py delete mode 100644 frappe/core/doctype/payment_gateway/test_payment_gateway.py delete mode 100644 frappe/integrations/doctype/integration_request/__init__.py delete mode 100644 frappe/integrations/doctype/integration_request/integration_request.js delete mode 100644 frappe/integrations/doctype/integration_request/integration_request.json delete mode 100644 frappe/integrations/doctype/integration_request/integration_request.py delete mode 100644 frappe/integrations/doctype/integration_request/test_integration_request.py diff --git a/frappe/core/doctype/payment_gateway/__init__.py b/frappe/core/doctype/payment_gateway/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frappe/core/doctype/payment_gateway/payment_gateway.js b/frappe/core/doctype/payment_gateway/payment_gateway.js deleted file mode 100644 index 0eff5a5608..0000000000 --- a/frappe/core/doctype/payment_gateway/payment_gateway.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Payment Gateway', { - refresh: function(frm) { - - } -}); diff --git a/frappe/core/doctype/payment_gateway/payment_gateway.json b/frappe/core/doctype/payment_gateway/payment_gateway.json deleted file mode 100644 index 7195b3949e..0000000000 --- a/frappe/core/doctype/payment_gateway/payment_gateway.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "actions": [], - "autoname": "field:gateway", - "creation": "2022-01-24 21:09:47.229371", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "gateway", - "gateway_settings", - "gateway_controller" - ], - "fields": [ - { - "fieldname": "gateway", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Gateway", - "reqd": 1, - "unique": 1 - }, - { - "fieldname": "gateway_settings", - "fieldtype": "Link", - "label": "Gateway Settings", - "options": "DocType" - }, - { - "fieldname": "gateway_controller", - "fieldtype": "Dynamic Link", - "label": "Gateway Controller", - "options": "gateway_settings" - } - ], - "links": [], - "modified": "2022-01-24 21:17:03.864719", - "modified_by": "Administrator", - "module": "Core", - "name": "Payment Gateway", - "naming_rule": "By fieldname", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "read": 1, - "role": "System Manager", - "write": 1 - } - ], - "quick_entry": 1, - "sort_field": "modified", - "sort_order": "DESC", - "states": [] -} \ No newline at end of file diff --git a/frappe/core/doctype/payment_gateway/payment_gateway.py b/frappe/core/doctype/payment_gateway/payment_gateway.py deleted file mode 100644 index 74306ae4ad..0000000000 --- a/frappe/core/doctype/payment_gateway/payment_gateway.py +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors -# License: MIT. See LICENSE - -from frappe.model.document import Document - - -class PaymentGateway(Document): - pass diff --git a/frappe/core/doctype/payment_gateway/test_payment_gateway.py b/frappe/core/doctype/payment_gateway/test_payment_gateway.py deleted file mode 100644 index 6900e79434..0000000000 --- a/frappe/core/doctype/payment_gateway/test_payment_gateway.py +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors -# License: MIT. See LICENSE -import unittest - -# test_records = frappe.get_test_records('Payment Gateway') - - -class TestPaymentGateway(unittest.TestCase): - pass diff --git a/frappe/integrations/doctype/integration_request/__init__.py b/frappe/integrations/doctype/integration_request/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/frappe/integrations/doctype/integration_request/integration_request.js b/frappe/integrations/doctype/integration_request/integration_request.js deleted file mode 100644 index 4b3b9a2de7..0000000000 --- a/frappe/integrations/doctype/integration_request/integration_request.js +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2016, Frappe Technologies and contributors -// For license information, please see license.txt - -frappe.ui.form.on('Integration Request', { - refresh: function(frm) { - - } -}); diff --git a/frappe/integrations/doctype/integration_request/integration_request.json b/frappe/integrations/doctype/integration_request/integration_request.json deleted file mode 100644 index 98db8ea748..0000000000 --- a/frappe/integrations/doctype/integration_request/integration_request.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "actions": [], - "creation": "2022-03-28 12:25:29.929952", - "doctype": "DocType", - "editable_grid": 1, - "engine": "InnoDB", - "field_order": [ - "request_id", - "integration_request_service", - "is_remote_request", - "column_break_5", - "request_description", - "status", - "section_break_8", - "url", - "request_headers", - "data", - "response_section", - "output", - "error", - "reference_section", - "reference_doctype", - "column_break_16", - "reference_docname" - ], - "fields": [ - { - "fieldname": "integration_request_service", - "fieldtype": "Data", - "label": "Service", - "read_only": 1 - }, - { - "default": "Queued", - "fieldname": "status", - "fieldtype": "Select", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Status", - "options": "\nQueued\nAuthorized\nCompleted\nCancelled\nFailed", - "read_only": 1 - }, - { - "fieldname": "data", - "fieldtype": "Code", - "label": "Request Data", - "read_only": 1 - }, - { - "fieldname": "output", - "fieldtype": "Code", - "label": "Output", - "read_only": 1 - }, - { - "fieldname": "error", - "fieldtype": "Code", - "label": "Error", - "read_only": 1 - }, - { - "fieldname": "reference_doctype", - "fieldtype": "Link", - "label": "Reference Document Type", - "options": "DocType", - "read_only": 1 - }, - { - "fieldname": "reference_docname", - "fieldtype": "Dynamic Link", - "label": "Reference Document Name", - "options": "reference_doctype", - "read_only": 1 - }, - { - "default": "0", - "fieldname": "is_remote_request", - "fieldtype": "Check", - "label": "Is Remote Request?", - "read_only": 1 - }, - { - "fieldname": "request_description", - "fieldtype": "Data", - "label": "Request Description", - "read_only": 1 - }, - { - "fieldname": "request_id", - "fieldtype": "Data", - "label": "Request ID", - "read_only": 1 - }, - { - "fieldname": "column_break_5", - "fieldtype": "Column Break" - }, - { - "fieldname": "section_break_8", - "fieldtype": "Section Break" - }, - { - "fieldname": "url", - "fieldtype": "Data", - "label": "URL", - "read_only": 1 - }, - { - "fieldname": "response_section", - "fieldtype": "Section Break", - "label": "Response" - }, - { - "depends_on": "eval:doc.reference_doctype", - "fieldname": "reference_section", - "fieldtype": "Section Break", - "label": "Reference" - }, - { - "fieldname": "column_break_16", - "fieldtype": "Column Break" - }, - { - "fieldname": "request_headers", - "fieldtype": "Code", - "label": "Request Headers", - "read_only": 1 - } - ], - "in_create": 1, - "links": [], - "modified": "2022-04-07 11:32:27.557548", - "modified_by": "Administrator", - "module": "Integrations", - "name": "Integration Request", - "owner": "Administrator", - "permissions": [ - { - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1 - } - ], - "sort_field": "modified", - "sort_order": "DESC", - "states": [], - "title_field": "integration_request_service", - "track_changes": 1 -} \ No newline at end of file diff --git a/frappe/integrations/doctype/integration_request/integration_request.py b/frappe/integrations/doctype/integration_request/integration_request.py deleted file mode 100644 index 334736bc9b..0000000000 --- a/frappe/integrations/doctype/integration_request/integration_request.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies and contributors -# License: MIT. See LICENSE - -import json - -import frappe -from frappe.integrations.utils import json_handler -from frappe.model.document import Document - - -class IntegrationRequest(Document): - def autoname(self): - if self.flags._name: - self.name = self.flags._name - - def update_status(self, params, status): - data = json.loads(self.data) - data.update(params) - - self.data = json.dumps(data) - self.status = status - self.save(ignore_permissions=True) - frappe.db.commit() - - def handle_success(self, response): - """update the output field with the response along with the relevant status""" - if isinstance(response, str): - response = json.loads(response) - self.db_set("status", "Completed") - self.db_set("output", json.dumps(response, default=json_handler)) - - def handle_failure(self, response): - """update the error field with the response along with the relevant status""" - if isinstance(response, str): - response = json.loads(response) - self.db_set("status", "Failed") - self.db_set("error", json.dumps(response, default=json_handler)) diff --git a/frappe/integrations/doctype/integration_request/test_integration_request.py b/frappe/integrations/doctype/integration_request/test_integration_request.py deleted file mode 100644 index 45963d5096..0000000000 --- a/frappe/integrations/doctype/integration_request/test_integration_request.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright (c) 2015, Frappe Technologies and Contributors -# License: MIT. See LICENSE -import unittest - -import frappe - -# test_records = frappe.get_test_records('Integration Request') - - -class TestIntegrationRequest(unittest.TestCase): - pass From 5c2cfdd1e91c6627b86275aaf84acab36161f687 Mon Sep 17 00:00:00 2001 From: phot0n Date: Tue, 5 Apr 2022 23:54:34 +0530 Subject: [PATCH 20/48] fix: remove integration request check from test_is_set_is_not_set --- frappe/tests/test_db_query.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py index ad9f59b3cd..e031bc87e3 100644 --- a/frappe/tests/test_db_query.py +++ b/frappe/tests/test_db_query.py @@ -501,10 +501,9 @@ class TestReportview(unittest.TestCase): ) def test_is_set_is_not_set(self): - res = DatabaseQuery("DocType").execute(filters={"autoname": ["is", "not set"]}) - self.assertTrue({"name": "Integration Request"} in res) - self.assertTrue({"name": "User"} in res) - self.assertFalse({"name": "Blogger"} in res) + res = DatabaseQuery('DocType').execute(filters={'autoname': ['is', 'not set']}) + self.assertTrue({'name': 'User'} in res) + self.assertFalse({'name': 'Blogger'} in res) res = DatabaseQuery("DocType").execute(filters={"autoname": ["is", "set"]}) self.assertTrue({"name": "DocField"} in res) From 6c75787d406b9e1eb1d3e48715ba7d201ae52f8b Mon Sep 17 00:00:00 2001 From: phot0n Date: Wed, 6 Apr 2022 11:34:33 +0530 Subject: [PATCH 21/48] chore: remove payments section from webform doctype --- frappe/website/doctype/web_form/web_form.json | 56 ------------------- 1 file changed, 56 deletions(-) diff --git a/frappe/website/doctype/web_form/web_form.json b/frappe/website/doctype/web_form/web_form.json index 0872c1d654..56b957e274 100644 --- a/frappe/website/doctype/web_form/web_form.json +++ b/frappe/website/doctype/web_form/web_form.json @@ -233,62 +233,6 @@ "fieldtype": "Check", "label": "Show Sidebar" }, - { - "default": "0", - "fieldname": "accept_payment", - "fieldtype": "Check", - "label": "Accept Payment" - }, - { - "depends_on": "accept_payment", - "fieldname": "payment_gateway", - "fieldtype": "Link", - "label": "Payment Gateway", - "options": "Payment Gateway" - }, - { - "default": "Buy Now", - "depends_on": "accept_payment", - "fieldname": "payment_button_label", - "fieldtype": "Data", - "label": "Button Label" - }, - { - "depends_on": "accept_payment", - "fieldname": "payment_button_help", - "fieldtype": "Text", - "label": "Button Help" - }, - { - "fieldname": "column_break_28", - "fieldtype": "Column Break" - }, - { - "default": "0", - "depends_on": "accept_payment", - "fieldname": "amount_based_on_field", - "fieldtype": "Check", - "label": "Amount Based On Field" - }, - { - "depends_on": "eval:doc.accept_payment && doc.amount_based_on_field", - "fieldname": "amount_field", - "fieldtype": "Select", - "label": "Amount Field" - }, - { - "depends_on": "eval:doc.accept_payment && !doc.amount_based_on_field", - "fieldname": "amount", - "fieldtype": "Currency", - "label": "Amount" - }, - { - "depends_on": "accept_payment", - "fieldname": "currency", - "fieldtype": "Link", - "label": "Currency", - "options": "Currency" - }, { "description": "List as [{\"label\": _(\"Jobs\"), \"route\":\"jobs\"}]", "fieldname": "breadcrumbs", From be4b7906c0a0e5f8df39a50d3945f474a7f751c3 Mon Sep 17 00:00:00 2001 From: phot0n Date: Wed, 6 Apr 2022 23:03:26 +0530 Subject: [PATCH 22/48] chore: remove payment stuff from web form controller class --- frappe/website/doctype/web_form/web_form.py | 41 +-------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py index e1c9e798e5..836ec8f632 100644 --- a/frappe/website/doctype/web_form/web_form.py +++ b/frappe/website/doctype/web_form/web_form.py @@ -10,7 +10,6 @@ from frappe.core.api.file import get_max_file_size from frappe.core.doctype.file import remove_file_by_url from frappe.custom.doctype.customize_form.customize_form import docfield_properties from frappe.desk.form.meta import get_code_files_via_hooks -from frappe.integrations.utils import get_payment_gateway_controller from frappe.modules.utils import export_module_json, get_doc_module from frappe.rate_limiter import rate_limit from frappe.utils import cstr, dict_with_keys, strip_html @@ -50,9 +49,6 @@ class WebForm(WebsiteGenerator): if not frappe.flags.in_import: self.validate_fields() - if self.accept_payment: - self.validate_payment_amount() - def validate_fields(self): """Validate all fields are present""" from frappe.model import no_value_fields @@ -66,12 +62,6 @@ class WebForm(WebsiteGenerator): if missing: frappe.throw(_("Following fields are missing:") + "
" + "
".join(missing)) - def validate_payment_amount(self): - if self.amount_based_on_field and not self.amount_field: - frappe.throw(_("Please select a Amount Field.")) - elif not self.amount_based_on_field and not self.amount > 0: - frappe.throw(_("Amount must be greater than 0.")) - def reset_field_parent(self): """Convert link fields to select with names as options""" for df in self.web_form_fields: @@ -320,36 +310,6 @@ def get_context(context): context.reference_doc = json.loads(context.reference_doc.as_json()) - def get_payment_gateway_url(self, doc): - if self.accept_payment: - controller = get_payment_gateway_controller(self.payment_gateway) - - title = f"Payment for {doc.doctype} {doc.name}" - amount = self.amount - if self.amount_based_on_field: - amount = doc.get(self.amount_field) - - from decimal import Decimal - - if amount is None or Decimal(amount) <= 0: - return frappe.utils.get_url(self.success_url or self.route) - - payment_details = { - "amount": amount, - "title": title, - "description": title, - "reference_doctype": doc.doctype, - "reference_docname": doc.name, - "payer_email": frappe.session.user, - "payer_name": frappe.utils.get_fullname(frappe.session.user), - "order_id": doc.name, - "currency": self.currency, - "redirect_to": frappe.utils.get_url(self.success_url or self.route), - } - - # Redirect the user to this url - return controller.get_payment_url(**payment_details) - def add_custom_context_and_script(self, context): """Update context from module if standard and append script""" if self.web_form_module: @@ -591,6 +551,7 @@ def accept(web_form, data, docname=None, for_payment=False): frappe.flags.web_form_doc = doc if for_payment: + # this is needed for Payments app return web_form.get_payment_gateway_url(doc) else: return doc From 83fe747f755c369245e7f5eb2b2d633944d094e4 Mon Sep 17 00:00:00 2001 From: phot0n Date: Thu, 7 Apr 2022 00:03:42 +0530 Subject: [PATCH 23/48] chore: remove payment utils and hooks --- frappe/hooks.py | 3 +- frappe/integrations/utils.py | 108 ----------------------------------- 2 files changed, 1 insertion(+), 110 deletions(-) diff --git a/frappe/hooks.py b/frappe/hooks.py index 66820ecd0f..90c64b006f 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -199,8 +199,7 @@ scheduler_events = { "frappe.email.queue.flush", "frappe.email.doctype.email_account.email_account.pull", "frappe.email.doctype.email_account.email_account.notify_unreplied", - "frappe.integrations.doctype.razorpay_settings.razorpay_settings.capture_payment", - "frappe.utils.global_search.sync_global_search", + 'frappe.utils.global_search.sync_global_search', "frappe.monitor.flush", ], "hourly": [ diff --git a/frappe/integrations/utils.py b/frappe/integrations/utils.py index f215a73dc6..8d3d23bb85 100644 --- a/frappe/integrations/utils.py +++ b/frappe/integrations/utils.py @@ -2,7 +2,6 @@ # License: MIT. See LICENSE import datetime -import json from urllib.parse import parse_qs import frappe @@ -28,122 +27,15 @@ def make_request(method, url, auth=None, headers=None, data=None): frappe.log_error() raise exc - def make_get_request(url, **kwargs): return make_request("GET", url, **kwargs) - def make_post_request(url, **kwargs): return make_request("POST", url, **kwargs) - def make_put_request(url, **kwargs): return make_request("PUT", url, **kwargs) - -def create_request_log( - data, - integration_type=None, - service_name=None, - name=None, - error=None, - request_headers=None, - output=None, - **kwargs, -): - """ - DEPRECATED: The parameter integration_type will be removed in the next major release. - Use is_remote_request instead. - """ - if integration_type == "Remote": - kwargs["is_remote_request"] = 1 - - elif integration_type == "Subscription Notification": - kwargs["request_description"] = integration_type - - reference_doctype = reference_docname = None - if "reference_doctype" not in kwargs: - if isinstance(data, str): - data = json.loads(data) - - reference_doctype = data.get("reference_doctype") - reference_docname = data.get("reference_docname") - - integration_request = frappe.get_doc( - { - "doctype": "Integration Request", - "integration_request_service": service_name, - "request_headers": get_json(request_headers), - "data": get_json(data), - "output": get_json(output), - "error": get_json(error), - "reference_doctype": reference_doctype, - "reference_docname": reference_docname, - **kwargs, - } - ) - - if name: - integration_request.flags._name = name - - integration_request.insert(ignore_permissions=True) - frappe.db.commit() - - return integration_request - - -def get_json(obj): - return obj if isinstance(obj, str) else frappe.as_json(obj, indent=1) - - -def get_payment_gateway_controller(payment_gateway): - """Return payment gateway controller""" - gateway = frappe.get_doc("Payment Gateway", payment_gateway) - if gateway.gateway_controller is None: - try: - return frappe.get_doc(f"{payment_gateway} Settings") - except Exception: - frappe.throw(_("{0} Settings not found").format(payment_gateway)) - else: - try: - return frappe.get_doc(gateway.gateway_settings, gateway.gateway_controller) - except Exception: - frappe.throw(_("{0} Settings not found").format(payment_gateway)) - - -@frappe.whitelist(allow_guest=True, xss_safe=True) -def get_checkout_url(**kwargs): - try: - if kwargs.get("payment_gateway"): - doc = frappe.get_doc("{} Settings".format(kwargs.get("payment_gateway"))) - return doc.get_payment_url(**kwargs) - else: - raise Exception - except Exception: - frappe.respond_as_web_page( - _("Something went wrong"), - _( - "Looks like something is wrong with this site's payment gateway configuration. No payment has been made." - ), - indicator_color="red", - http_status_code=frappe.ValidationError.http_status_code, - ) - - -def create_payment_gateway(gateway, settings=None, controller=None): - # NOTE: we don't translate Payment Gateway name because it is an internal doctype - if not frappe.db.exists("Payment Gateway", gateway): - payment_gateway = frappe.get_doc( - { - "doctype": "Payment Gateway", - "gateway": gateway, - "gateway_settings": settings, - "gateway_controller": controller, - } - ) - payment_gateway.insert(ignore_permissions=True) - - def json_handler(obj): if isinstance(obj, (datetime.date, datetime.timedelta, datetime.datetime)): return str(obj) From 70284ad6b0397cdac89bd81f1df57d777b2f71e6 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 26 Jul 2022 15:39:37 +0000 Subject: [PATCH 24/48] fix: use comma as separator instead of space for offset (#17627) --- frappe/public/js/frappe/ui/filters/filter_list.js | 2 +- frappe/public/js/frappe/ui/group_by/group_by.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/ui/filters/filter_list.js b/frappe/public/js/frappe/ui/filters/filter_list.js index 5e13f086cb..6d90aaa7eb 100644 --- a/frappe/public/js/frappe/ui/filters/filter_list.js +++ b/frappe/public/js/frappe/ui/filters/filter_list.js @@ -31,7 +31,7 @@ frappe.ui.FilterGroup = class { trigger: 'manual', container: 'body', placement: 'bottom', - offset: '-100px 0' + offset: '-100px, 0' }); } diff --git a/frappe/public/js/frappe/ui/group_by/group_by.js b/frappe/public/js/frappe/ui/group_by/group_by.js index 692d675c62..9625e1d2af 100644 --- a/frappe/public/js/frappe/ui/group_by/group_by.js +++ b/frappe/public/js/frappe/ui/group_by/group_by.js @@ -42,7 +42,7 @@ frappe.ui.GroupBy = class { trigger: 'manual', container: 'body', placement: 'bottom', - offset: '-100px 0', + offset: '-100px, 0', }); } From 84c6c09b804755c3733c6993ec7d4bfb6a0576be Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 26 Jul 2022 15:40:54 +0000 Subject: [PATCH 25/48] fix: fallback to unscrubbed table fieldname if label not found (#17599) --- frappe/public/js/frappe/form/save.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/save.js b/frappe/public/js/frappe/form/save.js index f1cb42250a..d1486ea5d7 100644 --- a/frappe/public/js/frappe/form/save.js +++ b/frappe/public/js/frappe/form/save.js @@ -156,7 +156,12 @@ frappe.ui.form.save = function (frm, action, callback, btn) { if (error_fields.length) { let meta = frappe.get_meta(doc.doctype); if (meta.istable) { - const table_label = __(frappe.meta.docfield_map[doc.parenttype][doc.parentfield].label).bold(); + const table_field = frappe.meta.docfield_map[doc.parenttype][doc.parentfield]; + + const table_label = __( + table_field.label || frappe.unscrub(table_field.fieldname) + ).bold(); + var message = __('Mandatory fields required in table {0}, Row {1}', [table_label, doc.idx]); } else { var message = __('Mandatory fields required in {0}', [__(doc.doctype)]); From 91b04c21544a6d2e2ac5c79cfa6d2e075b34efcc Mon Sep 17 00:00:00 2001 From: phot0n Date: Sat, 23 Jul 2022 16:16:06 +0530 Subject: [PATCH 26/48] test: fix test_set_field_tables removed amount_field from groupby and fields --- frappe/tests/test_db_query.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py index e031bc87e3..03bdf8b5ee 100644 --- a/frappe/tests/test_db_query.py +++ b/frappe/tests/test_db_query.py @@ -516,8 +516,7 @@ class TestReportview(unittest.TestCase): data = frappe.db.get_list( "Web Form", filters=[["Web Form Field", "reqd", "=", 1]], - group_by="amount_field", - fields=["count(*) as count", "`amount_field` as name"], + fields=["count(*) as count"], order_by="count desc", limit=50, ) From f71562fd49ba917cffaba2b4d93e15705a672b35 Mon Sep 17 00:00:00 2001 From: phot0n Date: Sat, 23 Jul 2022 16:23:06 +0530 Subject: [PATCH 27/48] chore: add integration request doctype back (with utils) --- .../doctype/integration_request/__init__.py | 0 .../integration_request.js | 8 + .../integration_request.json | 154 ++++++++++++++++++ .../integration_request.py | 37 +++++ .../test_integration_request.py | 11 ++ frappe/integrations/utils.py | 54 ++++++ 6 files changed, 264 insertions(+) create mode 100644 frappe/integrations/doctype/integration_request/__init__.py create mode 100644 frappe/integrations/doctype/integration_request/integration_request.js create mode 100644 frappe/integrations/doctype/integration_request/integration_request.json create mode 100644 frappe/integrations/doctype/integration_request/integration_request.py create mode 100644 frappe/integrations/doctype/integration_request/test_integration_request.py diff --git a/frappe/integrations/doctype/integration_request/__init__.py b/frappe/integrations/doctype/integration_request/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frappe/integrations/doctype/integration_request/integration_request.js b/frappe/integrations/doctype/integration_request/integration_request.js new file mode 100644 index 0000000000..4b3b9a2de7 --- /dev/null +++ b/frappe/integrations/doctype/integration_request/integration_request.js @@ -0,0 +1,8 @@ +// Copyright (c) 2016, Frappe Technologies and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Integration Request', { + refresh: function(frm) { + + } +}); diff --git a/frappe/integrations/doctype/integration_request/integration_request.json b/frappe/integrations/doctype/integration_request/integration_request.json new file mode 100644 index 0000000000..98db8ea748 --- /dev/null +++ b/frappe/integrations/doctype/integration_request/integration_request.json @@ -0,0 +1,154 @@ +{ + "actions": [], + "creation": "2022-03-28 12:25:29.929952", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "request_id", + "integration_request_service", + "is_remote_request", + "column_break_5", + "request_description", + "status", + "section_break_8", + "url", + "request_headers", + "data", + "response_section", + "output", + "error", + "reference_section", + "reference_doctype", + "column_break_16", + "reference_docname" + ], + "fields": [ + { + "fieldname": "integration_request_service", + "fieldtype": "Data", + "label": "Service", + "read_only": 1 + }, + { + "default": "Queued", + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Status", + "options": "\nQueued\nAuthorized\nCompleted\nCancelled\nFailed", + "read_only": 1 + }, + { + "fieldname": "data", + "fieldtype": "Code", + "label": "Request Data", + "read_only": 1 + }, + { + "fieldname": "output", + "fieldtype": "Code", + "label": "Output", + "read_only": 1 + }, + { + "fieldname": "error", + "fieldtype": "Code", + "label": "Error", + "read_only": 1 + }, + { + "fieldname": "reference_doctype", + "fieldtype": "Link", + "label": "Reference Document Type", + "options": "DocType", + "read_only": 1 + }, + { + "fieldname": "reference_docname", + "fieldtype": "Dynamic Link", + "label": "Reference Document Name", + "options": "reference_doctype", + "read_only": 1 + }, + { + "default": "0", + "fieldname": "is_remote_request", + "fieldtype": "Check", + "label": "Is Remote Request?", + "read_only": 1 + }, + { + "fieldname": "request_description", + "fieldtype": "Data", + "label": "Request Description", + "read_only": 1 + }, + { + "fieldname": "request_id", + "fieldtype": "Data", + "label": "Request ID", + "read_only": 1 + }, + { + "fieldname": "column_break_5", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_8", + "fieldtype": "Section Break" + }, + { + "fieldname": "url", + "fieldtype": "Data", + "label": "URL", + "read_only": 1 + }, + { + "fieldname": "response_section", + "fieldtype": "Section Break", + "label": "Response" + }, + { + "depends_on": "eval:doc.reference_doctype", + "fieldname": "reference_section", + "fieldtype": "Section Break", + "label": "Reference" + }, + { + "fieldname": "column_break_16", + "fieldtype": "Column Break" + }, + { + "fieldname": "request_headers", + "fieldtype": "Code", + "label": "Request Headers", + "read_only": 1 + } + ], + "in_create": 1, + "links": [], + "modified": "2022-04-07 11:32:27.557548", + "modified_by": "Administrator", + "module": "Integrations", + "name": "Integration Request", + "owner": "Administrator", + "permissions": [ + { + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1 + } + ], + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "title_field": "integration_request_service", + "track_changes": 1 +} \ No newline at end of file diff --git a/frappe/integrations/doctype/integration_request/integration_request.py b/frappe/integrations/doctype/integration_request/integration_request.py new file mode 100644 index 0000000000..334736bc9b --- /dev/null +++ b/frappe/integrations/doctype/integration_request/integration_request.py @@ -0,0 +1,37 @@ +# Copyright (c) 2015, Frappe Technologies and contributors +# License: MIT. See LICENSE + +import json + +import frappe +from frappe.integrations.utils import json_handler +from frappe.model.document import Document + + +class IntegrationRequest(Document): + def autoname(self): + if self.flags._name: + self.name = self.flags._name + + def update_status(self, params, status): + data = json.loads(self.data) + data.update(params) + + self.data = json.dumps(data) + self.status = status + self.save(ignore_permissions=True) + frappe.db.commit() + + def handle_success(self, response): + """update the output field with the response along with the relevant status""" + if isinstance(response, str): + response = json.loads(response) + self.db_set("status", "Completed") + self.db_set("output", json.dumps(response, default=json_handler)) + + def handle_failure(self, response): + """update the error field with the response along with the relevant status""" + if isinstance(response, str): + response = json.loads(response) + self.db_set("status", "Failed") + self.db_set("error", json.dumps(response, default=json_handler)) diff --git a/frappe/integrations/doctype/integration_request/test_integration_request.py b/frappe/integrations/doctype/integration_request/test_integration_request.py new file mode 100644 index 0000000000..45963d5096 --- /dev/null +++ b/frappe/integrations/doctype/integration_request/test_integration_request.py @@ -0,0 +1,11 @@ +# Copyright (c) 2015, Frappe Technologies and Contributors +# License: MIT. See LICENSE +import unittest + +import frappe + +# test_records = frappe.get_test_records('Integration Request') + + +class TestIntegrationRequest(unittest.TestCase): + pass diff --git a/frappe/integrations/utils.py b/frappe/integrations/utils.py index 8d3d23bb85..b05d2ef74d 100644 --- a/frappe/integrations/utils.py +++ b/frappe/integrations/utils.py @@ -2,6 +2,7 @@ # License: MIT. See LICENSE import datetime +import json from urllib.parse import parse_qs import frappe @@ -36,6 +37,59 @@ def make_post_request(url, **kwargs): def make_put_request(url, **kwargs): return make_request("PUT", url, **kwargs) +def create_request_log( + data, + integration_type=None, + service_name=None, + name=None, + error=None, + request_headers=None, + output=None, + **kwargs, +): + """ + DEPRECATED: The parameter integration_type will be removed in the next major release. + Use is_remote_request instead. + """ + if integration_type == "Remote": + kwargs["is_remote_request"] = 1 + + elif integration_type == "Subscription Notification": + kwargs["request_description"] = integration_type + + reference_doctype = reference_docname = None + if "reference_doctype" not in kwargs: + if isinstance(data, str): + data = json.loads(data) + + reference_doctype = data.get("reference_doctype") + reference_docname = data.get("reference_docname") + + integration_request = frappe.get_doc( + { + "doctype": "Integration Request", + "integration_request_service": service_name, + "request_headers": get_json(request_headers), + "data": get_json(data), + "output": get_json(output), + "error": get_json(error), + "reference_doctype": reference_doctype, + "reference_docname": reference_docname, + **kwargs, + } + ) + + if name: + integration_request.flags._name = name + + integration_request.insert(ignore_permissions=True) + frappe.db.commit() + + return integration_request + +def get_json(obj): + return obj if isinstance(obj, str) else frappe.as_json(obj, indent=1) + def json_handler(obj): if isinstance(obj, (datetime.date, datetime.timedelta, datetime.datetime)): return str(obj) From a52483f110cb040ebd2e46a1dade30607c55577a Mon Sep 17 00:00:00 2001 From: phot0n Date: Sat, 23 Jul 2022 16:23:10 +0530 Subject: [PATCH 28/48] Revert "fix: remove integration request check from test_is_set_is_not_set" This reverts commit b3f57f0e7774928df90bdf84c7ec23b5d3be53c8. --- frappe/tests/test_db_query.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py index 03bdf8b5ee..0eb54c7ab0 100644 --- a/frappe/tests/test_db_query.py +++ b/frappe/tests/test_db_query.py @@ -501,9 +501,10 @@ class TestReportview(unittest.TestCase): ) def test_is_set_is_not_set(self): - res = DatabaseQuery('DocType').execute(filters={'autoname': ['is', 'not set']}) - self.assertTrue({'name': 'User'} in res) - self.assertFalse({'name': 'Blogger'} in res) + res = DatabaseQuery("DocType").execute(filters={"autoname": ["is", "not set"]}) + self.assertTrue({"name": "Integration Request"} in res) + self.assertTrue({"name": "User"} in res) + self.assertFalse({"name": "Blogger"} in res) res = DatabaseQuery("DocType").execute(filters={"autoname": ["is", "set"]}) self.assertTrue({"name": "DocField"} in res) From 090d0321a8cf2da00696302093278bc9f8741813 Mon Sep 17 00:00:00 2001 From: phot0n Date: Sat, 23 Jul 2022 17:27:50 +0530 Subject: [PATCH 29/48] chore: fix linter --- frappe/hooks.py | 2 +- frappe/integrations/utils.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/frappe/hooks.py b/frappe/hooks.py index 90c64b006f..14e76adc22 100644 --- a/frappe/hooks.py +++ b/frappe/hooks.py @@ -199,7 +199,7 @@ scheduler_events = { "frappe.email.queue.flush", "frappe.email.doctype.email_account.email_account.pull", "frappe.email.doctype.email_account.email_account.notify_unreplied", - 'frappe.utils.global_search.sync_global_search', + "frappe.utils.global_search.sync_global_search", "frappe.monitor.flush", ], "hourly": [ diff --git a/frappe/integrations/utils.py b/frappe/integrations/utils.py index b05d2ef74d..5ae8965c83 100644 --- a/frappe/integrations/utils.py +++ b/frappe/integrations/utils.py @@ -28,15 +28,19 @@ def make_request(method, url, auth=None, headers=None, data=None): frappe.log_error() raise exc + def make_get_request(url, **kwargs): return make_request("GET", url, **kwargs) + def make_post_request(url, **kwargs): return make_request("POST", url, **kwargs) + def make_put_request(url, **kwargs): return make_request("PUT", url, **kwargs) + def create_request_log( data, integration_type=None, @@ -87,9 +91,11 @@ def create_request_log( return integration_request + def get_json(obj): return obj if isinstance(obj, str) else frappe.as_json(obj, indent=1) + def json_handler(obj): if isinstance(obj, (datetime.date, datetime.timedelta, datetime.datetime)): return str(obj) From a02bd94d16368bee40a2ba7bfb6baba7d7751f30 Mon Sep 17 00:00:00 2001 From: phot0n Date: Sat, 23 Jul 2022 18:39:23 +0530 Subject: [PATCH 30/48] chore: remove payment gateway libraries --- pyproject.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2d9027309d..3c47edc440 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,16 +75,12 @@ dependencies = [ # integration dependencies "boto3~=1.17.53", - "braintree~=4.8.0", "dropbox~=11.7.0", "google-api-python-client~=2.2.0", "google-auth-httplib2~=0.1.0", "google-auth-oauthlib~=0.4.4", "google-auth~=1.29.0", "googlemaps~=4.4.5", - "paytmchecksum~=1.7.0", - "razorpay~=1.2.0", - "stripe~=2.56.0", ] [build-system] From 4b069374f5b3649405d7cde920b86db7cf8e0162 Mon Sep 17 00:00:00 2001 From: phot0n Date: Sat, 23 Jul 2022 18:43:59 +0530 Subject: [PATCH 31/48] chore: remove stripe patch --- frappe/patches.txt | 1 - .../sync_stripe_settings_before_migrate.py | 25 ------------------- 2 files changed, 26 deletions(-) delete mode 100644 frappe/patches/v11_0/sync_stripe_settings_before_migrate.py diff --git a/frappe/patches.txt b/frappe/patches.txt index ee2eb0d2a1..240a96cb7d 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -66,7 +66,6 @@ execute:frappe.delete_doc_if_exists('Page', 'user-permissions') frappe.patches.v10_0.set_no_copy_to_workflow_state frappe.patches.v10_0.increase_single_table_column_length frappe.patches.v11_0.create_contact_for_user -frappe.patches.v11_0.sync_stripe_settings_before_migrate frappe.patches.v11_0.update_list_user_settings frappe.patches.v11_0.rename_workflow_action_to_workflow_action_master #13-06-2018 frappe.patches.v11_0.rename_email_alert_to_notification #13-06-2018 diff --git a/frappe/patches/v11_0/sync_stripe_settings_before_migrate.py b/frappe/patches/v11_0/sync_stripe_settings_before_migrate.py deleted file mode 100644 index 019ecef67c..0000000000 --- a/frappe/patches/v11_0/sync_stripe_settings_before_migrate.py +++ /dev/null @@ -1,25 +0,0 @@ -import frappe -from frappe.utils.password import get_decrypted_password - - -def execute(): - publishable_key = frappe.db.sql( - "select value from tabSingles where doctype='Stripe Settings' and field='publishable_key'" - ) - if publishable_key: - secret_key = get_decrypted_password( - "Stripe Settings", "Stripe Settings", fieldname="secret_key", raise_exception=False - ) - if secret_key: - frappe.reload_doc("integrations", "doctype", "stripe_settings") - frappe.db.commit() - - settings = frappe.new_doc("Stripe Settings") - settings.gateway_name = ( - frappe.db.get_value("Global Defaults", None, "default_company") or "Stripe Settings" - ) - settings.publishable_key = publishable_key - settings.secret_key = secret_key - settings.save(ignore_permissions=True) - - frappe.db.delete("Singles", {"doctype": "Stripe Settings"}) From a2571b5490726cd1454b3de1ab1b3a0fb769fc4b Mon Sep 17 00:00:00 2001 From: phot0n Date: Sun, 24 Jul 2022 01:40:35 +0530 Subject: [PATCH 32/48] chore: patch for deleting payment doctypes --- frappe/patches.txt | 1 + frappe/patches/v14_0/delete_payment_gateways.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 frappe/patches/v14_0/delete_payment_gateways.py diff --git a/frappe/patches.txt b/frappe/patches.txt index 240a96cb7d..0dce4b9f71 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -195,6 +195,7 @@ frappe.patches.v14_0.clear_long_pending_stale_logs frappe.patches.v14_0.log_settings_migration frappe.patches.v14_0.setup_likes_from_feedback frappe.patches.v14_0.update_webforms +frappe.patches.v14_0.delete_payment_gateways [post_model_sync] frappe.patches.v14_0.drop_data_import_legacy diff --git a/frappe/patches/v14_0/delete_payment_gateways.py b/frappe/patches/v14_0/delete_payment_gateways.py new file mode 100644 index 0000000000..c06f63a2d3 --- /dev/null +++ b/frappe/patches/v14_0/delete_payment_gateways.py @@ -0,0 +1,16 @@ +import frappe + + +def execute(): + if "payments" in frappe.get_installed_apps(): + return + + for doctype in ( + "Payment Gateway", + "Razorpay Settings", + "Braintree Settings", + "PayPal Settings", + "Paytm Settings", + "Stripe Settings", + ): + frappe.delete_doc_if_exists("DocType", doctype, force=True) From 332919317d2f8c0b02de951a74d6b46e8d1ef606 Mon Sep 17 00:00:00 2001 From: phot0n Date: Sun, 24 Jul 2022 20:31:00 +0530 Subject: [PATCH 33/48] chore: remove payments_tab from web form --- frappe/website/doctype/web_form/web_form.json | 21 ++----------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/frappe/website/doctype/web_form/web_form.json b/frappe/website/doctype/web_form/web_form.json index 56b957e274..f9ebb3a4e7 100644 --- a/frappe/website/doctype/web_form/web_form.json +++ b/frappe/website/doctype/web_form/web_form.json @@ -48,17 +48,7 @@ "website_sidebar", "scripting_style_tab", "client_script", - "custom_css", - "payments_tab", - "accept_payment", - "payment_gateway", - "payment_button_label", - "payment_button_help", - "column_break_28", - "amount_based_on_field", - "amount_field", - "amount", - "currency" + "custom_css" ], "fields": [ { @@ -329,20 +319,13 @@ "fieldname": "scripting_style_tab", "fieldtype": "Tab Break", "label": "Scripting / Style" - }, - { - "collapsible": 1, - "collapsible_depends_on": "accept_payment", - "fieldname": "payments_tab", - "fieldtype": "Tab Break", - "label": "Payments" } ], "has_web_view": 1, "icon": "icon-edit", "is_published_field": "published", "links": [], - "modified": "2022-07-18 15:51:15.288860", + "modified": "2022-07-24 20:29:23.059834", "modified_by": "Administrator", "module": "Website", "name": "Web Form", From a1ffcb37ee5a00e9129d60ee2952eed77d73f9e2 Mon Sep 17 00:00:00 2001 From: phot0n Date: Mon, 25 Jul 2022 14:07:33 +0530 Subject: [PATCH 34/48] chore: remove payments fields from edit_profile, request_data & request_to_delete_data webforms --- frappe/core/web_form/edit_profile/edit_profile.json | 3 --- frappe/website/web_form/request_data/request_data.json | 5 ----- .../request_to_delete_data/request_to_delete_data.json | 5 ----- 3 files changed, 13 deletions(-) diff --git a/frappe/core/web_form/edit_profile/edit_profile.json b/frappe/core/web_form/edit_profile/edit_profile.json index cedef71c0e..8abb2164f9 100644 --- a/frappe/core/web_form/edit_profile/edit_profile.json +++ b/frappe/core/web_form/edit_profile/edit_profile.json @@ -1,13 +1,10 @@ { - "accept_payment": 0, "allow_comments": 0, "allow_delete": 0, "allow_edit": 1, "allow_incomplete": 0, "allow_multiple": 0, "allow_print": 0, - "amount": 0.0, - "amount_based_on_field": 0, "apply_document_permissions": 0, "breadcrumbs": "[{\"title\": _(\"My Account\"), \"route\": \"me\"}]", "creation": "2016-09-19 05:16:59.242754", diff --git a/frappe/website/web_form/request_data/request_data.json b/frappe/website/web_form/request_data/request_data.json index c52a2f6203..e895ec9ff4 100644 --- a/frappe/website/web_form/request_data/request_data.json +++ b/frappe/website/web_form/request_data/request_data.json @@ -1,19 +1,15 @@ { - "accept_payment": 0, "allow_comments": 0, "allow_delete": 0, "allow_edit": 0, "allow_incomplete": 0, "allow_multiple": 0, "allow_print": 0, - "amount": 0.0, - "amount_based_on_field": 0, "apply_document_permissions": 0, "breadcrumbs": "", "button_label": "Request Data", "client_script": "", "creation": "2019-01-24 16:19:26.886096", - "currency": "INR", "doc_type": "Personal Data Download Request", "docstatus": 0, "doctype": "Web Form", @@ -29,7 +25,6 @@ "module": "Website", "name": "request-data", "owner": "Administrator", - "payment_button_label": "Buy Now", "published": 1, "route": "request-data", "route_to_success_link": 1, diff --git a/frappe/website/web_form/request_to_delete_data/request_to_delete_data.json b/frappe/website/web_form/request_to_delete_data/request_to_delete_data.json index ce11666a34..b3bf7d6b42 100644 --- a/frappe/website/web_form/request_to_delete_data/request_to_delete_data.json +++ b/frappe/website/web_form/request_to_delete_data/request_to_delete_data.json @@ -1,19 +1,15 @@ { - "accept_payment": 0, "allow_comments": 0, "allow_delete": 0, "allow_edit": 0, "allow_incomplete": 0, "allow_multiple": 0, "allow_print": 0, - "amount": 0.0, - "amount_based_on_field": 0, "apply_document_permissions": 0, "breadcrumbs": "", "button_label": "Submit", "client_script": "", "creation": "2019-01-25 14:24:12.588810", - "currency": "INR", "custom_css": "[data-doctype=\"Web Form\"] {\n width: 50%;\n margin: 6rem auto;\n}", "doc_type": "Personal Data Deletion Request", "docstatus": 0, @@ -30,7 +26,6 @@ "module": "Website", "name": "request-to-delete-data", "owner": "Administrator", - "payment_button_label": "Buy Now", "published": 1, "route": "request-for-account-deletion", "route_to_success_link": 0, From cd2664bf998d5b1804f0382fb24dfe0cadd889f5 Mon Sep 17 00:00:00 2001 From: phot0n Date: Tue, 26 Jul 2022 23:18:23 +0530 Subject: [PATCH 35/48] chore: remove get_payment_gateway_controller safe global --- frappe/utils/safe_exec.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/utils/safe_exec.py b/frappe/utils/safe_exec.py index 8e983f11b2..6fdfba19e3 100644 --- a/frappe/utils/safe_exec.py +++ b/frappe/utils/safe_exec.py @@ -146,7 +146,6 @@ def get_safe_globals(): ), make_get_request=frappe.integrations.utils.make_get_request, make_post_request=frappe.integrations.utils.make_post_request, - get_payment_gateway_controller=frappe.integrations.utils.get_payment_gateway_controller, socketio_port=frappe.conf.socketio_port, get_hooks=get_hooks, enqueue=safe_enqueue, From 0b9a9ebfac598d732be656e99e4e326bb170d620 Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Wed, 27 Jul 2022 10:42:01 +0530 Subject: [PATCH 36/48] fix: load avatars of user in notification dropdown (#17630) --- .../notification_log/notification_log.py | 16 +++++++++++++++ .../frappe/ui/notifications/notifications.js | 20 ++++++++++--------- frappe/public/js/frappe/utils/user.js | 10 ++++++++++ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/frappe/desk/doctype/notification_log/notification_log.py b/frappe/desk/doctype/notification_log/notification_log.py index 17734635dd..482f404e65 100644 --- a/frappe/desk/doctype/notification_log/notification_log.py +++ b/frappe/desk/doctype/notification_log/notification_log.py @@ -133,6 +133,22 @@ def get_email_header(doc): return header_map[doc.type or "Default"] +@frappe.whitelist() +def get_notification_logs(limit=20): + notification_logs = frappe.db.get_list( + "Notification Log", fields=["*"], limit=limit, order_by="creation desc" + ) + + users = [log.from_user for log in notification_logs] + users = [*set(users)] # remove duplicates + user_info = frappe._dict() + + for user in users: + frappe.utils.add_user_info(user, user_info) + + return {"notification_logs": notification_logs, "user_info": user_info} + + @frappe.whitelist() def mark_all_as_read(): unread_docs_list = frappe.db.get_all( diff --git a/frappe/public/js/frappe/ui/notifications/notifications.js b/frappe/public/js/frappe/ui/notifications/notifications.js index bf1cee2cbf..4d20ef1414 100644 --- a/frappe/public/js/frappe/ui/notifications/notifications.js +++ b/frappe/public/js/frappe/ui/notifications/notifications.js @@ -189,19 +189,22 @@ class NotificationsView extends BaseNotificationsView { ); this.setup_notification_listeners(); - this.get_notifications_list(this.max_length).then(list => { - this.dropdown_items = list; + this.get_notifications_list(this.max_length).then(r => { + if (!r.message) return; + this.dropdown_items = r.message.notification_logs; + frappe.update_user_info(r.message.user_info); this.render_notifications_dropdown(); if (this.settings.seen == 0) { this.toggle_notification_icon(false); } }); - } update_dropdown() { this.get_notifications_list(1).then(r => { - let new_item = r[0]; + if (!r.message) return; + let new_item = r.message.notification_logs[0]; + frappe.update_user_info(r.message.user_info); this.dropdown_items.unshift(new_item); if (this.dropdown_items.length > this.max_length) { this.container @@ -322,11 +325,10 @@ class NotificationsView extends BaseNotificationsView { } get_notifications_list(limit) { - return frappe.db.get_list('Notification Log', { - fields: ['*'], - limit: limit, - order_by: 'creation desc' - }); + return frappe.call( + 'frappe.desk.doctype.notification_log.notification_log.get_notification_logs', + { limit: limit } + ); } get_item_link(notification_doc) { diff --git a/frappe/public/js/frappe/utils/user.js b/frappe/public/js/frappe/utils/user.js index a5a7801cc1..e888fbcd9a 100644 --- a/frappe/public/js/frappe/utils/user.js +++ b/frappe/public/js/frappe/utils/user.js @@ -14,6 +14,16 @@ frappe.user_info = function(uid) { return user_info; }; +frappe.update_user_info = function(user_info) { + for (let user in user_info) { + if (frappe.boot.user_info[user]) { + Object.assign(frappe.boot.user_info[user], user_info[user]); + } else { + frappe.boot.user_info[user] = user_info[user]; + } + } +}; + frappe.provide('frappe.user'); $.extend(frappe.user, { From ed39d2c6ed9e9203a516a11ef67c80102f8d8489 Mon Sep 17 00:00:00 2001 From: phot0n Date: Wed, 27 Jul 2022 02:16:48 +0530 Subject: [PATCH 37/48] chore: remove payments params from webform's whitelisted accept fuction --- frappe/public/js/frappe/web_form/web_form.js | 2 ++ frappe/website/doctype/web_form/web_form.py | 14 ++------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/frappe/public/js/frappe/web_form/web_form.js b/frappe/public/js/frappe/web_form/web_form.js index 21d88eac49..8cb30be529 100644 --- a/frappe/public/js/frappe/web_form/web_form.js +++ b/frappe/public/js/frappe/web_form/web_form.js @@ -280,6 +280,7 @@ export default class WebForm extends frappe.ui.FieldGroup { if (!doc_values) return; if (window.saving) return; + // TODO: remove this (used for payments app) let for_payment = Boolean(this.accept_payment && !this.doc.paid); Object.assign(this.doc, doc_values); @@ -342,6 +343,7 @@ export default class WebForm extends frappe.ui.FieldGroup { } handle_success(data) { + // TODO: remove this (used for payments app) if (this.accept_payment && !this.doc.paid) { window.location.href = data; } diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py index 836ec8f632..95f58e12fd 100644 --- a/frappe/website/doctype/web_form/web_form.py +++ b/frappe/website/doctype/web_form/web_form.py @@ -454,10 +454,9 @@ def get_context(context): @frappe.whitelist(allow_guest=True) @rate_limit(key="web_form", limit=5, seconds=60, methods=["POST"]) -def accept(web_form, data, docname=None, for_payment=False): +def accept(web_form, data, docname=None): """Save the web form""" data = frappe._dict(json.loads(data)) - for_payment = frappe.parse_json(for_payment) files = [] files_to_delete = [] @@ -495,10 +494,6 @@ def accept(web_form, data, docname=None, for_payment=False): doc.set(fieldname, value) - if for_payment: - web_form.validate_mandatory(doc) - doc.run_method("validate_payment") - if doc.name: if web_form.has_web_form_permission(doc.doctype, doc.name, "write"): doc.save(ignore_permissions=True) @@ -549,12 +544,7 @@ def accept(web_form, data, docname=None, for_payment=False): remove_file_by_url(f, doctype=doc.doctype, name=doc.name) frappe.flags.web_form_doc = doc - - if for_payment: - # this is needed for Payments app - return web_form.get_payment_gateway_url(doc) - else: - return doc + return doc @frappe.whitelist() From f26894936e30876d29678c68549fed9fee87ffe6 Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Wed, 27 Jul 2022 11:27:23 +0530 Subject: [PATCH 38/48] fix: grid search breaks if filter from other grid pages (#17632) --- frappe/public/js/frappe/form/grid.js | 8 ++++---- frappe/public/js/frappe/form/grid_row.js | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/frappe/public/js/frappe/form/grid.js b/frappe/public/js/frappe/form/grid.js index 7bbe4b123a..6e8ee75ffd 100644 --- a/frappe/public/js/frappe/form/grid.js +++ b/frappe/public/js/frappe/form/grid.js @@ -298,15 +298,14 @@ export default class Grid { show_search: true }); - Object.keys(this.filter).length !== 0 && - this.update_search_columns(); + this.filter_applied && this.update_search_columns(); } update_search_columns() { for (const field in this.filter) { if (this.filter[field] && !this.header_search.search_columns[field]) { delete this.filter[field]; - this.data = this.get_data(Object.keys(this.filter).length !== 0); + this.data = this.get_data(this.filter_applied); break; } @@ -323,7 +322,8 @@ export default class Grid { refresh() { if (this.frm && this.frm.setting_dependency) return; - this.data = this.get_data(Object.keys(this.filter).length !== 0); + this.filter_applied = Object.keys(this.filter).length !== 0; + this.data = this.get_data(this.filter_applied); !this.wrapper && this.make(); let $rows = $(this.parent).find('.rows'); diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index a1c3dce91f..0d71b3b305 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -14,7 +14,7 @@ export default class GridRow { make() { var me = this; - this.wrapper = $('
').appendTo(this.parent).data("grid_row", this); + this.wrapper = $('
'); this.row = $('
').appendTo(this.wrapper) .on("click", function(e) { if($(e.target).hasClass('grid-row-check') || $(e.target).hasClass('row-index') || $(e.target).parent().hasClass('row-index')) { @@ -33,9 +33,9 @@ export default class GridRow { } else { this.render_row(); } - if(this.doc) { - this.set_data(); - } + + this.set_data(); + this.wrapper.appendTo(this.parent); } set_docfields(update=false) { @@ -55,8 +55,9 @@ export default class GridRow { set_data() { this.wrapper.data({ - "doc": this.doc - }) + "grid_row": this, + "doc": this.doc || "", + }); } set_row_index() { if(this.doc) { @@ -750,6 +751,7 @@ export default class GridRow { .option('disabled', Object.keys(this.grid.filter).length !== 0); this.grid.prevent_build = true; + this.grid.grid_pagination.go_to_page(1); this.grid.refresh(); this.grid.prevent_build = false; }, 500)); From 21bbe18cc497ed21ed7526c46e5d7f71c7a476d5 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 26 Jul 2022 01:41:08 +0530 Subject: [PATCH 39/48] fix: absolute option for terminal progress bar --- frappe/utils/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/frappe/utils/__init__.py b/frappe/utils/__init__.py index 82e1cb3510..47eae314f7 100644 --- a/frappe/utils/__init__.py +++ b/frappe/utils/__init__.py @@ -559,7 +559,7 @@ def is_cli() -> bool: return invoked_from_terminal -def update_progress_bar(txt, i, l): +def update_progress_bar(txt, i, l, absolute=False): if os.environ.get("CI"): if i == 0: sys.stdout.write(txt) @@ -581,8 +581,9 @@ def update_progress_bar(txt, i, l): complete = int(float(i + 1) / l * col) completion_bar = ("=" * complete).ljust(col, " ") - percent_complete = str(int(float(i + 1) / l * 100)) - sys.stdout.write(f"\r{txt}: [{completion_bar}] {percent_complete}%") + percent_complete = f"{str(int(float(i + 1) / l * 100))}%" + status = f"{i} of {l}" if absolute else percent_complete + sys.stdout.write(f"\r{txt}: [{completion_bar}] {status}") sys.stdout.flush() From 97429e801281e5c92d16e1d648040d5b299fc4d6 Mon Sep 17 00:00:00 2001 From: Aditya Hase Date: Wed, 27 Jul 2022 19:21:13 +0530 Subject: [PATCH 40/48] fix(report-view): Honor disable_auto_refresh and disable_count (#17641) --- frappe/public/js/frappe/list/base_list.js | 8 ++++++++ frappe/public/js/frappe/list/list_view.js | 8 -------- .../public/js/frappe/views/reports/report_view.js | 13 +++++++++++++ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/frappe/public/js/frappe/list/base_list.js b/frappe/public/js/frappe/list/base_list.js index e5272ccd91..912016d330 100644 --- a/frappe/public/js/frappe/list/base_list.js +++ b/frappe/public/js/frappe/list/base_list.js @@ -69,6 +69,14 @@ frappe.views.BaseList = class BaseList { ]; } + get_list_view_settings() { + return frappe + .call("frappe.desk.listview.get_list_settings", { + doctype: this.doctype, + }) + .then((doc) => (this.list_view_settings = doc.message || {})); + } + setup_fields() { this.set_fields(); this.build_fields(); diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index cbeda50e53..9c5dba3370 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -107,14 +107,6 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { return this.get_list_view_settings(); } - get_list_view_settings() { - return frappe - .call("frappe.desk.listview.get_list_settings", { - doctype: this.doctype, - }) - .then((doc) => (this.list_view_settings = doc.message || {})); - } - on_sort_change(sort_by, sort_order) { this.sort_by = sort_by; this.sort_order = sort_order; diff --git a/frappe/public/js/frappe/views/reports/report_view.js b/frappe/public/js/frappe/views/reports/report_view.js index 2ea780c13d..945ec83439 100644 --- a/frappe/public/js/frappe/views/reports/report_view.js +++ b/frappe/public/js/frappe/views/reports/report_view.js @@ -43,6 +43,7 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { this.add_totals_row = this.view_user_settings.add_totals_row || 0; this.chart_args = this.view_user_settings.chart_args; } + return this.get_list_view_settings(); } setup_view() { @@ -53,6 +54,9 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { } setup_events() { + if (this.list_view_settings?.disable_auto_refresh) { + return; + } frappe.realtime.on("list_update", (data) => this.on_update(data)); } @@ -216,6 +220,9 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { } render_count() { + if (this.list_view_settings?.disable_count) { + return; + } let $list_count = this.$paging_area.find('.list-count'); if (!$list_count.length) { $list_count = $('') @@ -1540,6 +1547,12 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView { }); } + if (frappe.user.has_role("System Manager")) { + if (this.get_view_settings) { + items.push(this.get_view_settings()); + } + } + return items.map(i => Object.assign(i, { standard: true })); } From cb6438158b3d184249d2e6a353ed07438b87ab48 Mon Sep 17 00:00:00 2001 From: Ritwik Puri Date: Wed, 27 Jul 2022 22:46:56 +0530 Subject: [PATCH 41/48] fix: don't use cache for sequence in mariadb (#17640) * fix: don't use cache for sequence in mariadb * chore: update sequence related comments --- frappe/database/database.py | 17 +++++++++++++++++ frappe/database/mariadb/database.py | 9 --------- frappe/database/mariadb/schema.py | 2 +- frappe/database/postgres/database.py | 6 ------ 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/frappe/database/database.py b/frappe/database/database.py index 68286507ba..c55704eb64 100644 --- a/frappe/database/database.py +++ b/frappe/database/database.py @@ -54,6 +54,23 @@ class Database: CHILD_TABLE_COLUMNS = ("parent", "parenttype", "parentfield") MAX_WRITES_PER_TRANSACTION = 200_000 + # NOTE: + # FOR MARIADB - using no cache - as during backup, if the sequence was used in anyform, + # it drops the cache and uses the next non cached value in setval query and + # puts that in the backup file, which will start the counter + # from that value when inserting any new record in the doctype. + # By default the cache is 1000 which will mess up the sequence when + # using the system after a restore. + # + # Another case could be if the cached values expire then also there is a chance of + # the cache being skipped. + # + # FOR POSTGRES - The sequence cache for postgres is per connection. + # Since we're opening and closing connections for every request this results in skipping the cache + # to the next non-cached value hence not using cache in postgres. + # ref: https://stackoverflow.com/questions/21356375/postgres-9-0-4-sequence-skipping-numbers + SEQUENCE_CACHE = 0 + class InvalidColumnName(frappe.ValidationError): pass diff --git a/frappe/database/mariadb/database.py b/frappe/database/mariadb/database.py index 5e6d62f842..303098049a 100644 --- a/frappe/database/mariadb/database.py +++ b/frappe/database/mariadb/database.py @@ -129,15 +129,6 @@ class MariaDBConnectionUtil: class MariaDBDatabase(MariaDBConnectionUtil, MariaDBExceptionUtil, Database): REGEX_CHARACTER = "regexp" - - # NOTE: using a very small cache - as during backup, if the sequence was used in anyform, - # it drops the cache and uses the next non cached value in setval query and - # puts that in the backup file, which will start the counter - # from that value when inserting any new record in the doctype. - # By default the cache is 1000 which will mess up the sequence when - # using the system after a restore. - # issue link: https://jira.mariadb.org/browse/MDEV-21786 - SEQUENCE_CACHE = 50 CONVERSION_MAP = conversions | { FIELD_TYPE.NEWDECIMAL: float, FIELD_TYPE.DATETIME: get_datetime, diff --git a/frappe/database/mariadb/schema.py b/frappe/database/mariadb/schema.py index 24a78012e1..99297fbab2 100644 --- a/frappe/database/mariadb/schema.py +++ b/frappe/database/mariadb/schema.py @@ -44,7 +44,7 @@ class MariaDBTable(DBTable): # NOTE: not used nextval func as default as the ability to restore # database with sequences has bugs in mariadb and gives a scary error. - # issue link: https://jira.mariadb.org/browse/MDEV-21786 + # issue link: https://jira.mariadb.org/browse/MDEV-20070 name_column = "name bigint primary key" # create table diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index 58b63e6547..cb566736ad 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -102,12 +102,6 @@ class PostgresExceptionUtil: class PostgresDatabase(PostgresExceptionUtil, Database): REGEX_CHARACTER = "~" - - # NOTE; The sequence cache for postgres is per connection. - # Since we're opening and closing connections for every transaction this results in skipping the cache - # to the next non-cached value hence not using cache in postgres. - # ref: https://stackoverflow.com/questions/21356375/postgres-9-0-4-sequence-skipping-numbers - SEQUENCE_CACHE = 0 default_port = "5432" def setup_type_map(self): From ed4412c55a56eab85d282fd0ad9c75be3edcefe5 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Thu, 28 Jul 2022 10:37:08 +0530 Subject: [PATCH 42/48] fix: Show notification indicator badge only if there are unread notifications --- frappe/public/js/frappe/ui/notifications/notifications.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/ui/notifications/notifications.js b/frappe/public/js/frappe/ui/notifications/notifications.js index bf1cee2cbf..0c36e151ec 100644 --- a/frappe/public/js/frappe/ui/notifications/notifications.js +++ b/frappe/public/js/frappe/ui/notifications/notifications.js @@ -192,7 +192,7 @@ class NotificationsView extends BaseNotificationsView { this.get_notifications_list(this.max_length).then(list => { this.dropdown_items = list; this.render_notifications_dropdown(); - if (this.settings.seen == 0) { + if (this.settings.seen == 0 && this.dropdown_items.length > 0) { this.toggle_notification_icon(false); } }); @@ -323,7 +323,7 @@ class NotificationsView extends BaseNotificationsView { get_notifications_list(limit) { return frappe.db.get_list('Notification Log', { - fields: ['*'], + fields: ['subject', "type", "document_type", "document_name", "creation", "from_user", "name"], limit: limit, order_by: 'creation desc' }); From ef234da171cd3cb0aa59c0039cd095895688e770 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Tue, 26 Jul 2022 15:40:13 +0530 Subject: [PATCH 43/48] fix: Don't retry asset caching in CI or developer_mode --- esbuild/utils.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/esbuild/utils.js b/esbuild/utils.js index 82490adb36..b2a4e98d54 100644 --- a/esbuild/utils.js +++ b/esbuild/utils.js @@ -112,16 +112,21 @@ function log(...args) { function get_redis_subscriber(kind) { // get redis subscriber that aborts after 10 connection attempts - let { get_redis_subscriber: get_redis } = require("../node_utils"); - return get_redis(kind, { - retry_strategy: function(options) { + let retry_strategy; + let { get_redis_subscriber: get_redis, get_conf } = require("../node_utils"); + + if (process.env.CI == 1 || get_conf().developer_mode == 1) { + retry_strategy = () => { } + } else { + retry_strategy = function (options) { // abort after 10 connection attempts if (options.attempt > 10) { return undefined; } return Math.min(options.attempt * 100, 2000); } - }); + } + return get_redis(kind, { retry_strategy }); } module.exports = { From 8fe4fa72ef36d465eb1a3712cd2faaa40f921afb Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 28 Jul 2022 18:01:53 +0530 Subject: [PATCH 44/48] fix: hide border for a section break (#17653) --- frappe/public/scss/desk/form.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frappe/public/scss/desk/form.scss b/frappe/public/scss/desk/form.scss index f56d9da59a..655c0a1539 100644 --- a/frappe/public/scss/desk/form.scss +++ b/frappe/public/scss/desk/form.scss @@ -62,6 +62,10 @@ border-bottom: none; } +.form-section.card-section.hide-border { + border-bottom: none; +} + .form-dashboard-section { .section-body:first-child { margin-top: 0; From 4fadc21d85d6dab8468b9ed1ad04e650b0e2ff5a Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Thu, 28 Jul 2022 18:29:33 +0530 Subject: [PATCH 45/48] feat: Role based permission for Dashboard Chart (#17634) --- .../doctype/dashboard_chart/dashboard_chart.json | 13 +++++++++++-- .../desk/doctype/dashboard_chart/dashboard_chart.py | 7 ++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json index a5d30c10e5..a5aa6cc20a 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.json +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.json @@ -42,7 +42,8 @@ "column_break_2", "color", "section_break_10", - "last_synced_on" + "last_synced_on", + "roles" ], "fields": [ { @@ -277,13 +278,20 @@ "fieldtype": "Link", "label": "Parent Document Type", "options": "DocType" + }, + { + "fieldname": "roles", + "fieldtype": "Table", + "label": "Roles", + "options": "Has Role" } ], "links": [], - "modified": "2021-11-09 17:18:11.456145", + "modified": "2022-07-27 11:09:09.203236", "modified_by": "Administrator", "module": "Desk", "name": "Dashboard Chart", + "naming_rule": "By fieldname", "owner": "Administrator", "permissions": [ { @@ -323,5 +331,6 @@ ], "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file diff --git a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py index 75f230a901..aa76932050 100644 --- a/frappe/desk/doctype/dashboard_chart/dashboard_chart.py +++ b/frappe/desk/doctype/dashboard_chart/dashboard_chart.py @@ -11,7 +11,7 @@ from frappe.config import get_modules_from_all_apps_for_user from frappe.model.document import Document from frappe.model.naming import append_number_if_name_exists from frappe.modules.export_file import export_to_files -from frappe.utils import cint, get_datetime, getdate, now_datetime, nowdate +from frappe.utils import cint, get_datetime, getdate, has_common, now_datetime, nowdate from frappe.utils.dashboard import cache_source from frappe.utils.data import format_date from frappe.utils.dateutils import ( @@ -87,6 +87,11 @@ def has_permission(doc, ptype, user): if doc.document_type in allowed_doctypes: return True + if doc.roles: + allowed = [d.role for d in doc.roles] + if has_common(roles, allowed): + return True + return False From a772cc0796158d720bb5f5bd8eb6434a73ee0dcf Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Fri, 29 Jul 2022 10:24:49 +0530 Subject: [PATCH 46/48] fix: removing unused import line (#17654) --- frappe/database/query.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/frappe/database/query.py b/frappe/database/query.py index e23c0b4b63..8dbb564edc 100644 --- a/frappe/database/query.py +++ b/frappe/database/query.py @@ -187,8 +187,6 @@ class Engine: @cached_property def OPERATOR_MAP(self): - from frappe.boot import get_additional_filters_from_hooks - # default operators all_operators = OPERATOR_MAP.copy() From 8fa2caa4a2f69650bef69394b31bb5a824412459 Mon Sep 17 00:00:00 2001 From: Raffael Meyer <14891507+barredterra@users.noreply.github.com> Date: Fri, 29 Jul 2022 07:19:13 +0200 Subject: [PATCH 47/48] fix: return promise (#17646) --- frappe/public/js/frappe/ui/tree.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/frappe/public/js/frappe/ui/tree.js b/frappe/public/js/frappe/ui/tree.js index c32d92aa32..4b2c0bc12b 100644 --- a/frappe/public/js/frappe/ui/tree.js +++ b/frappe/public/js/frappe/ui/tree.js @@ -134,7 +134,7 @@ frappe.ui.Tree = class { } reload_node(node) { - this.load_children(node); + return this.load_children(node); } toggle() { @@ -150,21 +150,20 @@ frappe.ui.Tree = class { } load_children(node, deep=false) { - let lab = node.label, value = node.data.value, is_root = node.is_root; + const value = node.data.value, + is_root = node.is_root; - if(!deep) { - frappe.run_serially([ + return deep + ? frappe.run_serially([ + () => this.get_all_nodes(value, is_root, node.label), + data_list => this.render_children_of_all_nodes(data_list), + () => this.set_selected_node(node), + ]) + : frappe.run_serially([ () => this.get_nodes(value, is_root), - (data_set) => this.render_node_children(node, data_set), - () => this.set_selected_node(node) + data_set => this.render_node_children(node, data_set), + () => this.set_selected_node(node), ]); - } else { - frappe.run_serially([ - () => this.get_all_nodes(value, is_root, lab), - (data_list) => this.render_children_of_all_nodes(data_list), - () => this.set_selected_node(node) - ]); - } } render_children_of_all_nodes(data_list) { From 6102c1be4e63ec31a51b15eeafa31ef099ef9d35 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Fri, 29 Jul 2022 06:33:06 +0000 Subject: [PATCH 48/48] chore: remove obsolete whitelisting from `get_link_title_doctypes` (#17664) --- frappe/boot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/frappe/boot.py b/frappe/boot.py index e43446f352..ab559d7c4d 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -391,7 +391,6 @@ def get_notification_settings(): return frappe.get_cached_doc("Notification Settings", frappe.session.user) -@frappe.whitelist() def get_link_title_doctypes(): dts = frappe.get_all("DocType", {"show_title_field_in_link": 1}) custom_dts = frappe.get_all(