`);
}
From 268c851f858a8aec020c4454dbf654d402242298 Mon Sep 17 00:00:00 2001
From: "avazquez@ctgalega.com"
Date: Wed, 8 Nov 2023 00:29:46 +0100
Subject: [PATCH 019/262] fix: description for columns property in docfield
---
frappe/core/doctype/docfield/docfield.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json
index 6b8469bd48..065e00c6aa 100644
--- a/frappe/core/doctype/docfield/docfield.json
+++ b/frappe/core/doctype/docfield/docfield.json
@@ -416,7 +416,7 @@
"width": "50px"
},
{
- "description": "Number of columns for a field in a List View or a Grid (Total Columns should be less than 11)",
+ "description": "Number of columns for a field in a Grid (Total Columns should be less than 11)",
"fieldname": "columns",
"fieldtype": "Int",
"label": "Columns"
From 9baf5e6de481e24fbbf0ad93c76d61e59ea93317 Mon Sep 17 00:00:00 2001
From: "avazquez@ctgalega.com"
Date: Wed, 8 Nov 2023 00:38:16 +0100
Subject: [PATCH 020/262] fix: typo accuracy
---
frappe/core/doctype/docfield/docfield.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/core/doctype/docfield/docfield.json b/frappe/core/doctype/docfield/docfield.json
index 065e00c6aa..42e8d21e34 100644
--- a/frappe/core/doctype/docfield/docfield.json
+++ b/frappe/core/doctype/docfield/docfield.json
@@ -416,7 +416,7 @@
"width": "50px"
},
{
- "description": "Number of columns for a field in a Grid (Total Columns should be less than 11)",
+ "description": "Number of columns for a field in a grid (total columns should be less than 11)",
"fieldname": "columns",
"fieldtype": "Int",
"label": "Columns"
From 88113b6c089d99a2f4547615614fe0c869fd81ef Mon Sep 17 00:00:00 2001
From: Shariq Ansari
Date: Wed, 8 Nov 2023 11:54:35 +0530
Subject: [PATCH 021/262] fix: added Dropdown component
---
.../js/form_builder/components/Dropdown.vue | 129 ++++++++++++++++++
1 file changed, 129 insertions(+)
create mode 100644 frappe/public/js/form_builder/components/Dropdown.vue
diff --git a/frappe/public/js/form_builder/components/Dropdown.vue b/frappe/public/js/form_builder/components/Dropdown.vue
new file mode 100644
index 0000000000..23e1a0443d
--- /dev/null
+++ b/frappe/public/js/form_builder/components/Dropdown.vue
@@ -0,0 +1,129 @@
+
+
+
+
+
+
+
From 78c78ece342d9eeecae48c4bdf8abb0604e7b823 Mon Sep 17 00:00:00 2001
From: Suraj Shetty
Date: Wed, 22 Nov 2023 16:51:07 +0530
Subject: [PATCH 155/262] fix: Show list similar to how it looks in text editor
---
frappe/public/scss/email.bundle.scss | 82 ++++++++++++++++++++++++++++
1 file changed, 82 insertions(+)
diff --git a/frappe/public/scss/email.bundle.scss b/frappe/public/scss/email.bundle.scss
index ef274f023f..860c0df8e4 100644
--- a/frappe/public/scss/email.bundle.scss
+++ b/frappe/public/scss/email.bundle.scss
@@ -346,3 +346,85 @@ blockquote {
margin: 5px 0;
}
}
+
+.ql-editor li {
+ list-style-type: none;
+ padding-left: 1.5em;
+ position: relative;
+}
+.ql-editor li > .ql-ui:before {
+ display: inline-block;
+ margin-left: -1.5em;
+ margin-right: 0.3em;
+ text-align: right;
+ white-space: nowrap;
+ width: 1.2em;
+}
+.ql-editor li[data-list="checked"] > .ql-ui,
+.ql-editor li[data-list="unchecked"] > .ql-ui {
+ color: #777;
+}
+.ql-editor li[data-list="bullet"] > .ql-ui:before {
+ content: "\2022";
+}
+.ql-editor li[data-list="checked"] > .ql-ui:before {
+ content: "\2611";
+}
+.ql-editor li[data-list="unchecked"] > .ql-ui:before {
+ content: "\2610";
+}
+.ql-editor li[data-list="ordered"] {
+ counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+ counter-increment: list-0;
+}
+.ql-editor li[data-list="ordered"] > .ql-ui:before {
+ content: counter(list-0, decimal) ". ";
+}
+.ql-editor li[data-list="ordered"].ql-indent-1 {
+ counter-increment: list-1;
+}
+.ql-editor li[data-list="ordered"].ql-indent-1 > .ql-ui:before {
+ content: counter(list-1, lower-alpha) ". ";
+}
+.ql-editor li[data-list="ordered"].ql-indent-1 {
+ counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor li[data-list="ordered"].ql-indent-2 {
+ counter-increment: list-2;
+}
+.ql-editor li[data-list="ordered"].ql-indent-2 > .ql-ui:before {
+ content: counter(list-2, lower-roman) ". ";
+}
+.ql-editor li[data-list="ordered"].ql-indent-2 {
+ counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor li[data-list="ordered"].ql-indent-3 {
+ counter-increment: list-3;
+}
+.ql-editor li[data-list="ordered"].ql-indent-3 > .ql-ui:before {
+ content: counter(list-3, decimal) ". ";
+}
+.ql-editor li[data-list="ordered"].ql-indent-3 {
+ counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
+}
+.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
+ padding-left: 3em;
+}
+
+.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
+ padding-left: 4.5em;
+}
+
+.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
+ padding-left: 6em;
+}
+.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
+ padding-left: 7.5em;
+}
+
+.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
+ padding-left: 9em;
+}
+.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
+ padding-left: 10.5em;
+}
From 3896750e2e6f0d07675e9f67a026626acdb62fa0 Mon Sep 17 00:00:00 2001
From: Akhil Narang
Date: Wed, 22 Nov 2023 17:01:01 +0530
Subject: [PATCH 156/262] refactor(web_form): cleanup code
`frappe.get_meta()` gives us all the data we require
Signed-off-by: Akhil Narang
---
frappe/website/doctype/web_form/web_form.py | 26 ++++-----------------
1 file changed, 4 insertions(+), 22 deletions(-)
diff --git a/frappe/website/doctype/web_form/web_form.py b/frappe/website/doctype/web_form/web_form.py
index b848c11385..ded5eb7f02 100644
--- a/frappe/website/doctype/web_form/web_form.py
+++ b/frappe/website/doctype/web_form/web_form.py
@@ -679,32 +679,14 @@ def get_link_options(web_form_name, doctype, allow_read_on_all_link_options=Fals
fields = ["name as value"]
- title_field = frappe.get_cached_value("DocType", doctype, "title_field")
- show_title_field_in_link = (
- frappe.get_cached_value("DocType", doctype, "show_title_field_in_link") == 1
- )
- if not show_title_field_in_link:
- value = frappe.db.get_value(
- "Property Setter",
- fieldname="value",
- filters={"property": "show_title_field_in_link", "doc_type": doctype},
- )
- if value and int(value) == 1:
- show_title_field_in_link = True
+ meta = frappe.get_meta(doctype)
- if not title_field:
- title_field = frappe.db.get_value(
- "Property Setter",
- fieldname="value",
- filters={"property": "title_field", "doc_type": doctype},
- )
-
- if title_field and show_title_field_in_link:
- fields.append(f"{title_field} as label")
+ if meta.title_field and meta.show_title_field_in_link:
+ fields.append(f"{meta.title_field} as label")
link_options = frappe.get_all(doctype, filters, fields)
- if title_field and show_title_field_in_link:
+ if meta.title_field and meta.show_title_field_in_link:
return json.dumps(link_options, default=str)
else:
return "\n".join([str(doc.value) for doc in link_options])
From 31e3b3f98118cef238581d0c27abd751b87894bb Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Wed, 22 Nov 2023 17:02:45 +0530
Subject: [PATCH 157/262] fix: social key signup without signup conf (#23359)
---
.../integrations/doctype/social_login_key/social_login_key.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/integrations/doctype/social_login_key/social_login_key.py b/frappe/integrations/doctype/social_login_key/social_login_key.py
index 4c1fc8708f..3445bb92e3 100644
--- a/frappe/integrations/doctype/social_login_key/social_login_key.py
+++ b/frappe/integrations/doctype/social_login_key/social_login_key.py
@@ -222,6 +222,6 @@ def provider_allows_signup(provider: str) -> bool:
sign_up_config = frappe.db.get_value("Social Login Key", provider, "sign_ups")
- if not (sign_up_config and provider): # fallback to global settings
+ if not sign_up_config: # fallback to global settings
return is_signup_disabled()
return sign_up_config == "Allow"
From 6e3b1cc0adc7f6279b4cc43d970ff1158ce22a67 Mon Sep 17 00:00:00 2001
From: Md Hussain Nagaria <34810212+NagariaHussain@users.noreply.github.com>
Date: Wed, 22 Nov 2023 18:27:54 +0530
Subject: [PATCH 158/262] docs: add BWH link to resources (#23365)
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 50540ad1c7..9a1cee5534 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ Full-stack web application framework that uses Python and MariaDB on the server
1. [frappeframework.com](https://frappeframework.com) - Official documentation of the Frappe Framework.
1. [frappe.school](https://frappe.school) - Pick from the various courses by the maintainers or from the community.
+1. [buildwithhussain.dev](https://buildwithhussain.dev) - Watch Frappe Framework being used in the wild to build world-class web apps.
## License
This repository has been released under the [MIT License](LICENSE).
From 21e8abf89904c1358e1f764129284303604ca3fb Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 23 Nov 2023 11:42:51 +0530
Subject: [PATCH 159/262] build: python 3.12 support (#22706)
* ci: use python 3.12
We'll use minimum versions on stable branch CI configs.
* build(deps): bump dependencies
- Some for v12 support
- some just for new stuff
---
.github/workflows/server-tests.yml | 2 +-
.github/workflows/ui-tests.yml | 2 +-
pyproject.toml | 12 ++++++------
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 97000bff15..e20ae8fc6e 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -85,7 +85,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v4
with:
- python-version: '3.11'
+ python-version: '3.12'
- name: Check for valid Python & Merge Conflicts
run: |
diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml
index 00e370e4ed..4742d97a37 100644
--- a/.github/workflows/ui-tests.yml
+++ b/.github/workflows/ui-tests.yml
@@ -67,7 +67,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v4
with:
- python-version: '3.11'
+ python-version: '3.12'
- name: Check for valid Python & Merge Conflicts
run: |
diff --git a/pyproject.toml b/pyproject.toml
index 28eb0858b9..c371e87ac1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,14 +4,14 @@ authors = [
{ name = "Frappe Technologies Pvt Ltd", email = "developers@frappe.io"}
]
description = "Metadata driven, full-stack low code web framework"
-requires-python = ">=3.10,<3.12"
+requires-python = ">=3.10,<3.13"
readme = "README.md"
dynamic = ["version"]
dependencies = [
# core dependencies
- "Babel~=2.12.1",
+ "Babel~=2.13.1",
"Click~=8.1.7",
- "filelock~=3.8.0",
+ "filelock~=3.13.1",
"filetype~=1.2.0",
"GitPython~=3.1.34",
"Jinja2~=3.1.2",
@@ -22,7 +22,7 @@ dependencies = [
"PyPika~=0.48.9",
"PyQRCode~=1.2.1",
"PyYAML~=6.0.1",
- "RestrictedPython~=6.2",
+ "RestrictedPython~=7.0",
"WeasyPrint==59.0",
"Werkzeug~=3.0.1",
"Whoosh~=2.7.4",
@@ -31,7 +31,7 @@ dependencies = [
"bleach[css]~=6.0.0",
"cairocffi==1.5.1",
"chardet~=5.1.0",
- "croniter~=1.4.1",
+ "croniter~=2.0.1",
"cryptography~=41.0.3",
"email-reply-parser~=0.5.12",
"git-url-parse~=1.2.2",
@@ -57,7 +57,7 @@ dependencies = [
"python-dateutil~=2.8.2",
"pytz==2023.3",
"rauth~=0.7.3",
- "redis~=4.5.5",
+ "redis~=5.0.1",
"hiredis~=2.2.3",
"requests-oauthlib~=1.3.1",
"requests~=2.31.0",
From c2309969d570243010c44ad8cc75ed9b1e3e4b06 Mon Sep 17 00:00:00 2001
From: Maharshi Patel <39730881+maharshivpatel@users.noreply.github.com>
Date: Thu, 23 Nov 2023 11:46:54 +0530
Subject: [PATCH 160/262] fix: typo in strip folder name quotes (#23368)
fixed incorrect negative index.
---
frappe/email/receive.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/email/receive.py b/frappe/email/receive.py
index 2d81edd297..19798851fe 100644
--- a/frappe/email/receive.py
+++ b/frappe/email/receive.py
@@ -222,7 +222,7 @@ class EmailServer:
if self.settings.use_imap:
# Remove {"} quotes that are added to handle spaces in IMAP Folder names
if folder[0] == folder[-1] == '"':
- folder = folder[1:-2]
+ folder = folder[1:-1]
# new update for the IMAP Folder DocType
IMAPFolder = frappe.qb.DocType("IMAP Folder")
frappe.qb.update(IMAPFolder).set(IMAPFolder.uidvalidity, current_uid_validity).set(
From 89dbb42f6fb0369a40a7d3a236ca56366d00a344 Mon Sep 17 00:00:00 2001
From: RitvikSardana
Date: Thu, 23 Nov 2023 13:12:16 +0530
Subject: [PATCH 161/262] fix: link field shown only for Link fieldtype
---
frappe/public/js/form_builder/components/Field.vue | 9 +++++++--
.../js/form_builder/components/FieldProperties.vue | 6 +++++-
frappe/public/js/form_builder/store.js | 8 ++++++--
3 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/frappe/public/js/form_builder/components/Field.vue b/frappe/public/js/form_builder/components/Field.vue
index 08e65473ee..92825e2375 100644
--- a/frappe/public/js/form_builder/components/Field.vue
+++ b/frappe/public/js/form_builder/components/Field.vue
@@ -174,8 +174,13 @@ function edit_filters() {
}
function is_filter_applied() {
- if (props.field.df.link_filters && JSON.parse(props.field.df.link_filters).length > 0) {
- return "btn-filter-applied";
+ if (props.field.df.link_filters) {
+ try {
+ JSON.parse(props.field.df.link_filters).length > 0;
+ return "btn-filter-applied";
+ } catch (error) {
+ return "";
+ }
}
}
diff --git a/frappe/public/js/form_builder/components/FieldProperties.vue b/frappe/public/js/form_builder/components/FieldProperties.vue
index 7132bfeba9..5f903ed36c 100644
--- a/frappe/public/js/form_builder/components/FieldProperties.vue
+++ b/frappe/public/js/form_builder/components/FieldProperties.vue
@@ -51,6 +51,11 @@ let docfield_df = computed(() => {
}
}
+ // show link_filters docfield only when link field is selected
+ if (df.fieldname === "link_filters" && store.form.selected_field.fieldtype !== "Link") {
+ return false;
+ }
+
if (search_text.value) {
if (
df.label.toLowerCase().includes(search_text.value.toLowerCase()) ||
@@ -62,7 +67,6 @@ let docfield_df = computed(() => {
}
return true;
});
-
return [...fields];
});
diff --git a/frappe/public/js/form_builder/store.js b/frappe/public/js/form_builder/store.js
index 069cd10540..97aa89b58c 100644
--- a/frappe/public/js/form_builder/store.js
+++ b/frappe/public/js/form_builder/store.js
@@ -202,14 +202,18 @@ export const useStore = defineStore("form-builder-store", () => {
);
}
- // check if link_filters format is correct or not
+ if (df.link_filters === "") {
+ delete df.link_filters;
+ }
+ // check if link_filters format is correct or not
if (df.link_filters) {
try {
let link_filters = JSON.parse(df.link_filters);
} catch (e) {
error_message = __(
- `Invalid Filter Format. Try using filter icon on the field to set it correctly`
+ "Invalid Filter Format for field {0} of type {1}. Try using filter icon on the field to set it correctly",
+ get_field_data(df)
);
}
}
From 9e7a0b73edb7444581863e6a5f5744c2bfa1bf69 Mon Sep 17 00:00:00 2001
From: Shadrak Gurupnor
Date: Thu, 23 Nov 2023 13:18:08 +0530
Subject: [PATCH 162/262] fix: show fieldname if field label is not set
---
frappe/public/js/frappe/ui/group_by/group_by.js | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
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 2f218678ac..46b85a05cb 100644
--- a/frappe/public/js/frappe/ui/group_by/group_by.js
+++ b/frappe/public/js/frappe/ui/group_by/group_by.js
@@ -147,10 +147,13 @@ frappe.ui.GroupBy = class {
doctype_fields.forEach((field) => {
// pick numeric fields for sum / avg
if (frappe.model.is_numeric_field(field.fieldtype)) {
+ let field_label = field.label
+ ? field.label
+ : frappe.model.unscrub(field.fieldname);
let option_text =
doctype == this.doctype
- ? field.label
- : `${field.label} (${__(doctype)})`;
+ ? field_label
+ : `${field_label} (${__(doctype)})`;
this.aggregate_on_html += ``;
}
From f526054ae2e140a27dae27a3c7fb5ced68ee74b1 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Thu, 23 Nov 2023 13:21:27 +0530
Subject: [PATCH 163/262] refactor: Remove usage of utcnow (#23369)
---
frappe/core/doctype/rq_worker/rq_worker.py | 5 ++++-
.../integrations/doctype/token_cache/token_cache.py | 6 +++---
frappe/monitor.py | 7 ++++---
frappe/oauth.py | 2 +-
frappe/rate_limiter.py | 7 ++++---
frappe/utils/caching.py | 10 ++++++----
frappe/utils/data.py | 12 +++++++-----
7 files changed, 29 insertions(+), 20 deletions(-)
diff --git a/frappe/core/doctype/rq_worker/rq_worker.py b/frappe/core/doctype/rq_worker/rq_worker.py
index d3ea97203e..68dd83c41b 100644
--- a/frappe/core/doctype/rq_worker/rq_worker.py
+++ b/frappe/core/doctype/rq_worker/rq_worker.py
@@ -4,6 +4,7 @@
import datetime
from contextlib import suppress
+import pytz
from rq import Worker
import frappe
@@ -105,5 +106,7 @@ def serialize_worker(worker: Worker) -> frappe._dict:
def compute_utilization(worker: Worker) -> float:
with suppress(Exception):
- total_time = (datetime.datetime.utcnow() - worker.birth_date).total_seconds()
+ total_time = (
+ datetime.datetime.now(pytz.UTC) - worker.birth_date.replace(tzinfo=pytz.UTC)
+ ).total_seconds()
return worker.total_working_time / total_time * 100
diff --git a/frappe/integrations/doctype/token_cache/token_cache.py b/frappe/integrations/doctype/token_cache/token_cache.py
index da72335413..5619030499 100644
--- a/frappe/integrations/doctype/token_cache/token_cache.py
+++ b/frappe/integrations/doctype/token_cache/token_cache.py
@@ -1,7 +1,7 @@
# Copyright (c) 2019, Frappe Technologies and contributors
# License: MIT. See LICENSE
-from datetime import datetime, timedelta
+import datetime
import pytz
@@ -73,8 +73,8 @@ class TokenCache(Document):
system_timezone = pytz.timezone(get_system_timezone())
modified = frappe.utils.get_datetime(self.modified)
modified = system_timezone.localize(modified)
- expiry_utc = modified.astimezone(pytz.utc) + timedelta(seconds=self.expires_in)
- now_utc = datetime.utcnow().replace(tzinfo=pytz.utc)
+ expiry_utc = modified.astimezone(pytz.utc) + datetime.timedelta(seconds=self.expires_in)
+ now_utc = datetime.datetime.now(pytz.utc)
return cint((expiry_utc - now_utc).total_seconds())
def is_expired(self):
diff --git a/frappe/monitor.py b/frappe/monitor.py
index 9b8f500358..aae54987c8 100644
--- a/frappe/monitor.py
+++ b/frappe/monitor.py
@@ -1,12 +1,13 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
+import datetime
import json
import os
import traceback
import uuid
-from datetime import datetime
+import pytz
import rq
import frappe
@@ -50,7 +51,7 @@ class Monitor:
self.data = frappe._dict(
{
"site": frappe.local.site,
- "timestamp": datetime.utcnow(),
+ "timestamp": datetime.datetime.now(pytz.UTC),
"transaction_type": transaction_type,
"uuid": str(uuid.uuid4()),
}
@@ -92,7 +93,7 @@ class Monitor:
def dump(self, response=None):
try:
- timediff = datetime.utcnow() - self.data.timestamp
+ timediff = datetime.datetime.now(pytz.UTC) - self.data.timestamp
# Obtain duration in microseconds
self.data.duration = int(timediff.total_seconds() * 1000000)
diff --git a/frappe/oauth.py b/frappe/oauth.py
index 1094194348..f0a13488da 100644
--- a/frappe/oauth.py
+++ b/frappe/oauth.py
@@ -245,7 +245,7 @@ class OAuthWebRequestValidator(RequestValidator):
)
token_expiration_utc = token_expiration_local.astimezone(pytz.utc)
is_token_valid = (
- frappe.utils.datetime.datetime.utcnow().replace(tzinfo=pytz.utc) < token_expiration_utc
+ datetime.datetime.now(pytz.UTC) < token_expiration_utc
) and otoken.status != "Revoked"
client_scopes = frappe.db.get_value("OAuth Client", otoken.client, "scopes").split(
get_url_delimiter()
diff --git a/frappe/rate_limiter.py b/frappe/rate_limiter.py
index 11f3be8cb3..e1c93338e7 100644
--- a/frappe/rate_limiter.py
+++ b/frappe/rate_limiter.py
@@ -1,10 +1,11 @@
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. See LICENSE
+import datetime
from collections.abc import Callable
-from datetime import datetime
from functools import wraps
+import pytz
from werkzeug.wrappers import Response
import frappe
@@ -34,7 +35,7 @@ class RateLimiter:
self.limit = int(limit * 1000000)
self.window = window
- self.start = datetime.utcnow()
+ self.start = datetime.datetime.now(pytz.UTC)
timestamp = int(frappe.utils.now_datetime().timestamp())
self.window_number, self.spent = divmod(timestamp, self.window)
@@ -79,7 +80,7 @@ class RateLimiter:
def record_request_end(self):
if self.end is not None:
return
- self.end = datetime.utcnow()
+ self.end = datetime.datetime.now(pytz.UTC)
self.duration = int((self.end - self.start).total_seconds() * 1000000)
def respond(self):
diff --git a/frappe/utils/caching.py b/frappe/utils/caching.py
index a0e40abc8a..9b359e9209 100644
--- a/frappe/utils/caching.py
+++ b/frappe/utils/caching.py
@@ -1,12 +1,14 @@
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
# License: MIT. Check LICENSE
+import datetime
import json
from collections import defaultdict
from collections.abc import Callable
-from datetime import datetime, timedelta
from functools import wraps
+import pytz
+
import frappe
_SITE_CACHE = defaultdict(lambda: defaultdict(dict))
@@ -96,7 +98,7 @@ def site_cache(ttl: int | None = None, maxsize: int | None = None) -> Callable:
if ttl is not None and not callable(ttl):
func.ttl = ttl
- func.expiration = datetime.utcnow() + timedelta(seconds=func.ttl)
+ func.expiration = datetime.datetime.now(pytz.UTC) + datetime.timedelta(seconds=func.ttl)
if maxsize is not None and not callable(maxsize):
func.maxsize = maxsize
@@ -106,9 +108,9 @@ def site_cache(ttl: int | None = None, maxsize: int | None = None) -> Callable:
if getattr(frappe.local, "initialised", None):
func_call_key = json.dumps((args, kwargs))
- if hasattr(func, "ttl") and datetime.utcnow() >= func.expiration:
+ if hasattr(func, "ttl") and datetime.datetime.now(pytz.UTC) >= func.expiration:
func.clear_cache()
- func.expiration = datetime.utcnow() + timedelta(seconds=func.ttl)
+ func.expiration = datetime.datetime.now(pytz.UTC) + datetime.timedelta(seconds=func.ttl)
if hasattr(func, "maxsize") and len(_SITE_CACHE[func_key][frappe.local.site]) >= func.maxsize:
_SITE_CACHE[func_key][frappe.local.site].pop(
diff --git a/frappe/utils/data.py b/frappe/utils/data.py
index d3cb996c9d..f3cf219603 100644
--- a/frappe/utils/data.py
+++ b/frappe/utils/data.py
@@ -14,6 +14,7 @@ from enum import Enum
from typing import Any, Literal, Optional, TypeVar, Union
from urllib.parse import parse_qsl, quote, urlencode, urljoin, urlparse, urlunparse
+import pytz
from click import secho
from dateutil import parser
from dateutil.parser import ParserError
@@ -295,7 +296,7 @@ def time_diff_in_hours(string_ed_date, string_st_date):
def now_datetime():
- dt = convert_utc_to_system_timezone(datetime.datetime.utcnow())
+ dt = convert_utc_to_system_timezone(datetime.datetime.now(pytz.UTC))
return dt.replace(tzinfo=None)
@@ -322,15 +323,16 @@ def get_system_timezone():
def convert_utc_to_timezone(utc_timestamp, time_zone):
from pytz import UnknownTimeZoneError, timezone
- utcnow = timezone("UTC").localize(utc_timestamp)
+ if utc_timestamp.tzinfo is None:
+ utc_timestamp = timezone("UTC").localize(utc_timestamp)
try:
- return utcnow.astimezone(timezone(time_zone))
+ return utc_timestamp.astimezone(timezone(time_zone))
except UnknownTimeZoneError:
- return utcnow
+ return utc_timestamp
def get_datetime_in_timezone(time_zone):
- utc_timestamp = datetime.datetime.utcnow()
+ utc_timestamp = datetime.datetime.now(pytz.UTC)
return convert_utc_to_timezone(utc_timestamp, time_zone)
From 71201675ba5e5f9c2d65b4442dc6ffb3058fe05f Mon Sep 17 00:00:00 2001
From: RitvikSardana
Date: Thu, 23 Nov 2023 13:33:15 +0530
Subject: [PATCH 164/262] fix: add back if condition
---
frappe/public/js/form_builder/components/Field.vue | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/frappe/public/js/form_builder/components/Field.vue b/frappe/public/js/form_builder/components/Field.vue
index 92825e2375..26d488cdf8 100644
--- a/frappe/public/js/form_builder/components/Field.vue
+++ b/frappe/public/js/form_builder/components/Field.vue
@@ -176,8 +176,9 @@ function edit_filters() {
function is_filter_applied() {
if (props.field.df.link_filters) {
try {
- JSON.parse(props.field.df.link_filters).length > 0;
- return "btn-filter-applied";
+ if (JSON.parse(props.field.df.link_filters).length > 0) {
+ return "btn-filter-applied";
+ }
} catch (error) {
return "";
}
From fbc88a4d24b34d6e7c9339645c06465634581934 Mon Sep 17 00:00:00 2001
From: Akhil Narang
Date: Fri, 10 Nov 2023 18:31:30 +0530
Subject: [PATCH 165/262] refactor(treewide): code cleanup
Drop redundant bool conversion
Signed-off-by: Akhil Narang
---
frappe/__init__.py | 10 ++++------
frappe/auth.py | 5 ++---
frappe/commands/site.py | 5 ++---
frappe/core/doctype/communication/mixins.py | 2 +-
frappe/core/doctype/data_import/exporter.py | 3 +--
frappe/core/doctype/domain/domain.py | 3 ++-
frappe/core/doctype/recorder/recorder.py | 5 +++--
frappe/core/doctype/report/report.py | 6 +++---
frappe/core/doctype/rq_job/rq_job.py | 3 ++-
frappe/core/doctype/rq_worker/rq_worker.py | 3 ++-
frappe/core/doctype/system_settings/system_settings.py | 7 ++++---
frappe/core/doctype/user/user.py | 4 ++--
frappe/core/doctype/user_type/user_type.py | 3 ++-
frappe/database/mariadb/schema.py | 2 +-
frappe/database/postgres/schema.py | 2 +-
frappe/database/schema.py | 6 +++---
frappe/desk/doctype/desktop_icon/desktop_icon.py | 5 +++--
frappe/email/doctype/email_domain/email_domain.py | 3 ++-
frappe/oauth.py | 2 +-
frappe/rate_limiter.py | 2 +-
.../doctype/energy_point_log/test_energy_point_log.py | 2 +-
frappe/twofactor.py | 6 +++---
frappe/utils/dashboard.py | 2 +-
frappe/utils/file_manager.py | 5 +----
frappe/utils/install.py | 3 ++-
frappe/website/doctype/blog_post/blog_post.py | 7 ++++---
.../personal_data_deletion_request.py | 3 ++-
.../doctype/website_settings/website_settings.py | 5 +++--
frappe/website/website_generator.py | 5 ++---
frappe/workflow/doctype/workflow/workflow.py | 7 ++++---
30 files changed, 65 insertions(+), 61 deletions(-)
diff --git a/frappe/__init__.py b/frappe/__init__.py
index 90f142c14c..6cb6e4a3d4 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -17,7 +17,6 @@ import inspect
import json
import os
import re
-import unicodedata
import warnings
from collections.abc import Callable
from typing import TYPE_CHECKING, Any, Literal, Optional, TypeAlias, overload
@@ -43,7 +42,6 @@ from .utils.jinja import (
get_template,
render_template,
)
-from .utils.lazy_loader import lazy_import
__version__ = "15.0.0-dev"
__title__ = "Frappe Framework"
@@ -418,7 +416,7 @@ def errprint(msg: str) -> None:
:param msg: Message."""
msg = as_unicode(msg)
- if not request or (not "cmd" in local.form_dict) or conf.developer_mode:
+ if not request or ("cmd" not in local.form_dict) or conf.developer_mode:
print(msg)
error_log.append({"exc": msg})
@@ -433,7 +431,7 @@ def log(msg: str) -> None:
:param msg: Message."""
if not request:
- if conf.get("logging") or False:
+ if conf.get("logging"):
print(repr(msg))
debug_log.append(as_unicode(msg))
@@ -1959,7 +1957,7 @@ def get_all(doctype, *args, **kwargs):
frappe.get_all("ToDo", fields=["*"], filters = [["modified", ">", "2014-01-01"]])
"""
kwargs["ignore_permissions"] = True
- if not "limit_page_length" in kwargs:
+ if "limit_page_length" not in kwargs:
kwargs["limit_page_length"] = 0
return get_list(doctype, *args, **kwargs)
@@ -2008,7 +2006,7 @@ def as_json(obj: dict | list, indent=1, separators=None, ensure_ascii=True) -> s
def are_emails_muted():
- return flags.mute_emails or cint(conf.get("mute_emails") or 0) or False
+ return flags.mute_emails or cint(conf.get("mute_emails"))
def get_test_records(doctype):
diff --git a/frappe/auth.py b/frappe/auth.py
index 941edb9277..084489b19a 100644
--- a/frappe/auth.py
+++ b/frappe/auth.py
@@ -96,7 +96,6 @@ class HTTPRequest:
class LoginManager:
-
__slots__ = ("user", "info", "full_name", "user_type", "resume")
def __init__(self):
@@ -305,8 +304,8 @@ class LoginManager:
def validate_hour(self):
"""check if user is logging in during restricted hours"""
- login_before = int(frappe.db.get_value("User", self.user, "login_before", ignore=True) or 0)
- login_after = int(frappe.db.get_value("User", self.user, "login_after", ignore=True) or 0)
+ login_before = cint(frappe.db.get_value("User", self.user, "login_before", ignore=True))
+ login_after = cint(frappe.db.get_value("User", self.user, "login_after", ignore=True))
if not (login_before or login_after):
return
diff --git a/frappe/commands/site.py b/frappe/commands/site.py
index 28d6cac695..729e19594a 100644
--- a/frappe/commands/site.py
+++ b/frappe/commands/site.py
@@ -413,7 +413,6 @@ def _reinstall(
verbose=False,
):
from frappe.installer import _new_site
- from frappe.utils.synchronization import filelock
if not yes:
click.confirm("This will wipe your database. Are you sure you want to reinstall?", abort=True)
@@ -951,9 +950,9 @@ def move(dest_dir, site):
site_dump_exists = True
count = 0
while site_dump_exists:
- final_new_path = new_path + (count and str(count) or "")
+ final_new_path = new_path + str(count)
site_dump_exists = os.path.exists(final_new_path)
- count = int(count or 0) + 1
+ count += 1
shutil.move(old_path, final_new_path)
frappe.destroy()
diff --git a/frappe/core/doctype/communication/mixins.py b/frappe/core/doctype/communication/mixins.py
index 8db13b8993..bbe5881d7a 100644
--- a/frappe/core/doctype/communication/mixins.py
+++ b/frappe/core/doctype/communication/mixins.py
@@ -288,7 +288,7 @@ class CommunicationEmailMixin:
"delayed": True,
"communication": self.name,
"read_receipt": self.read_receipt,
- "is_notification": (self.sent_or_received == "Received" and True) or False,
+ "is_notification": (self.sent_or_received == "Received"),
"print_letterhead": print_letterhead,
}
diff --git a/frappe/core/doctype/data_import/exporter.py b/frappe/core/doctype/data_import/exporter.py
index 88d5b2b4b1..691474c3d3 100644
--- a/frappe/core/doctype/data_import/exporter.py
+++ b/frappe/core/doctype/data_import/exporter.py
@@ -144,8 +144,7 @@ class Exporter:
value = doc.get(df.fieldname, None)
if df.fieldtype == "Duration":
- value = flt(value or 0)
- value = format_duration(value, df.hide_days)
+ value = format_duration(flt(value), df.hide_days)
row[i] = value
return rows
diff --git a/frappe/core/doctype/domain/domain.py b/frappe/core/doctype/domain/domain.py
index 0c98856490..50e187968e 100644
--- a/frappe/core/doctype/domain/domain.py
+++ b/frappe/core/doctype/domain/domain.py
@@ -4,6 +4,7 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from frappe.model.document import Document
+from frappe.utils import cint
class Domain(Document):
@@ -28,7 +29,7 @@ class Domain(Document):
self.setup_properties()
self.set_values()
- if not int(frappe.defaults.get_defaults().setup_complete or 0):
+ if not cint(frappe.defaults.get_defaults().setup_complete):
# if setup not complete, setup desktop etc.
self.setup_sidebar_items()
self.set_default_portal_role()
diff --git a/frappe/core/doctype/recorder/recorder.py b/frappe/core/doctype/recorder/recorder.py
index c8ca1cc798..f5ef909a2a 100644
--- a/frappe/core/doctype/recorder/recorder.py
+++ b/frappe/core/doctype/recorder/recorder.py
@@ -4,7 +4,7 @@
import frappe
from frappe.model.document import Document
from frappe.recorder import get as get_recorder_data
-from frappe.utils import cint, evaluate_filters, make_filter_dict
+from frappe.utils import cint, evaluate_filters
class Recorder(Document):
@@ -27,6 +27,7 @@ class Recorder(Document):
sql_queries: DF.Table[RecorderQuery]
time: DF.Datetime | None
time_in_queries: DF.Float
+
# end: auto-generated types
def load_from_db(self):
@@ -38,7 +39,7 @@ class Recorder(Document):
@staticmethod
def get_list(args):
- start = cint(args.get("start")) or 0
+ start = cint(args.get("start"))
page_length = cint(args.get("page_length")) or 20
requests = Recorder.get_filtered_requests(args)[start : start + page_length]
diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py
index 0443766de1..65fa096df0 100644
--- a/frappe/core/doctype/report/report.py
+++ b/frappe/core/doctype/report/report.py
@@ -45,6 +45,7 @@ class Report(Document):
report_script: DF.Code | None
report_type: DF.Literal["Report Builder", "Query Report", "Script Report", "Custom Report"]
roles: DF.Table[HasRole]
+
# end: auto-generated types
def validate(self):
"""only administrator can save standard report"""
@@ -129,7 +130,7 @@ class Report(Document):
if frappe.flags.in_import:
return
- if self.is_standard == "Yes" and (frappe.local.conf.get("developer_mode") or 0) == 1:
+ if self.is_standard == "Yes" and (frappe.local.conf.get("developer_mode", 0) == 1):
export_to_files(
record_list=[["Report", self.name]], record_module=self.module, create_init=True
)
@@ -155,7 +156,6 @@ class Report(Document):
def execute_script_report(self, filters):
# save the timestamp to automatically set to prepared
threshold = 15
- res = []
start_time = datetime.datetime.now()
@@ -382,7 +382,7 @@ class Report(Document):
def is_prepared_report_enabled(report):
- return cint(frappe.db.get_value("Report", report, "prepared_report")) or 0
+ return cint(frappe.db.get_value("Report", report, "prepared_report"))
def get_report_module_dotted_path(module, report_name):
diff --git a/frappe/core/doctype/rq_job/rq_job.py b/frappe/core/doctype/rq_job/rq_job.py
index 453a375a5a..81fa3fdf3e 100644
--- a/frappe/core/doctype/rq_job/rq_job.py
+++ b/frappe/core/doctype/rq_job/rq_job.py
@@ -59,6 +59,7 @@ class RQJob(Document):
]
time_taken: DF.Duration | None
timeout: DF.Duration | None
+
# end: auto-generated types
def load_from_db(self):
try:
@@ -79,7 +80,7 @@ class RQJob(Document):
@staticmethod
def get_list(args):
- start = cint(args.get("start")) or 0
+ start = cint(args.get("start"))
page_length = cint(args.get("page_length")) or 20
order_desc = "desc" in args.get("order_by", "")
diff --git a/frappe/core/doctype/rq_worker/rq_worker.py b/frappe/core/doctype/rq_worker/rq_worker.py
index 68dd83c41b..025feb18a6 100644
--- a/frappe/core/doctype/rq_worker/rq_worker.py
+++ b/frappe/core/doctype/rq_worker/rq_worker.py
@@ -34,6 +34,7 @@ class RQWorker(Document):
total_working_time: DF.Duration | None
utilization_percent: DF.Percent
worker_name: DF.Data | None
+
# end: auto-generated types
def load_from_db(self):
@@ -47,7 +48,7 @@ class RQWorker(Document):
@staticmethod
def get_list(args):
- start = cint(args.get("start")) or 0
+ start = cint(args.get("start"))
page_length = cint(args.get("page_length")) or 20
workers = get_workers()
diff --git a/frappe/core/doctype/system_settings/system_settings.py b/frappe/core/doctype/system_settings/system_settings.py
index 9a34ccd5b6..1c64a22e54 100644
--- a/frappe/core/doctype/system_settings/system_settings.py
+++ b/frappe/core/doctype/system_settings/system_settings.py
@@ -93,12 +93,13 @@ class SystemSettings(Document):
time_zone: DF.Literal
two_factor_method: DF.Literal["OTP App", "SMS", "Email"]
welcome_email_template: DF.Link | None
+
# end: auto-generated types
def validate(self):
from frappe.twofactor import toggle_two_factor_auth
- enable_password_policy = cint(self.enable_password_policy) and True or False
- minimum_password_score = cint(getattr(self, "minimum_password_score", 0)) or 0
+ enable_password_policy = cint(self.enable_password_policy)
+ minimum_password_score = cint(getattr(self, "minimum_password_score", 0))
if enable_password_policy and minimum_password_score <= 0:
frappe.throw(_("Please select Minimum Password Score"))
elif not enable_password_policy:
@@ -195,7 +196,7 @@ def update_last_reset_password_date():
def load():
from frappe.utils.momentjs import get_all_timezones
- if not "System Manager" in frappe.get_roles():
+ if "System Manager" not in frappe.get_roles():
frappe.throw(_("Not permitted"), frappe.PermissionError)
all_defaults = frappe.db.get_defaults()
diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py
index cdb3e394ee..78ba86de3f 100644
--- a/frappe/core/doctype/user/user.py
+++ b/frappe/core/doctype/user/user.py
@@ -872,7 +872,7 @@ def test_password_strength(
"Arguments `key` and `old_password` are deprecated in function `test_password_strength`."
)
- enable_password_policy = frappe.get_system_settings("enable_password_policy") or 0
+ enable_password_policy = frappe.get_system_settings("enable_password_policy")
if not enable_password_policy:
return {}
@@ -885,7 +885,7 @@ def test_password_strength(
if new_password:
result = _test_password_strength(new_password, user_inputs=user_data)
password_policy_validation_passed = False
- minimum_password_score = cint(frappe.get_system_settings("minimum_password_score")) or 0
+ minimum_password_score = cint(frappe.get_system_settings("minimum_password_score"))
# score should be greater than 0 and minimum_password_score
if result.get("score") and result.get("score") >= minimum_password_score:
diff --git a/frappe/core/doctype/user_type/user_type.py b/frappe/core/doctype/user_type/user_type.py
index 355b390b3f..0d7c2f9c9f 100644
--- a/frappe/core/doctype/user_type/user_type.py
+++ b/frappe/core/doctype/user_type/user_type.py
@@ -31,6 +31,7 @@ class UserType(Document):
user_doctypes: DF.Table[UserDocumentType]
user_id_field: DF.Literal
user_type_modules: DF.Table[UserTypeModule]
+
# end: auto-generated types
def validate(self):
self.set_modules()
@@ -140,7 +141,7 @@ class UserType(Document):
for row in self.user_doctypes:
docperm = add_role_permissions(row.document_type, self.role)
- values = {perm: row.get(perm) or 0 for perm in perms}
+ values = {perm: row.get(perm, default=0) for perm in perms}
for perm in ["print", "email", "share"]:
values[perm] = 1
diff --git a/frappe/database/mariadb/schema.py b/frappe/database/mariadb/schema.py
index d57335f589..0486ab9463 100644
--- a/frappe/database/mariadb/schema.py
+++ b/frappe/database/mariadb/schema.py
@@ -24,7 +24,7 @@ class MariaDBTable(DBTable):
additional_definitions += index_defs
# child table columns
- if self.meta.get("istable") or 0:
+ if self.meta.get("istable", default=0):
additional_definitions += [
f"parent varchar({varchar_len})",
f"parentfield varchar({varchar_len})",
diff --git a/frappe/database/postgres/schema.py b/frappe/database/postgres/schema.py
index 946747aa47..48fd66e31a 100644
--- a/frappe/database/postgres/schema.py
+++ b/frappe/database/postgres/schema.py
@@ -17,7 +17,7 @@ class PostgresTable(DBTable):
additional_definitions += ",\n".join(column_defs)
# child table columns
- if self.meta.get("istable") or 0:
+ if self.meta.get("istable", default=0):
if column_defs:
additional_definitions += ",\n"
diff --git a/frappe/database/schema.py b/frappe/database/schema.py
index 90c3055452..1387cbc549 100644
--- a/frappe/database/schema.py
+++ b/frappe/database/schema.py
@@ -213,11 +213,11 @@ class DbColumn:
unique = False
if self.fieldtype in ("Check", "Int"):
- default = cint(self.default) or 0
+ default = cint(self.default)
null = False
elif self.fieldtype in ("Currency", "Float", "Percent"):
- default = flt(self.default) or 0
+ default = flt(self.default)
null = False
elif (
@@ -292,7 +292,7 @@ class DbColumn:
if (current_def["index"] and not self.set_index) and column_type not in ("text", "longtext"):
self.table.drop_index.append(self)
- elif (not current_def["index"] and self.set_index) and not (column_type in ("text", "longtext")):
+ elif (not current_def["index"] and self.set_index) and column_type not in ("text", "longtext"):
self.table.add_index.append(self)
def default_changed(self, current_def):
diff --git a/frappe/desk/doctype/desktop_icon/desktop_icon.py b/frappe/desk/doctype/desktop_icon/desktop_icon.py
index 7901ef9500..fda9eed7bb 100644
--- a/frappe/desk/doctype/desktop_icon/desktop_icon.py
+++ b/frappe/desk/doctype/desktop_icon/desktop_icon.py
@@ -37,6 +37,7 @@ class DesktopIcon(Document):
reverse: DF.Check
standard: DF.Check
type: DF.Literal["module", "list", "link", "page", "query-report"]
+
# end: auto-generated types
def validate(self):
if not self.label:
@@ -225,7 +226,7 @@ def add_user_icon(_doctype, _report=None, label=None, link=None, type="link", st
icon_name = new_icon.name
- except frappe.UniqueValidationError as e:
+ except frappe.UniqueValidationError:
frappe.throw(_("Desktop Icon already exists"))
except Exception as e:
raise e
@@ -262,7 +263,7 @@ def set_desktop_icons(visible_list, ignore_duplicate=True):
an icon for the doctype"""
# clear all custom only if setup is not complete
- if not int(frappe.defaults.get_defaults().setup_complete or 0):
+ if not frappe.defaults.get_defaults().get("setup_complete", 0):
frappe.db.delete("Desktop Icon", {"standard": 0})
# set standard as blocked and hidden if setting first active domain
diff --git a/frappe/email/doctype/email_domain/email_domain.py b/frappe/email/doctype/email_domain/email_domain.py
index 5b9f38615a..fef6e1b303 100644
--- a/frappe/email/doctype/email_domain/email_domain.py
+++ b/frappe/email/doctype/email_domain/email_domain.py
@@ -73,6 +73,7 @@ class EmailDomain(Document):
use_ssl_for_outgoing: DF.Check
use_starttls: DF.Check
use_tls: DF.Check
+
# end: auto-generated types
def validate(self):
"""Validate POP3/IMAP and SMTP connections."""
@@ -120,4 +121,4 @@ class EmailDomain(Document):
elif self.use_tls:
self.smtp_port = self.smtp_port or 587
- conn_method((self.smtp_server or ""), cint(self.smtp_port) or 0).quit()
+ conn_method((self.smtp_server or ""), cint(self.smtp_port)).quit()
diff --git a/frappe/oauth.py b/frappe/oauth.py
index f0a13488da..78a70a2c1e 100644
--- a/frappe/oauth.py
+++ b/frappe/oauth.py
@@ -252,7 +252,7 @@ class OAuthWebRequestValidator(RequestValidator):
)
are_scopes_valid = True
for scp in scopes:
- are_scopes_valid = are_scopes_valid and True if scp in client_scopes else False
+ are_scopes_valid = are_scopes_valid if scp in client_scopes else False
return is_token_valid and are_scopes_valid
diff --git a/frappe/rate_limiter.py b/frappe/rate_limiter.py
index e1c93338e7..f1451ef91c 100644
--- a/frappe/rate_limiter.py
+++ b/frappe/rate_limiter.py
@@ -140,7 +140,7 @@ def rate_limit(
cache_key = f"rl:{frappe.form_dict.cmd}:{identity}"
- value = frappe.cache.get(cache_key) or 0
+ value = frappe.cache.get(cache_key)
if not value:
frappe.cache.setex(cache_key, seconds, 0)
diff --git a/frappe/social/doctype/energy_point_log/test_energy_point_log.py b/frappe/social/doctype/energy_point_log/test_energy_point_log.py
index 4cc176013d..2b4a8335fc 100644
--- a/frappe/social/doctype/energy_point_log/test_energy_point_log.py
+++ b/frappe/social/doctype/energy_point_log/test_energy_point_log.py
@@ -376,7 +376,7 @@ def create_a_todo(description=None):
def get_points(user, point_type="energy_points"):
- return _get_energy_points(user).get(point_type) or 0
+ return _get_energy_points(user).get(point_type, 0)
def assign_users_to_todo(todo_name, users):
diff --git a/frappe/twofactor.py b/frappe/twofactor.py
index 2236be3267..c166af56ce 100644
--- a/frappe/twofactor.py
+++ b/frappe/twofactor.py
@@ -43,10 +43,10 @@ def toggle_two_factor_auth(state, roles=None):
def two_factor_is_enabled(user=None):
"""Returns True if 2FA is enabled."""
- enabled = int(frappe.db.get_single_value("System Settings", "enable_two_factor_auth") or 0)
+ enabled = cint(frappe.db.get_single_value("System Settings", "enable_two_factor_auth"))
if enabled:
- bypass_two_factor_auth = int(
- frappe.db.get_single_value("System Settings", "bypass_2fa_for_retricted_ip_users") or 0
+ bypass_two_factor_auth = cint(
+ frappe.db.get_single_value("System Settings", "bypass_2fa_for_retricted_ip_users")
)
if bypass_two_factor_auth and user:
user_doc = frappe.get_doc("User", user)
diff --git a/frappe/utils/dashboard.py b/frappe/utils/dashboard.py
index 4ec3f090fc..d3fa6ac6fa 100644
--- a/frappe/utils/dashboard.py
+++ b/frappe/utils/dashboard.py
@@ -22,7 +22,7 @@ def cache_source(function):
return function(chart=chart, no_cache=no_cache)
chart_name = frappe.parse_json(chart).name
cache_key = f"chart-data:{chart_name}"
- if int(kwargs.get("refresh") or 0):
+ if cint(kwargs.get("refresh")):
results = generate_and_cache_results(kwargs, function, cache_key, chart)
else:
cached_results = frappe.cache.get_value(cache_key)
diff --git a/frappe/utils/file_manager.py b/frappe/utils/file_manager.py
index 17901c56e8..02ddcc2940 100644
--- a/frappe/utils/file_manager.py
+++ b/frappe/utils/file_manager.py
@@ -3,7 +3,6 @@
import base64
import hashlib
-import io
import json
import mimetypes
import os
@@ -283,9 +282,7 @@ def remove_file(
ignore_permissions, comment = False, None
if attached_to_doctype and attached_to_name and not from_delete:
doc = frappe.get_doc(attached_to_doctype, attached_to_name)
- ignore_permissions = doc.has_permission("write") or False
- if frappe.flags.in_web_form:
- ignore_permissions = True
+ ignore_permissions = frappe.flags.in_web_form or doc.has_permission("write")
if not file_name:
file_name = frappe.db.get_value("File", fid, "file_name")
comment = doc.add_comment("Attachment Removed", file_name)
diff --git a/frappe/utils/install.py b/frappe/utils/install.py
index df918c27e0..2fb423bb0b 100644
--- a/frappe/utils/install.py
+++ b/frappe/utils/install.py
@@ -4,6 +4,7 @@ import getpass
import frappe
from frappe.geo.doctype.country.country import import_country_and_currency
+from frappe.utils import cint
from frappe.utils.password import update_password
@@ -166,7 +167,7 @@ def before_tests():
frappe.clear_cache()
# complete setup if missing
- if not int(frappe.db.get_single_value("System Settings", "setup_complete") or 0):
+ if not cint(frappe.db.get_single_value("System Settings", "setup_complete")):
complete_setup_wizard()
frappe.db.set_single_value("Website Settings", "disable_signup", 0)
diff --git a/frappe/website/doctype/blog_post/blog_post.py b/frappe/website/doctype/blog_post/blog_post.py
index f6a2c2f495..a59ae89764 100644
--- a/frappe/website/doctype/blog_post/blog_post.py
+++ b/frappe/website/doctype/blog_post/blog_post.py
@@ -53,6 +53,7 @@ class BlogPost(WebsiteGenerator):
read_time: DF.Int
route: DF.Data | None
title: DF.Data
+
# end: auto-generated types
@frappe.whitelist()
def make_route(self):
@@ -211,14 +212,14 @@ class BlogPost(WebsiteGenerator):
"reference_name": self.name,
}
- context.like_count = frappe.db.count("Comment", filters) or 0
+ context.like_count = frappe.db.count("Comment", filters)
filters["comment_email"] = user
if user == "Guest":
filters["ip_address"] = frappe.local.request_ip
- context.like = frappe.db.count("Comment", filters) or 0
+ context.like = frappe.db.count("Comment", filters)
def set_read_time(self):
content = self.content or self.content_html or ""
@@ -385,7 +386,7 @@ def get_blog_list(
if (
post.avatar
- and (not "http:" in post.avatar and not "https:" in post.avatar)
+ and ("http:" not in post.avatar and "https:" not in post.avatar)
and not post.avatar.startswith("/")
):
post.avatar = "/" + post.avatar
diff --git a/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py b/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py
index 63ed5c24ed..6b166d2a14 100644
--- a/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py
+++ b/frappe/website/doctype/personal_data_deletion_request/personal_data_deletion_request.py
@@ -29,6 +29,7 @@ class PersonalDataDeletionRequest(Document):
deletion_steps: DF.Table[PersonalDataDeletionStep]
email: DF.Data
status: DF.Literal["Pending Verification", "Pending Approval", "On Hold", "Deleted"]
+
# end: auto-generated types
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -154,7 +155,7 @@ class PersonalDataDeletionRequest(Document):
row_data = {
"status": "Pending",
"document_type": step.get("doctype"),
- "partial": step.get("partial") or False,
+ "partial": step.get("partial", False),
"fields": json.dumps(step.get("redact_fields", [])),
"filtered_by": step.get("filtered_by") or "",
}
diff --git a/frappe/website/doctype/website_settings/website_settings.py b/frappe/website/doctype/website_settings/website_settings.py
index 931acb87cf..d19ac375a5 100644
--- a/frappe/website/doctype/website_settings/website_settings.py
+++ b/frappe/website/doctype/website_settings/website_settings.py
@@ -6,7 +6,7 @@ from urllib.parse import quote
import frappe
from frappe import _
from frappe.model.document import Document
-from frappe.utils import encode, get_request_site_address
+from frappe.utils import cint, encode, get_request_site_address
from frappe.website.utils import get_boot_data
@@ -63,6 +63,7 @@ class WebsiteSettings(Document):
top_bar_items: DF.Table[TopBarItem]
website_theme: DF.Link | None
website_theme_image_link: DF.Code | None
+
# end: auto-generated types
def validate(self):
self.validate_top_bar_items()
@@ -216,7 +217,7 @@ def get_website_settings(context=None):
"linked_in_share",
"disable_signup",
]:
- context[k] = int(context.get(k) or 0)
+ context[k] = cint(context.get(k))
if settings.address:
context["footer_address"] = settings.address
diff --git a/frappe/website/website_generator.py b/frappe/website/website_generator.py
index 509a01033c..43db2a780e 100644
--- a/frappe/website/website_generator.py
+++ b/frappe/website/website_generator.py
@@ -98,8 +98,8 @@ class WebsiteGenerator(Document):
def is_website_published(self):
"""Return true if published in website"""
- if self.get_condition_field():
- return self.get(self.get_condition_field()) and True or False
+ if data := self.get_condition_field():
+ return self.get(data) or False
else:
return True
@@ -141,7 +141,6 @@ class WebsiteGenerator(Document):
and self.is_website_published()
and self.meta.allow_guest_to_view
):
-
url = frappe.utils.get_url(self.route)
frappe.enqueue(
"frappe.website.doctype.website_settings.google_indexing.publish_site",
diff --git a/frappe/workflow/doctype/workflow/workflow.py b/frappe/workflow/doctype/workflow/workflow.py
index 9591d3df69..a8c59748b1 100644
--- a/frappe/workflow/doctype/workflow/workflow.py
+++ b/frappe/workflow/doctype/workflow/workflow.py
@@ -3,8 +3,8 @@
import frappe
from frappe import _
-from frappe.model import no_value_fields
from frappe.model.document import Document
+from frappe.utils import cint
class Workflow(Document):
@@ -29,6 +29,7 @@ class Workflow(Document):
workflow_data: DF.JSON | None
workflow_name: DF.Data
workflow_state_field: DF.Data
+
# end: auto-generated types
def validate(self):
self.set_active()
@@ -69,7 +70,7 @@ class Workflow(Document):
docstatus_map = {}
states = self.get("states")
for d in states:
- if not d.doc_status in docstatus_map:
+ if d.doc_status not in docstatus_map:
frappe.db.sql(
"""
UPDATE `tab{doctype}`
@@ -140,7 +141,7 @@ class Workflow(Document):
frappe.throw(frappe._("Cannot cancel before submitting. See Transition {0}").format(t.idx))
def set_active(self):
- if int(self.is_active or 0):
+ if cint(self.is_active):
# clear all other
frappe.db.sql(
"""UPDATE `tabWorkflow` SET `is_active`=0
From 43ffd175590f1d5c0072764ac292fec11e1d1096 Mon Sep 17 00:00:00 2001
From: Shadrak Gurupnor
Date: Thu, 23 Nov 2023 14:26:29 +0530
Subject: [PATCH 166/262] chore: translation
---
frappe/public/js/frappe/ui/group_by/group_by.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 46b85a05cb..2f62904813 100644
--- a/frappe/public/js/frappe/ui/group_by/group_by.js
+++ b/frappe/public/js/frappe/ui/group_by/group_by.js
@@ -153,7 +153,7 @@ frappe.ui.GroupBy = class {
let option_text =
doctype == this.doctype
? field_label
- : `${field_label} (${__(doctype)})`;
+ : `${__(field_label)} (${__(doctype)})`;
this.aggregate_on_html += ``;
}
From 1e0920409fc22455a118cec7c13003266af20841 Mon Sep 17 00:00:00 2001
From: ruthra kumar
Date: Thu, 23 Nov 2023 14:49:28 +0530
Subject: [PATCH 167/262] fix: ignore dynamic fields in virtual doctypes
---
frappe/model/dynamic_links.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/model/dynamic_links.py b/frappe/model/dynamic_links.py
index 523d587389..61ed86de46 100644
--- a/frappe/model/dynamic_links.py
+++ b/frappe/model/dynamic_links.py
@@ -13,7 +13,7 @@ dynamic_link_queries = [
`tabDocField`.fieldname, `tabDocField`.options
from `tabDocField`, `tabDocType`
where `tabDocField`.fieldtype='Dynamic Link' and
- `tabDocType`.`name`=`tabDocField`.parent
+ `tabDocType`.`name`=`tabDocField`.parent and `tabDocType`.is_virtual = 0
order by `tabDocType`.read_only, `tabDocType`.in_create""",
"""select `tabCustom Field`.dt as parent,
`tabDocType`.read_only, `tabDocType`.in_create,
From f007f16ce98a61beafc2507eba60065ed9484caa Mon Sep 17 00:00:00 2001
From: Akhil Narang
Date: Thu, 23 Nov 2023 15:35:37 +0530
Subject: [PATCH 168/262] fix: handle invalid passwords better (#23377)
* chore(login): show a message for response code 500 as well
Signed-off-by: Akhil Narang
* refactor: reject passwords > 512 characters
Signed-off-by: Akhil Narang
---------
Signed-off-by: Akhil Narang
---
frappe/auth.py | 4 ++++
frappe/core/doctype/user/user.py | 4 ++++
frappe/templates/includes/login/login.js | 5 +++--
3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/frappe/auth.py b/frappe/auth.py
index 941edb9277..efd1428545 100644
--- a/frappe/auth.py
+++ b/frappe/auth.py
@@ -25,6 +25,7 @@ from frappe.website.utils import get_home_page
SAFE_HTTP_METHODS = frozenset(("GET", "HEAD", "OPTIONS"))
UNSAFE_HTTP_METHODS = frozenset(("POST", "PUT", "DELETE", "PATCH"))
+MAX_PASSWORD_SIZE = 512
class HTTPRequest:
@@ -235,6 +236,9 @@ class LoginManager:
if not (user and pwd):
self.fail(_("Incomplete login details"), user=user)
+ if len(pwd) > MAX_PASSWORD_SIZE:
+ self.fail(_("Password size exceeded the maximum allowed size"), user=user)
+
_raw_user_name = user
user = User.find_by_credentials(user, pwd)
diff --git a/frappe/core/doctype/user/user.py b/frappe/core/doctype/user/user.py
index cdb3e394ee..711c07ed95 100644
--- a/frappe/core/doctype/user/user.py
+++ b/frappe/core/doctype/user/user.py
@@ -9,6 +9,7 @@ import frappe.defaults
import frappe.permissions
import frappe.share
from frappe import STANDARD_USERS, _, msgprint, throw
+from frappe.auth import MAX_PASSWORD_SIZE
from frappe.core.doctype.user_type.user_type import user_linked_with_permission_on_doctype
from frappe.desk.doctype.notification_settings.notification_settings import (
create_notification_settings,
@@ -823,6 +824,9 @@ def update_password(
old_password (str, optional): Old password. Defaults to None.
"""
+ if len(new_password) > MAX_PASSWORD_SIZE:
+ frappe.throw(_("Password size exceeded the maximum allowed size."))
+
result = test_password_strength(new_password)
feedback = result.get("feedback", None)
diff --git a/frappe/templates/includes/login/login.js b/frappe/templates/includes/login/login.js
index 6e18421837..90e12cf3d0 100644
--- a/frappe/templates/includes/login/login.js
+++ b/frappe/templates/includes/login/login.js
@@ -287,8 +287,9 @@ login.login_handlers = (function () {
}
},
401: get_error_handler('{{ _("Invalid Login. Try again.") }}'),
- 417: get_error_handler('{{ _("Oops! Something went wrong") }}'),
- 404: get_error_handler('{{ _("User does not exist.")}}')
+ 417: get_error_handler('{{ _("Oops! Something went wrong.") }}'),
+ 404: get_error_handler('{{ _("User does not exist.")}}'),
+ 500: get_error_handler('{{ _("Something went wrong.") }}')
};
return login_handlers;
From f8c5a61bbd27629dc16d6e18903e1d2b3cf8bd52 Mon Sep 17 00:00:00 2001
From: Akhil Narang
Date: Thu, 23 Nov 2023 15:54:13 +0530
Subject: [PATCH 169/262] refactor(report): simplify check further
NoneType will evaluate to False here so we don't need this complexity
Co-authored-by: Ankush Menat
---
frappe/core/doctype/report/report.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py
index 65fa096df0..2d78892f14 100644
--- a/frappe/core/doctype/report/report.py
+++ b/frappe/core/doctype/report/report.py
@@ -130,7 +130,7 @@ class Report(Document):
if frappe.flags.in_import:
return
- if self.is_standard == "Yes" and (frappe.local.conf.get("developer_mode", 0) == 1):
+ if self.is_standard == "Yes" and frappe.conf.developer_mode:
export_to_files(
record_list=[["Report", self.name]], record_module=self.module, create_init=True
)
From cc58fd20ca2dd52a8c5761358137ee645d1716d1 Mon Sep 17 00:00:00 2001
From: Akhil Narang
Date: Thu, 23 Nov 2023 16:04:56 +0530
Subject: [PATCH 170/262] refactor(oauth): simplify scopes check with the usage
of `all()`
Signed-off-by: Akhil Narang
---
frappe/oauth.py | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/frappe/oauth.py b/frappe/oauth.py
index 78a70a2c1e..ebd6b91ae7 100644
--- a/frappe/oauth.py
+++ b/frappe/oauth.py
@@ -250,10 +250,7 @@ class OAuthWebRequestValidator(RequestValidator):
client_scopes = frappe.db.get_value("OAuth Client", otoken.client, "scopes").split(
get_url_delimiter()
)
- are_scopes_valid = True
- for scp in scopes:
- are_scopes_valid = are_scopes_valid if scp in client_scopes else False
-
+ are_scopes_valid = all(scope in client_scopes for scope in scopes)
return is_token_valid and are_scopes_valid
# Token refresh request
From 23bcb6733ebfcc5a4eaef14d6c938ea6dda2a1c6 Mon Sep 17 00:00:00 2001
From: Akhil Narang
Date: Thu, 23 Nov 2023 16:06:07 +0530
Subject: [PATCH 171/262] refactor(website_generator): update variable name to
make more sense as per usage
Co-authored-by: Ankush Menat
---
frappe/website/website_generator.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/frappe/website/website_generator.py b/frappe/website/website_generator.py
index 43db2a780e..8f814f60cb 100644
--- a/frappe/website/website_generator.py
+++ b/frappe/website/website_generator.py
@@ -98,8 +98,8 @@ class WebsiteGenerator(Document):
def is_website_published(self):
"""Return true if published in website"""
- if data := self.get_condition_field():
- return self.get(data) or False
+ if condition_field := self.get_condition_field():
+ return self.get(condition_field) or False
else:
return True
From d21c7730dab6b8e8dc946af49a31f3b423e03aca Mon Sep 17 00:00:00 2001
From: Akhil Narang
Date: Thu, 23 Nov 2023 16:34:10 +0530
Subject: [PATCH 172/262] fix(commands/site): the old logic did rely on 0
evaluting to false
Signed-off-by: Akhil Narang
---
frappe/commands/site.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frappe/commands/site.py b/frappe/commands/site.py
index 729e19594a..65f896eb24 100644
--- a/frappe/commands/site.py
+++ b/frappe/commands/site.py
@@ -950,7 +950,7 @@ def move(dest_dir, site):
site_dump_exists = True
count = 0
while site_dump_exists:
- final_new_path = new_path + str(count)
+ final_new_path = new_path + str(count or "")
site_dump_exists = os.path.exists(final_new_path)
count += 1
From 06fbe6df20efc69714b778aa588dd14761ada5ab Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Thu, 23 Nov 2023 16:51:23 +0100
Subject: [PATCH 173/262] fix: default Email Group in system language
---
frappe/email/doctype/newsletter/newsletter.py | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/frappe/email/doctype/newsletter/newsletter.py b/frappe/email/doctype/newsletter/newsletter.py
index 5aabe3d85e..efe93bf5ed 100644
--- a/frappe/email/doctype/newsletter/newsletter.py
+++ b/frappe/email/doctype/newsletter/newsletter.py
@@ -308,11 +308,11 @@ def confirmed_unsubscribe(email, group):
@frappe.whitelist(allow_guest=True)
@rate_limit(limit=10, seconds=60 * 60)
-def subscribe(email, email_group=None): # noqa
+def subscribe(email, email_group=None):
"""API endpoint to subscribe an email to a particular email group. Triggers a confirmation email."""
if email_group is None:
- email_group = _("Website")
+ email_group = get_default_email_group()
# build subscription confirmation URL
api_endpoint = frappe.utils.get_url(
@@ -355,13 +355,16 @@ def subscribe(email, email_group=None): # noqa
@frappe.whitelist(allow_guest=True)
-def confirm_subscription(email, email_group=_("Website")): # noqa
+def confirm_subscription(email, email_group=None):
"""API endpoint to confirm email subscription.
This endpoint is called when user clicks on the link sent to their mail.
"""
if not verify_request():
return
+ if email_group is None:
+ email_group = get_default_email_group()
+
if not frappe.db.exists("Email Group", email_group):
frappe.get_doc({"doctype": "Email Group", "title": email_group}).insert(ignore_permissions=True)
@@ -438,3 +441,7 @@ def newsletter_email_read(recipient_email=None, reference_doctype=None, referenc
finally:
frappe.response.update(frappe.utils.get_imaginary_pixel_response())
+
+
+def get_default_email_group():
+ return _("Website", lang=frappe.db.get_default("language"))
From a99bf561603f8e9f17c373bc7ed9ff7df6bfde50 Mon Sep 17 00:00:00 2001
From: barredterra <14891507+barredterra@users.noreply.github.com>
Date: Fri, 24 Nov 2023 00:59:22 +0100
Subject: [PATCH 174/262] fix: german translations for timespan
---
frappe/translations/de.csv | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/frappe/translations/de.csv b/frappe/translations/de.csv
index 9a9154467b..7977b4d716 100644
--- a/frappe/translations/de.csv
+++ b/frappe/translations/de.csv
@@ -1428,6 +1428,7 @@ Landing Page,Zielseite,
Language,Sprache,
Language Code,Sprachcode,
"Language, Date and Time settings","Einstellungen zu Sprache, Datum und Uhrzeit",
+Last 6 months,Vergangene zwei Quartale,
Last Active,Zuletzt aktiv,
Last IP,Letzte IP,
Last Known Versions,Letzte bekannte Versionen,
@@ -1436,14 +1437,14 @@ Last Message,Letzte Nachricht,
Last Modified By,Zuletzt geändert durch,
Last Modified Date,Zuletzt geändertes Datum,
Last Modified On,Zuletzt geändert am,
-Last Month,Im vergangenen Monat,
+Last Month,Vergangener Monat,
Last Point Allocation Date,Datum der letzten Punktzuweisung,
-Last Quarter,Letztes Quartal,
+Last Quarter,Vergangenes Quartal,
Last Synced On,Zuletzt synchronisiert am,
Last Updated By,Zuletzt aktualisiert von,
Last Updated On,Zuletzt aktualisiert am,
Last User,Letzter Benutzer,
-Last Week,Letzte Woche,
+Last Week,Vergangene Woche,
Last Year,Vergangenes Jahr,
Last synced {0},Zuletzt synchronisiert {0},
Learn more,Mehr erfahren,
@@ -1641,6 +1642,11 @@ Next Scheduled Date,Nächstes geplantes Datum,
Next State,Nächster Status,
Next Sync Token,Nächstes Sync-Token,
Next actions,Nächste Aktionen,
+Next Week,Kommende Woche,
+Next Month,Kommender Monat,
+Next Quarter,Kommendes Quartal,
+Next 6 months,Kommende zwei Quartale,
+Next Year,Kommendes Jahr,
No Active Sessions,Keine aktiven Sessions,
No Copy,Keine Kopie,
No Email Account,Kein E-Mail-Konto,
@@ -4213,10 +4219,10 @@ Google Snippet Preview,Google Snippet-Vorschau,
This is an example Google SERP Preview.,Dies ist ein Beispiel für die Google SERP-Vorschau.,
Add Gray Background,Fügen Sie grauen Hintergrund hinzu,
Hide Block,Block ausblenden,
-This Week,Diese Woche,
-This Month,Diesen Monat,
-This Quarter,Dieses Quartal,
-This Year,Dieses Jahr,
+This Week,Aktuelle Woche,
+This Month,Aktueller Monat,
+This Quarter,Aktuelles Quartal,
+This Year,Aktuelles Jahr,
All Time,Alle Zeit,
Select From Date,Wählen Sie Von Datum,
since yesterday,seit gestern,
From 770598df4998304611d59bcabf949c0ca7665379 Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Fri, 24 Nov 2023 10:18:29 +0530
Subject: [PATCH 175/262] Revert "refactor: remove code that manually prevents
bulk refresh (#23138)"
This reverts commit 60d99eb20c8c49a976b3b48c829d9c8d9f1c5919.
---
frappe/public/js/frappe/list/list_view.js | 35 ++++++++++++++++++-----
1 file changed, 28 insertions(+), 7 deletions(-)
diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js
index 893c212f23..58f8a7606c 100644
--- a/frappe/public/js/frappe/list/list_view.js
+++ b/frappe/public/js/frappe/list/list_view.js
@@ -1520,8 +1520,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
if (this.filter_area.is_being_edited()) {
return true;
}
- // this flag is left for backward compatibility, there's no need to prevent realtime
- // refresh. They are by default debounced now and there's no way to bypass that.
+ // this is set when a bulk operation is called from a list view which might update the list view
+ // this is to avoid the list view from refreshing a lot of times
+ // the list view is updated once after the bulk operation is complete
if (this.disable_list_update) {
return true;
}
@@ -1723,6 +1724,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
get_workflow_action_menu_items() {
const workflow_actions = [];
+ const me = this;
if (frappe.model.has_workflow(this.doctype)) {
const actions = frappe.workflow.get_all_transition_actions(this.doctype);
@@ -1731,11 +1733,16 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
label: __(action),
name: action,
action: () => {
- frappe.xcall("frappe.model.workflow.bulk_workflow_approval", {
- docnames: this.get_checked_items(true),
- doctype: this.doctype,
- action: action,
- });
+ me.disable_list_update = true;
+ frappe
+ .xcall("frappe.model.workflow.bulk_workflow_approval", {
+ docnames: this.get_checked_items(true),
+ doctype: this.doctype,
+ action: action,
+ })
+ .finally(() => {
+ me.disable_list_update = false;
+ });
},
is_workflow_action: true,
});
@@ -1796,7 +1803,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return {
label: __("Assign To", null, "Button in list view actions menu"),
action: () => {
+ this.disable_list_update = true;
bulk_operations.assign(this.get_checked_items(true), () => {
+ this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@@ -1809,7 +1818,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return {
label: __("Apply Assignment Rule", null, "Button in list view actions menu"),
action: () => {
+ this.disable_list_update = true;
bulk_operations.apply_assignment_rule(this.get_checked_items(true), () => {
+ this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@@ -1822,7 +1833,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return {
label: __("Add Tags", null, "Button in list view actions menu"),
action: () => {
+ this.disable_list_update = true;
bulk_operations.add_tags(this.get_checked_items(true), () => {
+ this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@@ -1859,7 +1872,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
);
}
frappe.confirm(message, () => {
+ this.disable_list_update = true;
bulk_operations.delete(docnames, () => {
+ this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@@ -1882,7 +1897,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
"Title of confirmation dialog"
),
() => {
+ this.disable_list_update = true;
bulk_operations.submit_or_cancel(docnames, "cancel", () => {
+ this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@@ -1907,7 +1924,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
"Title of confirmation dialog"
),
() => {
+ this.disable_list_update = true;
bulk_operations.submit_or_cancel(docnames, "submit", () => {
+ this.disable_list_update = false;
this.clear_checked_items();
this.refresh();
});
@@ -1931,7 +1950,9 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
}
});
+ this.disable_list_update = true;
bulk_operations.edit(this.get_checked_items(true), field_mappings, () => {
+ this.disable_list_update = false;
this.refresh();
});
},
From 62529f3d74dc4fea87a09cce6a50928b2d2a1d9b Mon Sep 17 00:00:00 2001
From: Ankush Menat
Date: Fri, 24 Nov 2023 10:25:12 +0530
Subject: [PATCH 176/262] chore(telemetry): track logged errors (#23390)
Also includes unhandled errors
---
frappe/utils/error.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/frappe/utils/error.py b/frappe/utils/error.py
index 7d4e5c7c16..fa78697d88 100644
--- a/frappe/utils/error.py
+++ b/frappe/utils/error.py
@@ -38,6 +38,7 @@ def log_error(
):
"""Log error to Error Log"""
from frappe.monitor import get_trace_id
+ from frappe.utils.telemetry import capture
# Parameter ALERT:
# the title and message may be swapped
@@ -58,14 +59,16 @@ def log_error(
print(f"Failed to log error in db: {title}")
return
+ trace_id = get_trace_id()
error_log = frappe.get_doc(
doctype="Error Log",
error=traceback,
method=title,
reference_doctype=reference_doctype,
reference_name=reference_name,
- trace_id=get_trace_id(),
+ trace_id=trace_id,
)
+ capture("error_logged", "frappe", properties={"title": title, "trace_id": trace_id})
if frappe.flags.read_only or defer_insert:
error_log.deferred_insert()
From 01fb455a76716836a90289dc904c03216785c1f8 Mon Sep 17 00:00:00 2001
From: Shariq Ansari
Date: Fri, 24 Nov 2023 11:29:29 +0530
Subject: [PATCH 177/262] fix: webform banner_image name replacing navbar
banner_image
---
frappe/website/doctype/web_form/templates/web_form.html | 8 ++++----
frappe/website/doctype/web_form/web_form.py | 3 +++
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/frappe/website/doctype/web_form/templates/web_form.html b/frappe/website/doctype/web_form/templates/web_form.html
index 1d663933c3..e30284e1ca 100644
--- a/frappe/website/doctype/web_form/templates/web_form.html
+++ b/frappe/website/doctype/web_form/templates/web_form.html
@@ -7,9 +7,9 @@
{% block breadcrumbs %}{% endblock %}
{% block header %}
- {% if banner_image %}
+ {% if webform_banner_image %}
-
+
{% endif %}
{% endblock %}
@@ -51,7 +51,7 @@
- {% if not banner_image and has_header and login_required and show_list %}
+ {% if not webform_banner_image and has_header and login_required and show_list %}
{% include "templates/includes/breadcrumbs.html" %}
{% else %}
@@ -59,7 +59,7 @@
- {% if banner_image and has_header and login_required and show_list %}
+ {% if webform_banner_image and has_header and login_required and show_list %}
{% include "templates/includes/breadcrumbs.html" %}
{% endif %}