From ac842872666e5ff92a9a58183efd2b6ef12c2e58 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Fri, 24 Jun 2022 18:31:43 +0530 Subject: [PATCH 1/9] fix: improve SVG for expenses icon --- frappe/public/icons/timeless/icons.svg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frappe/public/icons/timeless/icons.svg b/frappe/public/icons/timeless/icons.svg index fbd72d6fb5..af63d0c8ff 100644 --- a/frappe/public/icons/timeless/icons.svg +++ b/frappe/public/icons/timeless/icons.svg @@ -613,8 +613,8 @@ - + From b7514a05ca9039bf9336ece3938b69bdeecb6585 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Tue, 28 Jun 2022 00:37:31 +0530 Subject: [PATCH 2/9] fix(redis): pass shared param when setting value based on generator --- frappe/utils/redis_wrapper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/utils/redis_wrapper.py b/frappe/utils/redis_wrapper.py index 178c3d4416..c29836af32 100644 --- a/frappe/utils/redis_wrapper.py +++ b/frappe/utils/redis_wrapper.py @@ -199,7 +199,7 @@ class RedisWrapper(redis.Redis): frappe.local.cache[_name][key] = value elif generator: value = generator() - self.hset(name, key, value) + self.hset(name, key, value, shared=shared) return value def hdel(self, name, key, shared=False): From c6fa8ab090fdc0d07dbd295b5a262ed2a5acf456 Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Tue, 28 Jun 2022 11:50:57 +0530 Subject: [PATCH 3/9] fix: email not sent if contain file with current site url (#17250) --- frappe/core/doctype/file/file.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index e8b8da76ab..bb4b441680 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -16,7 +16,7 @@ from requests.exceptions import HTTPError, SSLError import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import call_hook_method, cint, get_files_path, get_hook_method +from frappe.utils import call_hook_method, cint, get_files_path, get_hook_method, get_url from frappe.utils.file_manager import is_safe_path from frappe.utils.image import optimize_image, strip_exif_data @@ -61,7 +61,12 @@ class File(Document): self.set_file_name() self.validate_attachment_limit() - if not self.is_folder and not self.is_remote_file: + if self.is_folder: + return + + if self.is_remote_file: + self.validate_remote_file() + else: self.save_file(content=self.get_content()) self.flags.new_file = True frappe.local.rollback_observers.append(self) @@ -255,6 +260,12 @@ class File(Document): title=_("Attachment Limit Reached"), ) + 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): + self.file_url = self.file_url.split(site_url, 1)[1] + def set_folder_name(self): """Make parent folders if not exists based on reference doctype and name""" if self.folder: @@ -445,6 +456,10 @@ class File(Document): file_path = self.file_url or self.file_name + site_url = get_url() + if "/files/" in file_path and file_path.startswith(site_url): + file_path = file_path.split(site_url, 1)[1] + if "/" not in file_path: if self.is_private: file_path = f"/private/files/{file_path}" From 9bd753551b6af9cb25a445526969f563bb738e5a Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 28 Jun 2022 12:07:34 +0530 Subject: [PATCH 4/9] ci: temp fix for semgrep (#17228) * ci: respekt my authoritah * ci: use pip semgrep --- .github/helper/roulette.py | 8 ++++---- .github/workflows/linters.yml | 16 +++++++--------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/.github/helper/roulette.py b/.github/helper/roulette.py index 9165198012..b859b87047 100644 --- a/.github/helper/roulette.py +++ b/.github/helper/roulette.py @@ -77,13 +77,13 @@ if __name__ == "__main__": updated_py_file_count = len(list(filter(is_py, files_list))) only_py_changed = updated_py_file_count == len(files_list) - if ci_files_changed: - print("CI related files were updated, running all build processes.") - - elif has_skip_ci_label(pr_number, repo): + if has_skip_ci_label(pr_number, repo): print("Found `Skip CI` label on pr, stopping build process.") sys.exit(0) + elif ci_files_changed: + print("CI related files were updated, running all build processes.") + elif only_docs_changed: print("Only docs were updated, stopping build process.") sys.exit(0) diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 4c845dba8c..6d1029d51d 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -11,10 +11,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.8 + - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.8 + python-version: '3.10' - name: Install and Run Pre-commit uses: pre-commit/action@v3.0.0 @@ -22,10 +22,8 @@ jobs: - name: Download Semgrep rules run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules - - uses: returntocorp/semgrep-action@v1 - env: - SEMGREP_TIMEOUT: 120 - with: - config: >- - r/python.lang.correctness - ./frappe-semgrep-rules/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 From 4bf7cd8210d92e89e9ad818fc9c72e317688d8d7 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 28 Jun 2022 12:19:52 +0530 Subject: [PATCH 5/9] fix: ignore virtual docfield property conflicts --- frappe/core/doctype/doctype/doctype.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py index b4cbbd6233..e56803acb7 100644 --- a/frappe/core/doctype/doctype/doctype.py +++ b/frappe/core/doctype/doctype/doctype.py @@ -171,7 +171,7 @@ class DocType(Document): if docfield.fieldname in method_set: conflict_type = "controller method" - if docfield.fieldname in property_set: + if docfield.fieldname in property_set and not docfield.is_virtual: conflict_type = "class property" if conflict_type: From 600186488866709b2099630fc3a402b6d0e5bb30 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Tue, 28 Jun 2022 11:38:40 +0530 Subject: [PATCH 6/9] fix(UX): show next execution time on scheduled job --- .../scheduled_job_type.json | 25 +++++++++++++++++-- .../scheduled_job_type/scheduled_job_type.py | 4 +++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json index d4d79b21fb..cc2a0e870a 100644 --- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json +++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.json @@ -16,8 +16,11 @@ "server_script", "frequency", "cron_format", + "create_log", + "status_section", "last_execution", - "create_log" + "column_break_9", + "next_execution" ], "fields": [ { @@ -72,6 +75,22 @@ "options": "Server Script", "read_only": 1, "search_index": 1 + }, + { + "fieldname": "next_execution", + "fieldtype": "Datetime", + "is_virtual": 1, + "label": "Next Execution", + "read_only": 1 + }, + { + "fieldname": "status_section", + "fieldtype": "Section Break", + "label": "Status" + }, + { + "fieldname": "column_break_9", + "fieldtype": "Column Break" } ], "in_create": 1, @@ -81,7 +100,7 @@ "link_fieldname": "scheduled_job_type" } ], - "modified": "2020-10-07 10:39:24.519460", + "modified": "2022-06-28 02:55:12.470915", "modified_by": "Administrator", "module": "Core", "name": "Scheduled Job Type", @@ -103,5 +122,7 @@ "quick_entry": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], + "title_field": "method", "track_changes": 1 } \ No newline at end of file diff --git a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py index 318b156dcd..673805ae8b 100644 --- a/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py +++ b/frappe/core/doctype/scheduled_job_type/scheduled_job_type.py @@ -50,6 +50,10 @@ class ScheduledJobType(Document): queued_jobs = get_jobs(site=frappe.local.site, key="job_type")[frappe.local.site] return self.method in queued_jobs + @property + def next_execution(self): + return self.get_next_execution() + def get_next_execution(self): CRON_MAP = { "Yearly": "0 0 1 1 *", From 971b8160a33fab9ce939e9c751fa45da7499e387 Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Tue, 28 Jun 2022 12:39:45 +0530 Subject: [PATCH 7/9] fix: extra column in excel after exporting report with group by (#17126) Co-authored-by: gavin --- frappe/desk/reportview.py | 22 ++++++++++++++++------ frappe/model/db_query.py | 5 +++++ frappe/tests/test_db_query.py | 4 +--- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/frappe/desk/reportview.py b/frappe/desk/reportview.py index d6dce68399..893c2a6606 100644 --- a/frappe/desk/reportview.py +++ b/frappe/desk/reportview.py @@ -156,8 +156,6 @@ def setup_group_by(data): **data ) ) - if data.aggregate_on_field: - data.fields.append(f"`tab{data.aggregate_on_doctype}`.`{data.aggregate_on_field}`") else: raise_invalid_field(data.aggregate_on_field) @@ -435,11 +433,20 @@ def append_totals_row(data): def get_labels(fields, doctype): """get column labels based on column names""" labels = [] + doctype = doctype.lower() for key in fields: - key = key.split(" as ")[0] + aggregate_function = "" + + key = key.casefold().split(" as ", maxsplit=1)[0] if key.startswith(("count(", "sum(", "avg(")): - continue + # Get aggregate function and _aggregate_column + # key = 'sum(`tabDocType`.`fieldname`)' + if not key.rstrip().endswith(")"): + continue + _agg_fn, _key = key.split("(", maxsplit=1) + aggregate_function = _agg_fn.lower() # aggregate_function = 'sum' + key = _key[:-1] # key = `tabDocType`.`fieldname` if "." in key: parenttype, fieldname = key.split(".")[0][4:-1], key.split(".")[1].strip("`") @@ -455,7 +462,10 @@ def get_labels(fields, doctype): if parenttype != doctype: # If the column is from a child table, append the child doctype. # For example, "Item Code (Sales Invoice Item)". - label += f" ({ _(parenttype) })" + label += f" ({ _(parenttype.title()) })" + + if aggregate_function: + label = _("{0} of {1}").format(aggregate_function.capitalize(), label) labels.append(label) @@ -464,7 +474,7 @@ def get_labels(fields, doctype): def handle_duration_fieldtype_values(doctype, data, fields): for field in fields: - key = field.split(" as ")[0] + key = field.casefold().split(" as ", maxsplit=1)[0] if key.startswith(("count(", "sum(", "avg(")): continue diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py index 7fb38848e2..0b8f790246 100644 --- a/frappe/model/db_query.py +++ b/frappe/model/db_query.py @@ -417,6 +417,8 @@ class DatabaseQuery(object): "extract(", "locate(", "strpos(", + ] + aggregate_functions = [ "count(", "sum(", "avg(", @@ -427,6 +429,9 @@ class DatabaseQuery(object): if not ("tab" in field and "." in field) or any(x for x in sql_functions if x in field): continue + if any(x for x in aggregate_functions if x in field): + field = field.split("(", 1)[1][:-1] + table_name = field.split(".")[0] if table_name.lower().startswith("group_concat("): diff --git a/frappe/tests/test_db_query.py b/frappe/tests/test_db_query.py index c1b2e05266..2dd1743767 100644 --- a/frappe/tests/test_db_query.py +++ b/frappe/tests/test_db_query.py @@ -643,9 +643,7 @@ class TestReportview(unittest.TestCase): ) response = execute_cmd("frappe.desk.reportview.get") - self.assertListEqual( - response["keys"], ["field_label", "field_name", "_aggregate_column", "columns"] - ) + self.assertListEqual(response["keys"], ["field_label", "field_name", "_aggregate_column"]) def test_cast_name(self): from frappe.core.doctype.doctype.test_doctype import new_doctype From 4dff0d25a36942560bf65ace9e58bbb2da73d351 Mon Sep 17 00:00:00 2001 From: Shariq Ansari <30859809+shariquerik@users.noreply.github.com> Date: Tue, 28 Jun 2022 16:17:26 +0530 Subject: [PATCH 8/9] feat: add email retry limit in system settings (#17259) **MAX_RETRY_COUNT** for email was hard coded as 3. Added **Email Retry Limit** field in **Email** section in **System Settings** image >no-docs --- .../doctype/system_settings/system_settings.json | 13 ++++++++++--- frappe/email/doctype/email_queue/email_queue.py | 8 +++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/frappe/core/doctype/system_settings/system_settings.json b/frappe/core/doctype/system_settings/system_settings.json index c954e41202..a444062b5a 100644 --- a/frappe/core/doctype/system_settings/system_settings.json +++ b/frappe/core/doctype/system_settings/system_settings.json @@ -63,6 +63,7 @@ "otp_issuer_name", "email", "email_footer_address", + "email_retry_limit", "column_break_18", "disable_standard_email_footer", "hide_footer_in_auto_email_reports", @@ -495,8 +496,8 @@ "fieldname": "allow_older_web_view_links", "fieldtype": "Check", "label": "Allow Older Web View Links (Insecure)" - }, - { + }, + { "fieldname": "column_break_64", "fieldtype": "Column Break" }, @@ -518,12 +519,18 @@ "fieldtype": "Duration", "label": "Reset Password Link Expiry Duration", "non_negative": 1 + }, + { + "default": "3", + "fieldname": "email_retry_limit", + "fieldtype": "Int", + "label": "Email Retry Limit" } ], "icon": "fa fa-cog", "issingle": 1, "links": [], - "modified": "2022-05-19 00:00:18.095269", + "modified": "2022-06-21 13:55:04.796152", "modified_by": "Administrator", "module": "Core", "name": "System Settings", diff --git a/frappe/email/doctype/email_queue/email_queue.py b/frappe/email/doctype/email_queue/email_queue.py index c3002607b4..4fc828eb62 100644 --- a/frappe/email/doctype/email_queue/email_queue.py +++ b/frappe/email/doctype/email_queue/email_queue.py @@ -30,8 +30,6 @@ from frappe.utils import ( split_emails, ) -MAX_RETRY_COUNT = 3 - class EmailQueue(Document): DOCTYPE = "Email Queue" @@ -210,7 +208,7 @@ class SendMailContext: email_status = (self.sent_to and "Partially Sent") or "Not Sent" self.queue_doc.update_status(status=email_status, commit=True) elif exc_type: - if self.queue_doc.retry < MAX_RETRY_COUNT: + if self.queue_doc.retry < get_email_retry_limit(): update_fields = {"status": "Not Sent", "retry": self.queue_doc.retry + 1} else: update_fields = {"status": (self.sent_to and "Partially Errored") or "Error"} @@ -372,6 +370,10 @@ def on_doctype_update(): ) +def get_email_retry_limit(): + return cint(frappe.db.get_system_setting("email_retry_limit")) or 3 + + class QueueBuilder: """Builds Email Queue from the given data""" From d58f2ed8e7cf1ef33df8196174193c760f2d2daf Mon Sep 17 00:00:00 2001 From: Samuel Danieli <23150094+scdanieli@users.noreply.github.com> Date: Tue, 28 Jun 2022 13:58:27 +0200 Subject: [PATCH 9/9] fix: german translations (#17324) --- frappe/translations/de.csv | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/frappe/translations/de.csv b/frappe/translations/de.csv index d00548458c..b22befd321 100644 --- a/frappe/translations/de.csv +++ b/frappe/translations/de.csv @@ -1993,7 +1993,7 @@ QR Code,QR-Code, QR Code for Login Verification,QR Code für Login-Bestätigung, QZ Tray Connection Active!,QZ-Tray-Verbindung aktiv!, QZ Tray Failed: ,QZ-Fach fehlgeschlagen:, -Quarter Day,Quartalstag, +Quarter Day,Viertel-Tag, Query,Abfrage, Query Report,Abfragebericht, Query must be a SELECT,Abfrage muss ein SELECT sein, @@ -4793,3 +4793,17 @@ Reset to default,Auf Standard zurücksetzen, Column Width,Spaltenbreite, Choose Kanban Board,Kanban-Tafel auswählen, Create New Board,Neue Tafel erstellen, +Only If Creator,Nur wenn Ersteller, +Rebuild Tree,Baum neu aufbauen, +Customize Dashboard,Dashboard anpassen, +Reset Dashboard Customizations,Dashboard-Anpassungen zurücksetzen, +Add {0},{0} hinzufügen, +descending,absteigend, +ascending,aufsteigend, +Next Document,Nächstes Dokument, +Previous Document,Vorheriges Dokument, +Mark all as read,Alle als gelesen markieren, +See all Activity,Alle Aktivitäten anzeigen, +Go to Notification Settings List,Gehe zur Listenansicht Benachrichtigungseinstellungen, +Load more,Mehr laden, +Edit Full Form,Vollständiges Formular bearbeiten,