瀏覽代碼

Merge branch 'develop' into enable-further-translations

version-14
Shariq Ansari 2 年之前
committed by GitHub
父節點
當前提交
6a3e43789b
沒有發現已知的金鑰在資料庫的簽署中 GPG Key ID: 4AEE18F83AFDEB23
共有 14 個文件被更改,包括 111 次插入37 次删除
  1. +4
    -4
      .github/helper/roulette.py
  2. +7
    -9
      .github/workflows/linters.yml
  3. +1
    -1
      frappe/core/doctype/doctype/doctype.py
  4. +17
    -2
      frappe/core/doctype/file/file.py
  5. +23
    -2
      frappe/core/doctype/scheduled_job_type/scheduled_job_type.json
  6. +4
    -0
      frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
  7. +10
    -3
      frappe/core/doctype/system_settings/system_settings.json
  8. +16
    -6
      frappe/desk/reportview.py
  9. +5
    -3
      frappe/email/doctype/email_queue/email_queue.py
  10. +5
    -0
      frappe/model/db_query.py
  11. +2
    -2
      frappe/public/icons/timeless/icons.svg
  12. +1
    -3
      frappe/tests/test_db_query.py
  13. +15
    -1
      frappe/translations/de.csv
  14. +1
    -1
      frappe/utils/redis_wrapper.py

+ 4
- 4
.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)


+ 7
- 9
.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

+ 1
- 1
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:


+ 17
- 2
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}"


+ 23
- 2
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
}

+ 4
- 0
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 *",


+ 10
- 3
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",


+ 16
- 6
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


+ 5
- 3
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"""



+ 5
- 0
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("):


+ 2
- 2
frappe/public/icons/timeless/icons.svg 查看文件

@@ -613,8 +613,8 @@
<symbol viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" id="icon-expenses">
<path d="M17 16a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V2.37a.2.2 0 0 1 .31-.168l1.75 1.143a.5.5 0 0 0 .547 0L7.393 2.18a.5.5 0 0 1 .547 0l1.787 1.166a.5.5 0 0 0 .546 0L12.06 2.18a.5.5 0 0 1 .547 0l1.786 1.166a.5.5 0 0 0 .547 0l1.75-1.143a.2.2 0 0 1 .31.167V16z"
stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="square"></path>
<path d="M12.925 9.097l-.298 1.052h-.904c-.174 1.15-.997 1.986-2.748 2.093l2.787 3.413v.072h-1.556l-3.05-3.703-.01-.83H8.66c.938 0 1.53-.372 1.705-1.045H7.04l.298-1.052h2.992c-.196-.601-.737-.963-1.67-.963H7.04L7.351 7h5.578l-.302 1.061-1.343-.008c.222.298.367.652.43 1.044h1.211z"
fill="#192734" stroke="none"></path>
<path d="m13.13,8.1l-0.3,1.05l-0.91,0c-0.17,1.15 -0.99,1.98 -2.74,2.09l2.78,3.41l0,0.08l-1.55,0l-3.05,-3.71l-0.01,-0.83l1.51,0c0.94,0 1.53,-0.37 1.71,-1.04l-3.33,0l0.3,-1.05l2.99,0c-0.2,-0.6 -0.74,-0.97 -1.67,-0.97l-1.62,0l0.31,-1.13l5.58,0l-0.3,1.06l-1.35,-0.01c0.23,0.3 0.37,0.66 0.43,1.05l1.22,0z"
fill="var(--icon-stroke)" stroke="none"></path>
</symbol>

<symbol viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" id="icon-income">


+ 1
- 3
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


+ 15
- 1
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,

+ 1
- 1
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):


Loading…
取消
儲存